#############################################################
#
# CheatSheet
#
#############################################################


#############################################################
## Android
#############################################################

# Copy android files over the network (like myPhoneExplorer)
sudo apt install syncthing
syncthing

# Launch "My Files" on Android.
am start -n 'com.sec.android.app.myfiles/.external.ui.MainActivity'


#############################################################
## Apache
#############################################################

# Start apache server web pages
sudo apachectl start

# Check status of apache server web pages
apachectl status

# Show apache settings as in config files
httpd -S


#############################################################
## Apt Mark
#############################################################

# Prevent certain packages from ever automatically
# upgrading or being removed.
apt-mark hold apksigner


#############################################################
## ASM
#############################################################

# Compile, link, and run assembly program on windows
nasm -fwin64 hello.asm && gcc hello.obj -o hello.exe && hello.exe


#############################################################
## Batch - Conditions
#############################################################

# If statement in windows 10 DOS (windows 10, command prompt)
if exist "C:\Program Files\Git\usr\bin\perl2.exe" (echo FOUND) else (echo not found)

# Batch check if file/folder exists (windows,dos)
set folder=D:\my\ncfile\dev\assets
echo %folder%
IF EXIST %folder% (
	echo Yes;
	echo 123;
) ELSE (
	echo No;
	echo 456;
)

# If else statement in windows 10 DOS (windows 10, command prompt)
if "%val%" == "-1" (
	echo.
	echo Error: No tool provided! tool="%tool%"
	echo.
) else (
	if "%val%" == "-2" (
		echo.
		echo Error: Tool "%tool%" is not found in the PATH!
		echo.
	) else (
		echo.
		echo Info: %tool% Version: %val%
		echo.
	)
)


#############################################################
## Batch - Files
#############################################################

# Find all folders (directory)
dir E:\*.* /s /b /ad

# Recursively search through files
findstr /s /c cell *js


#############################################################
## Batch - Foreach Loop
#############################################################

# Windows 10 dos command prompt for each loop
for %a in (path-a, path-b, path-c) do (@echo %a)
#
# Use %%a inside a script (%a on the command line)
for %%a in (
		path-a,
		path-b,
		path-c
	) do (
	@echo "[%%a]"
)


#############################################################
## Batch - Functions
#############################################################

# It is necessary to "call" each inner batch script
# Otherwise only the first will run.
call myProgram1
call myProgram2

# Create and call a function (Windows,DOS,Functions)
call :my_func
call :my_func
goto :eof
::
:my_func
echo.
echo hey
echo.
exit /b

# Create and call a function with arguments (Windows,DOS,Functions)
call :my_func 1
call :my_func 2
goto :eof
::
:my_func
echo hey %1
exit /b

# Create and call a function with arguments (Windows,DOS,Functions)
# Remove quotes using %~1 syntax
call :my_func "1"
call :my_func "2"
goto :eof
::
:my_func
echo hey %~1
exit /b

# Return a value from a function (Windows,DOS,Functions)
call :my_func "1" val
echo val1: %val%
goto :eof
::------------------------------------------------
:: 				Functions Section
::------------------------------------------------
:my_func
echo hey %~1
set %~2=INFO
exit /b

# Local (my) variables in a function (Windows,DOS,Functions)
call :my_func "1" val
echo val1: %val%
echo key: %key%
goto :eof
::------------------------------------------------
:: 				Functions Section
::------------------------------------------------
:my_func
SETLOCAL
set key=not
echo hey %~1
set %~2=INFO
ENDLOCAL
exit /b

# Template (Windows,DOS,Functions)
:get_dir
::
SETLOCAL
set key=%1
set val=
::
for /f "tokens=*" %%a in ('perl get_setup.pl %key%') do set val=%%a
if "%val%" == "" (
	echo.
	echo Error: Cannot determine %key%!
	echo.
)
::
(ENDLOCAL & REM
	set "%~2=%val%"
)
goto :eof


#############################################################
## Batch - Shell Substitution
#############################################################

# Shell substitution in Windows
@echo off
for /f "tokens=*" %%A in ('perl -x -S -l %0 %*') do set my_path=%%A
echo Going to : %my_path%
cd %my_path%


#############################################################
## Batch - Strings
#############################################################

# Remove double quotes from a variable in dos (windows 10, command prompt)
set a="here is data"
set a=%a:"=%
echo %a%


# Split long commands unto multiple lines (windows 10)
long command^
can be split^
this this


#############################################################
## Batch - Terminal
#############################################################

# Change the title of the command prompt window
title MY_TITLE

# Change the dimentions/size of a commmand prompt window (length,width)
mode con: cols=80 lines=10

# Temporarily chang ethe command prompt language to english
set LANG=US

# Enable ANSI colors in Windows 10 using system '' (magic!?)
perl -E "system ''; say qq(\033[35mHEY\033[0m)"


#############################################################
## Bison/Flex Parsing (Regex)
#############################################################

# Good tutorial
https://aquamentus.com/flex_bison.html

# Simple Lexer
%{
	#include <iostream>
	using namespace std;
	extern int yylex();
%}
/*
	Compile:
		win_flex --outfile=mylex.cpp --wincompat my.l && ^
		g++ mylex.cpp -o my.exe
	Run:
		echo "this is test 123" | my.exe
*/
%option noyywrap
%%
[ \t\n]
[0-9]+\.[0-9]+		{ cout << "Float:  " << yytext << endl; }
[0-9]+				{ cout << "Number: " << yytext << endl; }
[A-Za-z0-9]+		{ cout << "String: " << yytext << endl; }
.		     		{ cout << "Any:    " << yytext << endl; }
%%
int main (int argc, char **argv) {
	while( yylex() );
	return 0;
}

# Info (flex,bison,parse,regex)
# Flex (and Bison) use a Determinitistic Finite Automata (DFA) regex engine.
# Notes on this engine:
#  1. No look arounds (for the most part). These is LALR and GLR.
#     a. LALR - Look Around Left Right with one character of look ahead.
#        Faster.
#     b. GRL  - General Left Right. Slowly but more powerful.
#  2. If multiple patterns can match a string selected pattern (winner) is:
#     a. Longest string.
#        This means that the order of the pattern does not matter. can do this
#        and "CMD" will instead of just "C":
.        {...}
CMD      {...}
#     b. Leftmost if multiple patterns of the same length.
#        That is why the last pattern should be a simple dot otherwise it may
#        match when not intended. plus very hard to detect this bug.
#  3. Use quotes for literal strings
"CMD"
#  4. Flex patterns return tokens that bison can use.
#     - yytext contains the actual value/string found.
#     - yylval.sval will be carried over to bison if a value is needed.
#  5. Dollar variable ($1..$n) are the values of the tokens
#     - Numbering includes actions. $1=CORRUPT $3=CMD below
CORRUPT  {cout << "CORRUPT" << endl; }
CMD      {cout << "CMD"     << endl; }
#     - Do not use actions in between $1=CORRUPT $2=CMD
CORRUPT CMD

# Ignore case for the whole parser (flex,bison,parse,regex)
%option case-insensitive

# Left hand side value (flex,bison,parse,regex)
# Acts like a variable that contains the semantic value
# for the grouping made by the current rule.
$$

# Step:1 Add this to file count.l (flex,bison,parse,regex)
%{
int chars = 0;
int words = 0;
int lines = 0;
%}
%%
[a-zA-Z]+ { words++; chars += strlen(yytext); }
\n        { chars++; lines++; }
.         { chars; }
%%
main(int argc, char **argv)
{
   yylex();
   printf("%8d%8d%8d\n", lines, words, chars);
}

# Step:2 Build (flex,bison,parse,regex)
# -lfl means to compile using the flex library
flex count.l
gcc lex.yy.c -lfl -o wc2
cat count.l | wc2

%{
#include <iostream>
using namespace std;
#define YY_DECL extern "C" int yylex()
%}
%%

# Step:1 Add this to file look.l (flex,bison,parse,regex,OMS)
[ \t\n]     ;
[0-9]+\.[0-9]+    { cout << "Found a float: " << yytext << endl; }
[0-9]+            { cout << "Found an int:  " << yytext << endl; }
[a-zA-Z0-0]+      { cout << "Found a string: " << yytext << endl; }
%%
int main(int, char **)
{
   yylex();
}

# Step:2 Build (flex,bison,parse,regex,OMS,compile)
# Make a makefile with this
look : *.c
   g++ $^ -lfl -o $@

*c : *.l
   flex $^

# ERROR: lex.yy.c:(.text+0x6a6): undefined reference to `yywrap' (flex,bison,parse,regex)
# Do one of these:
#  1. Add "%option noyywrap" to flex file
#  2. Add flex library "-lfl" to makefile

# WARNING: rule never reduced because of conflicts (flex,bison,parse,regex,OMS)
bison -v my.y
vi my.output

# Useless nonterminals (flex,bison,parse,regex,OMS)
# Target not used in bison file
debug : ...
# But debug never got used

# Terminals which are not used (flex,bison,parse,regex,OMS)
# Terminal or TOKENs from flex that are not used.

# Match the end-of-file in Flex (flex,bison,parse,regex,OMS)
<<EOF>>

# Character class difference in flex (flex,bison,parse,regex)
[a-z]{-}[aeiou]

# States conditions (flex,bison,parse,regex)
%x eXclusive_state
%s inclusive_state
# %x means that only rules prefixed with the state name will be active when
#  the scanner is in that state (think of %x as meaning eXclusive).
# %s means that both rules prefixed by the state name and rules with no state names
#  will be active when the scanner is in that state (%s means inclusive, as
#  in including states active in the INITIAL state).

# Start a new state (flex,bison,parse,regex)
BEGIN(eXclusive_state);

# Return to original state (flex,bison,parse,regex)
# Stop state
BEGIN(INITIAL);
yylex_destroy();     # in cwrapper();

# View current state level (flex,bison,parse,regex)
{cout << YYSTATE << endl; }

# Convert hex to decimal in c code (flex,bison,parse,regex,c_code)
yylval.ival = strtol(yytext,NULL,0)

# Notes on using strdup (flex,bison,parse,regex)
# Used due to possible bison/flex bugs in string management.
#
# Note that whenever lookup makes a new entry, it calls strdup to make a copy of the
# string to put into the symbol table entry. Flex and bison programs often have hard-to track
# string storage management bugs, because it is easy to forget that the string in
# yytext will be there only until the next token is scanned.

# /*--------------------------------------------------------------------------------------------------------
#
#    TVP - 3/8/2018
#    Notes on using state conditions in Bison/Flex:
#
#       - States tell the parser to allow certain patterns and actions.
#          <MY_STATE_1>pattern             { action; }
#          <MY_STATE_2>pattern             { action; }
#
#       - By default all patterns without an explicit state are in state "INITIAL" (value of 0).
#         (This means all patterns are allowed to be used by default).
#          pattern                         { action; }
#          <INITIAL>pattern                { action; }        // same thing
#
#       - A pattern can be used in multiple states by separating each state with a comma ","
#          <STATE_1,STATE_2>pattern        { action; }
#
#       - View a state number (depth) with YYSTATE
#          [ ]+                            {cout << YYSTATE << endl; }         // Print the state number when a space is entered.
#
#       - A excellent example of using states is parsing a "C" file with comments:
#          / *                             { BEGIN(COMMENT); }    // Start reading comments
#          <COMMENT>[NOT_COMMENT_GOES_HERE]+ { action; }          // Anything inside the comment
#          * /                             { BEGIN(INITIAL); }    // Stop reading comments
#
#       - Use BEGIN to select a state.
#          / *                             { BEGIN(COMMENT); }
#
#       - Use BEGIN(INITIAL) or possibly BEGIN(0) to reset to the starting state (which is called INITIAL)
#          * /                             { BEGIN(INITIAL); }
#
#       - States come in two flavors:
#
#          %x eXclusive
#             Only rules prefixed with the state name will be active when the scanner is in that
#             state (think of %x as meaning eXclusive).
#
#          %s inclusive
#             Both rules prefixed by the state name and rules with no state names will be active when the
#             scanner is in that state (%s means inclusive, as in including states active in the INITIAL state)
#             This is useful for a special state that is off by default (such as debug).
#
#       - End Of File (EOF) or end of line/string can be found with <<EOF>>
#          <<EOF>>                         { action; }
#          <MY_STATE><<EOF>>               { action; }             // EOF can be limited to certain states
#          <INITIAL,MY_STATE><<EOF>>       { action; }             // Causes infinite loop !!!
#          <MY_STATE><<EOF>>               { BEGIN(INITIAL); }     // Return to INITIAL at end of string
#
#          That last line is very useful for clearing the state back to INITIAL, but every state
#          (excluding INITIAL) would need to be mentioned like this (due to a possible bug):
#          <STATE_1,STATE_2,STATE_3 ... ,STATE_N><<EOF>> { BEGIN(INITIAL); }
#
#          It is therefore more convenient that the parser host (that is cwrapper.cpp) were to perform
#          a more thorough purging after utilizing the parser by executing the function yylex_destroy()
#
# --------------------------------------------------------------------------------------------------------*/

# Test yacc program to take .y file and convert it into a parsing file (OMS,parse,regex)
cat <HERE >my.y
%token A B C D E
%%
list: A B C
   | de
de : D E
HERE


#############################################################
## C,CPP General
#############################################################

# View where a c code function is defined (Symbol table,OMS)
nm file -l 2>/dev/null
080fb204 T function
0804fa75 T function2   file:123
# T - The symbol is in the text (code) section
# Uppercase means global (external)

# View strings in a binary file
strings <file>

# Turn c code into assembler code
objdump -d <bin_file>

# In C code, pointers and arrays are closely related:
int var[] = {10, 100, 200};
int *ptr = var;
# &ptr is bfbab19c
# &var is bfbab1a0
# ptr is bfbab1a0
# var is bfbab1a0
# &ptr[0] is bfbab1a0
# &var[0] is bfbab1a0

# In C code, array name, address of array name, and
# address of first array element are all the same
var     is bffddf20
&var    is bffddf20
&var[0] is bffddf20

# Array of pointer in c code
# Array of strings
char *name[] = {
   "name1",
   "name2",
   "name3",
   "name4",
   "name5",
   "name6",
};

# Read from the command line in c code
int main(int argc, char *argv[])

# Process command line inputs in c code
#include<stdio.h>
int main(int argc, char *argv[]){
   int i;
   for(i=0; i<argc; i++){
      printf("argv[%d]: %s\n", argc, argv[i]);
   }
   return(0);
}

# Get ascii and characters in c code (DES)
printf("d:%d c:%c\n", 'A', 'A');

# Rename the oms trace files
ls -1 | perl -lpe '$o=$_; s/_[c0][a-z0-9]*_\d+//; rename $o => $_'

# Call C++/CPP function from C Step 1(OMS)
# Put code inside:
#ifdef __cplusplus
# // c++ code goes here
#endif

# Call C++/CPP function from C Step 2(OMS)
# Make external the function
extern "C" void my_func(void);

# Macro function in c code (OMS,bison,flex)
#define DEBUG 1
#define PRINT_IN_DEBUG(token) if(DEBUG){ cout << "   Flex saw [" << yytext << "] (" << token << ")" << endl; }

# Use value from a string.
# Convert "std:string" to "const char *"
std::string name
name.c_str()

# Convert "std:string" to "char *"
std::string name
&name[0u]

# Read lines from a file (c program)
char *file_name = strcat(name, ".cmd");
char line[512];
FILE *fp;
fp = fopen(file_name, "r");
if(fp == NULL)
{
   sendlog("ERROR: Could not open file: '%s'", file_name);
   return 1;
}
while (fgets( line, sizeof(line), fp ) != NULL)
{
   line[strlen(line) - 1] = '\0';
   sendlog("Line1: '%s'", line);
   yyParseAndExecute( line );
}

# The -m32 flag is necessary for both compiling and linking (gcc,DES)

# Sample C program. Prints to STDOUT and STDERR
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
	fprintf(stderr, "Select folder:\n");
	fprintf(stderr, "1 C:\\TOOLS\n");
	fprintf(stderr, "2 C:\\BAT\n");
	printf("C:\\TOOLS\n");
	fprintf(stderr, "3 C:\\BAT2\n");
	return 0;
}

# Fix Error: forbids converting a string constant to 'char*'
argv[1] = (char *) "name = bob";


#############################################################
## C,CPP Asynchronous (Threads)
#############################################################

# Run a process/function async (thread)
# Add this to makefile
LIB += -pthread
#
# Add library
#include <pthread.h>
#
# Declare threads
pthread_t threads[1];
#
# Create threads and get return code
# Sending pattern as parameter (only one allowed)
# Thread ID is first parameter
int rc;
rc = pthread_create(&thread, NULL, send_thread, (void *) pattern  );
pattern->tid = thread;     // Save thread ID so we can later kill it (if needed)
if(rc) return;             // Error
#
# Check return value
if(rc) sendlog("ERROR: return code from pthread_create() is %d", rc);
#
# Function is declared like this:
void *send_thread (void * args){
   COMMAND_PATTERN* pattern = (COMMAND_PATTERN*) args;  // Can use pattern normally
   ...
}
#
# Make sure to end the function with this:
# (it will exit the thread. don't use in main otherwise will get defunct/zombie process)
pthread_exit(NULL);

# Determine version and library used for threads
# NPTL - Native POSIX Threads Library     # Threads share PID
# LinuxThreads                            # May be different PIDs (plus may other differences)
getconf GNU_LIBPTHREAD_VERSION            # NPTL 2.7


#############################################################
## C,CPP - Debug
#############################################################

# Sleepy poll (debug,ddd,gdb,break)
# How to debug a progam
# Then after getting in using ddd, set wait_variable=0
int wait_variable = 1; while (wait_variable) sleep(1);

# Debug a UI program (DES,UI)
# Flags after --args are passed to the program
gdb progarm --args arg1 arg2

# Debug a c program given its pid (DES,UI)
gdb --pid 21620
gdb --pid `myps | grep snv | grep -v grep | awk '{print $4}'`

# gdb debugger navitation (commands,DES,UI)
(gdb) l[ist]              # view code
(gdb) l[ist] main         # view main code
(gdb) b[reak] main        # Put a breakpoint at main()
(gdb) r[un]               # start the program
(gdb) h[elp] all          # View all help sections
(gdb) f[rame]             # Show current line (line number and file)
(gdb) c[ontinue]          # Continue to a breakpoint
(gdb) d[elete]            # Delete all breakpoints

# View all functions in ddd (gdp,debugger)
info functions

# View entry point of executable program (OMS)
readelf -h omsGUI | grep "Entry point address"
# was: 0x80524a0
ddd <pid>
att <pid>
b * 0x80524a0
c

# Problem: Debugger (ddd,gdb) is ignoring my breakpoint and
#          moving unto another function
# Answer:  Add this line inside the function you want to breakpoint
# Note:    Causes a segmentation fault SIGSEGV
*(char*)0 = 0;

# Set outer variable in bash shell (hack)
a=123; (gdb --batch-silent -ex "attach $$" -ex 'set bind_variable("a", "456", 0)'); echo $a


#############################################################
## C,CPP - Errors
#############################################################

# Error: Illegal deallocation of memory
//
// my.c:
//		#include <stdio.h>
//		#include <stdlib.h>
//		#include <string.h>
//
//		int main(int argc, char ** argv){
//			char * str;
//
//			if (argc>1) {
//				str = (char *) malloc(10);
//			}
//
//			printf("Str: %s\n",str);
//			free(str);
//
//			return 0;
//		}
//
// MAKE.bat
g++ my.c -o my.exe

# Try Catch in Cpp
# No throw means no catch
//
#include <iostream>
using namespace std;
int main(int,char**){
	int n = 10;
	int m = 0;
	try {
		// if( m == 0 ) throw "Division by zero condition!";
		int val = n / m;
		cout << "Divided: " << val << endl;
	}
	catch (...){
		cout << "Caught error" << endl;
	}
	cout << "DONE" << endl;
	return 0;
}

# Nested Try Catch in Cpp
# No throw means no catch
//
#include <iostream>
using namespace std;
int main(int,char**){
	int n = 10;
	int m = 0;
	int val;
	try {
		try {
			if( m == 0 ) throw "Division by zero condition!";
			val = n / m;
			cout << "Divided: " << val << endl;
		}
		catch (runtime_error& e){ cout << "Caught inner error1" << endl; }
		catch (out_of_range& e) { cout << "Caught inner error2" << endl; }
	}
	catch (...){ cout << "Caught outer error" << endl; }
	cout << "DONE" << endl;
	return 0;
}


#############################################################
## C,CPP - File Handles
#############################################################

# Open a file in CPP. This ensures the file exists.
MY_FILEHANDLE.open(SMART_FILE_PATH, std::ios::in | std::ios::out | std::ios::app);
MY_FILEHANDLE.close();
MY_FILEHANDLE.open(SMART_FILE_PATH, std::ios::in | std::ios::out);


#############################################################
## C,CPP - Header Files
#############################################################

# Missing sys/cdefs.h header file (DES,library)
sudo apt-get install libc6-dev-i386

# Missing curses.h 32 bit (DES,library)
sudo apt-get install lib32ncurses5-dev

# Missing readline/history.h header file (DES,library)
sudo apt-get install libreadline-dev

# Missing libelf.h header file (DES,library)
sudo apt-get install libelf-dev libelfg0

# Missing dwarf.h header file (DES,library)
sudo apt-get install libdwarf-dev

# Missing y.tab.h header file (DES,library)
sudo apt-get install byacc bison flex


#############################################################
## C,CPP - Functions
#############################################################

# Define a pure virtual function (OMS,cpp)
# It must be overriden/inherited in a derived class
virtual void func( int option, int count, int start_bit, int end_bit) = 0;


#############################################################
## C,CPP - Map
#############################################################

# std::map to std::string conversion in cpp
std::string column_names_new = "";
int count = 0;
for (auto const& item : map_column_names) {
	std::string key   = item.first;
	std::string value = std::to_string(item.second);
	std::string delim = count++ ? "," : "";
	column_names_new += delim + key + ":" + value;
}

# Loop through std::map
for (auto &set : myMap)
{
	std::string key = set.first;
	std::string val = set.second;
}


#############################################################
## C,CPP - Regex
#############################################################

# Cpp check if regex is empty
if (!matches[2].str().empty())
	table = matches[2];

# Simple program to use/test regular expressions in cpp
//
#include <iostream>
#include <string>
#include <regex>
using namespace std;
int main(){
	std::string str = "/tooltypes.html/table=1";
    std::smatch matches;
    std::regex_search( str, matches, std::regex("table=([01])") );
    for(auto val: matches)
        cout << val << endl;
	return 0;
}

# There are 2 main matching functions (cpp,regex)
	- std:regex_match	// Match the whole string /^ string $/
	- std:regex_search	// Match a partial string /  string  /

# Check for the existence of a string (cpp,regex)
if(std::regex_search(line, std::regex("^\\s*#")))
	continue;

# Cpp regex substitution (replace)
// Remove invalid characters
timestamp = std::regex_replace(timestamp, std::regex("\\W+"), "-");
//
// Remove leading and/or trailing dashes if any
timestamp = std::regex_replace(timestamp, std::regex("^-+"), "");
timestamp = std::regex_replace(timestamp, std::regex("-+$"), "");

// Loop through all matches in cpp (like /(\w+)/g in perl)
std::string body = "";
std::string info = "uname='NAME', version='VERSION'";
std::regex hasKeyVal("(\\w+)='([^']*)'");
std::sregex_iterator it = sregex_iterator(info.begin(), info.end(), hasKeyVal);
while(it != std::sregex_iterator()) {
	std::smatch match = *it;
	std::string key   = match.str(1);
	std::string value = match.str(2);
	cout << "key: "   << key   << endl;
	cout << "value: " << value << endl;
		it++;
}

# Thread safe and not safe regeular expressions in Qt (Cpp Qt Regex)
// Declare
#include <QRegularExpression>
#define THREAD_SAFE_REGEX
#ifdef THREAD_SAFE_REGEX
    QRegularExpression MoveCheckRegex;
#else
    QRegExp *MoveCheckRegex=nullptr;  //constant one high performance
#endif

# Thread safe and not safe regeular expressions in Qt (Cpp Qt Regex)
// Definition
#ifdef THREAD_SAFE_REGEX
    MoveCheckRegex.setPattern("(?=^[ABCFGIJKNXYZ\\d][\\d +-])((?:N?[\\s0-9]+)?(?:G[0123]{1,2})?(?:(?:[XYFZNABCIJK\\s]{1,2})(?:[0-9.\\s+-])+)+)");
#else
    MoveCheckRegex = new QRegExp(QString("(N?[\\s0-9]+)?(G[0123]{1,2})?(([XYFZNABCIJK\\s]{1,2})([0-9.\\s+-])+)+"));
#endif

# Thread safe and not safe regular expressions in Qt (Cpp Qt Regex)
// Usage
#ifdef THREAD_SAFE_REGEX
    // QRegularExpressionMatch match = MoveCheckRegex.match(line);
    // if  (match.hasMatch())
    // {
    //     if (match.capturedLength()==line.length()) return true;
    // }
    if(MoveCheckRegex.match(line).hasMatch()) return true;
#else
    if  (MoveCheckRegex->indexIn(line)>=0)
    {
        if (MoveCheckRegex->matchedLength()==line.length()) return true;
    }
#endif

# Thread safe and not safe regeular expressions in Qt (Cpp Qt Regex)
// Cleanup
#ifdef THREAD_SAFE_REGEX
#else
    delete MoveCheckRegex;
#endif


#############################################################
## C,CPP - Shared Libraries (.so)
#############################################################

# Difference between .so and .a (DES)
.a    - current ar archive
         Static library.
.so   - dynamically linked    (dll on Windows)
         Linked only when needed.
         Reduces size of executable.

# Step:1 Compile with Position Independent Code (PIC,shared library)
gcc -c -Wall -Werror -fpic foo.c

# Step:2 Create a shared library from an object file
gcc -shared -o libfoo.so foo.o

# View contents of a shared library (files)
ldd libfoo.so

# Step:3 Linking with a shared library
gcc -Wall -o tool main.c libfoo.so
gcc -Wall -o tool main.c -lfoo -L.

# Step:4 Making the library available at runtime
# Will normally get warning "cannot open shared object file"
./tool
#
# Option_1: Fix that by telling the loader (ld) where your file is located
# Can be done even if -rpath used was a different path
export LD_LIBRARY_PATH=~/<USER>/pad/c    # Either one
export LD_LIBRARY_PATH=$PWD
export LD_LIBRARY_PATH=.              # Always in same place as tool
#
# Option_2: Fix that by using -rpath
gcc -Wall -o tool main.c -lfoo -L. -Wl,-rpath=$PWD

# View system shared libraries
ldconfig -p

# Update the cache to the system shared libraries
sudo ldconfig
#
# Place your .so file if you want everyone to use it:
cd /usr/lib          # Or
cd /usr/local/lib

# View unsued shared library symbols
ldd -r tool

# View the dynamic sections of a shared library. (.so)
# Shows RPATH which is the path to the library (per design).
# This is the private header information.
objdump -p tool


#############################################################
## C,CPP - Signals
#############################################################

# Syntax for connect
connect(sender_object, &sender_object::signal, receiver_object , &receiver_object::slot);


#############################################################
## C,CPP - Socket Programming
#############################################################

# Protocol families, same as address families (socket)
vii /usr/src/linux/include/linux/socket.h:204
#define PF_INET      AF_INET

# Client address given a request (c,cpp)
const HTTPServerRequest &request
auto clientAddress = request.clientAddress().host().toString();


#############################################################
## C,CPP - Static Archive Library (.a)
#############################################################

# View contents of an archive library
# "Tell me"
ar -t  libOmsFilter.a
ar -tv libOmsFilter.a

# Add new files to archive
ar -rv libMy.a 1.o 2.o

# Show verbose messages (info)
ar -rv libMy.a 1.o

# Append to archive (no duplicates)
# "Read-in"
ar -rv libMy.a 1.o
ar -rv libMy.a 2.o
ar -rv libMy.a 3.o

# Append to archive (allow duplicates)
ar -qv libMy.a 1.o
ar -qv libMy.a 1.o
ar -qv libMy.a 1.o

# Delete a member from an archive
ar -dv libMy.a 1.o

# Checkout a member from an archive
# "Extract" (but still stays in archive)
ar -xv libMy.a 1.o

# Insert after 1.o (order,archive)
ar -rav 1.o libMy.a 3.o 4.o 5.o
#
# Order is not quite expected since the insert location
# is constant ("|" below).
# 1.o | 5.o 4.o 3.o 2.o

# Update a member of an archive of if a newer file exists
ar -ruv libMy.a 1.o

# Alternate syntax to link to an archive library
-lABC          # looks for libABC.so, then for libABC.a
-l:libABC.a    # Looks for libABC.a (more explicit, but simplier)


#############################################################
## C,CPP - String
#############################################################

# Convert anything to a string in cpp using string streams (DWORD,int)
#include <string>
#include <sstream>
if(it->GetName() == L"MyProg.exe"){
	std::stringstream ss;
	ss << "taskkill /T /F /PID " << it->GetPID();
	std::string command = ss.str();
	system(command.c_str());
}

# String comparison breakpoint in Visual studio
strcmp(static_cast<const char *>(name),"place_absolute")==0

// In cpp split a string by a delimeter and put the contents into a map (or vector)
std::map<std::string, int> map_column_names;
std::istringstream ss(default_columns);
std::string token;
while (std::getline(ss, token, ',')) {
	map_column_names[token] = 1;
}

# Convert a float to an integer in cpp.
int myInt = static_cast<int>(myFloat);

# Check if a string is NOT found in a vector in cpp
# This returns a bool (true if present, false otherwise)
#
if ( std::find(vec.begin(), vec.end(), item) == vec.end() )
   do_this();
else
   do_that();

# Cpp double to string conversion
std::string makeTime = std::to_string(time_span.count());

# Cpp uses floor() to get the integer part of a float.
# like int() in perl.
# ceil() returns the smallest integer, but rounding up.
#
# ceil did not for so used this instead:
int total_pages = (amount + tool_limit - 1) / tool_limit;

# Cpp std::string for const char *
string myStr;
myStr.c_str();

# Raw string in CPP. Do not need to escape characters.
# R"ABC(TEXT)ABC";
#
R"sql(CREATE TABLE IF NOT EXISTS version (
	version INTEGER
);)sql"


#############################################################
## C,CPP - Templates
#############################################################

# Function Template example in Cpp
// Make a generic to_string function to convert anything to a string
//
#include <string>
#include <sstream>
//
template <typename T>
std::string to_string (T data) {
	std::stringstream ss;
	ss << data;
	return ss.str();
}


#############################################################
## C,CPP - Threads
#############################################################

# Get the current thread's name (like thread ID, tid)
QThread::currentThread()->objectName()


#############################################################
## C,CPP - Timer
#############################################################

# Timer in Cpp
#
#include <ctime>
#include <chrono>
std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now();
// run something
std::chrono::high_resolution_clock::time_point t2 = std::chrono::high_resolution_clock::now();
std::chrono::milliseconds rawTime = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1);
std::string stringTime = std::to_string(rawTime.count());

# Timer in Cpp (simpler)
#
#include <ctime>
#include <chrono>
//
typedef std::chrono::high_resolution_clock Time;
typedef std::chrono::milliseconds ms;
//
auto t1 = Time::now();
auto t2 = Time::now();
std::string runTime = std::to_string(std::chrono::duration_cast<ms>(t2 - t1).count());

# Timer in Cpp (as a function)
#include <ctime>
#include <chrono>
//
std::string elapsedTime(std::chrono::high_resolution_clock::time_point t1)
{
	auto t2 = std::chrono::high_resolution_clock::now();
	std::string duration = std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count());
	return duration;
}
//
auto t1 = std::chrono::high_resolution_clock::now();
// code ...
std::string generateTime = elapsedTime(t1);


#############################################################
## C,CPP - Vector
#############################################################

# Example vector in cpp
//
std::vector< std::tuple<std::string, std::string> > get_vector () {
	std::ofstream *file = nullptr;
	std::ofstream file2;
	// file->open("MAKE2.txt");
	file2.open("MAKE2.txt");
//
	std::vector< std::tuple<std::string, std::string> > myVector;
//
	myVector.push_back( std::make_tuple("test1", to_string(file)   ));
	myVector.push_back( std::make_tuple("test2", to_string(&file2) ));
	myVector.push_back( std::make_tuple("test3", to_string("125")  ));
	myVector.push_back( std::make_tuple("test4", to_string(1.3)  ));
	myVector.push_back( std::make_tuple("test5", to_string(&file2) ));
	myVector.push_back( std::make_tuple("test6", to_string("126") ));
//
	return myVector;
}

# Print the elements of a cpp vector
//
#include <string>
#include <vector>
#include <tuple>
void show_vector ( std::vector< std::tuple<std::string, std::string> > myVector ) {
	for(auto &vec : myVector){
		std::cout << "vec: " << std::get<0>(vec) << ", " << std::get<1>(vec) << std::endl;
	}
}

# Find duplicate values in a cpp vector using a mapping table
//
#include <string>
#include <vector>
#include <tuple>
#include <map>
void show_duplicates ( std::vector< std::tuple<std::string, std::string> > myVector ) {
	std::map<std::string, int> myMap;
	for(auto &vec : myVector){
		auto test_name = std::get<0>(vec);
		auto address   = std::get<1>(vec);
		if(myMap.count(address)){
			std::cout << "vec: " << test_name << ", " << address << std::endl;
			std::cout << "	* Seen address already!" << std::endl;
		}
		myMap[address]++;
	}
}

# Join the contents of a std::vector into a string (cpp)
std::string str = "";
for (int i=0, end=vec.size(); i<end; i++) {
	str += (i ? ", " : "");
	str += vec[i];
}

# Join the contents of a std::map into a string (cpp)
// Build a json string of the possible names
std::string sJson = "{";
int count = 1;
int size = mNames.size();
for (auto &item : mNames)
	sJson += "\"" + item.second + "\": \"" + item.first + "\"" + ( (count++ == size) ? "" : ",");
sJson += "}";
return sJson;

# Read a space delimited/separated file into a vector (cpp)
//
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <tuple>
#include <sstream>
#include <regex>
//
std::vector<std::tuple<std::string, std::string>> file_to_vector (std::string file_path) {
//
	std::vector<std::tuple<std::string, std::string>> vec;
	std::ifstream file(file_path);
	std::string line;
//
	while (std::getline(file, line))
	{
		// Skip comment lines
		if(std::regex_search(line, std::regex("^\\s*#")))
			continue;
//
		// Skip blank lines
		if(std::regex_search(line, std::regex("^\\s*$")))
			continue;
//
		std::stringstream  ss(line);
		std::string        str1;
		std::string        str2;
//
		ss >> str1;
		ss >> str2;
//
		vec.push_back({str1,str2});
	}
//
	return vec;
}

# Cpp check if map key exists(is found)
if (m_query_parameters.count("get_state")) {
	body = "STRING";
}

# Check if a string is found in a vector in cpp
# This returns a bool (true if present, false otherwise)
#
#include <algorithm>
#include <vector>
if ( std::find(vec.begin(), vec.end(), item) != vec.end() )
   do_this();
else
   do_that();
#
# Or this way
#include <map>
if (map.find(item) != map.end())
   do_this();
else
   do_that();

# Cpp string to std::vector function
std::vector<std::string> stringToVector(std::string myString)
{
	std::vector<std::string> myVec;
	std::istringstream ss(myString);
	std::string token;
	while (std::getline(ss, token, ','))
        myVec.push_back(token);
	return myVec;
}

# Cpp working with vectors and tuples (arrays)
std::vector<std::tuple<std::string, std::string, std::string>> possibilities_vec;
possibilities_vec.push_back(std::make_tuple( row.get_string(0), row.get_string(1), row.get_string(2) ));
body += "\n\n// options:";
for (auto &val : possibilities_vec)
	body += "\n//   " + std::get<0>(row) + " " + std::get<1>(row) + " " + std::get<2>(row);

# Check if a vector is empty (cpp)
if (Vector.empty()) { /* operations */ }

# Cpp int to string (toString)
to_string(USE_DISPLAY_NONE)

# Cpp check if a value is defined (not null)
std::string Renderer::renderTable(const std::string &module, const std::string *id /*= nullptr*/)
if (id != nullptr)
//
// declared here
std::string renderTable(const std::string &module, const std::string *id = nullptr,
	const std::string *useDisplayNone = nullptr, const std::string *useTablePush = nullptr); // TODO: added for debug


#############################################################
## Cmake
#############################################################

# Exit from cmake
return()

# Print a message in cmake
message( "PROJECT_NAME: ${PROJECT_NAME}" )

# Assign variable in cmake
set(GENERATE_OUTPUT_DIR "${CMAKE_BINARY_DIR}/src_generated/")

# Remove files from a folder using cmake
file(GLOB REMOVE_FILES "${CMAKE_BINARY_DIR}/*")
message("REMOVE_FILES: ${REMOVE_FILES}")
file(REMOVE_RECURSE ${REMOVE_FILES})

# Include submodules in *.cmake
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/tools/cmake")
include(macros_internal)
include(macros_public)

# Minimal cmake example (step0)
# Copy into CMakeLists.txt
#
cmake_minimum_required(VERSION 3.10)
#
# set the project name
project(Tutorial VERSION 1.0)
#
# After assigned project, PROJECT_SOURCE_DIR is set
message("")
message("PROJECT_NAME:       ${PROJECT_NAME}")
message("PROJECT_SOURCE_DIR: ${PROJECT_SOURCE_DIR}")
message("PROJECT_BINARY_DIR: ${PROJECT_BINARY_DIR}")
message("")
#
# Add an executable to the project using the specified source files.
add_executable(Tutorial tutorial.cxx)

# Minimal cmake example (step0)
# Copy into tutorial.cxx
#
#include <iostream>
int main(int argc, char* argv[])
{
    std::cout << "Hello CMake" << std::endl;
    return 0;
}

# Building with cmake (step0)
mkdir build
cd build
cmake ..
cmake --build .


#############################################################
## Chrome
#############################################################

# Jump to address bar in Chrome (url,pi)
Control + L

# View source code in Android chrome browser
view-source:MY_URL

# Audit the speed of a website using the Google Chrome extension Lighthouse.

# Enable "Smooth Scrolling" in Chrome
chrome://flags/
Enable: #smooth-scrolling
#
# Does not appear to make a difference on the pi.

# View chrome case information (debug)
chrome://net-internals

# Force Chrome to reload the website and not use the cache (page,renderStatic)
Control + F5

Open the previous page from your browsing history in the current tab (Chrome)
Alt + Left arrow

# Allow running local files in Chrome on Windows 10
# Close all Chrome windows
cd "C:\Program Files (x86)\Google\Chrome\Application"
chrome.exe --allow-file-access-from-files

# Chrome Full Screen Mode
F11

# Create a link in the console which can be opened in the browser (hyperlink,terminal)
using Control+Click
file://absolute_path

# Install Chrome on Ubuntu
#
# Add Key:
wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
#
# Set repository:
echo 'deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main' | sudo tee /etc/apt/sources.list.d/google-chrome.list
#
# Install package:
sudo apt-get update
sudo apt-get install google-chrome-stable


#############################################################
## CSS - Anchor
#############################################################

# CSS to keep an element anchor on the top side
    position: absolute;
    top: 15%;


#############################################################
## CSS - Blur
#############################################################

# Blur/Unblur (CSS,style)
# blanket is a direct child of body
function blur () {
    document.querySelector("#blanket").className = "overlay";
}
function unblur () {
    document.querySelector("#blanket").className = "";
}
.overlay{
  position: absolute;
  width: 100%;
  height: 100%;
  z-index: 10;
  background-color: rgba(0,0,0,0.5); /*dim the background*/
}


#############################################################
## CSS - Box
#############################################################

# Create an empty (check) box using CSS
h1::before {
    border: 2px solid black;
    width: 1rem;
    height: 1rem;
    content: "";
    box-sizing: border-box;
    display: inline-block;
    border-radius: 15%;
    margin-right: 1rem;
}


#############################################################
## CSS - Center
#############################################################

# Center a child of unknown width and height (CSS,style)
# both vertically and horizontally
.parent {
 	position: relative;
}
.child {
  	position: absolute;
  	top: 50%;
  	left: 50%;
  	transform: translate(-50%, -50%);
}


#############################################################
## CSS - Debug
#############################################################

# Show the element placement/postion (css,color)
# Debug html/table
* { border: 1px dashed blue }


#############################################################
## CSS - Display
#############################################################

# Content inside an element is shown vertically. (CSS)
# This will make it be horizontal (spread out).
display: contents;


#############################################################
## CSS - Flex
#############################################################

# Vertically align elements inside a container (CSS,style)
.container {
  display:     flex;
  align-items: center;
}


#############################################################
## CSS - Force
#############################################################

# Force a style even though there is a longer (more specific one) (CSS Style)
#details .failed_validation {
  background-color: #ff5050 !important;
}


#############################################################
## CSS - Grid
#############################################################

# Avoid having to always set the grid-template-columns by using (HTML,section)
grid-auto-rows: min-content;


#############################################################
## CSS - Orientation
#############################################################

# Differentiate between portrait and landscape mode (PC versus PI,CSS styles)
//
#main {
  width:    -webkit-fill-available;
  height:   91%;
  position: relative;
}
@media all and (orientation:landscape) {
  #main {
    height:   100%;
  }
}


#############################################################
## CSS - Progress Bar
#############################################################

# Create a progress bar in HTML (css)
background: linear-gradient(90deg, rgb(40, 135, 20) 59%, rgb(129, 199, 132) 0);


#############################################################
## CSS - Readonly
#############################################################

# Readonly checkboxes (HTML)
# Use the attribute "disabled" to make a checkbox readonly
# Both "readonly" and "disabled" work with other elements like "select".
# Note: "readonly" form elements make show up when serialized.
#       "disabled" form elements will not show up when serialized.


#############################################################
## CSS - Scroll
#############################################################

# Make sure an element is seen when scroll (without using the mouse,javascript)
document.querySelector("#id").scrollIntoViewIfNeeded(true);


#############################################################
## CSS - Selectors
#############################################################

# "*" - Universal selector (CSS,Basic selectors)
# Selects all elements. Optionally, it may be restricted to a specific
# namespace or to all namespaces.
# Syntax:
	* ns|* *|*
# Example:
	* will match all the elements of the document.

# "<node>" - Type selector (CSS,Basic selectors)
# Selects all elements that have the given node name.
# Syntax:
	elementname
# Example:
	input will match any <input> element.

# ".class" - Class selector (CSS,Basic selectors)
# Selects all elements that have the given class attribute.
# Syntax:
	.classname
# Example:
	.index will match any element that has a class of "index".

# "#id" - ID selector (CSS,Basic selectors)
# Selects an element based on the value of its id attribute.
# There should be only one element with # a given ID in a document.
# Syntax:
	#idname
# Example:
	#toc will match the element that has the ID "toc".

# "[attr=val]" - Attribute selector (CSS,Basic selectors)
# Selects all elements that have the given attribute.
# Syntax:
	[attr]
	[attr=value]
	[attr~=value]
	[attr|=value]
	[attr^=value]
	[attr$=value]
	[attr*=value]
# Example:
	[autoplay] will match all elements that have the autoplay attribute
		set (to any value).

# "A, B" - Selector list (CSS,Grouping selectors)
# The , is a grouping method, it selects all the matching nodes.
# Syntax:
	A, B
# Example:
	div, span will match both <span> and <div> elements.

# "A B" - Descendant combinator (CSS,Combinators)
# The   (space) combinator selects nodes that are descendants of the first element.
# Syntax:
	A B
# Example:
	div span will match all <span> elements that are inside a <div> element.

# "A > B" - Child combinator (CSS,Combinators)
# The > combinator selects nodes that are direct children of the first element.
# Syntax:
	A > B
# Example:
	ul > li will match all <li> elements that are nested directly inside a <ul> element.

# "A ~ B" General sibling combinator (CSS,Combinators)
# The ~ combinator selects siblings. This means that the second element follows the first (though # not necessarily immediately), and both share the same parent.
# Syntax:
	A ~ B
# Example:
	p ~ span will match all <span> elements that follow a <p>, immediately or not.

# "A + B" - Adjacent sibling combinator (CSS,Combinators)
# The + combinator selects adjacent siblings. This means that the second element directly follows # the first, and both share the same parent.
# Syntax:
	A + B
# Example:
	h2 + p will match all <p> elements that directly follow an <h2>.

# "A || B" Column combinator (CSS,Combinators)
# The || combinator selects nodes which belong to a column.
# Syntax:
	A || B
# Example:
	col || td will match all <td> elements that belong to the scope of the <col>.

# "p::first-line" - Pseudo classes (CSS)
# The : pseudo allow the selection of elements based on state information
# 	that is not contained in # the document tree.
# Example:
	a:visited will match all <a> elements that have been visited by the user.
# Pseudo elements
# The :: pseudo represent entities that are not included in HTML.
# Example:
	p::first-line will match the first line of all <p> elements.


#############################################################
## CSS - Stack Order
#############################################################

# Update the stacking order of elements (CSS,style)
# Elements with bigger number are placed above this.
# Default is 0.
.child {
	z-index: 20;
}


#############################################################
## CSS - Text Input
#############################################################

# Overwrite the Chrome placeholder background color (CSS Style)
# Color after choosing a past selected value.
#details input:-webkit-autofill {
    -webkit-box-shadow: 0 0 0px 1000px #ddd inset;
}


#############################################################
## CSS - Transform
#############################################################

# CSS uppercase text.
/* text-transform: uppercase; */


#############################################################
## CSS - Variables
#############################################################

# Use a variable inside CSS styling
html, body {
  --accent-color: #ae0000;
}
#main > span {
  background: var(--accent-color);
}


#############################################################
## CSS - Wrap
#############################################################

# Make an element (like div) wrap the text when too long
.wordwrap {
   white-space: pre-wrap;      /* CSS3. Chrome*/
   white-space: -moz-pre-wrap; /* Firefox */
   white-space: -o-pre-wrap;   /* Opera 7 */
   word-wrap: break-word;      /* IE */
   width: 8rem;
}


#############################################################
## Dig (nslookup)
#############################################################

# Install dig command.
apt install dnsutils


#############################################################
## Docker
#############################################################

# Remove all docker containers and images.
docker rm --force $(docker ps -aq)
docker rmi --force $(docker images -aq)

# Remove stuck containers
sudo systemctl stop docker.service
sudo su
rm -f /var/lib/docker/containers/*  # just "sudo ..." doesnt work for some reason.
exit
sudo systemctl start docker.service

# View docker log (warnings,errors)
docker compose logs -f --tail 200


## E


#############################################################
## FontForge
#############################################################

# FontForge program can update a .ttf file pixmap


#############################################################
## GCC
#############################################################

# Compile a c program (-g is for debugging, -o is for a new name)
gcc -g main.c -o new_name

# Compile a c++ program (-g is for debugging, -l is to include a library, -o is for a new name)
gcc -g cnt.cpp -l stdc++ -o cnt.exe

$ gcc documentation manual page
sudo apt-get install gcc-doc

# View Symbol table of C object file ".o" (OMS)
# Can also do it from an executable file
gcc -c mangle.c
nm mangle.o
nm mangle

# Specify output file with -o
gcc -o out

# Specify libraries ('-la' means there is a "a.a" or "a.so" file in "path")
gcc -o out 1.o 2.o -la -lb -c -Lpath

# Speficify header path with -Ipath
# only compile the source code. Need to link after.
gcc -c 1.c -Ipath

# View compiler optimizations
#
# Summary of each
gcc --help=optimizers
#
# Status of each optimization (enabled or disabled)
gcc -Q --help=optimizers

# Print search paths of gcc (gnu make,c programming)
# Default for "-L"
gcc -print-search-dirs

# Create shared library (.so)
gcc -Wall -fPIC -c *.c
gcc -shared -Wl,-soname,libctest.so.1 -o libctest.so.1.0   *.o

# Definition: (c programming,gcc)
# -fexceptions
#     Enable exception handling.  Generates extra code needed to propagate exceptions.  For some targets,
#     this implies GCC will generate frame unwind information for all functions, which can produce
#     significant data size overhead, although it does not affect execution.  If you do not specify this
#     option, GCC will enable it by default for languages like C++ which normally require exception
#     handling, and disable it for languages like C that do not normally require it.  However, you may need
#     to enable this option when compiling C code that needs to interoperate properly with exception
#     handlers written in C++.  You may also wish to disable this option if you are compiling older C++
#     programs that don't use exception handling.

# -l library (gcc option,flag,order)
# Search the library named library when linking.
#
# "
# It makes a difference where in the command you write this option;
# the linker searches and processes libraries and object files in the order they are specified.
# Thus, foo.o -lz bar.o
# searches library z after file foo.o but before bar.o.
# If bar.o refers to functions in z, those functions may not be loaded.
# "
#
# Think: at this point what is needed?
# If its not needed by now it wont be loaded in (although it may be available)

# Problem:  Seeing these errors
#    undefined reference to ...
#
# Solution: Change order of libraries


#############################################################
## Geb - General
#############################################################

# Geb manual
https://gebish.org/manual/current/

# Setup Geb (stuck)
#
# Go here
https://search.maven.org/
#
# Search and download these:
org.gebish:geb-core
org.seleniumhq.selenium:selenium-chrome-driver
org.seleniumhq.selenium:selenium-support
#

# Setup Geb (from repo,starting out)
cd D:\my\setup\geb\sample
git clone https://github.com/geb/geb-example-gradle
cd geb-example-gradle
gradlew chromeTest
#
# Install pip
D:\my\setup\pip\get-pip.py
#
# Install selenium
pip install selenium

# Using Python and Selenium (Geb)
#
cd D:\my\setup\geb\chromedriver_win32
ls
	chromedriver.exe
	sample.py
#
cat sample
	import time
	from selenium import webdriver
	driver = webdriver.Chrome(r'D:\my\setup\geb\chromedriver_win32\chromedriver.exe')  # Optional argument, if not specified will search path.
	driver.get('http://www.google.com/');
	time.sleep(5) # Let the user actually see something!
	search_box = driver.find_element_by_name('q')
	search_box.send_keys('ChromeDriver')
	search_box.submit()
	time.sleep(5) # Let the user actually see something!
	driver.quit()

# Cannot click on a element when Geb Testing:
# Use this approach:
js.exec(0, "document.querySelectorAll('.rowlink')[arguments[0]].click();");

# Pause a Geb test (Groovy,Geb,Spock)
pause()
#
# Unpause by running this in the controled console:
geb.unpause = true

# Waiting in Geb tasting (Groovy,Geb,Spock,sleep,wait)
waitFor(3){}		// 3 seconds
waitFor{}			// some default time
Thread.sleep(3000)	// 3 seconds

# Skip a test/function in Geb (Groovy,Geb,Spock)
import spock.lang.Ignore
@Ignore
def abc(){ }

# Run a single test with gradle in Geb (Groovy,Geb,Spock)
gradlew chromeTest -DchromeTest.single=My*

# Having given,when,and,then (Groovy,Geb,Spock)
# distinquish a regular function from a test function.

# Get the current url of the webpage (Groovy,Geb,Spock)
driver.currentUrl
getCurrentUrl()

# Another way to access elements that (Groovy,Geb,Spock)
# may return this error: StaleElementReferenceException
println(js.('document.title'))
println(js.('document.querySelector(".title").innerText'))
println(js.('document.querySelector("nav > a.active").innerText'))
return js.('document.querySelector(".title").innerText') =~ /NotSmart/

# Global debug variable (NotSmart Testing,Groovy,Geb,Spock)
# Ugly for now until a better way is found.
class Debug extends Module {
	def debug = 0
}
//
if( (module(Debug)).debug ){
	Thread.sleep(1000)
}

# Print to STDOUT (NotSmart Testing,Groovy,Geb,Spock)
println("var is $var")

// Maximize the chrome window (NotSmart Testing,Groovy,Geb,Spock)
def setupSpec() {
	driver.manage().window().maximize()
}

# IntelliJ IDEA support for Gen Testing.
# - Download latest IDEA IDE (community edition)
https://confluence.jetbrains.com/display/IDEADEV/IDEA+2020.1+latest+builds
# - Update gradle/wrapper/gradle-wrapper.properties to use: gradle-6.5-bin.zip
# - Update IDEA settings
#	- File -> Settings -> search: gradle

# View stack trace (not perfect since feature name is not shown)
// def getCurrentMethodName(){
//
// 	def marker = new Throwable()
//
// 	StackTraceUtils.sanitize(marker).stackTrace.eachWithIndex { e, i ->
// 		println "> $i ${e.toString().padRight(30)} ${e.methodName}"
// 	}
//
// 	// org.codehaus.groovy.runtime.StackTraceUtils.sanitize(new Exception()).printStackTrace()
//
// 	// def marker = new Throwable()
// 	// return StackTraceUtils.sanitize(marker).stackTrace[1].methodName
// }


#############################################################
## Gradle
#############################################################

# Installing Grade (download,setup)
#
# Install a JDK:
https://www.oracle.com/java/technologies/javase-jdk14-downloads.html
#
# Setup Environment:
JAVA_HOME			C:\Program Files\Java\jdk-14.0.1
JAVA_BIN			C:\Program Files\Java\jdk-14.0.1\bin
JAVA_LIB			C:\Program Files\Java\jdk-14.0.1\lib
#
# Install Gradle (Optional)
https://docs.gradle.org/current/userguide/installation.html
#
# Unzip and copy gradle-6.5 to:
cd C:\Gradle
#
# Setup Environment:
PATH_UNIX		 +=	C:\Gradle\gradle-6.5
GRADLE_HOME			C:\Gradle\gradle-6.5
#
# Check that its setup:
gradle -v
#
# Sample build.gradle
task hello {
	doLast {
		println 'hello Gradle'
	}
}
#
# Run using this command:
gradle hello
gradle -q hello

# Easiest way to setup Geb Testing with Gradle is to find a sample example.
geb-gradle-example-master


#############################################################
## Groovy
#############################################################

# Try groovy commands on the command line
groovysh

# Groovy replace all newlines and spaces with a single space
def text = $(query).eq(index).text().replaceAll(/\s+/, ' ')

# Groovy string to float
Float.parseFloat(string)

# Truthy-OR operator in Groovy (like defined-OR)
return Float.parseFloat(old ?: '0.0')
#
# Like this in perl:
$old || '0.0'

# Defined-OR operator in Groovy (like defined-OR)
num ?= 0
#
# Like this in perl:
$old //= '0.0'

# Mimic keyboard input (Groovy,Geb Testing)
$("[name='${name}']") << value.toString()

# Groovy split, map, join
groovy -e "def ids = 'id1, id2'; println(ids.split(/,\s*/).collect({ return '#$it' }).join(', '))"
#
# Same thing in perl
perl -le "$ids = 'id1, id2'; print join ', ', map {qq(#$_)} split(/,\s*/, $ids)"


## H

## I

#############################################################
## Journalctl
#############################################################

# Examples of journalctl commands.
journalctl _PID=1                      # From a precific PID.
journalctl -S -4h                      # Since last 4 hours.
journalctl -S 22:00:00                 # Since a sprecific time.
journalctl -S 2022-02-10               # Since a specific date.
journalctl -S '2022-02-10 22:00:00'    # Since a specific date and time.
journalctl -U 22:00:00                 # Until a specific time.
journalctl -u cron[.service]           # Search by unit type.
journalctl -F _SYSTEMD_UNIT            # List all units found in the logs.
journalctl -N                          # List all fields.
journalctl -g 'gas.*'                  # Grep through the logs.
journalctl -b                          # Start to end of current boot.
journalctl -b -1                       # Start to end of last boot.
journalctl -b -r                       # Start to end of current boot in reverse.
journalctl --list-boots                # List boots by IDs.
journalctl  -k                         # Display kernel messages.
journalctl -f                          # Like tail -f.


#############################################################
## Kate Editor
#############################################################

# Kate editor shortcuts
F6  - Left margin
F9  - Right margin (code folding)
F11 - Line numbers


#############################################################
# Linux Terminal
#############################################################

# Search through linux terminal history
Control + r


#############################################################
## Linux Commands - apt-cache
#############################################################

# Search for available apt-get modules/libraries/package
apt-cache search perl

# View more info of packages to be installed
sudo apt-cache show perl

# Show module/library dependancies
apt-cache depends perl


#############################################################
## Linux Commands - apt-get
#############################################################

# Install a package
apt-get install perl

# Upgrade all packages
apt-get update
apt-get upgrade

# Remove a system package
sudo apt-get remove <package>

# Remove a system package along with its dependencies
sudo apt-get remove --auto-remove <package>

# Remove a system package along with its configuration
sudo apt-get purge <package>

# Remove a system package along with its dependencies and configuration
sudo apt-get purge --auto-remove <package>

# Add packages to apt-get install list
apt edit-sources		# similar to: vi /etc/apt/sources.list
apt-get update


#############################################################
## Linux Commands - apt-key
#############################################################

# Add the key of a package site to allow installing from other sources
wget -q http://opensource.wandisco.com/wandisco-debian.gpg -O- | sudo apt-key add -


#############################################################
## Linux Commands - apt-list
#############################################################

# List trusted source lists for packages
sudo apt-key list


#############################################################
## Linux Commands - arp
#############################################################

# View all IP addresses (Debug,pi)
arp -a
netstat -a | findstr 172.17

# Remove arp -a cache (pi,debug)
netsh interface ip delete arpcache


#############################################################
## Linux Commands - awk
#############################################################

# Get the first line, second field (read file)
sui -u | grep "abc" | awk 'NR==1 {print $2}'


#############################################################
## Linux Commands - basename
#############################################################

# Get the basename or last file/directory of a string
basename <string>


#############################################################
## Linux Commands - cat
#############################################################

# Add line numbers to a file
cat -n <file>

# Skip the first line on the file
cat file | tail -n +2


#############################################################
## Linux Commands - chmod
#############################################################

# Set suid for a file
sudo chmod +s file

# Change permission of only the group
chmod g+w file


#############################################################
## Linux Commands - chown
#############################################################

# Fix ownership of user directory
cd home_dir/user_dir
sudo chown -Rh ${PWD##*/} `ls -A`


#############################################################
## Linux Commands - cmatrix
#############################################################

# See the matrix
cmatrix


#############################################################
## Linux Commands - cp
#############################################################

# Update all files that are less than 70 days old according to a file
# (Modified cp command)
cp2 -s --no-preserve=ownership  $FILE `find $DIR/*/$FILE -ctime -70`


#############################################################
## Linux Commands - crontab
#############################################################

# Add new crontab
crontab -e

# Start running cron tab
crontab <cron_file>

# View all crontabs on a bench
ls /var/spool/cron/crontabs

# Schedulers
crontab
cron
at

# Crontab job in interactive mode
* * * * * DISPLAY=localhost:11.0 xterm -e 'read -p "aaa - 3"'

# crontab job sent to any particular IP address
* * * * * DISPLAY=1.1.1.1:0 xterm -e 'read -p "aaa - 3"'

# Run a task according to a step amount (say every 5 minutes, crontab)
# min hr dom mon dow   command
  /5  *  *   *   *     my_command

# Run crontab at 3am and 3pm (task)
# min hr    dom mon dow   command
  *   3,15  *   *   *     my_command


#############################################################
## Linux Commands - curl
#############################################################

# View the heading of a server response
curl --head www.google.com

# Check if website/URL is up (Jira,ping)
curl -s --head http://localhost:8081/secure/Dashboard.jspa | head -1


#############################################################
## Linux Commands - cut
#############################################################

# Show so many character and everything after on a line
echo "1 2 3 5-d 4" | cut -c5-


#############################################################
## Linux Commands - date
#############################################################

# Format for date timestamps in scripts (primitive)
date "+%Y-%m-%d_%H:%M:%S"

# Convert epoch seconds to absolute time (@ means UNIX timestamp)
perl -le 'print ~~ localtime 1484048121'
date -d @1484048121

# Date is taken from a variable/string
tool_log_file=`date --date="@$START_DATE" "+%YY_%mm_%dd_%HH_%MM_%SS"`


#############################################################
## Linux Commands - declare, typeset
#############################################################

# List function declarations/names in bash
declare -F
typeset -F

# List function definitions in bash
declare -f
typeset -f

# Show all bash array declarations
declare -a

# Show select bash array declaration
declare -p a

# Create an associative array/hash in bash
declare -A h

# View an associative array/hash in bash
declare -p h


#############################################################
## Linux Commands - df
#############################################################

# See how much disk space is left on the device
df -h /tmp


#############################################################
## Linux Commands - diff, sdiff, patch
#############################################################

# Do a file comparison while showing the context (copy)
diff -c file1 file2

# Do a file comparison while showing the context (unified)
diff -u file1 file2

# Do a difference on variables (not just files)
diff -u <(echo "a") <(echo "b")

# Create a patch file
diff -rupN src2 src > test.patch

# Compare folders
diff -ruN  src_sean_latest/ src > diff

# Side by side difference
sdiff file1 file2

# Apply a patch file (-p1 ignore first later)
patch -p1 < ../test.patch

# Fix: "sh: -c: line 0: syntax error near unexpected token `('"
system qq(/bin/bash -c "diff -u <(echo a) <(echo b)");
system qq(/bin/bash -c "diff -u <(echo \\"a a2 a3\\") <(echo \\"b b2 b3\\")");


#############################################################
## Linux Commands - dos2unix
#############################################################

# Fix files endings of all files in folder (recursive)
find . -type f -print0 | xargs -0 dos2unix

# Convert newlines to unix format (trim off carriage returns, like dos2unix)
perl -lpe 'BEGIN{$n=chr 13; $r=qr/$n$/} s/$r//'


#############################################################
## Linux Commands - dpkg
#############################################################

# Print dpkg architecture (DES,machine)
# When installing packages.
dpkg --print-architecture

# Print allowed foreign architectures (DES,machine)
# When installing packages.
dpkg --print-foreign-architectures

# Error - Could not get lock /var/lib/dpkg/lock (admin)
sudo kill -9 $(sudo lsof | grep /var/lib/dpkg/lock | awk '{print $2}')
sudo dpkg --configure -a

# dpkg: error: dpkg status database is locked by another process (DES,bench)
sudo rm -f /var/lib/dpkg/lock

# Install a package from a file
sudo dpkg -i my.deb

# View packages installed on the system
dpkg -l

# Check if a package is installed on a system
dpkg -l | grep kate

# Check installion location of a package
dpkg -L <package>

# Add architecture to the list of architectures for which (DES)
# packages can be installed without using --force-architecture
dpkg --add-architecture i386

# Check if a package is on hold (no updates)
dpkg --get-selections apksigner
apt-mark showhold


#############################################################
## Linux Commands - dmesg
#############################################################

# View kernel messages
dmesg


#############################################################
## Linux Commands - du
#############################################################

# Get top 20 people using too much disk space
du -ms /* | sort -nr | head -n 20

# Find how much space each locked user is using
a=`sudo passwd -Sa | AND -r "\bL$" | get_nth 0 | while read u; do ls -d1 /net/home*/$u; done 2>/dev/null | col_2_row`
b=`sudo du -scm `echo $a` | sort -nr`
echo "$b" | perl -ple '($u)=m{/([^/]+)$} or ($_=sprintf "%-30s %s", $_,"Password Status (L - Locked)") and next; ($s)=(split " ",`sudo passwd -S $u`)[-1]; chomp $s; $_ = sprintf "%-30s %s", $_, $s'

# Find how much space each locked user is using (compact)
sudo passwd -Sa | AND "\bL$" | perl -aple '$d=qx{sudo du -sm /net/home*/$F[0]}; $d = $? ? "NO HOME DIR" : (chomp $d,$d); $_ = "$d - $_"'


#############################################################
## Linux Commands - eval
#############################################################

# Variable name is stored in another variable
n1=abc
abc=blue
abc2=green
eval var=\$$n1
echo $var
n1=abc2
eval var=\$$n1
echo $var

# Expand $HOME variable (dollar,bash)
file='$HOME/my_path'
"`eval echo $file`"

# Expand uicfg $HOME variables
cat $HOME/uicfg | while read line; do echo `eval echo $line`; done


#############################################################
## Linux Commands - expect
#############################################################

# Run a command where user input is required (script,auto,password)
expect -c 'spawn ssh SOME_USER@irkdes "date"; expect "password:"; send "asdf1234\r"; interact'

# Expect quirks (scipt,auto,password)
# This will NOT work
echo "SOME_USER" | while read n; do expect ... ; done
# This DOES work
for n in "SOME_USER"; do expect ... ; done

# Suppress output (scipt,auto,password)
# Some output
expect -c 'spawn -noecho ... '
# All output
expect -c 'log_user 0; spawn ... '     # Restore with "log_user 1"


#############################################################
## Linux Commands - find
#############################################################

# Find every file where a name is used (starting from pwd location)
find . * | perl -ne 'print unless /^\./' | perl -lne 'print if -f' | xargs perl -lne 'print $ARGV if /start.txt/'

# Find all files but do not look in certain directories
find $source -not \( -path '*.svn' -prune -or -path '*.git' -prune \) > $all_files

# Find specific files but return directories
find . -name "*.h" -printf '%h\n'
find . -name "*.h" -exec dirname {} ';'
find . -name "*.h" -exec dirname {} \;

# Find all git directories from current location
find . -name .git -type d | xargs -I{}  readlink -f {} | perl -ple 's#^/\w+##; s#/\.git$##'

# Find all files owned by a certain user
sudo find . -user xbe4092
sudo find . -maxdepth 3 -user xbe4092

# Find all files which are more than 100 days old (since they were accessed)
find $DIR -name "*.txt*" -atime +100
ll `find $DIR -name "*.txt*" -atime +100`

# Find all files which are more than 100 days old and deletes them
sudo find $DIR -name "*.txt*" -atime +100 -delete

# Search for multiple files patterns
find $DIR -name "*.glo*" -o -name "*name*"

# Find all files in current location
# but do not go into certain folders (omit, exclude)
find . -not \( -path '*.svn' -prune \)

# Find and perform an action (1,semicolon)
find $DIR -exec echo Arg: {} ';'

# Find and perform an action (2,plus)
find $DIR -exec echo Arg: {} '+'

# Find all empty folders (directory)
find . -type d -empty

# Delete all files using "find"
find dir/ -exec rm -f{} +								# real    0m7.810s	0m26.089s	0m28.655s
find dir/ -delete										# real    0m27.124s	0m40.121s
find dir -type f -print0 | xargs -0 -P13 -n100000 rm	# real	  38m5.886s

# Find all the hard links to a file (path)
find . -samefile otrs/.vimrc


#############################################################
## Linux Commands - fuser
#############################################################

# Find which process has a file open
fuser - identify processes using files or sockets


#############################################################
## Linux Commands - getconf
#############################################################

# Show/See/Displays all configuration variables
getconf -a


#############################################################
## Linux Commands - grep
#############################################################

# Find what is setting the sticky bit to /tmp folder upon machine reboot
grep -r chmod /etc/* 2>/dev/null | NOT "chmod (?:0?(?:-[f]\s+)?\d{3}|[aguo]*[+-][rwxs]+)\b" '^Binary' | add_color chmod
grep -r '/tmp' /etc/* 2>/dev/null | NOT '^Binary' | add_color tmp

# Return matching file name only
grep --color "trace config off"  * -l

# Return nonmatching file name only
grep --color "trace config off"  * -L

# Find what is common in both files (difference)
fgrep -Ff a b
grep -f a b
perl -e '@s{`cat a`}=(); exists $s{$_} and print for `cat b`'

# Find what is in second but not in first file (difference)
fgrep -v -Ff a b
grep -vf a b
perl -e '@s{`cat a`}=(); exists $s{$_} or print for `cat b`'

# Using grep for a OR like selection
cat file | grep -e this -e that -e those

# Change grep --color
export GREP_COLOR="32"              # green
echo "AabcC" | grep --color abc
export GREP_COLOR="32;4"            # green, underlined
echo "AabcC" | grep --color abc


#############################################################
## Linux Commands - groupadd
#############################################################

# Create new user group
groupadd


#############################################################
## Linux Commands - gzip
#############################################################

# Check file size of a gzip ubin file
# Shows compressed uncompressed  ratio uncompressed_name
gzip -l my.ubin2.gz


#############################################################
## Linux Commands - history
#############################################################

# Add more details to history command
export HISTTIMEFORMAT="%d/%m/%y %T "
export HISTTIMEFORMAT="%c %Z "
history | AND SoftBatch mv | NOT AND

# Clear history
history -c

# View all log in and log out history (need amin)
sudo vi /var/log/auth.log


#############################################################
## Linux Commands - id
#############################################################

# Show the user number on the bench (logged in)
id -u


#############################################################
## Linux Commands - ipcs
#############################################################

# View the details of a message queue (debug)
ipcs -q -i 101974057    # Send/receive time for an ID
ipcs -q -t              # Send/receive time for all

# Find out more info about a shared memory segment
ipcs -m -i 1620836354

# Delete shared memory segment
ipcrm shm 1620836354

# Show creator and last process for all the shared memory
ipcs -mp

# Show creator and last process for a pasticular shared memory (shmid)
ipcs -mp -i 1620836354
ipcs -m  -i 1620836354

# Find all shared memory processes that are still running (found in ps)
# Upon cleanup of last process, items in ipcx marked "dest"
# will be removed
ps -elf | grep -v grep | egrep "`ipcs -mp | AND '\d+' | get_nth -2 -1 | row_2_col | sort -u | transpose | replace ' ' '|'`"

# Attaches the shared memory segment identified by shmid to the address space of the calling process (IPC)
man shmat
# example from rtfsched.c:
# if ((pb = (RTFSCHED_SDEF *)shmat(shmid, 0, 0)) == (RTFSCHED_SDEF *)-1)

# Allocates a shared memory segment (IPC)
man shmget
# example from rtfsched.c:
# if ((shmid = shmget(key, sizeof(RTFSCHED_SDEF), 0666|create)) == -1)

# Fix UI start up error: Waiting for master session to start
ipcx
ipcclean


#############################################################
## Linux Commands - kill, killall, skill
#############################################################

# kills all possible processes
kill -9 -1

# Kill all of someones processes
skill -KILL -u xbe4092
killall -u xbe4092

# Remove myself from someone's bench (kill)
killall -u $USER

# Kill all user sessions/windows (cleanup)
skill -KILL <user>


#############################################################
## Linux Commands - last, lastlog
#############################################################

# Display all users that are logged in
last
last -i # IP address

# View all last login times for all users
lastlog
lastlog | NOT "Never logged" | AND "Jan\s+(9|10)"

# View last login for a user
last xbe4092


#############################################################
## Linux Commands - ld
#############################################################

# Check if library can be found (gnu make)
ld -libmy.a


#############################################################
## Linux Commands - ldd, ldconfig
#############################################################

# Print shared library dependancies (Added: 2017-10-04 02:02:51 PM)
ldd `which svn`

# configure dynamic library linker run-time bindings (Added: 2017-10-04 02:11:12 PM)
ldconfig -v

# Search locations of system libraries (DES, Setup new machine)
ldconfig -p | grep my_lib


#############################################################
## Linux Commands - locate
#############################################################

# Search for a c header file (DES)
sudo updatedb        # If added from apt-get
locate my_header


#############################################################
## Linux Commands - ls, ll
#############################################################

# Apply a character class to list (ls files)
ll *2[1-3]


#############################################################
## Linux Commands - mail
#############################################################

# Email the contents of a file to someone
echo $(cat mail.dat) | mail -s "File Name" timofey.potapov@pw.utc.com

# Print fixed width (monospace) emails
cat batch_report.formatted | perl -le 'print "<html><body><pre>\n", <>, "\n</pre></body></html>"' | mail -s "html report -a " -a "Content-Type: text/html" timofey.potapov@pw.utc.com

# Send email with a file as an attachment
cat ENV_linux.txt | mail -s "attachement" -a "Content-Type: html" timofey.potapov@pw.utc.com

# Send mail from another bench
ssh potapov@lnxbr25 'cat ~/bin/date.dat | mail -s "subject" timofey.potapov@pw.utc.com'

# Find out which benches can send emails
run_on_all_benches.p 'echo "on bench `uname -n`" | mail -s "`uname -n`" melvin.williams@pw.utc.com'

# View emails on bench
mail

# Delete single email of yours on bench
mail
>> d

# Delete all your emails on bench
mail
>> d*


#############################################################
## Linux Commands - man
#############################################################

# Show the location of all man page (manual/pod)
man --where --all date

# read a specific man page when there are many with the same name (Added: 2017-11-02 09:04:16 AM)
man -k readlink
man 2 readlink


#############################################################
## Linux Commands - mountpoint
#############################################################

# Check if a directory is mounted
mountpoint /media/tim/OTRS_BACKUP/ -q && echo "mounted"


#############################################################
## Linux Commands - netstat
#############################################################

# Display a table of all network interfaces
netstat -i

# Display summary statistics for each protocol
netstat -s

# View all network traffic for OMS
netstat -anpe | grep oms

# View routing table  (Debug,pi,IP addresses)
netstat -r
netstat -rn 	# No DNS lookup


#############################################################
## Linux Commands - nmon
#############################################################

# Monitor overrun processes (DES,UI)
sudo apt-get install nmon


#############################################################
## Linux Commands - nslookup (dig)
#############################################################

# Convert network address to name like DNS
nslookup 1.1.1.1
host sapbr01
# Find DNS servers
nslookup
> lserver


#############################################################
## Linux Commands - passwd, chpasswd, vipw, gpasswd
#############################################################

# Reset/Change a users password (admin)
 Log unto fs
sudo passwd xbexxxx
asdf1234
asdf1234
sudo make -C /var/yp

# Reset password in a script with no prompt (change)
# Can only supply one user to "passwd"
echo asdf1234 | sudo passwd xbe4092 --stdin; sudo make -C /var/yp
echo -e "xbe4092:asdf1234\npotapov:asdf1234" | sudo chpasswd; sudo make -C /var/yp

# Reset password over ssh (change,admin)
ssh -qtY potapov@lnxbrfs01 'echo -e "xbe4092:asdf123\npotapov:asdf123" | sudo /usr/sbin/chpasswd; sudo make -C /var/yp'
sb fs1 'echo -e "xbe4092:asdf123\npotapov:asdf123" | sudo /usr/sbin/chpasswd; sudo make -C /var/yp'

# Reset password of many users (admin,change)
echo "xbe4092:asdf1234" | sudo chpasswd
sudo make -C /var/yp

# Edit the password file. Disable/Lock user accounts before deleting
# Change /bin/bash to /bin/false
# Asterisk in password field disables account
sudo vipw
sudo make -C /var/yp

# Check if specific user account is:
# L  - Locked
# NP - No Password
# P  - Password is set (OK)
sudo passwd -S SOME_USER

# Check all user accounts if:
# L  - Locked
# NP - No Password
# P  - Password is set (OK)
sudo passwd -Sa

# Remove user from a group (delete, passwd)
Log unto fs01
sudo gpasswd -d potapov controls
sudo make -C /var/yp


#############################################################
## Linux Commands - pidof
#############################################################

# Process ID of a program (PID)
pidof omsCommand


#############################################################
## Linux Commands - ps
#############################################################

# Kill the ui when things aren't working
ps -ef | grep ui

# See all users on the bench
ps -elf | grep ui

# Show which processes were started by the current user
ps -elf | grep $USER

# Kill unigraph process if it is running in the background
ps -elf | grep unigraph | perl -anle '`skill -KILL $F[3]`'

# Be more specific in process selection (ps) options
ps -o user,ucmd --no-heading -C ui

# Currently running process (use in a script such as getinfo.sh)
ps -elf | grep getinfo.sh | grep -v grep | grep -v $$

# Check if puppet is running on all the benches
run_on_all_benches.pl 'ps -elf | grep puppet | grep -v grep'

# Check if systemd or init is used
ps -p 1


#############################################################
## Linux Commands - rcs
#############################################################

# Unlock a file
co -u file

# RCS error: file is in use
rm -f RCS/,file_name

# RCS error: file locked by pwxxxx
rcs -U file

# RCS: check in a file initially without the prompt message
ci -t-msg tiny2_rcs.tst


#############################################################
## Linux Commands - read
#############################################################

# Read input from the keyword/user without showing the password (much easier in bash)
read -s pass; echo "got [$pass]"
read -s -p "Password:" pass; echo; echo "got [$pass]"

# Read input from the keyword/user without showing the password. Limit password length
read -s -n 5 -p "Password:" pass; echo; echo "got [$pass]"


#############################################################
## Linux Commands - reptyr
#############################################################

# Attach to a running process on the existing terminal
sudo apt-get install reptyr


#############################################################
## Linux Commands - rsnapshot
#############################################################

# Install rsnapshot on centos
yum install epel-release
yum install rsnapshot

# Check if rsnapshot configuration file is valid
rsnapshot configtest

# Show the command that would be executed
rsnapshot -t daily
rsnapshot -t weekly


#############################################################
## Linux Commands - rsync
#############################################################

# Copy/Sync entire directories
rsync -avh FROM TO

# Copy/Sync entire directories including the folder structure
rsync -R FROM TO

# Delete all files using "rsync"
rsync -a --delete emptry_dir/ data_dir/


#############################################################
## Linux Commands - rm
#############################################################

# Apply a character class to remove files
rm -f *2[1-3]

# Time how long a process take
time rm -f file
#								# files:  100		20,000		30,000		50,000
# Delete all files using "rm"
rm -f dir/*						# real    0m0.329s	0m26.650s	0m33.476s	35m35.183
rm -fr dir						# real    0m0.181s	0m31.099s	0m45.349s	57m58.145s


#############################################################
## Linux Commands - screen
#############################################################

# Clean up dead UI sessions (for Tony, Cody)
screen -wipe


#############################################################
## Linux Commands - screen
#############################################################

# Fix screen -x when it is a display issue
script /dev/null


#############################################################
## Linux Commands - sed
#############################################################

# Remove lines which contain abc
a='
abc is here
its not here
nore here
but abs is here too
'
echo "$a" | grep -v abc
echo "$a" | sed '/abc/d'

# Remove first line from a file
cat my.csv | cut -d, -f1 | sed 1d

# Find and replace using sed
echo $STACK | sed 's/call/CALL/'
echo $STACK | sed 's/call/CALL/gi'

# Modify only select lines
echo "$a" | sed '/abc/  {s/here/NOT here/}'
echo "$a" | sed '/abc/! {s/here/NOT here/}'


#############################################################
## Linux Commands - set
#############################################################

# See what running running in the background of a linux script
set -x 		# Enable trace
set +x 		# Disable trace (default)

# Comparison of set and shopt in Bash
# set   -> $SHELLOPTS (Added: 2017-11-27 08:52:25 AM)
# shopt -> $BASHOPTS


#############################################################
## Linux Commands - set
#############################################################

# Reset xmodmap settings
setxkbmap


#############################################################
## Linux Commands - scp
#############################################################

# Copy a file over the network (using ssh)
scp file xbe4092@lnxbr35:location_to_place

# Copy a directory over the network (using ssh)
scp -r directory xbe4092@lnxbr35:location_to_place


#############################################################
## Linux Commands - shopt
#############################################################

# View various bash options that are set (Added: 2017-11-27 08:49:40 AM)
shopt


#############################################################
## Linux Commands - source
#############################################################

# Source a file
source .bashrc
. .bashrc

# Check if script is sourced
[[ $- = *i* ]] && echo "Sourced"

# Source a file from a file stream (Debian 7. at least bash 4.2)
source <(cat file | do_something)
source /dev/stdin <<<"$(cat <(cat file | do_something))"


#############################################################
## Linux Commands - sponge
#############################################################

# Read from and write to the same file without overwriting it (Linux)
cat abc | perl -ple 's/C/Z/' | sponge abc


#############################################################
## Linux Commands - ss (Sockets)
#############################################################

# View listening sockets on linux
ss -tlpn


#############################################################
## Linux Commands - ssh
#############################################################

# Pass data through ssh
cat ~/.ssh/id_rsa.pub | ssh SOME_USER@lnxbr24 'cat >> .ssh/authorized_keys'

# ssh while preserving X11
ssh -Y

# Cannot ssh. get message about error in locking .Xauthority file. no xauth data
rm -f ~/.Xauthority

# Port Forwarding (aka Tunneling)
ssh USER@localhost -p PORT -x -L local_socket:host:hostport
#
# Connect 8080 of remote to local 8081 (in browser)
ssh tim@localhost -p PORT -x -L 8081:host:8080

# Check if host is port forwarding (tunneling)
ss -o state listening | and 127.0.0.1 http

# Check if VM (remote) is port forwarding (tunneling)
ss -o state established | and 10.0.2.2


#############################################################
## Linux Commands - ssh-agent
#############################################################

# Add ssh agent
eval `ssh-agent -s`
ssh-add

# Kill agent
ssh-agent -k


#############################################################
## Linux Commands - ssh-keygen
#############################################################

# Setup new machine: key for quick access
# Use a longer key with ssh public keys
ssh-keygen -t rsa -b 4096
cd ~/.ssh/
cat id_rsa.pub >> authorized_keys

# Generate ssh key with more details
ssh-keygen -t rsa -b 4096 -C timofey.potapov@otrs.com -f id_rsa_OTRS_SAAS_$(date +%F)
# -C COMMENT
# -f Specific file to use
# -b Specific encryption bit size

# Problem: Host key differs from IP address
# Fix:     Remove offending ssh key ECDSA.
ssh-keygen -R 10..181.54

# Remove offending key for a host and port name
ssh-keygen -f "$HOME/.ssh/known_hosts" -R "host:port"
ssh-keygen -f "$HOME/.ssh/known_hosts" -R "[localhost]:2222"


#############################################################
## Linux Commands - sort
#############################################################

# Sort ignoring case (Bash)
sort -f
ls -1d [Ee]* | sort -f


#############################################################
## Linux Commands - stat
#############################################################

# View the number of hard links to a file or folder
stat -c %h /run


#############################################################
## Linux Commands - stty
#############################################################

# View the control character escapes
stty -a


#############################################################
## Linux Commands - systemctl
#############################################################

# Autostart linux service at boot
sudo systemctl enable elasticsearch.service

# Reload fstab without reboot
systemctl daemon-reload

# Run a user server (not system wide)
mkdir ~/.config/systemd/user/defaults.target.wants
cd ~/.config/systemd/user
vi selenium.service
#
# Add to file:
+ [Unit]
+ Description=Selenium Server
+
+ [Service]
+ Environment=DISPLAY=:1   # should match echo $DISPLAY
+ ExecStart=/usr/bin/java -Dwebdriver.chrome.driver=/usr/bin/chromedriver -jar /usr/local/lib/selenium/current.jar -role standalone -debug
+ SuccessExitStatus=143
+
+ [Install]
+ WantedBy=default.target
#
# Reload services
systemctl --user daemon-reload
#
# Restart user service
systemctl --user start selenium.service

# Workaround for not being able to set selenium service
# environmental dynamically.
# Add to ~/.profile
#
+ # Workaround: Update DISPLAY variable in selenium.service file
+ export SELENIUM_SERVICE_FILE=/etc/systemd/system/selenium.service
+ if [ -e "$SELENIUM_SERVICE_FILE" ]; then
+    if [ $(grep "Environment=DISPLAY=$DISPLAY" $SELENIUM_SERVICE_FILE -c) -eq 0 ]; then
+       sudo perl -i -lpe 's/ ^ Environment=DISPLAY= \K .* /$ENV{DISPLAY}/x' $SELENIUM_SERVICE_FILE
+       sudo systemctl daemon-reload
+       sudo systemctl stop selenium.service
+       sudo systemctl start selenium.service
+       echo "Updated DISPLAY in $SELENIUM_SERVICE_FILE"
+    fi
+ fi


#############################################################
## Linux Commands - su
#############################################################

# Get into a disabled account
sudo su -s /bin/bash SOME_USER


#############################################################
## Linux Commands - sudo
#############################################################

# sudo while preserving the original environment
sudo -E

# Check it you have sudo access (0 mean yes, 1 means no)
sudo -v 2>&1 | wc -l

# Become and stay root
sudo su -


#############################################################
## Linux Commands - svn (general)
#############################################################

# Install new version of svn (done on lnxbr43) (subversion) (Added: 2017-10-09 09:29:26 AM)
setup_http_proxy
mkdir ~/deb
url="http://opensource.wandisco.com/debian/dists/wheezy/svn18/binary-i386"
wget -q $url/libserf1_1.3.7-1+WANdisco_i386.deb
wget -q $url/libsvn1_1.8.19-1+WANdisco_i386.deb
wget -q $url/subversion_1.8.19-1+WANdisco_i386.deb
sudo apt-get install -f
sudo dpkg -i libserf1_1.3.7-1+WANdisco_i386.deb
sudo apt-get install -f
sudo dpkg -i libsvn1_1.8.19-1+WANdisco_i386.deb
sudo apt-get install -f
sudo dpkg -i subversion_1.8.19-1+WANdisco_i386.deb
sudo apt-get install -f
sudo apt-get autoremove

# Create an empty svn repository
svnadmin create .svn

# Find out the revision number of a svn directory
svn info
svn info <URL>

# Check the status of an SVN
svn status

# Check svn status ignoring unmodified
svn status -q

# Check svn status showing outdated files
svn status -u

# Check svn status showing details on all the files
svn status -v

# View the contents of a repository
svn ls <url>

# View a log of comited changed to repository
svn log <url>

# View incremental changes to a file
svn log --diff file

# View the files that were modified per checkin
svn log -v

# View only a view entries (2) in the log
svn log -l 2

# Compare current revision to a particular revision for a file
svn diff -r 4642 oms_sim.c

# Resolve conflicts in SVN repository
svn resolve

# Check out a specific revision/version
svn co -r 4705 file:////home/sb_dev/src/omspp/trunk .

# View all the tags for an svn repository
svn ls -v ^/tags
#
# ^   means head of repo
# ^/  means tags is found right in directly below repo head

# Add new file to existing svn repository
svn add file

# Commit new files to svn repository
svn ci file -m "comment"

# Check out a particular revision/version from the repository
svn co URL_GOES_HERE@DESIRED_REVISION WHERE_TO_SAVE

# Create a new svn directory (like batch_test)
svn import Batch_Test/ <url> -m "Added Batch_Test folder for nightly batch tool"

# Checkout a file/directory from SVN
svn export <url> --username tpotapov

# Update svn in the current directory
svn update

# Update SVN to a specific version
svn update -r 147

# Revert svn repository to a previous state/version (undo) (Added: 2017-10-31 04:32:02 PM)
svn update -r 4611


#############################################################
## Linux Commands - svn (misc)
#############################################################

# Remove/delete a file from the repository
svn rm <url>/abc -m "testing"

# clean up the svn (to remove locks)
svn cleanup

# ERROR: Failed to run the WC DB work queue associated with (svn)
cd ~/omspp/trunk
# Files still in queue
sqlite3 .svn/wc.db '.explain on' 'select * from work_queue'
# Delete all files in queue
sqlite3 .svn/wc.db '.explain on' 'delete from work_queue'
# Cleanup
svn cleanup

# Setup SVN Cyient variables (debugging use)
svn_pull_url="<url>/Tests"
svn_push_url="<url>/Results"
svn_username="tpotapov"
read -s -p "password: " svn_password
SB run 1234 t1+a "svn pull=$svn_pull_url push=$svn_push_url user=$svn_username pass=$svn_password"


#############################################################
## Linux Commands - tail
#############################################################

# Retain only the most rescent 10 logs (logs in this format: 2017Y_06m_22d_12H_34M_55S) (keep,remove)
max=10
ls -1 2* | tail -n +$(($max+1)) | xargs rm -f


#############################################################
## Linux Commands - tar, zip
#############################################################

# Extract a tar file (.gz) untar a file (unzip)
tar -zxvf <file>
tar -xvzf rakudo-star-2017.01.tar.gz

# Zip a file (compress)
zip my.zip dir/*

# Unzip a git repository/file
unzip <file>

# Unzip and word document into xml
unzip word.docx

# Compress a folder into a zipped file
tar -cvvf  dir.tar dir     # Normal size
tar -cvvzf dir.gz  dir     # Zipped, fraction of size

# Decompress a folder from a zipped file
tar -xvvf  dir.gz  dir

# Untar a file into another directory (uncompress)
tar -xvvf ~/dir1/tar_file -C ~/dir2


#############################################################
## Linux Commands - test
#############################################################

# Process only a certain file (Added: 2017-10-26 10:04:53 AM)
if test -s acteec_out.gloascii


#############################################################
## Linux Commands - top
#############################################################

# Monitor processes by user
top -b -U potapov -n1

# Monitor activity (like top which shows high load average)
sudo iftop -i eth1

# Tools for checking/detecting slow processing
ps
top
htop


#############################################################
## Linux Commands - tmux
#############################################################

# Start new tmux
tmux

# Start new tmux withh a session name
tmux new -s SESSION_NAME

# Attach to a tmux
tmux a -t SESSION_NAME_OR_NUMBER

# List tmux sessions
tmux ls

# Kill tmux session
tmux kill-session -t SESSION_NAME_OR_NUMBER

# Kill all tmux sessions (NOT PERMITTED)
tmux ls | grep : | cut -d. -f1 | awk '{print substr($1, 0, length($1)-1)}' | xargs kill

# Control-b help tmux menu
Control-b ?

# Dettach from a tmux session
Control-b d

# Kill all tmux sessions
tmux ls | perl -aF: -ne 'qx(tmux kill-session -t $F[0])'


#############################################################
## Linux Commands - touch
#############################################################

# Changes a timestamp to be a specific date
touch $FILE -d 'Feb 11 2015'
touch $FILE -d 'Apr 11 2017 10:11'


#############################################################
## Linux Commands - tr
#############################################################

# Remove all extra spaces in a line (squash)
echo " a    f    " | tr -s " "

# Convert a string to lower case (change case)
echo ABd | tr [:upper:] [:lower:]

# Convert a string to upper case (change case)
echo Abd | tr [:lower:] [:upper:]


#############################################################
## Linux Commands - useradd
#############################################################

# Create a new user account for BENCH
uid=$UID
user=SOME_USER
gid=123
/usr/sbin/useradd -u $uid -g $gid -d /home/$user -m $user
passwd SOME_USER          # asdf1234

# Create new user accounts
i=1001
for u in potapov SOME_USER; do
   /usr/sbin/useradd -u $i -g systems -d /home3/$u -m $u -s /bin/bash
   let "i++"
done
# run 'passwd $u' for each user

# Change default shell of current user (or use useradd -s /bin/bash)
chsh -s /bin/bash


#############################################################
## Linux Commands - userdel
#############################################################

# Remove all users accounts in a list
# $a contains a list of "username - home_directory"
echo "$a" | while read u h; do echo -e "\n# Deleting $u\n"; sudo userdel -r $u; done


#############################################################
## Linux Commands - usermod
#############################################################

# Change group id of a user (DES,gid)
sudo usermod -g 1000 potapov

# Change user id of a user (DES,uid)
sudo usermod -u 10285 potapov

# Add user to a new group/groups (passwd)
Log unto fs01
sudo usermod -a -G controls,system potapov
sudo make -C /var/yp

# Change the shell for a specific user
sudo usermod -s /bin/bash potapov   # can specify user here

# Change full name in passwd file
sudo usermod -c "Last First" xbeXXXX

# Change home directory
Log unto fs01
cd /home3
sudo usermod -d /home4/xbe4092 xbe4092

# Move home directory
Log unto fs01
sudo usermod -d /home4/xbe4092 -m xbe4092

# Add/append group to user
# Current user would need to log out and in again
# for changes to take effect.
sudo usermod -a -G GROUP_NAME USER


#############################################################
## Linux Commands - watch
#############################################################

# Watch the UI sessions
watch -d -n1 screen -list

# Alias command to watch all the files in the current directory for changes
alias watch_files='watch ls -alF'


#############################################################
## Linux Commands - wget
#############################################################

# Pass through wget firewall/proxy (Download)
read -sp "Password: " PASSWORD
export http_proxy=http://xbe4092:$PASSWORD@pratt-proxyva.utc.com:8080/
export https_proxy=http://xbe4092:$PASSWORD@pratt-proxyva.utc.com:8080/
# If password contains special characters (like #,@ ...)


#############################################################
## Linux Commands - whereis
#############################################################

# Locate a program
which perl
whereis perl


#############################################################
## Linux Commands - who
#############################################################

# See all users on the bench
who


#############################################################
## Linux Commands - xargs
#############################################################

# Make xargs work when files may have spaces in the name (Added: 2017-10-27 08:48:11 AM)
# changes the delimiter from a space to a newline
ls abc\ file.txt | xargs -d "\n" grep tuff


#############################################################
## Linux Commands - xrandr
#############################################################

# Find out the monitor/screen size (pi)
xrandr
/opt/vc/bin/tvservice -s


#############################################################
## Linux Commands - xterm
#############################################################

# Resize window (Putty,xterm)
echo -e '\e[8;50;100t'

# Minimize the window for a few seconds, then restore it (Putty,xterm)
echo -e '\e[2t' && sleep 2 && echo -e '\e[1t'

# Move the window to the top/left corner of the display (Putty,xterm)
echo -e '\e[3;0;0t'

# Zoom the window (Putty,xterm)
echo -e '\e[9;1t'

# Bring the window to the front (without changing keyboard focus) (Putty,xterm)
echo -e '\e[5t'

 Change the name of an xterm window to "string"
echo -ne "\033]2;string\007"

# Change the name of an xterm icon to "string"
echo -ne "\033]1;string\007"

# Change the name of an xterm icon and window to "string"
echo -ne "\033]0;string\007"

# Create alias to easily change the window name and icon name
# Must be run together!
set_title(){ echo -ne "\033]0;$@\007"; }
alias title='set_title'

# Get dimensions/size of a screen/xterm
xdpyinfo | grep dimensions
xrandr | grep '*'

# Get the size of an xterm window
xwininfo

# Get info about current xterm window
xdpyinfo

# Get size info of a named xterm window
xwininfo -name omsGUI_0_3

# Get info about an xterm window
xprop -id <window_id>
xprop -id 0x2400022

# Get position of the cursor
perl -e '$/ = "R";' -e 'print "\033[6n";my $x=<STDIN>;my($n, $m)=$x=~m/(\d+)\;(\d+)/;print "Current position: $m, $n\n";'

# Print how many columns and rows an xterm window uses for its screen size
tput cols
tput lines
reset

# Change fond/colors of an xterm window
RESTORE='\033[0m'
RED='\033[00;31m'
GREEN='\033[00;32m'
YELLOW='\033[00;33m'
VIOLET='\033[00;35m'
TEAL='\033[00;36m'
GREY='\033[00;37m'

# View color ansi escapes with less (like Vim)
less -R file

# Make xterm text color bold
BOLD='\033[1m'

# Make xterm text color blink
BLINK='\033[5m'

# Move mouse to a specific location on the screen/xterm window (on lnxbr42)
xdotool mousemove 764 11

# Click on a button (cannot on top bar , like the X for close)
xdotool click 1

# Get mouse location
xdotool getmouselocation

# Move mouse to a location and click at the same time
xdotool mousemove 1747 30 click 1

# print contents of X events (mouse activity/movement)
xev

# Install xdotool dependencies
sudo apt-get install libxcb-xtest0:i386 libxcb-xtest0-dbg:i386 libxcb-xtest0-dev:i386
dpkg -l | grep xtest

# Other xdotool dependenacies
sudo aptitude install

# install xdotool from repository
cd ~junk/xdo/xdotool-master
sudo make install

# Check dependencies of a debian package
dpkg -I xdotool_3.20160512.1-1_i386.deb

# Install package from source (.deb)
sudo dpkg -i xdotool_3.20160512.1-1_i386.deb
sudo apt-get install -f

# Launch an xterm window into a certain directory
xterm -e 'cd ~/dsu && /bin/bash'
xterm -fg White -bg Black -sl 10000 -fn a14 -geometry 84x51+1722-78 -title "sre2bin" -e 'cd ~/dsu && /bin/bash'
xterm -fg White -bg Black -sl 10000 -fn a14 -geometry 84x51+1722-78 -title "sre2bin" -e 'cd ~/dsu; /bin/bash'
xterm -fg White -bg Black -sl 10000 -fn a14 -geometry 84x51+1722-78 -title "sre2bin" -e 'cd ~/dsu; bash'

# Check if xterm environment is working (Added: 2017-11-02 03:56:18 PM)
xeyes

# Check what kind of terminal I am using (xterm,bench)
echo $TERM

# Wrap long lines unto next row in bash/linux
# Exclose PS1 in '\[PS1_VALUE\]'


#############################################################
## Linux Commands - xxd
#############################################################

# Convert a binary file to hex
xxd NVM_EDF_CHA.dat > tmp_file

# Convert a hex file to binary
xxd -r tmp_file > tmp.bin

# Open a binary file in hex with vim
vi <(xxd tmp.bin)


#############################################################
## Linux Commands - ypcat
#############################################################

# View password file on main server (yellow page cat)
ypcat passwd

# Add ypcat passwd command if missing
vi /var/yp/nicknames
# add entry: passwd      passwd.byname

# Return users which are found in the yellow pages password file
cat user_deletion_list | perl -ne 'print `ypcat passwd | grep $_` ' > found_in_yp

# Remove/Delete a user account
 1. Check username in Outlook (CTRL-K)
 2. Check username in Yellow Pages (ypcat passwd | grep username)
 3. Go to file server
sudo userdel -r username	# -r does this: sudo rm -rf username
sudo make -C /var/yp


#############################################################
## Linux Commands - yppasswd
#############################################################

# Change your password
yppasswd


#############################################################
## Linux Commands - zero
#############################################################

# Clear NVM/flash memory (from start to and including the end address)
zero -p ppa -s 0xSTART_ADDRESS -e 0xEND_ADDRESS


#############################################################
## Linux Accounts
#############################################################

# Check when a users account was created (good unless file was updated or touched)
ll ~SOME_USER/.bash_logout

# Check when a users account was created (good unless home account changed)
ll -d ~SOME_USER
echo ~SOME_USER | perl -lne 'print for -M,-C,-A'


#############################################################
## Linux Hardware
#############################################################

# View how many processors are on a machine/bench
cat proc/cpuinfo
cat /proc/cpuinfo | perl -ln0777e "print ~~split qq(\n\n)"

# Find out the service tag code of a machine (Bob)
# That is the same as the serial number
# Used for compability purposes (such as when getting new drives)
/usr/sbin/dmidecode | perl -ln00e 'print if /System Information/'

# Find out easily how many cpu there are (a command)
lscpu

# Add module to kernel (DES,UI,insert,library)
insmod /lib/modules/2.6.11/kernel/fs/fat/fat.ko
modprobe msdos

# Find out version of debian you are running (DES)
cat /etc/debian_version

# Check processor family (DES,UI)
grep "cpu family" /proc/cpuinfo
# Cpu family of "6" means use "Pentium-Pro"

# Change boot loader to use certain cpu's (DES,UI,Mark,shielding)
cd /boot/grub
sudo vi grub.cfg
/\Vlinux /boot/vmlinuz-3.16.51+20180205+1524
/\Vlinux /boot/vmlinuz-3.16.51+20180205+1524
# Add this to
isolcpus=0,1,2,3,4,5,6,7,8,9
cat /proc/cmdline

# Check timer frequency (DES,UI,CONFIG_HZ_1000)
cat /usr/src/linux.config | OR CONFIG_COMPAT_BRK CONFIG_HZ_PERIODIC CONFIG_X86_GENERIC CONFIG_SCHED_SMT CONFIG_HZ_1000

# find biggest binary number on the machine
perl -lE '@a=split //, sprintf "%b",  ~~-1; print @a'
perl -lE '@a=split //, sprintf "%b",  ~~-1; print scalar @a'

# Size of an integer on this system
perl -le 'print length pack "i"'


#############################################################
## Linux File Properties - General
#############################################################

# View more info about a file (Bash)
# Number of links, inode
stat $FILE

# Print all the symbolic links in a directory and show where they link to (for Melvin)
ls | perl -lne '$r=readlink; print "$_ -> $r" if -l'

# Check if a file is opened (Added: 2017-11-20 02:48:53 PM)
lsof | grep my_file

# Check if vi has open (Added: 2017-11-20 02:49:11 PM)
lsof -c vi

# Check/Detect a symbolic link
[ -L "link_file" ] && echo "A"


#############################################################
## Linux File Properties - Sticky Bit
#############################################################

# Show if sticky bit is set on temp directory
[ -k /tmp ] && echo t

# Set sticky bit
chmod +t /tmp

# Remove sticky bit
chmod -t /tmp


#############################################################
## Linux Firewall
#############################################################

# Add port to firewall
firewall-cmd --add-port=8081/tcp --permanent
firewall-cmd --reload

# Problem:
#     Created a docker container and published it to a certain port.
#     Port returns nothing in a web browser
# Solution:
#     The machine has a firewall.
#     I had to do as root:
firewall-cmd -add-port=8089/tcp --permanent


#############################################################
## Linux Logging
#############################################################

# View the error log for puppet
cat /var/log/syslog


#############################################################
## Linux Mounting
#############################################################

# Check paths to file servers
mount

# Fix Stale NFS on a file server. home4 down. cannot access
sudo umount -lf /net/home4
				# should automount in a few secs
/etc/init.d/autofs restart	# Otherwise, restart manually
/etc/init.d/nfs-common restart	# Do both

# Change path to file server.
sudo vi /etc/auto.pw 		# edit OLD to NEW
sudo service autofs reload	# reload auto mounting (only on higher benches)
sudo /etc/init.d/autofs restart
sudo /etc/init.d/autofs reload

# Get copy of latest auto loader server file
sudo \cp /home3/SOME_USER/auto.pw /etc/auto.pw
sudo /etc/init.d/autofs reload

# Setup puppet to change path to file server
sudo vi /etc/puppet/modules/autofs/files/auto.pw
sudo /etc/init.d/autofs reload


#############################################################
## Linux Software
#############################################################

# Which OS version are we using (DES)
lsb_release -a

# Find out if using 32 or 64 bit linux system
uname -m     # 32 is i686 or i386, 64 is x86_64

# Find out the release name (UI,bench,DES)
lsb_release -a

# Show which debian version name machine is (such as wheezy) (Added: 2017-10-05 11:26:48 AM)
lsb_release -cs


#############################################################
## Linux Swap Memory
#############################################################

# Create swap memory file
#
mkdir /media/fasthdd
dd if=/dev/zero of=/media/fasthdd/swapfile.img bs=512 count=1M
#
# Turn that swap file into a filesystem !?
mkswap /media/fasthdd/swapfile.img
chmod 600 /media/fasthdd/swapfile.img
#
# Add this line to /etc/fstab to be able to use the swap at startup
/media/fasthdd/swapfile.img swap swap sw 0 0
#
# Activate the swap file
swapon /media/fasthdd/swapfile.img
#
# Deactivate the swap file
swapoff /media/fasthdd/swapfile.img

# View swap memory
cat /proc/swaps
top


#############################################################
## Ansible
#############################################################

# Install ansible prerequisites (on lnxbr42)
sudo apt-get install vagrant virtualbox

# Install ansible
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 123456
sudo apt-get update
sudo apt-get install ansible


#############################################################
## Bash - General
#############################################################

# See max expansion of *
getconf ARG_MAX		# 2097152

# Run a bash command without using a file
bash -c 'echo abc'

# Link without having to go the that folder location
bash -c 'cd; cd sb_stats; rm -f latest; ln -s my latest'
#
latest_file=nytprof/1/my.out
latest_link=nytprof/latest
ln -r -s "$latest_file" "$latest_link"


#############################################################
## Bash - Arrays
#############################################################

# Making an array in bash ($* $@)
a=(one two "three four")

# Subtle differences in using an array in bash ($* $@)
print_args ${a[*]}
[one]
[two]
[three]
[four]

# Subtle differences in using an array in bash ($* $@)
print_args ${a[@]}
[one]
[two]
[three]
[four]

# Subtle differences in using an array in bash ($* $@)
print_args "${a[*]}"
[one two three four]

# Subtle differences in using an array in bash ($* $@)
print_args "${a[@]}"
[one]
[two]
[three four]

# Loop through array ($* $@)
for n in ${a[*]}; do echo $n; done
one
two
three
four

# Loop through array ($* $@)
for n in ${a[@]}; do echo $n; done
one
two
three
four

# Loop through array ($* $@)
for n in "${a[*]}"; do echo $n; done
one two three four

# Loop through array ($* $@)
for n in "${a[@]}"; do echo "$n"; done
one
two
three four

# Copy one array in bash to another array
b=("${a[@]}")

# Get size of an array (bash,var)
size=${#array[@]}

# Delete first or last element from an array (bash,shift,var)
unset array[0]
unset array[-1]

# Loop through array input ($* $@)
for n in "$@"; do echo "[$n]"; done

# Add to an associative array/hash in bash
h[a b c]="abc val"
h[d e f]="def val"
h[x y z]="xyz val"

# Print an associative array/hash in bash
echo ${h[@]}
echo ${h[*]}

# Bash var sublty (bug 1). Unset array is missing instead of empty
a=(one two "three four" "five")
print_args "${a[@]}"
print_args "${a[@]}" 5
unset b
print_args "${b[@]}" 5
print_args "${b}" 5


#############################################################
## Bash - Ascii Art
#############################################################

# Ascii Art
figlet "svn update"

# Nice format for representing binary numbers (art,ascii)
figlet "0000011111" -f digital

# Show all available figlest fonts (ascii art)
figlist | perl -lne '$a=/\bfonts.*:$/ ... /.*:/; print if $a > 1 and $a !~ /E/'
# There are the nicer fonts
banner big lean slant smslant standard
# favorite
slant
figlet "svn update" -f slant

# Center the ascii art (justify)
figlet "svn update" -f slant -c

# Right justify the ascii art and set a width of 60
figlet "svn update" -f slant -r -w 60


#############################################################
## Bash - Autocomplete
#############################################################

# Example of using autocompletion (tab)
/usr/share/bash-completion/completions/perl
/usr/share/bash-completion/completions/ip

# Generate autocompletion for own scripts (Bash,Tab)
# Options - aaa aba bbb ccc
_sb_tab(){
   COMPREPLY=( $(compgen -W "`sb info`" -- "${COMP_WORDS[COMP_CWORD]}") )
}
complete -F _sb_tab sb

# View all tab completions (Bash,Tab,auto)
complete

# Delete all tab completions (Bash,Tab,auto)
complete -r

# Use existing autocompletions
complete -p | grep ls      # finds _longopt
complete -F _longopt my_function

# Bash autocomplete special variables
# COMP_WORDS is an array containing all individual words in the current command line.
# COMP_CWORD is an index of the word containing the current cursor position.
# COMPREPLY is an array variable from which Bash reads the possible completions.

# Tab completions source of bash commands (Bash,Tab,auto)
vi /etc/bash_completion
vi /usr/share/bash-completion/bash_completion

# Generate autocompletion for own scripts (Bash,Tab)
bash_autotab(){
#  COMPREPLY=( $(compgen -W "$*" -- "${COMP_WORDS[COMP_CWORD]}") )
#
   local cur="${COMP_WORDS[COMP_CWORD]}"
#
   # Get possible words without consider colon characters
   _get_comp_words_by_ref -n : cur
#
   COMPREPLY=( $(compgen -W "$*" -- "$cur") )
#
   # Remove colon contain prefix from COMPREPLY
   __ltrim_colon_completions "$cur"
#
   #  echo "COMP_WORDS    = [${COMP_WORDS[@]}]"
   #  echo "COMP_CWORD    = [${COMP_CWORD[@]}]"
   #  echo "COMP_LINE     = [$COMP_LINE]"
   #  echo "COMPREPLY     = [${COMPREPLY[@]}]"
}
otrs_module_install(){
   echo "$OTRS_MODULE_TOOLS" Module::Package::Install "$@"
}
_otrs_module_install__tab(){
   local possible=( $(ls "$OTRS_PACKGES_DIR") )
   #
   base_autotab ${possible[*]}
   # base_autotab $(ls $OTRS_PACKGES_DIR)
   #
   # echo "COMP_WORDS    = [${COMP_WORDS[@]}]"
   # echo "COMP_CWORD    = [${COMP_CWORD[@]}]"
   # echo "COMPREPLY     = [${COMPREPLY[@]}]"
}
complete -F _otrs_module_install__tab otrs_module_install


#############################################################
## Bash - Command Info
#############################################################

# Get first command of current line
echo "abc" | AND b | while read line; do echo "$line -> $BASH_COMMAND"; done

# Get command just run (bash)
rcmd2 -n 0 -c "echo \"here\""; echo "$_"


#############################################################
## Bash - Command Line Options
#############################################################

# Example of using command line options in bash
while getopts :d:m opt; do
  case $opt in
      d) debug="$OPTARG";;
      m) more="$OPTARG";;
      :) /bin/echo -e "$usage"; exit 1;;
      \?) echo "undefined option -$OPTARG"; exit 1;;
  esac
done


#############################################################
## Bash - Conditions
#############################################################

# If else condifion in bash on a single line
if [ $a -gt 0 ]; then echo -e $a; else echo $a; fi

# Case (switch) statement. Run of the possiblities (bash)
var="aaa"
   case $var in
   aaa) echo 10 ;;
   bbb) echo 20 ;&      # Fallthrough condition.
   ccc) echo 30 ;;
esac

# Bash, multi if elseif (ternary)
a=5
[ $a -gt 3 ] && echo "A" || ([ $a -gt 2 ] && echo "B" || echo "C")
if [ $a -gt 3 ]; then echo "A"; elif [ $a -gt 2 ]; then echo "B"; else echo "C"; fi


#############################################################
## Bash - Expressions
#############################################################

# Check if variable has a value (not empty) (and logic)
[[ ! -z $msg ]] && echo "A"

# Check if variable has a value (not empty)
if [[ ! -z $msg ]]; then echo "A"; fi

# Bash regular expression (regex) comparision
[[ "R_EECB" =~ [LR]_EEC[AB] ]] && echo "A"
[[ ! "L_EECA" =~ [LR]_EEC[AB] ]] && echo "A"

# Check if a file is newer than another file
[ FILE1 -nt FILE2 ] && echo "is newer" || echo "not newer"


#############################################################
## Bash - File Test Operators
#############################################################

# Bash File Test Operators
# Operator syntax           Description
# -a <FILE>  True if <FILE> exists. (not recommended, may collide with -a for AND, see below)
# -e <FILE>  True if <FILE> exists.
# -f <FILE>  True, if <FILE> exists and is a regular file.
# -d <FILE>  True, if <FILE> exists and is a directory.
# -c <FILE>  True, if <FILE> exists and is a character special file.
# -b <FILE>  True, if <FILE> exists and is a block special file.
# -p <FILE>  True, if <FILE> exists and is a named pipe (FIFO).
# -S <FILE>  True, if <FILE> exists and is a socket file.
# -L <FILE>  True, if <FILE> exists and is a symbolic link.
# -h <FILE>  True, if <FILE> exists and is a symbolic link.
# -g <FILE>  True, if <FILE> exists and has sgid bit set.
# -u <FILE>  True, if <FILE> exists and has suid bit set.
# -r <FILE>  True, if <FILE> exists and is readable.
# -w <FILE>  True, if <FILE> exists and is writable.
# -x <FILE>  True, if <FILE> exists and is executable.
# -s <FILE>  True, if <FILE> exists and has size bigger than 0 (not empty).
# -t <fd>  True, if file descriptor <fd> is open and refers to a terminal.
# <FILE1> -nt <FILE2>  True, if <FILE1> is newer than <FILE2> (mtime).
# <FILE1> -ot <FILE2>  True, if <FILE1> is older than <FILE2> (mtime).
# <FILE1> -ef <FILE2>  True, if <FILE1> and <FILE2> refer to the same device and inode numbers.

# Read from either PIPE or from standard input STDIN (in Bash. 0 is STDIN)
[ -t 0 ] && echo "A"
cat file | [ -t 0 ] && echo "A"


#############################################################
## Bash - Functions
#############################################################

# Create a heredoc
cat <<HERE
stuff to print
more stuff
HERE

# Create a heredoc and put in a file (Bash)
cat <<HERE > file
stuff to print
more stuff
HERE

# Create a heredoc and put in a variable (Bash)
my_var=$(cat<<HERE
stuff to print
more stuff
HERE
);

# Get name of current function you are in (bash)
echo $FUNCNAME

# Get name of parent function you are in (bash)
echo ${FUNCNAME[0]}

# Get full stack trace of functions that lead you to current function (bash)
echo ${FUNCNAME[*]}

# Trim off variable in bash to select size (6 in example,bash)
echo ${USER:0:6}


#############################################################
## Bash - For Loop (C Style)
#############################################################

# C style for loop in bash
for((i=1; i<=10; i++)); do echo $i; done


#############################################################
## Bash - Foreach Loop
#############################################################

# Foreach loop in bash
my_list="
  file1
  file2
  file3
"
for name in $my_list; do ls -l $name; done


#############################################################
## Bash - Math
#############################################################

# Arithemetic in bash (add)
echo $((1+2))

# Arithmetic in bash (add/substract)
echo $((5-3))

# Arithmetic assignment in bash (add/substract)
echo $((5-3))
c=$((5+3)); echo $c

# Bash arithmetic in conditional (if block)
[[ 3 -lt "4 + 1" ]] && echo "A" || echo "B"

# Perform floating point arithmentic in bash
a=127.6
b=1800
a2=127
echo $a2+$b | bc
echo $a+$b | bc


#############################################################
## Bash - Script
#############################################################

# Get full stack trace of file that lead you to current location
echo ${BASH_SOURCE[*]}

# Get full stack trace of line numbers that lead you to current location
echo ${BASH_LINENO[*]}

# Basename of a file. bash remove longest
echo ${PWD##*/}

# Line number in a bash script
echo $LINENO


#############################################################
## Bash - String Test Operators
#############################################################

# Operator syntax           Description
# <INTEGER1> -eq <INTEGER2> True, if the integers are equal.
# <INTEGER1> -ne <INTEGER2> True, if the integers are NOT equal.
# <INTEGER1> -le <INTEGER2> True, if the first integer is less than or equal second one.
# <INTEGER1> -ge <INTEGER2> True, if the first integer is greater than or equal second one.
# <INTEGER1> -lt <INTEGER2> True, if the first integer is less than second one.
# <INTEGER1> -gt <INTEGER2> True, if the first integer is greater than second one.


#############################################################
## Bash - Paths
#############################################################

# Convert a relative path to an absolute path
readlink -f relative_path

# Convert relative to absolute path in perl
use Cwd qw(realpath);

# Compare relative to absolute path reatures (setup readlink)
ll -d file

# Compare relative to absolute path reatures
readlink -f file
readlink -e file
readlink -m file


#############################################################
## Bash - Pipeline
#############################################################

# Redirect STDERR to STDOUT
2>&1

# Redirect both STDOUT and STDERR to a pipe
2>&1 | tee out

# Swap STDERR with STDOUT
showpath | xargs ls -ld 3>&2 2>&1 1>&3

# Redirect STDERR to STDOUT
showpath | xargs ls -ld 2>&1 1>/dev/null

# Show only STDERR (redirect STDOUT)
ld_dsu.prl sre csv |1
ld_dsu.prl sre csv 1>/dev/null

# Send message to STDERR
say(){ echo "GOOD"; echo "BAD" >&2; }
say 2>/dev/null         # GOOD
say  >/dev/null         # BAD
say >> log 2>&1
say 2>&1 >> log


#############################################################
## Bash Signal Handling
#############################################################

# Use trap command to trap signals
trap arg signals

# Remove signal handling
trap signal

# Create an infinite loop (no end)
while true; do echo "$$ $BASHPID"; sleep 1; done

# See all available trap signals
trap -l

# Prevent control-C from doing anything (signal)
abc(){ echo -e "\n\nNOPE"; }
trap abc SIGINT
<Control-C>

# Prompt on a control-C (signal handling)
signal_handler(){ echo -e "\n${RED}Caught Control-C$RESTORE "; read -p "Are you sure you want to abort? (y/n): " ans; [[ $ans =~ [yY]  ]] && echo "continue" || echo "exit"; }
trap signal_handler SIGINT
<Control-C>

# Create a timer in bash (aborts the session)
handler(){ echo "done"; exit 1; }
set_timer(){ (sleep $1; kill -ALRM $$)& }
trap handler SIGALRM
set_timer 5
while [ 1 ]; do echo $$; sleep 1; done

# Trap alarm signal
trap 'echo "Hit alarm"; break' SIGALRM
while true; do echo $$; sleep 1; done
# In another window:
kill -s ALRM 11657


#############################################################
## Bash - Variables (Special)
#############################################################

# Return status $? (true/false are built-in commands)
true; echo $?
false; echo $?

# In bash return 0 means no error. return 1 means error
abc(){ return 0; }; abc && echo "OK" || echo "BAD"
abc(){ return 1; }; abc && echo "OK" || echo "BAD"

# Check if using Bash
echo $0


#############################################################
## Bash - Variables (User)
#############################################################

# Example of using a local variable
n=aaa; echo "1. n = $n"; a(){ m=$n; local n=xyz; echo "2. m = $m"; echo "3. n = $n"; }; a; echo "4. n = $n";
1. n = aaa
2. m = aaa
3. n = xyz
4. n = aaa

# Find out how many characters(length) are in a bash variable
n1=abcd
echo ${#n1}

# Remove from variable bash normal shortest
a="g2s -i ppb.gloascii -allow_overlays -ignore_errors"
echo ${a#*-}

# Remove from variable bash normal longest
a="g2s -i ppb.gloascii -allow_overlays -ignore_errors"
echo ${a##*-}

# Remove from variable bash reverse shortest
a="g2s -i ppb.gloascii -allow_overlays -ignore_errors"
echo ${a%-*}

# Remove from variable bash reverse longest
a="g2s -i ppb.gloascii -allow_overlays -ignore_errors"
echo ${a%%-*}

# View all bash variable with a matching name
echo ${!a*}

# Assign to multiple bash variables at once (list assignment)
# This uses process substitution <<<
# Can be thought of as < and <<HERE_DOC together
# Whatever is on the right is expected to be a string and
# it get fed into the STDIN on the command (read in this case).
read var1 var2 <<< $(echo "one two"); echo $var1 $var2

# Replace an occurence of a pattern in a bash variable
name=a_b_c
echo ${name/_/}

# Replace all occurences of a pattern in a bash variable
name=a_b_c
echo ${name//_/}

# Bash range expansion
echo {1..10}
for n in {1..10}; do echo $n; done


#############################################################
## Bash - While Loop
#############################################################

# While do bash readline
ls -1 | head -1  | while read line; do uicfgcheck $line; done

# read multiple words froma line in bash
while read keyfile hexkey junk; do echo "1[$keyfile] 2[$hexkey] 3[$junk]"; done

# Bash Bug when using a while loop.
# Inside of a loop not affecting outside
a="OUT"
echo "1: $a"
cat $tmp_list | while read line; do
   echo "2: $a"
   a="IN"
   echo "3: $a"
done
echo "4: $a"
# 4: OUT !!!
#
# A fix is to do this instead
a="OUT"
echo "1: $a"
while read line; do
   echo "2: $a"
   a="IN"
   echo "3: $a"
done < $tmp_list
echo "4: $a"


#############################################################
## Git - Ignore File Rules
#############################################################

# Ignore any folder named "old" anywhere (git ignore)
**/old/


#############################################################
## Git - Global Configuration Commands (once per user)
#############################################################

# Configure user information
git config --list
git config -l
git config --global user.email "<EMAIL>"
git config --global user.name "<NAME>"

# Alias commands
git config --global alias.cl         'config --list'
git config --global alias.alias      '!git config --list | grep alias'
git config --global alias.set        'config --global'
git config --global alias.unset      'config --global --unset'
git config --global alias.re         remote
git config --global alias.st         status
git config --global alias.sub        submodule
git config --global alias.supdate    'submodule update --remote'
git config --global alias.spush      'submodule push --recursive-submodules=on-demand'
git config --global alias.stmod      'status -uno'
git config --global alias.br         branch
git config --global alias.unstage    'reset HEAD --'
git config --global alias.co         checkout
git config --global alias.ci         commit
git config --global alias.colast     'checkout -- *'
git config --global alias.cleanup    'clean -fd'
git config --global alias.undo       '!git colast; git cleanup'
git config --global alias.mm         'merge --no-commit github/master'
git config --global alias.pm         'pull github master'
git config --global alias.untrack    'rm --cached'
git config --global alias.ct         '!git add .; git ci -m "Added cheats"'
git config --global alias.subup      'submodule update --recursive'

# Set the git commit editor
git config --global core.editor "vim"

# Unset a global config (such as user.name)
git config --global --unset user.name

# Remove all aliases
git config --global --remove-section alias

# Prevent line endings from being converted
git config --global core.autocrlf false

# Warning: Pulling without specifying how to reconcile divergent branches
git config --global pull.ff o


#############################################################
## Git - Folder Configuration Commands (once per local master)
#############################################################

# Create blank repository
git init

# Create blank repository, but in another location
git init --separate-git-dir BACKUP/.git

# Move a git repository to another location and preserving log history (Old Approach)
mv ~SOME_USER/.git BACKUP/.git
cd ~SOME_USER
git --git-dir=BACKUP/.git --work-tree=. init

# Move a git repository to another location and preserving log history (New Approach)
mv ~SOME_USER/.git BACKUP/.git
cd ~SOME_USER
git init --separate-git-dir BACKUP/.git

# Create blank repository, but in another location (alternative)
# .git is a file in this case
echo "gitdir: BACKUP/.git" > .git

# Copy a repository (and place it in the folder my_proj)
git clone <url>

# Copy a repository (and place it in the folder new_proj)
git clone <url> new_proj

# Copy a repository (and place it in the current directory)
git clone <url> .

# Display origin path (GitLab path)
git remote -v

# Diaply more remote information (shows also HEAD branch)
git remote show origin

# Add remote repository (remote is like an alias)
git remote add origin <url>

# Alter remote repository
git remote set-url origin <url>

# Git. Rename remote repository name
git remote rename origin github

# Do NOT ignore a particular file in git
!<file>
!/.gitignore


#############################################################
## Git - Stage Commands
#############################################################

# Add file to the staging area
git add file1

# Add txt files to the staging area
git add '*.txt'

# Use if separate commits modify the same file. Partially stage files
git add -patch

# Add all files in the current directory to the staging area
git add -A .

# Check status of the staging area
git status

# Remove from staging area
git reset file1

# Reset local area to be save as remote repository
git reset --hard github/addsvn

# Unmerge file, reset to a certain commit
git reset --hard bad_commit_id~N

# Remove file
git rm file1

# Remove files ('' to protect from shell interpolation)
git rm '*.txt'

# Remove folder
git rm -r folder1

# Revert untracked changes
git checkout -- *

# Remove untracked files and directories
git clean -fd

# Remove untracked files and directories (úsing not standard ignore rules)
git clean -xfd

# Stop tracking a certain file (will NOT remove file)
git rm --cached file1

# Stop tracking a certain directory (will NOT remove directory)
git rm --cached -r directory1

# fatal: Pathspec 'dir1' is in submodule 'dir2'
# Due to subdirectory having it's own .git
# Need to remove .git in subdirectory and recreate subdirectory


#############################################################
## Git - Diff Commands
#############################################################

# View changes between staged and branch
git diff --staged

# View whitespace changes
git diff --check

# View changes between playground and branch master
git diff HEAD

# View the last change made to a file (diff)
git diff file

# Show difference between 2 different commits
git diff <commit> <commit> <file>

# Show differences between 2 commits (relative to each other)
git diff <commit> <commit>~1 <file>

# Show a summary of differences between 2 commits (relative to each other,only filenames)
git diff --stat <commit> <commit>~1

# Compare 2 files in the same branch (need to disambiguate from 2 branches)
git diff :old :new
git diff :old new

# Compare exceptions template files for differences
cat ~/junk/exceptions | while read n; do ls -l $n~ $n; done
cat ~/junk/exceptions | while read n; do diff $n~ $n -qs; done
cat ~/junk/exceptions | while read n; do git diff $n~ $n; done


#############################################################
## Git - Commit/Checkout Commands
#############################################################

# Commit files to the branch
git commit -m "new file"

# Commit files to the branch and auto remove any extra files
git commit -a -m "new file"

# Reset files to last commit (file is not changed if in staging area)
git checkout -- file1

# No more options after command (used incase branch named file1 exists)
--

# Checkout a particular commit for a signle file
git checkout <commit> <file>

# Messed up in a commit. Checkout so many commits back
git checkout <commit>~1 <file>

# Checkout a remote branch (tracked,co)
git checkout --track origin/my_branhc

# Revert the last command which was NOT pushed out.
git reset --soft HEAD~1

# Revert the last command which was pushed out.
git revert <commit>
git push


#############################################################
## Git - Log Commands
#############################################################

# Show/Check commit log (basic usage)
git log

# Show/Check commit log with plus's for revisions per file
git log --stat

# Show/Check a summary of the commit log (does not seem too useful)
git log --summary

# Show/Check a really fancy progression of the branch revisions (commit log)
git log --oneline --decorate --graph --all

# See which what fetched changes need to be merged
git log --no-merges

# Find all log commits whose files match a pattern
git log -Garinc_xmt

# Find all commits where a file was changed (affected)
git log --follow <file>
git log <file>

# Show all commits/changes for a file (diff,generate patch report)
git log -p <file>
git log --patch <file>

# Show all commits/changes for a file in chronological order (diff,patch report)
git log -p --reverse <file>

# Display log without a pager
git -no-pager log

# Display a list of all commits made to a branch (prepare for cherry-pick)
# Shows commits which are not in the branch before ".."
# (In other words, unique to the branch).
git log --no-merges BRANCH..
git --no-pager log --no-merges rel-8_0.. --oneline --reverse --no-abbrev-commit
#
# Same but includes the committer (author).
local format="%C(yellow)%H%Creset %Cred%cn%Creset %s"
git --no-pager log --no-merges $branch.. --reverse --pretty="format:$format"
echo ""

# Display a list of all files changed between commits
git --no-pager log --no-merges rel-8_0.. --name-only --pretty= | sort -u


#############################################################
## Git - Push/Pull Commands
#############################################################

# Push upstream to origin from the branch (only after using -u switch)
git push

# Fetch (sync) from the assigned repository (but do NOT checkout any files)
git fetch

# Fetch from repository (origin)
git fetch origin

# Sync with a specific repository (but do NOT checkout any files)
git fetch <url>

# Pull down changes to branch from origin
git pull origin master
git pull github master

# When there is a conflict when pulling a branch,
# this will pull in the changes and put your commits
# as last
git pull --rebase

# Push upstream to origin from the branch
git push -u origin master
git push github addsvn

# Remove a remote branch
git push --delete origin <branch name>

# Checkout latest commit version of a single file
git init
git fetch <url>
git checkout FETCH_HEAD <file>

# Checkout select commit version of a single file
git init
git fetch <url>
git checkout -m <commit_id> <file>

# Checkout a specific version of a single file
git checkout -m <commit_id> file

# Checkout a file from another branch
git checkout master file1

# Checkout a file from 2 revisions back
git checkout master~2 file1

# Protect your changes when pulling from origin
git stash

# Unprotect changes
git stash apply

# To periodically update the repo on GitHub with what you have in GitLab
git fetch -p origin
git push --no-verify --mirror


#############################################################
## Git - Prune Commands
#############################################################

# warning: There are too many unreachable loose objects; run 'git prune' to remove them.
git gc


#############################################################
## Git - Branch Commands
#############################################################

# View all branches
git branch

# View all branches details
git branch -v

# View all branches (including remote)
git branch -a

# Create a branch of the local master
git branch my_branch

# Get current branch name
git branch --show-current

# Check out a branch
git checkout my_branch

# Create a new branch and check it out
git checkout -b my_branch

# Create a new branch (and check it out) from origin/master (repository/branch)
git checkout -b my_branch origin/master

# Rename branch
git branch -m svn_update SR15308587

# List git branch but without the asterisk
git for-each-ref --format='%(refname:short)' refs/heads/

# Merge branch into the current branch
git merge clean_up

# Delete/remove a branch
git branch -d my_branch

# Merge changes from repository into your local folders
git merge origin/master

# Read/merge in changes from master branch into current branch
git merge --no-commit github/master

# Merge remote branch and preferring local changes
git merge -X ours origin/master

# Git compare branches
git diff svn_update master


#############################################################
## Git - Tag Commands
#############################################################

# Create a new tag
git tag v1

# Push tag to master repository (not done by default)
git push --tags github addsvn

# List available tags
git tag -l

# List tags by date (OMS)
git tag -l --sort=taggerdate

# List available tags according to pattern
git tag -l <pattern>

# Upload branch and tag when they are the same
git push github refs/heads/V2.7.0 refs/tags/V2.7.0

# Checkout all tags
git fetch --all --tag --prune

# Show some changes in a tag (possibly since creating it)
git show <tag>

# Checkout a certain tag (pseudo way)
git checkout -b <branch> <tagname>

# Delete an existing tag
git tag -d <tag>

# Delete tag from remote repository
git push --delete origin TAG1
git push origin :TAG1

# Compare 2 separate tags
git diff --stat V1.0.0 V1.1.0


#############################################################
## Git - Submodule Commands
#############################################################

# Add new submodule to existing repository
git submodule add <url>
# Creates file .gitmodules

# update submodule
git submodule update --init --recursive

# Update all the submodules in the repository
git submodule update --init --recursive --rebase --force

# View submodule status
git status

# Diff submodule
git diff --cached                # wont show submodules unless inside the folder
git diff --cached --submodule

# Commit submodule changed
# Mode 16000 means "you're recoding a commit as a directory
# entry rather than a subdirecotry or file"
git ci -am "Added Submodules"

# Cloning project with submodules
# By default will get the submodule folder with no files
git clone <url>            # Clone project
cd <submodule_folder>
git submodule init         # Init local files
git submodule update       # Get latest content of submodule

# Cloning project with submodules (simpler)
git clone --recursive <url>

# To remove a git submodule you need to:
# 	Delete the relevant section from the .gitmodules file.
# 	Stage the .gitmodules changes git add .gitmodules
# 	Delete the relevant section from .git/config.
# 	Run git rm --cached path_to_submodule (no trailing slash).
# 	Run rm -rf .git/modules/path_to_submodule (no trailing slash).
# 	Commit git commit -m "Removed submodule "
# 	Delete the now untracked submodule files rm -rf path_to_submodule


#############################################################
## Git - Extra Unused Commands
#############################################################

# Push upstream to origin (GitLab) and set upstream
git push -u origin master

# Pull down changes from origin
git pull origin master

# Need to restart explorer.exe after installing TortoiseGit
# before the icons will change.


#############################################################
## HTML Attribute - href
#############################################################

# Run a javascript function when clicking a link instead of going to a page
<a class="myWrapper" href="javascript:myFunc()"><div class="myText">+</div></a>


#############################################################
## HTML Element - details
#############################################################

# Create an automatically foldable element in HTML
<details>
	<summary>Quick summary</summary>
	<h1>All details start here</h1>
	<p>and continue till the end</p>
</details>


#############################################################
## HTML - Validation
#############################################################

# Input element validation in html (check,regex)
<input name="NAME" type="number" placeholder="?" step="any" class="value" style="grid-column: 5 / 6; grid-row: 2 / 3;" value="4.000">
<input name="name" type="text" pattern="^[-\wÄäÖöÜü\.,_]+$" value="VALUE">


#############################################################
## Java
#############################################################

# Compile a java program (script)
javac hello.java

# Run a java program (execute script)
java hello


#############################################################
## Javascript - General
#############################################################

# Efficient way in javascript to insert text as html (append to body)
document.querySelector('#id').insertAdjacentHTML('beforeEnd', to_add)
# (works fast, but script tags are not usable).
#
# Use this to allow using script tags
$(id).append(details_rc);


#############################################################
## Javascript - Ajax
#############################################################

# Javascript loaded in via ajax is not automatically executed.

# AJAX Javascript Example
function loadDoc() {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
     document.getElementById("demo").innerHTML = this.responseText;
    }
  };
  xhttp.open("GET", "ajax_info.txt", true);
  xhttp.send();
}

# AJAX Javascript Example (simpler)
# 'onload' is newer and a replacement for 'onreadystatechange' with the state check
function loadDoc() {
  var xhttp = new XMLHttpRequest();
  xhttp.onload = function() {                       // <== Difference
     document.getElementById("demo").innerHTML = this.responseText;
  };
  xhttp.open("GET", "ajax_info.txt", true);
  xhttp.send();
}

# Submit a form using ajax. (prevents auto reload)
function save_details(endpoint) {
    console.log("POST ", endpoint);
    const form  = document.querySelector("form[id=details]");
    const xhttp = new XMLHttpRequest();
    xhttp.open("POST", endpoint);
    xhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
    xhttp.send( $("#details").serialize() );
}


#############################################################
## Javascript - Attributes
#############################################################

# Set/Get meta data for an HTML element
form = document.querySelector("form[id=details]");
form.setAttribute('_meta', "my_meta")
form.getAttribute('_meta')


#############################################################
## Javascript - Benchmark
#############################################################

# Time a function in javascript (benchmark)
# Not really accurate
const startTime = new Date().getTime();
const endTime = new Date().getTime();
console.log("sort function took " + (endTime-startTime) + "(ms)")

# Function for benchmarking different code snippets (timing,testing,profiling)
# Simple.
function benchmark(functions,iterations=1) {
  for(const code of functions){ // foreach loop in javascript
    const name = code.name;     // Code refence to name
    console.time(name);         // Timing/benchmarking function
    for(let i = 1; i <= iterations; i++ )
      code();
    console.timeEnd(name);
  }
}
# Usage
benchmark([get_head_checkbox, get_head_checkbox2]);
benchmark([get_head_checkbox, get_head_checkbox2],10000);

# Function for benchmarking different code snippets (timing,testing,profiling)
# Includes percentages and sorted.
// function benchmark() {
//   // Get inputs
//   let   code_refs  = [...arguments];
//   let   iterations = 1;
//   const last_index = code_refs.length - 1;
//
//   // Check last input
//   if(typeof(code_refs[last_index]) == "number")
//     iterations = code_refs.pop();
//
//   // Check for tests
//   if(!code_refs.length)
//     return;
//
//   const stats = [];
//
//   // Get statistics
//   for(const code of code_refs){           // foreach loop in javascript
//     const t0 = performance.now();         // High precision time
//     for(let i = 1; i <= iterations; i++ ) // Run a specified amount of times
//       code();
//     const time = (performance.now()-t0).toFixed(2);
//     stats.push({name: _get_code_name(code), time: time});
//   }
//
//   // Sort statistics: fastest (lowest time) first
//   stats.sort((a,b) => (Number(a.time) >= Number(b.time)) ? 1 : -1);
//
//   // Baseline to compare with
//   const longest_time = stats[stats.length-1]["time"];
//
//   // Add percentage to each test set
//   for(const set of stats){
//     const time    = set.time;
//     const percent = ((longest_time-time)/time*100).toFixed(0);
//     set.percent = percent;
//   }
//
//   // Print statistics
//   console.table(stats);
// }
//
# Javascript function to convert a block of code to a name
// function _get_code_name(code) {
//   const name     = code.name;             // Code reference to name
//   let   toString = code.toString();       // Code reference to name
//
//   if(name)
//     return name;
//
//   const is_anon_function1_start = /^\s*function\(\)\s*{\s*/;    // function(){ code }
//   const is_anon_function1_end   = /\s*}$/;
//   const is_anon_function2_start = /^\s*\(\s*\)\s*=>\s*{\s*/;    // () => { code }
//   const is_anon_function2_end   = /\s*}$/;
//   const is_anon_function3_start = /^\s*\(\s*\)\s*=>\s*(?!{)/;   // () => code
//   const is_anon_function3_end   = /\s*$/;
//
//   if(toString.match(is_anon_function1_start)){        // function(){ code }
//     toString = toString
//     .replace(is_anon_function1_start, "")
//     .replace(is_anon_function1_end,   "");
//   }
//   else if(toString.match(is_anon_function2_start)){   // () => { code }
//     toString = toString
//     .replace(is_anon_function2_start, "")
//     .replace(is_anon_function2_end,   "");
//   }
//   else if(toString.match(is_anon_function3_start)){   // () => code
//     toString = toString
//     .replace(is_anon_function3_start, "")
//     .replace(is_anon_function3_end,   "");
//   }
//
//   return toString;
// }
//
# Usage
benchmark(myfunc, myfunc2);
benchmark(myfunc, myfunc2,10000);
benchmark(myfunc, function(){ $('#table .row :checkbox') }, () => { $('#id') },() => $('#id') ,1000)


#############################################################
## Javascript - Callbacks
#############################################################

# Simple nameless function (coderef,annonym)
# No inputs.
#
# Perl
$greet = sub{ qq(Hello bob) }
print $greet->()
#
# JS
greet = () => `Hello bob`
greet = () => { return `Hello bob` }
greet()

# Simple nameless function (coderef,annonym)
# Scalar input. (single)
#
# Perl
$greet = sub{ my($name) = @_; qq(Hello $name) }
print $greet->()
#
# JS
greet = (name) => `Hello ${name}`
greet = (name) => { return `Hello ${name}` }
greet("bob")

# Simple nameless function (coderef,annonym)
# Hash input. Scalar out.
#
# Perl
$greet = sub{ my($hash) = @_; qq(Hello $hash->{name}) };
print $greet->({name => 'bob'})
#
# JS
greet = ({name}) => `Hello ${name}`
greet = ({name}) => { return `Hello ${name}` }
greet({name:"bob"})

# Simple nameless function (coderef,annonym)
# Hash input. Hash out.
#
# Perl
$greet = sub{ my($hash) = @_; {msg => qq(Hello $hash->{name})} };
print $greet->({name => 'bob'})->{msg}
#
# JS
greet = ({name}) => { return {msg: `Hello ${name}`} }
greet({name:"bob"}).msg


# Simple nameless function (coderef,annonym)
# Hash input. Hash out.
#
# Perl
$greet = sub{ my($hash) = @_; {msg => qq(Hello $hash->{name}), age => qq(You are $hash->{age})} };
$greet = sub{ $h=shift; {msg => qq(Hello $h->{name}), age => qq(You are $h->{age})} };				# Shorter
$params = {name => 'bob', age => 18};
print $greet->($params)->{msg};
print $greet->($params)->{age}
#
# JS
greet = ({name,age}) => { return {msg: `Hello ${name}`, age: `You are ${age}`} }
params = {name:"bob", age: 18}
greet(params).msg
#greet(params).age


#############################################################
## Javascript - Checkbox
#############################################################

# Check/uncheck a box in javascript
document.querySelector("input[name=NAME]").checked = true
document.querySelector("input[name=NAME]").checked = false
if(document.querySelector("input[name=NAME]").checked) ...

# CSS Selector for a checked checkbutton (input)
document.querySelectorAll(".row input[type='checkbox']:checked")

# CSS Selector for all the unchecked checkbutton (input)
document.querySelectorAll(".row input[type='checkbox']:not(:checked)")


#############################################################
## Javascript Content - Copy
#############################################################

# Make a clone/copy of an element. (html,javascript)
const svg_logo = document.querySelector(".logo svg").cloneNode(true);
# svg must be put in its own container (like a div) to be used.


#############################################################
## Javascript - Date
#############################################################

# Date arithmetic in Javascript (add 90 days to a date)
date = new Date();
date.setDate(date.getDate()+90);

# Build a date in Javascript.
function buildDate (time) {
    const date = new Date();
    date.setHours(time.split(':'), 0);
    return date;
}

# Timestamp in javascript
function _pad(n) {
    return n < 10 ? '0' + n : n;
}
// function make_timestamp() {
// 	const date      = new Date();
// 	const timestamp =		// 2020-10-06_09-12-10
// 		date.getFullYear() +
// 		"-" +
// 		_pad(date.getMonth()+1) +
// 		"-" +
// 		_pad(date.getDate()) +
// 		"_" +
// 		_pad(date.getHours()) +
// 		"-" +
// 		_pad(date.getMinutes()) +
// 		"-" +
// 		_pad(date.getSeconds());
//
// 	return	timestamp;
// }
// function make_timestamp_yyyy_mm_dd(date) {
// 	const timestamp =		// 2020-10-06
// 		date.getFullYear() +
// 		"-" +
// 		_pad(date.getMonth()+1) +
// 		"-" +
// 		_pad(date.getDate());
//
// 	return	timestamp;
// }

# Javascript get the hours between two times within a 24 hours period of time (same day).
startTime = new Date('01/01/2021 ' + '15:00:00')
endTime    = new Date('01/01/2021 ' + '16:30:00')
diff       = new Date(null)
diff.setMilliseconds(endTime - startTime)
diff.getUTCHours()

# Javascript ceiling function.
Math.ceil(9.2)          # 10


#############################################################
## Javascript - Events
#############################################################

# Capture javascript double click events
divOption.addEventListener("dblclick", () => {
    switchToNewOption(index);
    document.querySelector("#filterInput").focus();
});

# addEventListener useCapture parameter meaning (javascript)
//
window.addEventListener('load', function() {
  alert("All done");
}, false);
//
child.addEventListener("click", second);
parent.addEventListener("click", first, true);
when clicking child element, first method will be called before second.

# Add a function to an event (HTML Event Listener)
is_no_automatic_change.addEventListener("change", validate_general_tab_checks);
document.querySelector("input[name=NAME]").addEventListener("change", myFunc)

# Remove a function from an event (HTML Event Listener)
document.querySelector("input[name=NAME]").removeEventListener("change", myFunc, false)

# Check if an event is set (HTML Event Listener)
getEventListeners(document.querySelector("input[name=NAME]")).change


#############################################################
## Javascript - Functions
#############################################################

# Javascript function name (like __FUNCTION__)
console.log(arguments.callee.name);

# => arrow function expression in JavaScript
// The regular function above can be written as the arrow function below
elements.map((element) => {
  return element.length;
}); // [8, 6, 7, 9]

# Javascript functions for getting the name of the calling functions
// function whoami(){
//
//   return arguments.callee.caller.name;
// }

# Spread javascript array into a function arguments.
d = new Date();
d.setHours( ... [8, 0] );
d.setHours( ... '08:00'.split(':') )


#############################################################
## Javascript - Grid
#############################################################

# JavaScript - gridTemplateRow
Size (height) of each row. One number per row
gridTemplateRow 3rem 4rem 5rem			# set size of rows: 1, 2, 3


#############################################################
## Javascript - JSON
#############################################################

# Javascript string to object
JSON.parse('{"abc": "1"})
eval(`obj = ${data}`)


#############################################################
## Javascript - List
#############################################################

# Javascript filter a list according to a pattern (array)
const filterPattern   = new RegExp("^" + input.value, "i");
const filteredOptions = options.filter(text => { return text.match(filterPattern) });

# Javascript last element of a list/array
activeOption.id.split("-").slice(-1)[0]

# Convert iterable like HTMLCollection to an array (Javascript)
# then apply a map to it.
Array.from(activeOption.parentElement.children).map(o => {return o.id})

# Find the index of an array element in javascript
[4,5,6].indexOf(6)

# Javascript merge arrays (lists)
arr = [1,2,3]
arr2 = [11,12,13]
[arr,arr2]
	(2) [Array(3), Array(3)]
[ ...arr, ...arr2 ]
	(6) [1, 2, 3, 11, 12, 13]

# Javascript range operator alternatives. (100...500)
Array(400).fill().map( (_,i) => i+100)
#
# Usage:
ids = Array(490).fill().map( (_,i) => '000_auto_' + (i+10+1)).join(',')
remove_rows(ids)


#############################################################
## Javascript - Local Storage
#############################################################

# Create a file which the user can download
# function downloadForm() {
# 	const fileNameToSaveAs = 'out.xml';
# 	const textToWrite      = "hello world";
#
# 	/* Saves a text string as a blob file*/
# 	const ie     = navigator.userAgent.match(/MSIE\s([\d.]+)/);
# 	const ie11   = navigator.userAgent.match(/Trident\/7.0/) && navigator.userAgent.match(/rv:11/);
# 	const ieEDGE = navigator.userAgent.match(/Edge/g);
# 	const ieVer  =(ie ? ie[1] : (ie11 ? 11 : (ieEDGE ? 12 : -1)));
#
# 	if (ie && ieVer<10) {
# 		console.log("No blobs on IE ver<10");
# 		return;
# 	}
#
# 	const textFileAsBlob = new Blob([textToWrite], {
# 		type: 'text/plain'
# 	});
#
#   	if (ieVer>-1)
#     	window.navigator.msSaveBlob(textFileAsBlob, fileNameToSaveAs);
# 	else
# 	    $("<a>").attr({
# 	    	download: 	fileNameToSaveAs,
# 	    	href: 		window.URL.createObjectURL(textFileAsBlob),
# 	    })
# 	    .on("click", function(e){ document.body.removeChild(e.target) })
# 	    .hide()
# 	    .appendTo("body")
# 	    .get(0)
# 	    .click();
# }


#############################################################
## Javascript - Math
#############################################################

# Javascript float to integer
Math.trunc(3.5)

# Javascript round to 2 decimal places.
4.125456.toFixed(2)
parseFloat("4.125456").toFixed(1)		// String to float, then rounded

# Javascript truncate a number. Integer part only. Remove decimal point.
Math.trunc(19/60)


#############################################################
## Javascript - Objects/Hash
#############################################################

# Javascript check if key exists in a object/hash
"my_key" in machines

# Javascript variable name as object key
a="abc"
h={[a]: 123}
// h = {abc: 123}

# Javascript merge objects (hashes)
h1 = {"a":1, "b":2}
h2 = {"a2":12, "b2":22}
h2 = { ...h1, ...h2 }


#############################################################
## Javascript - Query
#############################################################

# Get the first option of a selection
document.getElementById("selection").options[0].value

# Multiple cells or return values from a query
document.querySelectorAll("#id1, #id2")


#############################################################
## Javascript - Regex
#############################################################

# Using a variable inside a Javascript pattern
const filterPattern = new RegExp("^" + input.value, "i");

# JavaScript regex
# 0 - Whole group
# 1 - First parenthesis
(document.querySelector("#table").style.gridTemplateRows.match(/repeat\(\s*(\d+)\s*,\s*min-content/))[1]

# Javascript replace function syntax (regex)
let newPageUrl = currentPageURL.replace(/\/([a-zA-Z_]+=.*)/, "");


#############################################################
## Javascript - Scroll
#############################################################

# Javascript element scrolling if needed
if(goingUp){
    // avtiveOption.scrollIntoView(true);
    avtiveOption.scrollIntoView({behavior: "smooth", block: "end", inline: "nearest"});
}
else{
    avtiveOption.scrollIntoView({behavior: "smooth", block: "start", inline: "nearest"});
    // avtiveOption.scrollIntoViewIfNeeded(true);
}

# Enable/Disable scrollbars (CSS,style)
function disable_scrollbars () {
    document.querySelector("#table").style.overflow = "hidden";
}
function enable_scrollbars () {
    document.querySelector("#table").style.overflow = "auto";
}

# Get/Set scroll position (CSS,style)
function get_scroll_position() {
    return document.querySelector("#table").scrollTop;
}
function set_scroll_position(pos) {
    document.querySelector("#table").scrollTop = pos;
}


#############################################################
## Javascript - Sort
#############################################################

# Javascript sort a list numerically in place
const arr = [1,2,11,3];
arr.sort( (a,b) => {return a - b } );

# Case insensitive sort in javascript
Object.keys(toolstoreNames)
	.map(n => [n, n.toLowerCase()])
	.sort( (a,b) => {return a >= b ? 1 : -1})
	.map(n => n[0])

# Binary sort and insert in javascript
// function _dom_add_job(row) {
// 	console.log("_dom_add_job_row(): ", row);
//
// 	// Input
// 	let $row;
// 	if(typeof(row) == "string")
// 		$row = $(document.getElementById(row));
// 	else
// 		$row = $(row);
//
// 	// Error checks
// 	if($row.length == 0){
// 		console.error(`_dom_add_job(): row with id='${row}' not found!`)
// 		return;
// 	}
//
// 	// Row id
// 	let row_id = $row.attr("id");
// 	if(row_id == null)
// 		row_id = "";
// 	// console.log(`row_id: ${row_id}`);
//
// 	// Table of rows (exluding the desired row)
// 	$rows = $('#table .row').not($row).map( (_,el) => [[el,el.id]] );
// 	const FIRST = 0; // Obviously
// 	const LAST  = $rows.length - 1;
// 	const ELEM  = 0;
// 	const ID    = 1;
//
// 	// Determine where to move the desired row.
// 	if($rows.length == 0){ 								// Empty table
// 		// console.log("- Insert before #last_row");
// 		$row.insertBefore('#last_row');
// 	}
// 	else if(row_id < $rows[FIRST][ID]){ 				// Before first row
// 		// console.log("- Insert FIRST", $rows);
// 		$row.insertBefore($rows[FIRST][ELEM]);
// 	}
// 	else if(row_id > $rows[LAST][ID]){ 					// After last row
// 		// console.log("- Insert LAST", $rows);
// 		$row.insertAfter($rows[LAST][ELEM]);
// 	}
// 	else {												// In the middle (binary search)
// 		// console.log("- Insert somewhere else!", $rows);
// 		let first  = FIRST;
// 		let last   = LAST;
// 		let mid;
// 		// console.log(`START: first=${first}, mid=${mid}, last=${last}`,  $rows[mid][ID]);
//
// 		while(first < last) {
// 			mid = first + Math.trunc( (last-first) / 2 );
// 			// console.log(`first=${first}, mid=${mid}, last=${last}`);
//
// 			if(row_id > $rows[mid][ID]){
// 				// console.log("RIGHT");
// 				first = mid + 1;
// 			}
// 			else {
// 				// console.log("LEFT");
// 				last = mid;
// 			}
// 		}
//
// 		mid = first + Math.trunc( (last-first) / 2 );
// 		// console.log(`END: first=${first}, mid=${mid}, last=${last}`);
// 		$row.insertBefore($rows[mid][ELEM]);
// 	}
//
// 	return $rows;
// }


#############################################################
## Javascript - Spinner
#############################################################

# Function to show a loading spinner
function show_loading(){
    const screen       = document.querySelector("#glass");
#
    // Return if we already have a screen up.
    if(screen.children.length)
        return;
#
    const canvas       = document.createElement("canvas");
    const spinner      = document.createElement("div");;
    const svg_box      = document.createElement("div");
    const logo         = document.querySelector(".logo svg").cloneNode(true);
    canvas.className   = "center";
    spinner.className  = "center loader";
    svg_box.className  = "center loading-svg";
#
    screen.append(canvas);
    screen.append(spinner);
    screen.append(svg_box);
    svg_box.appendChild(logo);
#
    svg_box.addEventListener("click", hide_loading);
    show_glass();
#
    // Setup
    const radius  = 75; // Inner circle radius
    const ctx     = canvas.getContext('2d');
    const centerX = canvas.width / 2;
    const centerY = canvas.height / 2;
    ctx.beginPath();
#
    // Draw shape
    ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
    ctx.fillStyle = '#ffffff'; // light grey
    ctx.fill();
}

# Create a simple CSS/HTML animation (blink an element)
.blink {
    animation: blinker 2s linear infinite;
}
@keyframes blinker {
  50% {
    opacity: 0.5;
  }
}

# Function to unshow the loading spinner
function hide_loading(){
    const screen = document.querySelector("#glass");
#
    if(screen.children.length){
        setTimeout(() => {
            while(screen.firstChild)
                screen.removeChild(screen.firstChild);
            hide_glass();
        }, 500);
    }
    else{
        hide_glass();
    }
}

# CSS for the loading spinner
.center {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
.loading-svg {
  width:  5.7375rem;
  height: 2.23125rem;
  cursor: pointer;
}
.loading-svg svg > path, .loading-svg svg > ellipse, .loading-svg svg > rect {
  fill: #888;
}
.loading-svg svg > .thicker {
  fill: #888;
}
.loading-svg svg > .thinner {
  fill: #777;
}
.loader {
  border-top:    2px solid #777;  /* dark */
  border-bottom: 2px solid #777;  /* dark */
  border-left:   2px solid #ccc;  /* light */
  border-right:  2px solid #ccc;  /* light */
  border-radius: 50%;
  height:        150px; /* Diameter of ring */
  width:         150px; /* Diameter of ring */
  margin-top:   -77px;  /* height/2 + border */
  margin-left:  -77px;  /* width/2  + border */
  animation:    spin 3s linear infinite;
}
@keyframes spin {
  0%   { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}


#############################################################
## Javascript - Strings
#############################################################

# Capitalize first letter of a word in Javascript
string = string.charAt(0).toUpperCase() + string.slice(1);

# Addition versus concatenation (javascript,to integer)
        5   +         2   => 7
       "5"  +        "2"  => 52
       "5"  +         2   => 52
Number("5") + Number("2") => 7
Number("5") +         2   => 7

# Javascript convert a string to lowercase (uppercase is similar)
"AAA".toLowerCase()

# Javascript check if a variable is defined
if(typeof file_root_name == 'undefined'){
    return;
}
if(file_root_name == null){
    return;
}

# String interpolation in javascript (only with backticks and curlys)
n = 123
console.log("here is: ${n}")		// here is: ${n}
console.log('here is: ${n}')		// here is: ${n}
console.log(`here is: ${n}`)		// here is: 123
console.log(`here is: $n`  ) 		// here is: $n

# Encode a url using Javascript
encodeURI('159278 #01')
159278%20#01
#
# Better Javascript encoding
encodeURIComponent('159278 #01')
159278%20%2301


#############################################################
## Javascript - WebSockets
#############################################################

# Create a websocket in Javascript (usage)
const ws = new WebSocket(`ws://${location.host}/${module}.ws`);
//
ws.send(JSON.stringify(data));
//
ws.onmessage = msg => {
    try {
        const data = JSON.parse(msg.data);
        console.log("onmessage msg: ", msg);
    } catch(e) {
        console.error(e, msg.data);
    }
}


#############################################################
## Javascript - Window
#############################################################

# JavaScript force reload/refresh a webpage
# Like Control + F5 in Chrome
window.location.reload();
location.reload(1)

# Javascript redirect to another page like the anchor tag would do
window.location.href = "http://www.w3schools.com";


#############################################################
## Javascript Commands - appendChild
#############################################################

# Import a javascript file dynamically
function import_js(file) {
    const script = document.createElement("script");
    script.src = file;
    document.querySelector("#id").appendChild(script);
}


#############################################################
## Javascript Commands - getBoundingClientRect
#############################################################

# Javascript function to check if child element is visible in the parent
function isVisible(element,parent) {
    const elementBox = element.getBoundingClientRect();
    const parentBox  = parent.getBoundingClientRect();
    let visible      = 0;
    let up;
    if(elementBox.top < parentBox.top){
        up = 1;
    }
    else if(elementBox.bottom > parentBox.bottom){
        up = 0;
    }
    else {
        visible = 1;
    }
    return {visible: visible, up: up};
}
//
// Usage
const view = isVisible( activeOption, OptionsDiv );
if(! view.visible){
    activeOption.scrollIntoView(view.up);
}


#############################################################
## Javascript Commands - removeChild
#############################################################

# Remove all the children of an element (javascript)
while(element.firstChild)
    element.removeChild(element.firstChild);


#############################################################
## Javascript Commands - table
#############################################################

# Output a table from data in Chrome console
console.table([{a:1,b:2},{a:3,b:4},{b:5,a:2}])


#############################################################
## JQuery - Ajax
#############################################################

# Submit a form using ajax. (structured format,compact)
function submit_form(file_root_name) {
    const endpoint = "/my_endpoint";
    console.log("POST ", endpoint);
    $.ajax({
        url: endpoint,
        headers: {
            'Content-type': 'application/x-www-form-urlencoded',
        },
        method: 'POST',
        data: $("#id").serialize(),
    });
}

# GET request using ajax
$.ajax({
    url: path,
    method: 'GET',
    success: (data, status, xhr) => {
        body.innerHTML += data;
    },
    error: (xhr,status,reason) => {
        cancel_callback();
        if(status == "timeout"){
        	alert("ERROR Making request);
        }
        else{
            const data = xhr.responseText;
            console.log(`status: ${status}, data: ${data}, reason: ${reason}, xhr: `, xhr);
            show_error_dialog(data);
        }
    },
});


#############################################################
## JQuery - Attributes
#############################################################

// Remove an attribute in jQuery
$('.ui-tooltip[id*=ui-id-]')
	.clone()
	.removeAttr("id")
	.removeAttr("opacity")
	.appendTo("body");


#############################################################
## JQuery - Benchmark
#############################################################

# Avoiding the Universal selector (JQuery,Optimizations,Permformance,Speed)
$('form :checkbox');			// Same ...
$('form *:checkbox');			// as this.
$('form input:checkbox');		// 200% faster
$('input:checkbox', 'form');	// Best
#
benchmark(()=>$('#table .row :checkbox'), ()=>$('#table .row input:checkbox'), ()=> $('#table .row *:checkbox'), ()=>$('.row input:checkbox', '#table'), ()=>$('input:checkbox', '#table .row'), ()=>$('#table .row input[type=checkbox]'),100)
0: $('#table .row input[type=checkbox]') 59.09ms  (1124%)
1: $('#table .row input:checkbox')		 205.39ms (252%)
2: $('.row input:checkbox', '#table')	 212.22ms (241%)
3: $('#table .row *:checkbox')			 663.52ms (9%)
4: $('input:checkbox', '#table .row')	 719.50ms (1%)
5: $('#table .row :checkbox')			 723.14ms (0%)

# Improving the Class selector (JQuery,Optimizations,Permformance,Speed)
# Combine the Element selector with the Class selector.
var $elements = $('p.description');

# Don’t abuse the context parameter (JQuery,Optimizations,Permformance,Speed)
# Dont need context when giving an ID
var $element = $('#test', 'div');		// Slow
var $element = $('#test');				// Faster
#
# Never prepend a tag name to an ID.
# This prevent jQuery from using the native getElementById()
$('p#test')								// BAD

# Optimizing filters (JQuery,Optimizations,Permformance,Speed)
# Prefer functions over selectors.
#
$('p:visible');					// Not native CSS. Therefore slow
$('p').filter(':visible');		// Better
#
$(':reset');					// BAD
$('[type="reset"]');			// Better (using native attribute selector)
$('input[type="reset"]');		// Even better
#
$('#my-list li:eq(2)');			// Slow
$('#my-list li').eq(2);			// Better
#
$('#my-list li:lt(2)');			// Slow
$('#my-list li').slice(0, 2);	// Better
#
$('input[placeholder!="Name"]');			// Slow
$('input').not('[placeholder="Name"]');		// Fast

# Don’t overspecify selectors (JQuery,Optimizations,Permformance,Speed)
# jQuery relies on a selector engine, called Sizzle, that parses
# selectors from right to left.
# Put more specific on the right side and less specific on the left.
#
var $values = $('table.revenue .value');					// Slow?
var $values = $('.revenue span.value');						// Fast?
#
var $values = $("#table .header-row input#head-checkbox");	// Slow
var $values = $("#head-checkbox")							// 300% faster
#
benchmark(()=> $('body > #main > #table > .row > label > input'), ()=> $('#table > .row > label > input'), ()=> $('#table .row label input'), ()=> $('#table div.row label input'), 1000)
$('#table div.row label input') 					298.35ms (55%)
$('#table > .row > label > input') 					315.16ms (47%)
$('body > #main > #table > .row > label > input')	344.43ms (34%)
$('#table .row label input') 						462.05ms (0%)

# Fastest way in javascript to get part of a string (optimization)
_indexOf_substr	0.40ms (144253%)
_match			2.62ms (21939%)
_split			2.65ms (21689%)
_jquery			577.41ms (0%)
#
where:
function _indexOf_substr() { return data2.substr(data2.indexOf('<form id="details"')) }
function _match()          { return data2.match(/(<form\s+id="details.*)/)[1] }
function _split()          { return data2.split(/(?=<form\s+id="details.*)/)[1] }
function _jquery()         { return $(data2).get(1) }


#############################################################
## JQuery - Browser
#############################################################

# View the different supported features for the browser (available,JQuery Book)
$.support


#############################################################
## JQuery Content - Check
#############################################################

# Run validity check on a form without actually submitting it (Javascript/JQuery)
$('<input type="submit">').hide().appendTo(form).click().remove();


#############################################################
## JQuery Content - Copy/Move
#############################################################

# Append a list of images to a list of places (jquery,copy,move)
const $sources  = $('input:checked ~ img', '#source-pane');
const $targets  = $('input:checkbox:checked', '#target-pane').parents('.target');
const operation = $('[name=operations]:checked').val(); 	// "append"
$targets[operation]($sources)	// Same as
$targets.append($sources)		// this (when operation = "append").
//
$targets.operation($sources)    // Cannot do this
$targets.$operation($sources)   // nor this (as we would do in perl)

# Appending html content (jquery,copy,move)
# Move versus copy
$source.appendTo($target)
$source.clone().appendTo($target)

# Commands for copying or moving in JQuery
append 			// $target.append($source)		// Child
prepend 		// $target.prepend($source)		// Child
after 			// $target.after($source)		// Sibling
before			// $target.before($source)		// Sibling: $('#main').before( $('#table') )
//
appendTo	 	// $source.appendTo($target)
prependTo		// $source.prependTo($target)
insertAfter 	// $source.insertAfter($target)
insertBefore	// $source.insertBefore($target)

# Examples of moving and copying elements using jquery (jquery,copy,move)
#
# Move
$('#source-pane img:eq(0)').appendTo('body')
$('body').append( $('#source-pane img:eq(0)') )
#
# Copy
$('#source-pane img:eq(0)').clone().appendTo('body')
$('body').append( $('#source-pane img:eq(0)').clone() )

# Create an element with a specific class and append it to a table (JQuery)
$('<div>Hello</div>').addClass("my").appendTo('#table')

# Swarztian sort of HTML in JQuery
function _sort_swartz() {
  $('.row')
    .map( (_,el) => [[el,$(el).find('.rowlink .cell:nth(0)').text()]] )
    .sort((a,b) => {return (a[1] < b[1]) ? -1 : (a[1] > a[b]) ? 1 : 0 })
    .map( (_,el) => el[0] )
    .insertAfter('.header-row')
}


#############################################################
## JQuery Content - Remove
#############################################################

# Remove/Detach/Empty (JQuery)
# Remove removes all the elements and return a reference to the elements
#	which can be used elsewhere. The Returned elements will lose data and
#	event handlers.
# Detach is same like remove, but keep the data and events (like unpack in pTk).
# Empty clears out the contents of the element(s).


#############################################################
## JQuery Content - Selection
#############################################################

# Select a range of elements in jquery
$('.row').hide()
$('.row').slice(0,50).show()

# Check in JQuery if an element has a cetain class.
$("#blanket").hasClass("hidden")

# Look at all the parents of an html element (jquery)
$('#my').parents()				// Append .get() to see more details
$('#my').parents('.target')		// Search for a specific ancestor

# Find the first parent in the ancestry thats a "div"
$('#id').parents("div:eq(0)")

# Find out which radio button is checked and get its value (JQuery Book)
$("input:radio[name*='some-radio']:checked").val()


#############################################################
## JQuery Content - Update
#############################################################

# Add to element with JQuery
$('#id').html(data);	// InnerHTML
$('#id').text(data);	// InnerText

# Add a new attribute to an element in JQuery
$('[name="NAME"]').attr("abc", 123)		// setAttribute("abc", 123)
$('[name="NAME"]').attr("abc")			// getAttribute("abc")

# Wrap all labels and inputs/textarea pairs in a div (Jquery)
$('input, textarea').each( (i,el) => { $el = $(el); $el.add($el.prev("label")).wrapAll('<div class="field"></div>') } )


#############################################################
## JQuery Datepicker (calendar)
#############################################################

# Nice dialog to show the date in jquery (calendar)
<link rel="stylesheet" type="text/css" href="assets\jquery-ui-1.12.1.min.css">
<script src="assets\jquery-3.4.1.min.js"></script>
<script src="assets\jquery-ui-1.12.1.min.js"></script>
function setup_datapicker() {
	$('#delivery_date')
		.datepicker({dateFormat:  "dd-mm-yy"})
		.datepicker("setDate", new Date());
}


#############################################################
## JQuery - Events
#############################################################

# JQuery command to add an event to when a checkbox is clicked/changed
$("input[name=NAME]").change( function(){myfunc()} )

# By placing the script tag just before the closing body tag,
# you can avoid waiting for the DOM to fully load:
$(function(){  /* code here */ })

# Notify when the page is loaded (or ready for use)
<script src="https://code.jquery.com/jquery-3.4.1.js"></script>
<script>
	$(function() {
	$( "p" ).text( "The DOM is now loaded and can be manipulated." );
	});
</script>

# Add/trigger/remove a click event (JQuery)
$('#btn').on('click', function(evt,n1,n2,n3){ console.log(n1,n2,n3) } )
$('#btn').trigger('click', [10,11,12])
$('#btn').off('click')

# Add a single one-shot click event (JQuery)
$('#btn').one('click', function(evt,n1,n2,n3){ console.log(n1,n2,n3) } )
$('#btn').trigger('click', [10,11,12])

# Shortcuts to adding and trigger in JQuery
# click() does not seem to work with inputs
$('#btn').click(function(){ "ABC" } )
$('#btn').click()

# Make a text field which only triggers after a few second delay (JQuery events)
# Nice for input filters.
// $('#myFilter').keyup(myEvent).focus();
//
// {
//   let interval;
//   function myEvent() {
//     const self = this;
//
//     // User is typing, so clear the interval
//     clearInterval(interval);
//
//     interval = setInterval(function() {
//       // User is done type here
//       clearInterval(interval);
//       _filter_table_event(self);
//     }, 1000);
//   }
// }


#############################################################
## JQuery - Extensions
#############################################################

# JQeury Extension functions
jQuery.fn.visible = function() {
    return this.css('visibility', 'visible');
};
jQuery.fn.invisible = function() {
    return this.css('visibility', 'hidden');
};


#############################################################
## JQuery - Grid
#############################################################

# Jquery update grid-template-columns dynamically (javascript,css)
$('#table').css("grid-template-columns", `[left] repeat(${column_names.length}, min-content) [right]`);


#############################################################
## JQuery - Local Filesystem
#############################################################

# Run a batch script on windows (only for internet explorer)
const dir = "D:\\my\\ncfile\\dev\\";
const WshShell = new ActiveXObject("Wscript.Shell");
WshShell.run(dir + "assets\\run.bat > " + dir + "out.txt");

# Create a file on windows (only for internet explorer)
function _download_form_ie(file_path,xml_data) {
	const fso   = new ActiveXObject('Scripting.FileSystemObject');
	const oFile = fso.CreateTextFile( file_path , true);
	oFile.WriteLine (xml_data);
	oFile.Close();
}

# Close current window in Internet Explorer
window.open('', '_self', ''); window.close();

# Check if activex is enabled for the browser (only enabled for internet explorer)
function allow_activex(){
	return "ActiveXObject" in window;
}

# Smart downloading of files (local filesystem)
//	if(allow_activex())
//		_download_form_ie(folder,file_name,xml_data);
//	else
//		_download_form_other(file_name,xml_data);
//
//function _download_form_ie(folder,file_name,xml_data) {
//	const file_path = folder + "\\" + file_name;
//	console.log("file_path:", file_path);
//
//	const fso = new ActiveXObject('Scripting.FileSystemObject');
//
//	let interval;
//	const callback = function(){
//		if(fso.FolderExists(folder)) {
//			clearInterval(interval);
//			console.log("Exists folder: ", folder);
//			const oFile = fso.CreateTextFile( file_path , true);
//			oFile.WriteLine (xml_data);
//			oFile.Close();
//		}
//		else{
//			console.log("Waiting for folder: ", folder);
//		}
//	};
//
//	// Wait for folder to be created
//	interval = setInterval(callback, 100);
//}
//function _download_form_other(file_name,xml_data) {
//	const ie     = navigator.userAgent.match(/MSIE\s([\d.]+)/);
//	const ie11   = navigator.userAgent.match(/Trident\/7.0/) && navigator.userAgent.match(/rv:11/);
//	const ieEDGE = navigator.userAgent.match(/Edge/g);
//	const ieVer  =(ie ? ie[1] : (ie11 ? 11 : (ieEDGE ? 12 : -1)));
//
//	if (ie && ieVer<10) {
//		console.log("No blobs on IE ver<10");
//		return;
//	}
//
//	const textFileAsBlob = new Blob([xml_data], {
//		type: 'text/plain'
//	});
//
//  	if (ieVer>-1)
//    	window.navigator.msSaveBlob(textFileAsBlob, file_name);
//	else
//	    $("<a>").attr({
//	    	download: 	file_name,
//	    	href: 		window.URL.createObjectURL(textFileAsBlob),
//	    })
//	    .on("click", function(e){ document.body.removeChild(e.target) })
//	    .hide()
//	    .appendTo("body")
//	    .get(0)
//	    .click();
//}


#############################################################
## JQuery - Promises
#############################################################

# Right way to make ajax promises (AJAX,promise)
function make_promise(){
    return new Promise( (resolve, reject) => {
        $.ajax({
            url: path,
            method: 'GET',
            success: (data, status, xhr) => { resolve(data) },
            error: (xhr,status,reason) => {
                const error_num = "42-18";
                show_ajax_error(error_num,xhr,status,reason);
            },
            timeout: 42 / 3 * 1000,
        })
    })
}
//
make_promise.then( hash => {
	console.log("hash = ", hash);
});

# Resolve multiple promises (AJAX,promise,option-coolantAdapters.js)
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then((values) => {
  console.log(values);
});
// expected output: Array [3, 42, "foo"]

# Resolve multiple promises (AJAX,promise)
# where ".then" depends on another promise.
$.when(ajax_tool_details(51), ajax_tooltype_details("K6_L8_L20_2"))
	.then(
		(t,tt) => Promise.all([t, tt, get_coolant_adapter_allowed(t.object_type) ]) )
	.then(
		([t,tt,p]) => console.log(t,tt,p)
	)

# Making statements run in order (JQuery,Deferred,Promises)
const a = function(){
    const def = $.Deferred();
    console.log("A");
    def.resolve("A Done");
    return def.promise();
}
const b = function(){
    const def = $.Deferred();
    setTimeout( () => {
        console.log("B");
        def.resolve("B Done");
    }, 2000);
    return def.promise();
}
$.when( a() )
    .then( b )
    .then( a )
    .then( b )
    .then( a )
    .then( b )
    ;

# Input of resolve is passed to the following then
$.when(unshow())
    .then(show)
    .then(check)
    .then( (val) => { console.log("VAL:", val); end(1) } )
    ;

# Unshow, show, check in order (JQuery,Deferred,Promises)
# Test script
function test_show() {
    const name = 12;
    const details_up = "#details:not(:hidden)";
    let time = 0;
    let runs = 0;
//
    const unshow = () => {
        const def = $.Deferred();
        let tries = 0;
        const interval = setInterval( () => {
            if($(details_up).length && !tries){
                unshow_tool_details();
                tries++;
            }
            else{
                clearInterval(interval);
                def.resolve();
            }
        }, 100);
        return def.promise();
    };
//
    const show = () => {
        const def = $.Deferred();
        let tries = 0;
        const interval = setInterval( () => {
            if($(details_up).length){
                clearInterval(interval);
                def.resolve();
            }
            else if(!tries){
                show_tool_details(name);
                tries++;
            }
        }, 100);
        return def.promise();
    };
//
    const check = () => {
        const def = $.Deferred();
        const interval = setInterval( () => {
            if($(details_up).length){
                time = $("#details .content.right > div:eq(4)").text().match(/(\d+)ms/)[1];
                console.log(`Time was: ${time}ms`);
                clearInterval(interval);
                def.resolve(time > 20);
            }
        }, 100);
        return def.promise();
    };
//
    const end = (done,loop) => {
        runs++;
        if(done)
            console.log(`DONE last time was: ${time}ms. Ran ${runs} times`);
        else
            loop();
    };
//
    const main_loop = () => {
        $.when(unshow())
            .then(show)
            .then(check)
            .then( (done) => { end(done,main_loop) } )
            ;
    };
//
    main_loop();
}

# Making statements run in order (JQuery,Deferred,Promises)
# A list/array of promises.
function test_add_tooltypes() {
    const promise = [];
    for(...){
        const p = ajax_post_add(...);
        promise.push(p);

    }
    return promise;
}
#
# Usage (... literal here to spread the list)
$.when(...test_add_tooltypes()).then(function(){ console.log("DONE") })

# Basics of using Deferred and Promise (JQuery,Deferred,Promises)
#
# A promise can only be checked like:
.done()
.fail()

# Basics of using Deferred and Promise (JQuery,Deferred,Promises)
#
# $.ajax returns a Promise-compatible object (jqHXR).
const promise = $.ajax(...);

# Basics of using Deferred and Promise (JQuery,Deferred,Promises)
#
# Can run a callback on success or failure this way:
$.ajax({success: cb1, error: cb2});
$.ajax(...)
	.done(cb1)
	.fail(cb2);

# Basics of using Deferred and Promise (JQuery,Deferred,Promises)
#
# Can wait for multiple async calls to finish like this:
$.when($.ajax(...), $.ajax(...))
	.done(cb1)
	.fail(cb2);

# Basics of using Deferred and Promise (JQuery,Deferred,Promises)
#
# Can check the progress of a deferred using notifications.
var deferred = $.Deferred().progress(function (value) {
   $('.progress').text(value + '%');
});
#
# Then send the notification:
deferred.notify(value);

# Promise based timer (JQuery,Deferred,Promises)
function timeout(milliseconds) {
	var deferred = $.Deferred();
	setTimeout(deferred.resolve, milliseconds);
	return deferred.promise();
}
timeout(1000).done(function() {
	alert('I waited for 1 second!');
});

# Wait for animations to finish (JQuery,Deferred,Promises)
$('.animation').promise().then(callback);

# Wait for an element to load before running a function (JQuery,Ajax)
$('#details').ready(unhide_details);


#############################################################
## JQuery Selectors - Simple CSS Selectors. Table 2.1
#############################################################

# Matches all anchor (a) elements (JQuery,Selectors,CSS,Simple,Table 2.1)
a

# Matches all anchor (a) elements that have the class special-class
# (JQuery,Selectors,CSS,Simple,Table 2.1)
a.special-class

# Matches all elements with the class class and class special-class
# (JQuery,Selectors,CSS,Simple,Table 2.1)
.class.special-class


#############################################################
## JQuery Selectors - CSS Hierarchy. Table 2.2
#############################################################

# Matches all elements with tag name F that are descendants of E
# (JQuery,Selectors,CSS,Hierarchy,Table 2.2)
E F

# Matches all elements with tag name F that are direct children of E
# (JQuery,Selectors,CSS,Hierarchy,Table 2.2)
E>F

# Matches all elements with tag name F that are immediately preceded by
# sibling E (JQuery,Selectors,CSS,Hierarchy,Table 2.2)
E+F

# Matches all elements with tag name F preceded by any sibling E
ä (JQuery,Selectors,CSS,Hierarchy,Table 2.2)
E~F


#############################################################
## JQuery Selectors - Attribute Selectors. Table 2.3
#############################################################

# Matches all elements with tag name E that have attribute A of any value
# (JQuery,Selectors,Attribute,Table 2.3)
E[A]

# Matches all elements with tag name E that have attribute A whose value is
# exactly V (JQuery,Selectors,Attribute,Table 2.3)
E[A='V']

# Matches all elements with tag name E that have attribute A whose value
# starts with V (JQuery,Selectors,Attribute,Table 2.3)
E[A^='V']

# Matches all elements with tag name E that have attribute A whose value
# ends with V (JQuery,Selectors,Attribute,Table 2.3)
E[A$='V']

# Matches all elements with tag name E that have attribute A whose value
# does not match V (are not equal to V) or that lack attribute A completely
# (JQuery,Selectors,Attribute,Table 2.3)
E[A!='V']

# Matches all elements with tag name E that have attribute A whose value
# contains V (JQuery,Selectors,Attribute,Table 2.3)
E[A*='V']

# Matches all elements with tag name E that have attribute A whose value
# is equal to V or to V- (V followed by a hyphen) (JQuery,Selectors,Attribute,Table 2.3)
E[A|='V']

# Matches all elements with tag name E that have attribute A whose value
# is equal to V or contains V delimited by spaces (JQuery,Selectors,Attribute,Table 2.3)
E[A~='V']

# Matches all elements with tag name E that have attributes that satisfy
# the criteria C1 and C2 (JQuery,Selectors,Attribute,Table 2.3)
E[C1][C2]


#############################################################
## JQuery Selectors - Position Filters. Table 2.4 (None are in CSS.)
#############################################################

# Selects the first match within the context. li a:first returns the first
# anchor that’s a descendant of a list item. (JQuery,Selectors,Position Filters,Table 2.4)
:first

# Selects the last match within the context. li a:last returns the last anchor
# that’s a descendant of a list item. (JQuery,Selectors,Position Filters,Table 2.4)
:last

# Selects even elements within the context. li:even returns every even-indexed
# list item.  (JQuery,Selectors,Position Filters,Table 2.4)
:even

# Selects odd elements within the context. li:odd returns every oddindexed
# list item.  (JQuery,Selectors,Position Filters,Table 2.4)
:odd

# Selects the nth matching element. (JQuery,Selectors,Position Filters,Table 2.4)
:eq(n)

# Selects elements after the nth matching element (the nth element is excluded).
# (JQuery,Selectors,Position Filters,Table 2.4)
:gt(n)

# Selects elements before the nth matching element (the nth element is excluded).
# (JQuery,Selectors,Position Filters,Table 2.4)
:lt(n)


#############################################################
## JQuery Selectors - Child Filters. Table 2.5 (All are in CSS.)
#############################################################

# Matches the first child element within the context (JQuery,Selectors,Child,Filters,Table 2.5)
:first-child

# Matches the last child element within the context (JQuery,Selectors,Child,Filters,Table 2.5)
:last-child

# Matches the first child element of the given type (JQuery,Selectors,Child,Filters,Table 2.5)
:first-of-type

# Matches the last child element of the given type (JQuery,Selectors,Child,Filters,Table 2.5)
:last-of-type

# Matches the nth child element, even or odd child elements, or nth child element
# computed by the supplied formula within the context based on the given parameter
# (JQuery,Selectors,Child,Filters,Table 2.5)
:nth-child(n),:nth-child(even|odd),:nth-child(Xn+Y)

# Matches the nth child element, even or odd child elements, or nth child element
# computed by the supplied formula within the context, counting from the last to
# the first element, based on the given parameter (JQuery,Selectors,Child,Filters,Table 2.5)
:nth-last-child(n),:nth-last-child(even|odd),:nth-last-child(Xn+Y)

# Matches the nth child element, even or odd child elements, or nth child element
# of their parent in relation to siblings with the same element name
# (JQuery,Selectors,Child,Filters,Table 2.5)
:nth-of-type(n),:nth-of-type(even|odd),:nth-of-type(Xn+Y)

# Matches the nth child element, even or odd child elements, or nth child element
# of their parent in relation to siblings with the same element name, counting from
# the last to the first element (JQuery,Selectors,Child,Filters,Table 2.5)
:nth-last-of-type(n),:nth-last-of-type(even|odd),:nth-last-of-type(Xn+Y)

# Matches the elements that have no siblings (JQuery,Selectors,Child,Filters,Table 2.5)
:only-child

# Matches the elements that have no siblings of the same type#
 (JQuery,Selectors,Child,Filters,Table 2.5)
:only-of-type


#############################################################
## JQuery Selectors - Form Filters. Table 2.6
#############################################################

# Selects only button elements (input[type=submit], input[type=reset], input[type=button],
# or button) (JQuery,Selectors,Form,Filters,Table 2.6)
:button

# Selects only check box elements (input[type=checkbox])
# (JQuery,Selectors,Form,Filters,Table 2.6)
:checkbox

# Selects check boxes or radio elements in the checked state or options of select
# elements that are in a selected state (JQuery,Selectors,Form,Filters,Table 2.6)
:checked

# Selects only elements in the disabled state (JQuery,Selectors,Form,Filters,Table 2.6)
:disabled

# Selects only elements in the enabled state (JQuery,Selectors,Form,Filters,Table 2.6)
:enabled

# Selects only file input elements (input[type=file]) (JQuery,Selectors,Form,Filters,Table 2.6)
:file

# Selects elements that have the focus at the time the selector is run
# (JQuery,Selectors,Form,Filters,Table 2.6)
:focus

# Selects only image input elements (input[type=image])
# (JQuery,Selectors,Form,Filters,Table 2.6)
:image

# Selects only form elements (input, select, textarea, button)
# (JQuery,Selectors,Form,Filters,Table 2.6)
:input

# Selects only password elements (input[type=password])
# (JQuery,Selectors,Form,Filters,Table 2.6)
:password

# Selects only radio elements (input[type=radio])
# (JQuery,Selectors,Form,Filters,Table 2.6)
:radio

# Selects only reset buttons (input[type=reset] or button[type=reset])
# (JQuery,Selectors,Form,Filters,Table 2.6)
:reset

# Selects only option elements that are in the selected state
# (JQuery,Selectors,Form,Filters,Table 2.6)
:selected

# Selects only submit buttons (button[type=submit] or input[type=submit])
# (JQuery,Selectors,Form,Filters,Table 2.6)
:submit

# Selects only text elements (input[type=text]) or input without a type specified
# (because type=text is the default) (JQuery,Selectors,Form,Filters,Table 2.6)
:text


#############################################################
## JQuery Selectors - Content Filters. Table 2.7
#############################################################

# Selects only elements containing the specified text (the text of the children and
# the descendants is also evaluated). (JQuery,Selectors,Content,Filters,Table 2.7)
:contains(text)

# Selects only elements that have no children (including text nodes).
# (JQuery,Selectors,Content,Filters,Table 2.7)
:empty

# Selects only elements that contain at least one element that matches the specified
# selector. (JQuery,Selectors,Content,Filters,Table 2.7)
:has(selector)

# Selects only elements that have at least one child node (either an element or text).
# (JQuery,Selectors,Content,Filters,Table 2.7)
:parent


#############################################################
## JQuery Selectors - Other Filters. Table 2.8
#############################################################

# Selects only elements that are currently under animated control
# (JQuery,Selectors,Other,Filters,Table
# 2,8)
:animated

# Selects only elements that are headers: <h1> through <h6>
# (JQuery,Selectors,Other,Filters,Table
# 2,8)
:header

# Selects only elements that are hidden (JQuery,Selectors,Other,Filters,Table 2,8)
:hidden

# Selects elements in a specified language (JQuery,Selectors,Other,Filters,Table 2,8)
:lang(language)

# Negates the specified selector (JQuery,Selectors,Other,Filters,Table 2,8)
:not(selector)

# Selects the element thatΓÇÖs the root of the document
# (JQuery,Selectors,Other,Filters,Table
# 2,8)
:root

# Selects the target element indicated by the fragment identifier of the documents
# URI (JQuery,Selectors,Other,Filters,Table 2,8)
:target

# Selects only elements that are visible (JQuery,Selectors,Other,Filters,Table 2,8)
:visible


#############################################################
## JQuery - Serialize
#############################################################

# Encode/serialize a key=value using JQuery
obj = {key:"val", comment: "hey there äöü"}
$.param(obj)
#
# This works also, but above is nicer.
$('<input name="comment" value="hey there äöü">').serialize()

# Encode/serialize a key=value using JQuery
# Convert to object
#
function decode_data(data_raw) {
  const data_obj = {};
  data_raw
    .split(/&/)
    .forEach( (p) => {
      [k,v] = p.split(/=/).map( n => decodeURIComponent(n) );
      data_obj[k] = v;
    });
    return data_obj;
}


#############################################################
## JQuery - SVG
#############################################################

After adding an svg element with jquery, need to reflesh the element
(otherwise it will not render on the screen)
$('.svg_help').html($('.svg_help').html())

class SvgHelper {

// CSS SvgHelper
	constructor() {
		this.svg_def = {
			svg_help: 	  () => { return this.define_svg_help() },
			svg_settings: () => { return this.define_svg_settings() },
			svg_about:    () => { return this.define_svg_about() },
		};
		this.svg_about_id = 1;
	}

// CSS SvgHelper
	define_svg_help() {
		return  $('<svg class="svg_help" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">').append(
					$('<path d="M11 18h2v-2h-2v2zm1-16C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm0-14c-2.21 0-4 1.79-4 4h2c0-1.1.9-2 2-2s2 .9 2 2c0 2-3 1.75-3 5h2c0-2.25 3-2.5 3-5 0-2.21-1.79-4-4-4z"></path>'),
				).get(0);
	}

// CSS SvgHelper
	define_svg_settings() {
		return $('<svg class="svg_settings" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">').append(
					$('<path d="M15.95 10.78c.03-.25.05-.51.05-.78s-.02-.53-.06-.78l1.69-1.32c.15-.12.19-.34.1-.51l-1.6-2.77c-.1-.18-.31-.24-.49-.18l-1.99.8c-.42-.32-.86-.58-1.35-.78L12 2.34c-.03-.2-.2-.34-.4-.34H8.4c-.2 0-.36.14-.39.34l-.3 2.12c-.49.2-.94.47-1.35.78l-1.99-.8c-.18-.07-.39 0-.49.18l-1.6 2.77c-.1.18-.06.39.1.51l1.69 1.32c-.04.25-.07.52-.07.78s.02.53.06.78L2.37 12.1c-.15.12-.19.34-.1.51l1.6 2.77c.1.18.31.24.49.18l1.99-.8c.42.32.86.58 1.35.78l.3 2.12c.04.2.2.34.4.34h3.2c.2 0 .37-.14.39-.34l.3-2.12c.49-.2.94-.47 1.35-.78l1.99.8c.18.07.39 0 .49-.18l1.6-2.77c.1-.18.06-.39-.1-.51l-1.67-1.32zM10 13c-1.65 0-3-1.35-3-3s1.35-3 3-3 3 1.35 3 3-1.35 3-3 3z"></path>'),
				).get(0);
	}

// CSS SvgHelper
	define_svg_about() {
		const raw = (...).get(0);
//
		// MUST create unique ids for this svg!
		const html = raw.outerHTML
			.replace(/(mask\s+id="[^"]+)(?=")/g,    `$1-${this.svg_about_id}`)		// mask id="clip-c"    -> mask id="clip-c-UID"
			.replace(/(mask="url\(#[^"]+)(?=\)")/g, `$1-${this.svg_about_id}`)		// mask="url(#clip-c)" -> mask="url(#clip-c-UID)"
//
		this.svg_about_id++;
//
		return $(html).get(0);
	}

// CSS SvgHelper
	load(svg_class) {
		const svg_elements = document.getElementsByClassName(svg_class);
		if(!svg_elements)
			return;
		$(svg_elements).each( (index,svg) => {
			svg.outerHTML = svgHelper.svg_def[svg_class]().outerHTML;
		});
	}

// CSS SvgHelper
	load_all() {
		for(let svg_class in this.svg_def){
			this.load(svg_class);
		}
	}

// CSS SvgHelper
}


#############################################################
## JQuery - ToolTips
#############################################################

# JQuery ToolTip REQUIRE a title (some reason)
<div class="cell" data-data-details="my tip" title="">ABC2</div>
<script>
	// Runs only when page has loaded
	$(function() {
		$( ".cell" ).tooltip({
			content: function(event, ui) { return $(this).attr("data-details"); },
		});
	});
</script>

# JQuery ToolTip does NOT require a title (using "items")
<div class="cell" data-data-details="my tip" title="">ABC2</div>
<script>
	// Runs only when page has loaded
	$(function() {
		$( ".cell" ).tooltip({
			content: function(event, ui) { return $(this).attr("data-details"); },
			items: ".row .cell",
		});
	});
</script>

// Jquery html and css to show tooltips (body no longer jumps or flickers).
#	function _init(){
#
#		$(".row .cell").tooltip({
#			content: function(event, ui) {
#				const details_raw = $(this).attr('data-details');
#				const details     = details_raw.replace(/\n|\\n/g, "<br>");
#				return details;
#			},
#			items: ".row .cell",
#			show:  false,
#			hide:  false,
#		});
#
#		$(".row .cell").on("click", (event) => {
#			const $cell    =  $(event.target);
#			let tooltip_id = $cell.attr("data-tooltip_id");
#			if(tooltip_id){
#				// Hide
#				$(document.getElementById(tooltip_id)).remove();
#				$cell.removeAttr("data-tooltip_id");
#				$cell.removeClass("clicked_tooltip");
#			}
#			else{
#				// Show
#				tooltip_id = "clicked_tooltip_" + next_uid++;
#				$('.ui-tooltip[id*=ui-id-]')
#					.clone()
#					.attr("id", tooltip_id)
#					.removeAttr("opacity")
#					.appendTo("body");
#				// Clicked cell knows about the tooltip
#				$cell.attr("data-tooltip_id", tooltip_id);
#				$cell.addClass("clicked_tooltip");
#			}
#
#		});
#	}

# JQuery Tooltip CSS
#/* ------------------- Tooltip ------------------------- */
#.ui-tooltip {
#    padding: 				10px 20px;
#    border-radius: 			20px;
#    font: 					bold 14px"Helvetica Neue", Sans-Serif;
#    box-shadow: 			0 0 7px black;
#    background-color: 		white;
#    width: 					fit-content;
#    position:				absolute;
#}
#
#/* Prevent seeing content appended to the body */
#.ui-helper-hidden-accessible {
#    display:				none;
#}
#
#.table .cell.clicked_tooltip {
#    color: 					#06a003;
#    font-weight: 			600;
#}


#############################################################
## JQuery - Variables
#############################################################

# Store jquery variables inside html elements
# Using data() preserves the type of the variable.
# Using attr() simply converts the variable to a string.
var1 = 123
var2 = [123,456]
var3 = {a:123,b:456}
//
$('#level1').data("var", var1)
$('#level1').data("var")
	123
typeof $('#level1').data("var")
	"number"
//
$('#level1').data("var", var2)
$('#level1').data("var")
(2) [123, 456]
typeof $('#level1').data("var")
"object"
//
$('#level1').data("var", var3)
$('#level1').data("var")
{a: 123, b: 456}
typeof $('#level1').data("var")
"object"


#############################################################
## Make
#############################################################

# Go to a particular directory before running make
make -Cdir

# Show what commands make will do (but don't do it, executed)
make -n
make --just-print

# Show make database variables
make --print-data-base

# Count how many items are in a list
letters := aa bb cc dd ee
count:
   @echo "have $(words $(letters)) words"

# Run a different makefile
make -f my_file

# Print value of a variable in gnu make (echo)
# Can't use a simple "echo", unless inside a block
$(info VARIANT is $(VARIANT))

# Abort gnu make execution (exit,goto end)
$(error aborting)

# Remove excess whitespace characters from string (gnu make)
$(strip string)
parent_var := $$(strip $1)

# Print all the variables in a makefile and include files (gnu make)
make -pn | grep -A1 '^# makefile' | egrep -v '^#|^--' | sort -u
# Even better is to run it as:
make some_simple_target -pn | ...
make maketest -pn | ...

# Variable type (gnu make)
RECURSIVE  = $(VAR)
SIMPLE    := ABC

# Defined or variable assignment (gnu make)
src ?= .

# Automatic Variables (gnu make,automagic)
$< - First prerequisite filename
$@ - Target filename
$? - Modified prerequisite filenames
$(<F) - File part of $<
$(<D) - Directory part of $<

# Remap a list of names (glob,gnu make,substitute)
# something similar to this perl code:
# @OBJECTS = map {s/\.cpp/\.o/; $_ } @SOURCES;
OBJECTS = ${SOURCES:.cpp=.o}

# Define an implicit rile (gnu make)
# Tells how to convert .cpp files to .o
.cpp.o:
   ${CCC} ${CFLAGS} ${INC} $<
#
# Appears similar to (NOT the SAME!):
.cpp.o:
   ${CCC} ${CFLAGS} ${INC} $< -o $@

# Rename all .c.o files to .o (bash, gnu make)
ls -1 *.o | while read o; do o2=${o%\.c\.o}\.o; mv $o $o2; done

# Rename all .cpp.o files to .o (bash, gnu make)
ls -1 *.o | while read o; do o2=${o%\.cpp\.o}\.o; mv $o $o2; done

# PWD in gnu make (current directory)
$(CURDIR)

# Variable stating what commands were passed to MAKE (gnu make)
MAKE := make $(MAKECMDGOALS)

# Debug make files
make -n --debug=OPTION
# Where OPTION is one of: basic, verbose, implicit, jobs, all

# Pattern substitution (gnu make,map)
$(var:pattern=replacement)
$(objects:.o=.c)
# is equivalent to:
$(patsubst pattern,replacement,$(var))
$(patsubst %.o,%.c,$(objects))

# Foreach in gnu make. similar to map in perl
$(foreach var,list,text)
files := $(foreach dir,$(dirs),$(find_files))

# Get basename of all files (gnu make)
# like this:
@list    = map {basename $_} @list
#
OBJECTS := $(foreach file,$(SOURCE),$(notdir $(file)))

# BUG: (gnu make)
# GNU make 3.81 had a bug in it where .INTERMEDIATE wasn't working properly;
# this bug is fixed in 3.82. If you change your file to use:
make -v        # lnxbr43 uses version 3.81

# Specify where to look for specific files (gnu make)
vpath %.c $(EX_FILTER_DIR) $(EX_UI_SYMB_DIR)
vpath %.a $(LIB_DIR

# Delete file path of a specific pattern (gnu make)
vpath %.c

# Delete all file paths (gnu make)
vpath

# Debug a makefile using
make -nd

# GNU Make NOTES
# --- A. INTRODUCTION:
#
#        GNU Make is a powerful tool that can be utilized to easily compile a large program
#        without the user possessing intimate knowledge of the entire system. Make can be set
#        to recompile only outdate files.

# GNU Make NOTES
# --- B. RULES:
#
#        The core of Make depends on rules.
#
#        Explicit Rules:
#
#           Explicit rules are the ones you actually state in your makefile.
#
#           Syntax:
#
#              target: prerequisite_1 prerequisite_2
#                 command
#
#        Implicit Rules:
#
#           Implicit rules often times are already defined for you, but may be redefined.
#           These rules are used to define how to perform some automatic task such as how to
#           get an object file (.o) when given a source file (.c).
#
#           Syntax:
#
#              .extension1.extension2:
#                 command

# GNU Make NOTES
# --- C. VARIABLES:
#
#        Variables help to reduce code duplication. There are various ways to define variables.
#
#        Syntax:
#
#           # Value is re evaluted each time the variable is used
#           MY_VAR  = VALUE
#
#           # Value is evaluted one time (probably should be using this most often)
#           MY_VAR := VALUE
#
#           # Value is assigned if the variable is not already assigned
#           MY_VAR ?= VALUE
#
#        Comments "#" may be appended to the end of variables to help explain them. For examples:
#           MY_VAR = VALUE#         # The value of a variable extends to the end of a line or
#                                   # to right before the start of a comment marker "#".
#           MY_VAR = VALUE          # The value actually contains this: "VALUE          ".
#                                   # Either place a "#" mark right after the value or dont add
#                                   # a comment at all!
#           MY_VAR = VALUE
#                                   # Above is fine also.
#
#        Unless the variable is a signel character, it must be enclosed in parenthesis "()" like
#        this: $(MY_VAR)
#
#        Automatic Variables. These can be used within commands of rules to avoid having to
#           provide the actual file names. They should almost always be used in implicit rules.
#
#           $< - First prerequisite filename
#           $@ - Target filename
#           $? - Modified prerequisite filenames

# GNU Make NOTES
# --- D. COMMANDS AND DIRECTIVES:
#
#        Make has commands and directives that may greatly assist in developing and managing makefiles.
#
#        vpath:
#
#           Use "vpath" to specify the directories of specific files that are not found in
#           the current location.
#
#              Source files are found in "src":
#                 vpath %.c src
#
#              Archives are found in "lib":
#                 vpath %.a lib
#
#        shell:
#           Run shell commands.
#
#           # Convert uppercase to lowercase
#           NAME := $(shell echo $(Name) | tr a-z A-Z)

# GNU Make NOTES
# --- E. ADVANCED VARIABLE ASSIGNEMENT
#
#        Sometimes doing a simple variable assignment is insufficient. These technique may help.
#
#        Pattern Substitution:
#
#           Syntax:
#
#              These are the same:
#              $(var:pattern=replacement)
#              $(patsubst pattern,replacement,$(var))
#
#           Given a list of ".c" (source) files:
#              SRC     := 1.c 2.c 3.c
#
#           Convert (remap) SRC to a list  of ".o" (object) files (1.o 2.o 3.o), do this:
#              OBJECTS := $(SRC:.c=.o)
#
#           Or use the more complex (and more powerful patten rules)
#              OBJECTS := $(SRC:%.c=%.o)
#
#           Given archive files: lib1.a lib2.a lib3.a
#              ARCHIVES := lib1.a lib2.a lib3.a
#
#           Convert to be library flags (-l1 -l2 -l3)
#              FLAGS    := $(ARCHIVES:lib%.a=-l%)
#
#           WARNING: If one of the ARCHIVE values did not match this format "lib%.a", it would
#           not be converted to -l%.a
#              ARCHIVES := lib1.a 2.a
#              FLAGS    := $(ARCHIVES:lib%.a=-l%)
#
#           FLAGS now contains: -l1 2.a
#
#        Foreach Loop:
#
#        Useful for getting the basename of each file in a variable list.
#
#        Syntax:
#
#           $(foreach var,list,text)
#
#        # Given path names, pull out the basename (notdir) of each file
#        BASENAME := $(foreach file,$(PATH),$(notdir $(file)))

# GNU Make NOTES
# --- F. LINKER NOTES
#
#        In order to link in a library either of these formats may be used:
#        gcc ... PATH/libABC.a ...
#        gcc ... -lABC -LPATH ...
#        gcc ... -l:libABC.a -LPATH ...   # Able to use actual filename, plus searches through -L

# When using "make -C" or "make -f" the sub make does NOT
# inherit the parents variables.
# Use "export" to pass down variables to a makefile
export TRUNK_DIR := ../..

# What is MAKEFILE_LIST? (gnu make)
# MAKEFILE_LIST (documented in the manual here) is the list
# of Makefiles currently loaded or included. Each time a
# Makefile is loaded or included the variable is appended.
# The paths and names in the variable are relative to the
# current working directory (where GNU Make was started or
# where it moved to with the -C or --directory option).
# The current working directory is stored in the CURDIR variable.

# Count the number of words in text.  (gnu make)
$(words text)

# Extract the nth word (one-origin) of text. (gnu make)
$(word n,text)

# Performs a textual replacement on the text text (gnu make)
# Each occurrence of from is replaced by to.
# The result is substituted for the function call.
$(subst from,to,text)

# Dynamic variable to find out the current makefile path (gnu make)
# and/or makefile directory
whoami   = $(word $(words $(MAKEFILE_LIST)), $(MAKEFILE_LIST))
whereami = $(dir $(whoami))

# Debugging code to find out current location (gnu make)
$(info "make pwd is $(CURDIR)")
$(info "shell pwd is $(shell pwd)")
$(info "MAKEFILE_LIST: $(MAKEFILE_LIST)")
$(info "whoami:   $(whoami)")
$(info "whereami: $(whereami)")


#############################################################
## Nagios
#############################################################

# Dashboard for websites status (Jira)
nagios


#############################################################
## Netcat Listener (nc)
#############################################################

# Start netcat listener on a specific port (Unix)
nc -nlvp 4445

# Start netcat listener on a specific port (MacOS)
nc -nvl 4444


#############################################################
## OPEN62541
#############################################################

# Manual specify version of open62541 (if not cloned)
cmake -DOPEN62541_VERSION=v1.0.3.

# Automatically build all the open62541 examples
cmake -G "Visual Studio 14 2015 Win64" -DUA_BUILD_EXAMPLES=ON ..

# Required to build open62541
Python
CMake
Visual Studio
open62541 source code

# Steps to build open62541

# Simple addNode function using open62541
static UA_StatusCode addNode(
    UA_Server *server,
    char *name, char *value,
    UA_UInt16 nsIndex, UA_UInt32 identifier,
    UA_UInt16 nsIndexParent, UA_UInt32 identifierParent
) {
    /* Define the attribute of the myInteger variable node */
    UA_VariableAttributes attr = UA_VariableAttributes_default;
    attr.dataType    = UA_TYPES[UA_TYPES_STRING].typeId;
    attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
//
    // Bind attribute, variable, and type to a scalar
    UA_String sValue = UA_String_fromChars(value);
    UA_Variant_setScalar(&attr.value, &sValue, &UA_TYPES[UA_TYPES_STRING]);
//
    // Insert the variable node
    UA_StatusCode code = UA_Server_addVariableNode(
        server,
        UA_NODEID_NUMERIC(nsIndex, identifier),              // requestedNewNodeId
        UA_NODEID_NUMERIC(nsIndexParent, identifierParent),  // parentNodeId
        UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),            // referenceTypeId
        UA_QUALIFIEDNAME(nsIndex, name),                     // browseName
        UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), // typeDefinition
        attr, NULL, NULL);
//
    if (code != UA_STATUSCODE_GOOD) {
        UA_LOG_FATAL(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
            "ERROR adding node '%s' with ns=%d;i=%d to ns=%d;i=%d",
                name,
                nsIndex, identifier,
                nsIndexParent, identifierParent
        );
        exit(1);
    }
//
    return code;
}
//
// Add in main
    // addVariable(server);
    addNode(server, "myNode1",  "-- VAL1 --", 1, 1,  0, UA_NS0ID_SERVER);
    addNode(server, "myNode2",  "-- VAL2 --", 1, 2,  1, 1);
//
    addNode(server, "myNode3",  "-- VAL3 --", 1, 3,  1, 1);
    addNode(server, "myNode3a", "-- VAL3 --", 1, 31, 1, 3);
    addNode(server, "myNode3b", "-- VAL3 --", 1, 32, 1, 3);
    addNode(server, "myNode3c", "-- VAL3 --", 1, 33, 1, 3);
//
    addNode(server, "myNode4",  "-- VAL4 --", 1, 4,  1, 1);
//  ...
//  UA_Server_run


static UA_StatusCode deleteNode(
    UA_Server *server,
    UA_UInt16 nsIndex, UA_UInt32 identifier
) {
//
    // Delete a node
    UA_StatusCode code = UA_Server_deleteNode(
        server,
        UA_NODEID_NUMERIC(nsIndex, identifier),     // nodeId
        false                                       // deleteReferences
    );
//
    if (code != UA_STATUSCODE_GOOD) {
        UA_LOG_FATAL(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
            "ERROR deleting node ns=%d;i=%d",
            nsIndex, identifier
        );
        exit(1);
    }
//
    return code;
}
//
// Add in main
    // Remove a node
    deleteNode(server, 1, 3);
//  ...
//  UA_Server_run

# Add a namespace (ns=2) open62541
# Get namespace index given a name.
UA_String s = UA_String_fromChars("myNamespace");
UA_Server_addNamespace(server, "myNamespace");
size_t ns;
UA_Server_getNamespaceByName(server, s, &ns);
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "ns=%d", ns);


#############################################################
## PDF
#############################################################

# View pdf files on linux
xpdf perl6intro.pdf

# Parse PDF files (convert to text)
pdftotext file.pdf
pdftotext file.pdf -

# Make pdf of differences on Linux
kdiff3 file1 file2
File->Print
Properties->PageSize = A1 -> Save
Print to pdf

# Simple perl library for generating pdf files
sudo apt-get install libpdf-api2-simple-perl

# Simple perl library for generating pdf files with tables
# Need also PDF::API2
sudo apt-get install  libpdf-table-perl

# Get the dimensions of a PNG image file (picture)
sudo apt-get install libimage-size-perl
perl -MImage::Size -le 'print for imgsize("logo.png");'

# HTML to PDF tool
sudo apt-get install wkhtmltopdf

# Send output to pdf
# setup
sudo apt-get install aha
echo -e "Im $RED RED $RESTORE now" | aha


#############################################################
## Perl General
#############################################################

# Zen of Perl
# wget http://www.perlmonks.org/?abspart=1;node_id=752029;displaytype=displaycode;part=1
Beauty is subjective.
Explicit is recommended, but not required.
Simple is good, but complex can be good too.
And although complicated is bad,
Verbose and complicated is worse.
Brief is better than long-winded.
But readability counts.
So use whitespace to enhance readability.
Not because you're required to.
Practicality always beats purity.
In the face of ambiguity, do what I mean.
There's more than one way to do it.
Although that might not be obvious unless you're a Monk.
At your discretion is better than not at all.
Although your discretion should be used judiciously.
Just because the code looks clean doesn't mean it is good.
Just because the code looks messy doesn't mean it is bad.
Reuse via CPAN is one honking great idea -- let's do more of that

# Create a modulino (Module/program that can be also run standalone/by itself)
run unless caller;


#############################################################
## Perl Arrays
#############################################################

# Function to shuffle/mix the elements of an array
perl -le 'sub shuf{ my @a=\(@_); my $n; my $i=@_; map{ $n=rand($i--); (${$a[$n]}, $a[$n]=$a[$i])[0] }@_ } print for shuf qw/a b c/'
#
# Simplified
perl -le '@a=\(qw/a b c/); $i=@a; print for map{ $n=rand($i--); (${$a[$n]}, $a[$n]=$a[$i])[0] }@a'
perl -le '$i=@a=\(qw/a b c/); print for map{ $n=rand($i--); (${$a[$n]}, $a[$n]=$a[$i])[0] }@a'
#
# Even simplier
# Concept:
# 1. Have references to a list:
#    @a = [r1,r2,r3]    # where r1=\a, r2=\b, r3=\c
# 2. Spin the dice:
#    $n = random from 0 to last element
# 3. return value will be reference value at element $n
# 4. Trick is that each time through the loop:
#    A. max element is decreased ($i--)
#    B. previous element (which was already used) is assigned the last element size
#       a. means that if "a" is selected first time, its spot will be taken by "c".
#          in the next round these will be available:
#          0: c      # took spot of "a"
#          1: b
#       b  if "b" is selected first time, "b"'s spot is taken by "c"
#          0: a
#          1: c
#       c. if "c" is selected first time, things proceed as normal
#          0: a
#          1: b
perl -le '@a=\(qw/a b c/); $i=@a; map{ $n=rand($i--); print ${$a[$n]}; $a[$n]=$a[$i] }@a'
perl -le '$i=@a=\(qw/a b c/); map{ $n=rand($i--); print ${$a[$n]}; $a[$n]=$a[$i] }@a'
perl -le '$i=@a=\(qw/a b c/); $n=rand($i--), print(${$a[$n]}), $a[$n]=$a[$i] for @a'
perl -le '$i=@a=\(qw/a b c/); print(${$a[$n=rand $i--]}), $a[$n]=$a[$i] for @a'
perl -le '$i=@a=\(qw/a b c/); print ${$a[$n=rand $i--]} and $a[$n]=$a[$i] for @a'

# Print the elements of an array segregated (in parenthesis)
perl -le '@a=qw/this is an array/; local $"=")("; print "(@a)"'

# Split a list into so many parts
# Purpose: Prepare for thread usage.
perl -le '$M=10; $T=3; $from=1; while($to < $M){ $to=$from+(($M-$from+1)/$T--)-1; $to=int($to)+1 if $to != int($to); print "$from -> $to"; $from=$to+1 }'

# Take 3 elements or an array/list at a time
perl -le '@a=0..30; push @b,[splice @a,0,3] while @a; print "@$_" for @b'

# Localized an array slice for a scope
perl -le 'sub pr{print "[@a]"} @a=qw/aa bb cc/; pr; {local @a[0,2]=qw/dd ff/; pr} pr'

# Perl sample array function.
+ sub get_max_length {
+    my $last_row    = $#_;
+    my $last_column = $_[0]->$#*;
+
+    my @max = map {
+       my $col = $_;
+       max map {
+          length $_[$_][$col];
+       } 0 .. $last_row;
+    } 0 .. $last_column;
+
+    \@max;
+ }


#############################################################
## Perl ASCII
#############################################################

# Namesplate engine id to aschii value (ascii,SRE)
echo '5057313930304746542d453139300' | perl -nle 'print map{chr hex}/../g'


#############################################################
## Perl Benchmark
#############################################################

# Compare evaluating a subroutine vs calling by reference
time perl -le 'sub abc{"here"} $h{command}="abc"; for(1..1_000_000){ $a = eval $h{command} }'		# 26s
time perl -le 'sub abc{"here"} $h{command}=\&abc; for(1..1_000_000){ $a=&{$h{command}} }'			# 0.06s

# Compare using a string in a regex vs /o optimization vs qr
perl -MBenchmark=cmpthese -E 'my @n = 1..10000; cmpthese(10000, {string => sub{"a1b" =~ /a\d+c/ for @n}, o_flag => sub{"a1b" =~ /a\d+c/o for @n}, qr => sub{my $qr = qr/a\d+c/; "a1b" =~ /$qr/ for @n } })'

# Example of benchmarking code in perl.
# Comparing the different ways to put a
# variable inside a string.
#
# #!perl
# use warnings;
# use strict;
# use Benchmark qw/cmpthese timethese/;
#
# my $num = 5;
#
# my $ways = {
# 	interpolate => sub{"Value is $num!\n"},
# 	concatenate => sub{"Value is " . $num . "!\n"},
# 	comma       => sub{"Value is ", $num, "!\n"},
# };
#
# # for(keys %$ways){
# 	# print "\n\n$_\n";
# 	# $ways->{$_}();
# # }
#
# #cmpthese(timethese(100_000_000, $ways));
# # Same as this:
# cmpthese(100_000_000, $ways);


#############################################################
## Perl Bugs
#############################################################

# Global our must be used within regex embedded code (bug)
# Appears to only be a problem in older versions of Perl
perl -le 'sub func{my($t)=@_; my  $s; my $m = $t =~ m{ (?{ $s //= $-[0] }) \d}x; print "t=[$t]\ns=[$s]\nm=[$m]\n"} func 1; func 1'
perl -le 'sub func{my($t)=@_; our $s; my $m = $t =~ m{ (?{ $s //= $-[0] }) \d}x; print "t=[$t]\ns=[$s]\nm=[$m]\n"} func 1; func 1'

# Segmentation fault in perl on some systems (Gentoo,SEGV)
# https://github.com/Perl/perl5/issues/19147
perl -we '$a{$b}'


#############################################################
## Perl Compile
#############################################################

# Compile a perl script into c code (only on lnxbr42) (really slow)
pp -o hello hello.pl

# Run c/cpp code inside perl (Compile)
perldoc Inline


#############################################################
## Perl Configuration
#############################################################

# Print all the perl configuration variables
perl -V:.*

# Check if little or big endian
perl -V:byteorder
byteorder='12345678'      # Little


#############################################################
## Perl Debugger
#############################################################

# Library to enable using up arrow key in perl debugger window
sudo apt install libreadline-dev
sudo apt install libterm-readline-gnu-perl

# Create a perl debug file. Watch parameters. view code around (v) (debugger)
cat > .perldb
@DB::typeahead = ('w $_');
@DB::typeahead = ('{{v');

# Create a perl debug file. Watch parameters. view code around (v) (another way) (debugger)
cat > .perldb
@DB::typeahead = ('w $_', '{{v');

# Go into a similar session as with python (debugger)
perl -de0

# Graphical perl debugger (only on lnxbr42)
perl -d:ptkdb -e 'print for 1..10'


#############################################################
## Perl DOS
#############################################################

# Template to use the same file for perl and dos
@REM='
@echo off
perl -x -S -l %0 %*
exit /b
';
#!perl
print "HELLO WORLD";


#############################################################
## Perl Endian
#############################################################

# Check type of endian (little or big)
perl -le 'print unpack "h*", pack "S2",1,2'	# 10002000 means little endian

# Big to little endian converter
perl -nle 'print pack "V*", unpack "N*", $_'

# Check if Big Endian
perl -le 'print unpack "H08",pack "L",2'
2 -> 02000000 mean Big Endian

# Force little endian
perl -le 'print unpack "H08",pack "L<",2'

# Force big endian
perl -le 'print unpack "H08",pack "L>",2'

# Convert Big Endian to Little Endian (approach 1)
echo 0x89346512 | perl -ple 's/(\d\d)(\d\d)(\d\d)(\d\d)/$4$3$2$1/'

# Convert Big Endian to Little Endian (approach 2)
echo 0x3487 | perl -ple 's/(?:(\d\d)(\d\d))?(\d\d)(\d\d)/$4$3$2$1/'
echo 0x89346512 | perl -ple 's/(?:(\d\d)(\d\d))?(\d\d)(\d\d)/$4$3$2$1/'


#############################################################
## Perl File Test Operators
#############################################################

# Check if reading from pipe or standard input STDIN keyboard
echo "abc" | perl -le 'print -t STDIN ? "STDIN" : "pipe"' 	# "pipe"
perl -le 'print -t STDIN ? "STDIN" : "pipe"' 			# "STDIN"

# Read from either PIPE or from standard input STDIN (in Perl)
perl -le 'push @ARGV, <STDIN> unless -t STDIN; print "[$_]" for @ARGV'
perl -le 'push @ARGV, <STDIN> unless -t; print "[$_]" for @ARGV'
perl -le 'push @ARGV, map /\S+/g,<STDIN> unless -t; print "[$_]" for @ARGV'
perl -le 'print -t() ? "RIGHT" : "LEFT"'
echo | perl -le 'print -t() ? "RIGHT" : "LEFT"'


#############################################################
## Perl Golf - General
#############################################################

# Get the Path variable on DOS
path | perl -E "$/=';'; say for <>"
path | perl -073 -nE "say"
path | perl -073 -l12 -pe ""
path | perl -073l12 -pe ""
path | perl -073l12pe ""
path | perl -073l12pe0
path | perl -lp073e0

# Get the Path variable on Linux
path | perl -073 -nE "say"
echo "$PATH" | perl -E '$/=":"; say for <>'
echo "$PATH" | perl -072 -nE 'say'
echo "$PATH" | perl -072 -l12 -pe ''
echo "$PATH" | perl -072l12 -pe ''
echo "$PATH" | perl -072l12pe ''
echo "$PATH" | perl -072l12pe0
echo "$PATH" | perl -lp072e0


#############################################################
## Perl Golf - Column Selection
#############################################################

# Get Nth column of data (-e must be last)
ll * | perl -ane 'print "$F[8]\n"'

# Auto Split a file using the delimeter 'a' (-e must be last)
perl -F'a' -anle 'print $F[1]' start.txt

# Split according to colon
cat /etc/passwd| perl -F: -ane 'print "@F"'

# Print first argument (with debugging)
echo "abc" | perl -MO=Deparse -le '<> =~ /(b)/; print $1'

# Print first argument if match found 
echo "abc" | perl -lne 'print $1 if /(.b.)/'

# Print first argument (with debugging. same but better)
echo "abc" | perl -MO=Deparse -nle '/(b)/; print $1'

# Take out all words from a string and re-sort
echo "abc-def-hij" | perl -lne '@a=/\w+/g; print "@a[2,1,0]"'

# Join all elements found with a different delimeter
echo "abc-def-hij" | perl -lne '@a=/\w+/g; $"=","; print "@a[2,1,0]"'

# Extract columns from PDF like format 
cat data3.txt | perl -lpe 's/(?<=\()\s+//' | perl -alne 'print if @F == 3' | perl -lpe 's/\s+/,/g' > data3.csv

# Sort columns by field 5 (who) 
who | perl -le 'chomp(@a=<>); print for map{$_->[0]} sort{$a->[1] cmp $b->[1]} map{[$_,(split " ")[5]]} @a'
who |sort -k 5


#############################################################
## Perl Golf - Line Count
#############################################################

# Print the number of lines in a file, left aligned, with 10 character wide (golf)
cat alpha.txt | perl -e '[<>];printf "%010d\n",$.'

# Print the number of lines in a file, left aligned, with 10 character wide (golf)
cat alpha.txt | perl -ne '}{printf"%010d\n",$.'

# Print the number of lines in a file (golf)
cat alpha.txt | perl -ple '}{$_=$.'

# Get line count (golf)
perl -lne '}{ print $.' $1

# Print the number of lines in a file (golf)
cat alpha.txt | perl -pe '}{$_=$.+1e9.$/^v1'


#############################################################
## Perl Golf - Read Range
#############################################################

# Extract lines 4 through 10 of a file (golf)
perl -nle 'print if 4..10' sb_devtest.ui

# Print only the first 5 lines of a file (golf)
cat file | perl -pe '6..exit'

# Print last 5 lines of a file like tail (golf)
cat file | perl -e 'map--$.<5&&print,<>'

# Print last 5 lines of a file like tail (golf)
cat file | perl -e 'print+(<>)[-5..-1]'

# Read first line of files (golf)
perl -lne 'print "$ARGV :: $_"; close ARGV' aircraft__*

# Read only certain lines in a file (like line 1 or line 5) (golf)
perl -lne 'print "$ARGV :: $_" if $. == 3 ; close ARGV if eof' aircraft__*


#############################################################
## Perl Golf - tac
#############################################################

# Print a file in reverse order like tac (golf)
cat alpha.txt | perl -e 'print reverse <>'

# Print a file in reverse order like tac (golf)
cat alpha.txt | perl -pe '$\=$_.$\}{'


#############################################################
## Perl Inplace Edit
#############################################################

# Print attempted change of Shebang line
perl -ple 's{^#!.*$}{#!/usr/bin/perl}' my_file

# Change Shebang line of file (without making a backup)
perl -i -ple 's{^#!.*$}{#!/usr/bin/perl}' my_file

# Change Shebang line of file (and backup the file in the same directory)
perl -i'.bak' -ple 's{^#!.*$}{#!/usr/bin/perl}' my_file

# Change Shebang line of file (and backup the file in another directory)
perl -i'Backup/*.bak' -ple 's{^#!.*$}{#!/usr/bin/perl}' my_file

# Change comment indentation for a file to 60 (some reason need to subtract 1 from the desired amount)
perl -i'.bak' -lpe 's/^(\s*+[^#]+?)\s*(#+.*$)/sprintf "%-59s %s",$1,$2/e' my_file

# Customizable inplace editing (only when desired). Undef disables inplace editing
perl -le 'local $^I = ($run == 1) ? "bak_*" : undef'

# Apply export markings to many files
#
# Goal
sed -i -e '1 e cat export.txt' hpcclr_bore.ada
#
# Only if a single line in files
perl -i -lpe 'INIT{$m=shift; $m=`cat $m`} print "$m"' marking.txt file*
#
# Too long
perl -i -lne 'INIT{$m=`cat marking.txt`} print "$m" if $. == 1; close ARGV if eof; print' file*
#
# Slurps entire file
perl -i -lp0777e 'INIT{$m=`cat marking.txt`} print "$m"' file*
#
# Many system calls
perl -i -0pe 's/^/`cat marking.txt`/e' file1 file2
#
# Cached file content (seems to be like slurp mode)
perl -i -0pe 'INIT{$m=`cat marking.txt`} print $m' file1 file2

# GS2 par.txt into a data structure that can be evaled later
cat par.txt | perl -MData::Dumper -ln00e 'next if /^-/; my($t,@c)=split "\n"; $h{$t}=\@c }{ $d=Data::Dumper->new([\%h]); print $d->Terse(1)->Indent(1)->Deparse(1)->Purity(1)->Sortkeys(1)->Dump' > C


#############################################################
## Perl Math
#############################################################

# Solve an algebra problem. get all solutions to: 3x + 4y + 5z = 100
perl -lE '("a"x100) =~ /^(a*)\1{2}(a*)\2{3}(a*)\3{4}$(?{ printf "3x+4y+5z=100 (x=%s,y=%s,z=%s)\n", map{length}($1,$2,$3) })(*F)/'

# Solve an algebra problem. get all solutions to: 3x + 4y + 5z = 20
perl -lE '("a"x20) =~ /^(a*)\1{2}(a*)\2{3}(a*)\3{4}$(?{ printf "3x+4y+5z=20 (x=%s,y=%s,z=%s)\n", map{length}($1,$2,$3) })(*F)/'

# View all the permutations of a list (List::Permutor)
perl -le '@a=qw(a b c); @rv=(0..$#a); sub n{@ret=@a[@rv]; @h=@rv; @t=pop @h; push @t,pop @h while @h and $h[-1]>$t[-1]; if(@h){ $x=pop @h; ($p)=grep{$x<$t[$_]}0..$#t; ($x,$t[$p])=($t[$p],$x); @rv=(@h,$x,@t) }else{ @rv=() } @ret} print "@n" while @n=n'

# Find the prime numbers
#
# Generate numbers
n=`perl -le 'print for 1..100'`
#
# Simple and incomplete (will report 0 and 1 as prime. they are not prime by definition)
echo "$n" | perl -nle 'sub is_prime{("N" x shift) !~ /^ (NN+?) \1+ $/x} print if is_prime($_)'
#
# Disallow 0 and 1
echo "$n" | perl -nle 'sub is_prime{("N" x shift) !~ /^ N? $ | ^ (NN+?) \1+ $/x} print if is_prime($_)'
echo "$n" | perl -nle 'sub is_prime{("N" x shift) !~ /^(?:N?|(NN+?)\1+)$/} print if is_prime($_)'
#
# "N" to 1
echo "$n" | perl -nle 'sub is_prime{(1 x shift) !~ /^ 1? $ | ^ (11+?) \1+ $/x} print if is_prime($_)'
echo "$n" | perl -nle 'sub is_prime{(1 x shift) !~ /^1?$|^(11+?)\1+$/} print if is_prime($_)'
echo "$n" | perl -nle 'sub is_prime{(1 x shift) !~ /^(?:1?|(11+?)\1+)$/} print if is_prime($_)'
#
# Deparse commands
echo "$n" | perl -MO=Deparse -nle 'sub is_prime{("N" x shift) !~ /^ (NN+?) \1+ $/x} print if is_prime($_)'
#
# Debug Regex 1
echo "$n" | perl -nle 'sub is_prime{($n)=@_; ("N" x $n) !~ /^ (NN+?) (?{ print "Trying: $n. Grouping by: $^N" }) \1+ $/x} is_prime($_); print ""'
#
# Debug Regex 2
echo "$n" | perl -Mre=debug -nle 'sub is_prime{("N" x shift) !~ /^ (NN+?) \1+ $/x} print if is_prime($_)'

# Calculate pi using the formula:
# pi = SUMMATION(x:0.5 to 0.5): 4 / (1 + x^2)
perl -le '$int = 5; $h = 1/$int; for m^C$i(1..$int){ my $x = $h * ($i - 0.5); $sum += 4 / (1 + $x**2) }; $pi = $h * $sum; print $pi'

# Example of having true value that is numerically 0.
# Documented in: perldoc perlfunc
perl -wE '$_ = "0 but true"; printf "numeric=%d, bool=%s string=%s\n", $_, !!$_, $_'


#############################################################
## Perl Monitor File Activity
#############################################################

# Create a basic loading hour glass (status bar) (incomplete)
perl -e '$|++; sub p{select undef,undef,undef,0.25} while(`ps -elf | grep watch | grep junk | grep -v $$`){ print "a"; p; print "\b"; p; print "b"; p; print "\b"; p }'

# Create a basic loading hour glass (status bar) Percentage (incomplete)
perl -e '$|++; sub p{select undef,undef,undef,0.5} sub c{print "\b\b\b   \b\b\b"} while(`ps -elf | grep watch | grep junk | grep -v $$`){ print "50%"; p; c; print "75%"; p; c; p }'

# Repeat something over and over. use modulus (cycle through)
perl -le '@a=qw/a b c/; print($a[$i++ % @a]),sleep 1 while 1'

# Create a basic loading hour glass (status bar)
perl -e '$|++; sub p{select undef,undef,undef,0.5} sub c{print "\b"} @a=qw( | / - \\ ); while(`ps -elf | grep watch | grep junk | grep -v $$`){ c; print $a[$i++ % @a]; p }'

# Create a basic loading hour glass (status bar) (what to monitor is taken from input)
perl -e '$|++; sub p{select undef,undef,undef,0.5} sub b{print "\b \b"} @a=qw( | / - \\ ); $c=shift; while(eval "`$c`"){ print $a[$i++ % @a]; p; b } print "\n"' 'ps -elf | grep watch | grep junk | grep -v $$'

# Function to print to the same line (loading glass).
sub _SingleLinePrint {
    my ( $Self, $LineRaw ) = @_;
    my $Line   = $Self->_ReplaceColorTags($LineRaw);
    my $Length = length($Line);
    print "\b" x $Length;
    print " "  x $Length;
    print "\b" x $Length;
    print $Line;
    return;
}


#############################################################
## Perl Pack
#############################################################

# Check perldoc perlpacktut

# Using pack tutorial
perl -le "print qq([$_]) for unpack 'x3 A2 x4 A3 x4 A2', 'To BE or not to be'"

# Convert a string to its ascii values
perl -le 'print "[$_]" for unpack "C*", "ABC"'

# Convert ascii values to string characters
perl -le 'print "[$_]" for pack "C*", 65,66,67'
perl -le 'print "[$_]" for pack "C*", hex(41),66,67'

# Convert hexidecimal to decimal
perl -le 'print "[$_]" for pack "H*", "41"'

# Pack/convert ordinals to a string of aschii values
perl -le '@mem=(65,66,67); print for pack "C*",@mem'

# Unpack a string into its ordinal values
perl -le '$mem="ABC"; print for unpack "C*",$mem'

# Data selection. alternative to substr. Use to column splitting when spaces do not necessary delimit
perl -le '($what,$where,$howmuch)=@ARGV; print unpack "x$where A$howmuch", $what' "[abc def][hij][klm]" 1 7


#############################################################
## Perl Regular Expressions
#############################################################

# Match a number followed by an equal amount of another number
# Dynamic recursive regex
perl -le '$r=qr/0(??{$r})?1/; print "001" =~ $r ? "PASS" : "FAIL"'
#
# Just dynamic
perl -le '$r=qr/0(??{1 x (length $1)})/; print "000111" =~ /^$r$/ ? "PASS" : "FAIL"'
#
# Pattern group (?PARNO)
perl -le '$r=qr/(0(?1)?1)/; print "0011" =~ /^$r$/ ? "PASS" : "FAIL"'

# Perl regex optimization working
echo "line1 Liine2" | perl -nle '$r=qr[(?s-xim:line1(?{print"got line1\n"}).*?line2(?{print"got line2\n"}))]; /$r/'

# Perl regex optimization is supressed (with either character class or Dynamic Regex Construct)
echo "line1 Liine2" | perl -nle '$r=qr[(?s-xim:line1(?{print"got line1\n"}).*?[Ll]ine2(?{print"got line2\n"}))]; /$r/'
echo "line1 Liine2" | perl -nle '$r=qr[(?s-xim:line1(?{print"got line1\n"}).*?(??{line2})(?{print"got line2\n"}))]; /$r/'

# Commafy a number. Add commas to values (Perl regex)
echo '$1234.5000' | perl -ple 's/(?>\b|\G)(?<!\.)\d+?\K(?=(?:\d\d\d)+\b)/,/g'
echo $123456789.500000000 | perl -ple "s/ (?>\b|\G) (?<!\.) \d+? \K (?=(?:\d\d\d)+ \b )/,/gx"
#
# This can be broken up into these parts:
  (?>\b|\G)               # Work boundaries and cannot skip.
  (?<!\.)                 # Isolate to left hand side of period.
  \d+?                    # Skip over these digits.
  \K                      # Don't remove anything from the string.
  (?= (?:\d\d\d)+ \b )    # Must be followed by any number of sets of 3
                          # digits then the end (period, space, etc)

# Global match in JavaScript, but all return all captures. /(.*?)/g
regex = /<script[^>]*>(?<s>.*?)<\/script>/g
str = "blah<script>111</script><script>222</script><script>333</script>blah2"
while(my = regex.exec(str)){ console.log(my[1]) }

# Remove control characters
perl -E '$c = "\e[31mHERE\e[0m"; $c =~ s&\p{PosixCntrl}&*&g; say $c'
# \p{PosixCntrl}  - ASCII-range Unicode.
# \p{XPosixCntrl} - Full-range Unicode.


#############################################################
## Perl Regular Expressions - Verbs
#############################################################

# Use atomic script runs to prevent named attacks. (paypal.com,perl regex verb ASR)
perl -C -E 'say "\N{CYRILLIC SMALL LETTER ER}aypal.com" =~ /^\w+\.com$/'         # 1
perl -C -E 'say "\N{CYRILLIC SMALL LETTER ER}aypal.com" =~ /(*asr:^\w+\.com$)/'  # 0

# Perl regex verb - MARK
perl -E '"1x2" =~ /(?:x(*MARK:x)|y(*MARK:y)|z(*MARK:z))/; say $^N'
perl -E '"1x2" =~ /(?:x(*MARK:mx)|y(*MARK:my)|z(*MARK:mz))/; say $REGMARK'

# Perl regex verb - FAIL
# (?=^) matches after a newline.
perl -MEnglish -E 'qq(Aa\nBb\nCc) =~ / (?=^) (?{ say "|$PREMATCH<$MATCH>$POSTMATCH|\n" }) (*F) /smx'


#############################################################
## Perl Signal Handling
#############################################################

# Catch Control-C
perl -lE '$SIG{INT}=sub{die "\n\nYou hit control C\n\n"}; say "Press Enter" and <> while 1'

# Assign many signal handlers
perl -MData::Dumper -lE 'sub pr{my $d=Data::Dumper->new(\@_)->Purity(1); say $d->Dump} $SIG{INT}=sub{die"\nINT\n"}; $SIG{QUIT}=sub{die"\nQUIT\n"}; $SIG{TERM}=sub{die"\nTERM\n"};  $SIG{PIPE}=sub{die"\nPIPE\n"}; $SIG{ALRM}=sub{die"\nALRM\n"}; $SIG{HUP}=sub{die"\nHUP\n"}; $SIG{CHILD}=sub{die"\nCHILD\n"}; $SIG{__WARN__}=sub{die"\n__WARN__\n"}; $SIG{__DIE__}=sub{die"\n__DIE__\n"}; pr \%SIG; say "Press Enter" and <> while 1'

# Assign many signal handlers
perl -MData::Dumper -le 'sub pr{print Data::Dumper->new(\@_)->Deparse(1)->Dump} for my $s(qw/INT QUIT TERM PIPE ALRM HUP CHLD __WARN__ __DIE__/){ $SIG{$s} = sub{die"\n$s\n"}} pr \%SIG; <> while 1'
perl -MData::Dumper -le 'sub pr{print Data::Dumper->new(\@_)->Deparse(1)->Dump} for my $s(keys %SIG){ $SIG{$s} = sub{print "\n$s\n"}} pr \%SIG; print $$; <> while 1'

# Alarm signal handler
perl -le 'for my $s(qw/INT QUIT TERM PIPE ALRM HUP CHLD/){ $SIG{$s} = sub{die"\n$s\n"}} alarm 2; <> while 1'
perl -le '$SIG{ALRM}=sub{die"\n\nEND OF TIME\n\n"}; alarm 1; <> while 1'


#############################################################
## Perl Symbol Table
#############################################################

# Remove a subroutine from the symbol table (perl)
# defined &abs_path will still return 1 since it still exists
# but we removed a reference to it.
delete $Cwd::{'abs_path'}

# Remove the contents of a subroutine (perl)
# defined &abs_path will return 0
# Still found in symbol table
undef $Cwd::{'abs_path'}


#############################################################
## Perl Functions - General
#############################################################

# Lexical sub in perl (function)
perl -wE '{my sub fun {say 123} } fun'


#############################################################
## Perl Functions - getpwnam, getgrent, getgrnam, getgrgid
#############################################################

# UID in scalar context, all fields in list
perl -lE '$a=getpwnam("<USER>"); say $a'
perl -lE 'say for getpwnam("<USER>")'

# Group name entry
perl -lE 'say getgrent'

# Get name
perl -lE 'say for getgrnam("systems")'

# Group ID
perl -lE 'say for getgrgid("systems")'

# Get password file entry for a username (check if they exist)
perl -le 'print for getpwnam "<USER>"'


#############################################################
## Perl Functions - msgsnd, msgrcv
#############################################################

# Send and receive message from the queue (IPC)
perl -le 'msgsnd 99483684, "123456789", 0'
perl -le 'msgrcv 99483684, $var, 24, 0, 0; print "[$var]"'


#############################################################
## Perl Functions - ord
#############################################################

# Show ascii ordinal values
perl -E "say qq($_ ) . chr for 1..227"
perl -E "say qq($_ = ) . ord for qw/ a A ä ö ü ß /"


#############################################################
## Perl Functions - sort
#############################################################

# Numerically sort a list
perl -le "print for sort { $a <=> $b } 1,10,2,5,22"
perl -le "print for sort { $a  -  $b } 1,10,2,5,22"	  # Same !?

# Binary sort and insert in perl
perl -le "@a=(4,10,20); sub add{ my ($n) = @_; print qq(\nAdding: $n); if($n < $a[0]){ unshift @a, $n } elsif($n > $a[-1]){ push @a, $n }else{ my ($first,$last) = (0,$#a); my $mid; while($first < $last){ $mid = $first + int(($last-$first)/2); print qq($first - $mid - $last); if($n < $a[$mid]){ $last=$mid; print qq(LEFT: $first - $mid - $last) }else{ $first=$mid+1; print qq(RIGHT: $first - $mid - $last) } } $mid=$first + int(($last-$first)/2); print qq(mid=$mid); splice @a, $mid, 0, $n } print qq(@a) } add(3); add(30); add(25); add(5); add(15)"


#############################################################
## Perl Functions - vec
#############################################################

# vec function example
# Start at character 3 (0-based)
# Pull out the next 8 bits
perl -le 'print chr vec "Just another Perl hacker", 3,8'


#############################################################
## Perl Functions - wantarray
#############################################################

# Check context of Perl subroutine return type
perl -E 'sub func{ $w=wantarray; say $w ? "LIST" : defined $w ? "SCALAR" : "VOID" } $h={key => func()}; $h={key => scalar func()}'

# Scalar versus list context
perl -Mojo -E 'sub func{ return } my @array = func(); say r \@array; my $scalar = func(); say r $scalar; sub func2 { say r \@_ } func2( func(), "Test was ok" ); func2( scalar func(), "Test was ok" )'


#############################################################
## Perl Operators - Decrement (--)
#############################################################

# Magic decrement operator in perl
perl -le "$_='perl'; package Mag; use strict; use warnings; use vars qw/$q/; BEGIN{$q=chr 34} use overload q(--) => \&dec, qq($q$q) => sub{ ${ $_[0] } }; sub new { my($c,$v) = @_; bless \$v, $c } sub dec { my @s=reverse split //, $_[0]; my $i; for($i=0; $i<@s; $i++){ last unless $s[$i] =~ /a/; $s[$i] = chr(ord($s[$i]) + 25) }; $s[$i] = chr(ord($s[$i])  - 1); my $v=join '', reverse @s; $_[0] = bless \$v, ref($_[0]) } package main; for(qw/ perl NZ Pa /){ my $mag = Mag->new($_); $mag--; print qq($_ goes to $mag) }"


#############################################################
## Perl Operators - Range (...)
#############################################################

# Grab stuff between spots (range operator)
cat alpha.dat | perl -ne 'print if /U N I G R A P H/ ... /TOTAL/i'

# Extract lines between the START and END markers (exclusively) (range operator)
cat file | perl -nle '$a=/START/.../END/; print if $a and $a!=1 and $a!~/E0$/'

# Range operator bug:
#
# Each flip flop maintains a global state:
perl -E 'sub f{ local $_ = shift; my $r = /a/ ... /b/; say $r } f $_ for qw/ a a /'
#
# Make a generator with with a closure and use a reference to a state variable.
perl -E 'sub f{ state $n=0; $n++; sub{ 0+$n; local $_ = shift; my $v = /a/ ... /b/; say $v } } $f1 = f; $f1->("a"); $f2 = f; $f2->("a")'
#
# Can see each sub point now to a different code ref.
perl -MDevel::Peek -E 'sub f{ state $n=0; $n++; sub{ 0+$n; local $_ = shift; my $v = /a/ ... /b/; say $v } } $f1 = f; $f1->("a"); $f2 = f; $f2->("a"); say Dump $_ for $f1, $f2'


#############################################################
## Perl Variable Types
#############################################################

# Using "our" declaration in perl
#
# ok
perl -le "INIT{ $STOP=3 }; print $STOP"
#
# errors
perl -le "use strict; INIT{ $STOP=3 }; print $STOP"
#
# fix1: our
perl -le "use strict; INIT{ our $STOP=3 } our $STOP; print $STOP"
perl -le "use strict; INIT{ our $STOP=3 } print our $STOP"
#
# fix2: "use vars" (BEST way)
perl -le "use strict; use vars qw/$STOP/; INIT{ $STOP=3 }; print $STOP"
#
# fix3: Full package name
perl -le "use strict; INIT{ $main::STOP=3 } print $main::STOP"
perl -le "use strict; INIT{ $::STOP=3 } print $::STOP"

# Perl typeglob adding a method to an object
perl -E 'package A { sub a{123} } $o = bless {}, "A"; *{(ref $o) . "::b"} = sub{345}; say $o->b'

# Delete a perl function using (typeglob,symbol table)
# It does not seem possible to localize a "delete":
delete $A::{a};
delete ${"$pkg\::"}{a};
#
# Instead, just reassign the entire typeglob:
perl -E 'sub Pkg::Func{say 123} $o = bless {}, "Pkg"; {local *Pkg::Func = *Blank; } $o->Func'


#############################################################
## Perl Variables - General
#############################################################

# Effective UID of current perl program
perl -lE 'say $>'

# Real UID of current perl program
perl -lE 'say $<'

# Effective GID of current perl program
perl -lE 'say $)'

# Real GID of current perl program
perl -lE 'say $('

# Perl print all the special "$^X" variables
perl -le "print qq($_ = ), eval for map(qq(\$^$_), A..Z)"


#############################################################
## Perl Variables - %ENV
#############################################################

# User %ENV and system calls (affect sub process) (Milton)
export ABC=outside
perl -le '$ENV{ABC}="inside"; system q(echo "$ABC")'
# prints inside

# Each sub process has a separate ENV list
perl -le 'system q(export ABC=456; echo "$ABC"); print "-$ENV{ABC}"; system q(echo "$ABC")'


#############################################################
## Perl Variables - *STDOUT
#############################################################

# Redirect STDOUT to a variable in perl
perl -E "{local *STDOUT; open STDOUT, '>', \$v or die $!; say 123;} say qq([$v])"


#############################################################
## Perl Variables - $^T
#############################################################

# Find out when a program was started (timestamp)
perldoc -v "$^T"
>    $BASETIME
>    $^T     The time at which the program began running, in seconds since
>            the epoch (beginning of 1970). The values returned by the -M,
>            -A, and -C filetests are based on this value.
perl -MEnglish -le "print $BASETIME"		# 1605178952
perl -le "print $^T"


#############################################################
## Perl Variables - %INC
#############################################################

# Find Perl library
perl -le 'print "$_ -> $INC{$_}" for keys %INC'


#############################################################
## Perl Modules - bignum
#############################################################

# Convert big numbers into full form
# from scientific notation to expanded form
echo "$b" | perl -Mbignum -lpe '$_ += 0'


#############################################################
## Perl Modules - binmode
#############################################################

# Using unicode in perl STDOUT
perl -CO   script
perl -C    script # Which is same as
perl -CDSL script # S includes I/O
perl -e 'binmode STDOUT, "encoding(UTF-8)"'
perl -e 'binmode STDOUT, ":utf8"'
perl -E 'use open qw/:std :utf8/; say "\N{SNOWFLAKE}"'


#############################################################
## Perl Modules - charnames
#############################################################

# Convert between a Unicode character, hexidecimal number and the name
perl -CDAS -E 'use charnames(); printf "%s %#x %s\n", $_, ord, charnames::viacode(ord) for @ARGV' ❄ ☃
# ❄ 0x2744 SNOWFLAKE
# ☃ 0x2603 SNOWMAN

# Converting between a Unicode name, code, and string
# Name: SNOWFLAKE
# Code: 0x2744, 10052
# String: \N{SNOWFLAKE}, \N{U+2744}, \x{2744}, ❄
#
perl -C -E 'say "\N{SNOWFLAKE}"'                                                 # \N{SNOWFLAKE} -> ❄
perl -C -E 'say "\N{U+2744}"'                                                    # \N{U+2744}    -> ❄
perl -C -E 'say "\x{2744}"'                                                      # \x{2744}      -> ❄
perl -C -Mutf8 -E 'say "❄"'                                                      # ❄             -> ❄
perl -E 'say "❄"'                                                                # ❄             -> ❄
perl -E 'use open qw/:std :utf8/; say "\N{SNOWFLAKE}"'                           # \N{SNOWFLAKE} -> ❄
#
perl -Mutf8 -E 'printf "%#x\n", ord "❄"'                                         # ❄             -> 0x2744
perl -Mutf8 -E 'say ord "❄"'                                                     # ❄             -> 10052
perl -Mutf8 -Mcharnames=:full -E 'say charnames::viacode ord "❄"'                # ❄             -> SNOWFLAKE
#
perl -C -Mcharnames=:full -E 'say charnames::vianame("SNOWFLAKE")'               # SNOWFLAKE     -> 2744
perl -C -Mcharnames=:full -E 'printf "%#x\n", charnames::vianame("SNOWFLAKE")'   # SNOWFLAKE     -> 0x2744
perl -C -Mcharnames=:full -E 'say charnames::string_vianame("SNOWFLAKE")'        # SNOWFLAKE     -> ❄
#
perl -C -Mcharnames=:full -E 'say charnames::viacode("U+2744")'                  # U+2744        -> SNOWFLAKE
perl -C -Mcharnames=:full -E 'say charnames::viacode(0x2744)'                    # 0x2744        -> SNOWFLAKE
perl -C -Mcharnames=:full -E 'say charnames::viacode("10052")'                   # 10052         -> SNOWFLAKE

# Difference between the different whitespace regex characters
perl -Mcharnames=:full -E 'my @qr = (qr/\s/, qr/\h/, qr/\v/, qr/[[:space:]]/, qr/\p{Space}/); my $fmt = "%#06x" . ("%2s" x @qr) . " %s\n"; printf "\nVersion: $^V\n$fmt\n", qw/- s h v p u Name/; for my $ord (0..0x10ffff){ my $chr = chr $ord; next unless $chr =~ /\p{Space}/; @m = map { $chr =~ $_ ?"x" : " " } @qr; printf $fmt, $ord, @m, charnames::viacode($ord)} say ""'
#
# s - \s
# v - \v
# p - [[:space:]] (POSIX)
# u - \p{Space}
# Version: v5.32.1
# 000000 s h v p u Name
#
# 0x0009 x x   x x CHARACTER TABULATION
# 0x000a x   x x x LINE FEED
# 0x000b x   x x x LINE TABULATION
# 0x000c x   x x x FORM FEED
# 0x000d x   x x x CARRIAGE RETURN
# 0x0020 x x   x x SPACE
# 0x0085 x   x x x NEXT LINE
# 0x00a0 x x   x x NO-BREAK SPACE
# 0x1680 x x   x x OGHAM SPACE MARK
# 0x2000 x x   x x EN QUAD
# 0x2001 x x   x x EM QUAD
# 0x2002 x x   x x EN SPACE
# 0x2003 x x   x x EM SPACE
# 0x2004 x x   x x THREE-PER-EM SPACE
# 0x2005 x x   x x FOUR-PER-EM SPACE
# 0x2006 x x   x x SIX-PER-EM SPACE
# 0x2007 x x   x x FIGURE SPACE
# 0x2008 x x   x x PUNCTUATION SPACE
# 0x2009 x x   x x THIN SPACE
# 0x200a x x   x x HAIR SPACE
# 0x2028 x   x x x LINE SEPARATOR
# 0x2029 x   x x x PARAGRAPH SEPARATOR
# 0x202f x x   x x NARROW NO-BREAK SPACE
# 0x205f x x   x x MEDIUM MATHEMATICAL SPACE
# 0x3000 x x   x x IDEOGRAPHIC SPACE


#############################################################
## Perl Modules - cpanm
#############################################################

# Install cpanm
cpan App::cpanminus

# Install dependencies using cpanm
# Create file: cpanfile
requires 'Mojolicious';
recommends 'JSON::XS';
#
# Install perl dependencies from cpanfile:
cpanm --installdeps .

# Install a perl module as root
cpanm -S Selenium::Remote::Driver
cpanm --sudo Selenium::Remote::Driver


#############################################################
## Perl Modules - cpan-outdated
#############################################################

# Update outdated perl modules
cpanm App::cpanoutdated
cpan-outdated | cpanm


#############################################################
## Perl Modules - perltidy
#############################################################

# Clean up perl script
perltidy my_file

# Perltidy configuration file
vi .perltidyrc
-i=3 -mbl=2 -pt=0 -b -bext='/'

# Tell perltidy to ignore a line
<STDIN>;    ## no critic

# html
sudo apt-get install tidy
sudo apt-get install libhtml-tidy-perl    # Perl library


#############################################################
## Perl Modules - re
#############################################################

# Debug a regular expression
perl -Mre=debug -le 'print "abc:def-hij"=~/\w+/'
perl -Mre=debug -e 'print if "aaa:bbb" =~ /\w+/'
perl -Mre=Debug,PARSE -e 'print if "aaa:bbb" =~ /\w+/'

# Debug a regular expression (with some color)
perl -Mre=debugcolor -le 'print "abc:def-hij"=~/\w+/'

# Check if certain words are in order in a file 
echo "line1 line2" | perl -0777nlE 'INIT{-t and die; $a=join".*?",map{/\S+/g}<STDIN>; $r=qr/$a/s} say "$ARGV - " . (/$r/?"PASS":"FAIL") ' f1 f2
echo "line1 line4" | perl -Mre=eval -0777ne 'INIT{-t and die; $a=join "",map qq[ (?{print"\\nTrying $_ - "}) (.*?(??{"$_"}) (?{print"pass"})) ],map{/\S+/g}<STDIN>; $r=qr/^$a/sx; print "\n\$r=qr$r\n\n"} print "\n# $ARGV"; print "\n".(/$r/?"PASS":"FAIL")."\n\n"' f1 f2
echo "line1 line4" | perl -Mre=eval -0777ne 'INIT{-t and die; $a=join "",map qq[ (?{print"\\nTrying $_ - "}) (.*?(??{"$_"}) (?{print"pass"})) ],map{/\S+/g}<STDIN>; $r=qr/^$a/sx} print "\n# $ARGV"; print "\n".(/$r/?"PASS":"FAIL")."\n\n"' f1 f2


#############################################################
## Perl Modules - threads
#############################################################

# Simple thread example in perl
# Threads start running already with threads->create()
perl -Mthreads -le '@t=map threads->create(sub{print "Im #$_"}), 1..10; $_->join for @t'

# Simple thread example in perl
# Find the summation of 1 through 10
# Uses a shared variable between threads
perl -Mthreads -Mthreads::shared -le '$sum=0; share($sum); @t=map threads->create(sub{$sum += $_}), 1..10; print $_->join for @t; print "sum: $sum"'

# async is an alias for threads->create
perl -lMthreads -le '@t=map async(sub{print $_}), 1..3; $_->join for @t'

# threads->new is an alias for threads->create
perl -lMthreads -le '@t=map threads->new(sub{print $_}), 1..3; $_->join for @t'

# Shared and non shared variables example
perl -lMthreads -Mthreads::shared -le '$a=$b=1; share($a); async(sub{$a++; $b++})->join; print "a=$a, b=$b"'

# Thread pitfall. $a can be either 2 or 3 (race condition)
perl -lMthreads -Mthreads::shared -le '$a=1; share($a); $_->join for map async(sub{my $foo=$a; $a=$foo+1}), 1..2; print "a=$a"'

# Allow only one thread to touch a variable at a time
# This will cause a "deadlock" where one thread requires a reourses
# locked by another thread and vice versa
perl -Mthreads -Mthreads::shared -le 'share $a; share $b; push @t, async(sub{lock $a; sleep 20; lock $b}); push @t, async(sub{lock $b; sleep 20; lock $a}); $_->join for @t'
#
# Alternate syntax 1
perl -Mthreads -le 'my $a :shared; my $b :shared; push @t, async(sub{lock $a; sleep 20; lock $b}); push @t, async(sub{lock $b; sleep 20; lock $a}); $_->join for @t'
#
# Alternate syntax 2
perl -Mthreads -le 'my $a :shared; my $b :shared; push @t, threads->create(sub{lock $a; sleep 20; lock $b}); push @t, threads->create(sub{lock $b; sleep 20; lock $a}); $_->join for @t'

# Thread safe queues. Passing Data Around
perl -Mthreads -MThread::Queue -le 'my $q=Thread::Queue->new; $t=async(sub{ print "Popped $d off the queue" while $d=$q->dequeue  }); $q->enqueue(12); $q->enqueue(qw/A B C/); sleep 1; $q->enqueue(undef); $t->join'

# Compute pi using parallel threading
time perl -Mthreads -Mthreads::shared -le 'share $sum; $M=100_000_000; $T=6; $h=1/$M; sub sum { my $s; my($from,$to)=@_; for($from..$to){ my $x=$h*($_-0.5); $s += 4/(1+$x**2)}; $s } sub split_by { my($max,$by)=@_; my $from=1; my @l; while($to<$max){ $to=$from+(($max-$from+1)/$by--)-1; $to=int($to)+1 if $to != int($to); push @l, [$from,$to]; $from=$to+1 }; @l } @a=split_by($M,$T); @t=map {async sub{sum(@$_)}} @a; $sum += $_->join() for @t; $pi = $h * $sum; print $p'


#############################################################
## Perl Modules - Carton
#############################################################

# Keep track of the installed modules in a local directory by making a
# virtual environment. Like virtualenv and requirements.txt, but for Perl.
cpanm Carton

# Perl install modules found in cpanfile
carton install

# Perl zip modules found in cpanfile
carton bundle


#############################################################
## Perl Modules - CGI
#############################################################

# Make html ordered lists from array lists
perl -MCGI=ol,li -le 'print ol(li([qw/red blue green/]))'
perl -MCGI=ol,li -le 'print ol(li [qw/red blue green/])'
perl -MCGI=ol,li -le 'print ol li [qw/red blue green/]'

# Generate a sample html page
perl -MCGI=:standard,:html3 -le 'print header(),start_html(),ol(li [qw/red blue green/]),end_html()' > my.html
perl -MCGI=:standard,:html3 -le 'print header(),start_html(),td(Tr [qw/red blue green/]),end_html()' > my2.html


#############################################################
## Perl Modules - Crypt::PasswdMD5
#############################################################

# Generate MD5 Password
perl -MCrypt::PasswdMD5 -lE 'say unix_md5_crypt('pass','salt')'
openssl passwd -1 -salt salt pass


#############################################################
## Perl Modules - Cwd
#############################################################

# Get current working directory (slightly different than pwd)
perl -MCwd -le 'print getcwd'

# Get absolute path to a file (works same for link and regular files,DES)
perl -MCwd=realpath  -le '$_="file"; print realpath($_)'


#############################################################
## Perl Modules - DateTime
#############################################################

# Create expiration dates (Start of tomorrow,start of next week)
perl -MDateTime -E '$dt = DateTime->now; say $dt->add(days => 1)->truncate(to => "day" )'
# 2021-08-06T00:00:00
perl -MDateTime -E '$dt = DateTime->now; say $dt->add(weeks => 1)->truncate(to => "local_week" )'
# 2021-08-08T00:00:00

# Truncate date to start of this week (Monday).
perl -MDateTime -E '$dt = DateTime->now; say $dt->truncate(to => "week" )->strftime("%e %b %Y")'

# Truncate date to end of 3 weeks from now on a Friday.
perl -MDateTime -E '$dt = DateTime->now; say $dt->truncate(to => "week" )->add(weeks => 3, days => 4)->strftime("%e %b %Y")'


#############################################################
## Perl Modules - Data::Dumper
#############################################################

# Deparse a subroutine in a data structure
perl -MData::Dumper -le '$ref=sub{print "in sub"}; &$ref; my $d=Data::Dumper->new([$ref])->Deparse(1); print $d->Dump'

# Deparse/show the code of a subroutine
perl -MData::Dumper -le '$Data::Dumper::Deparse=1; sub add{my($a,$b)=@_; $a+$b}; print Dumper \&add'
perl -MData::Dumper -le '$Data::Dumper::Deparse=1; $add=sub{my($a,$b)=@_; $a+$b}; print Dumper $add'

# Data Dumper subroutine template
sub pr{
   require Data::Dumper;
   my $d = Data::Dumper->new([@_]);
    $d->Terse(1)->Indent(1)->Sortkeys(1)->Purity(1);
   print $d->Dump, "\n";
}


#############################################################
## Perl Modules - DBI
#############################################################

# How to connect to database using perl DBI (postgres,sample,sql)
perl -MDBI -E '$dbh = DBI->connect("DBI:Pg:dbname=$db; host=127.0.0.1", "$user", "$pass", {RaiseError => 1}) or die $DBI::errstr; say "\nOpened db successfully!\n"'

# How to query information from a database using perl (postgres,sample,sql)
perl -MDBI -E 'sub Die { die $DBI::errstr } $dbh = DBI->connect("DBI:Pg:$db=srto_8_0; host=127.0.0.1", "$user", "$pass", {RaiseError => 1}) or Die; $sth = $dbh->prepare(q(SELECT * from MyTable;)) or Die; $sth->execute() or Die; while(@row = $sth->fetchrow_array()){ say "@row" }


#############################################################
## Perl Modules - DBI::Profile
#############################################################

# Profile SQL statements in perl DBI.
# Install and export.
cpanm DBI::Profile
export DBI_PROFILE='!Statement'
#
# Report explicitly (instead of on DESTROY)
DBI->trace(1, $DBITraceOutput);


#############################################################
## Perl Modules - Devel::NYTProf
#############################################################

# Install NYTProf profiler for perl
sudo apt-get install libdevel-nytprof-perl

# Run profiler
perl -d:NYTProf fetch_excel t/data/1-7.xls abc
nytprofhtml
w3m nytprof/index.html
iceweasel nytprof/index.html

# Profile a perl program
cd ~/<USER>/Excel
perl -d:NYTProf fetch_excel Data/1-7.xls 1.7.15
nytprofhtml -o Profiling         # View Profiling/index.html in internet explorer

# NYTProf writing to a file.
use Devel::NYTProf qw();
use File::Path qw();
File::Path::make_path($Dir);
#
DB::enable_profile($newfile);    # Create or truncate existing file.
DB::enable_profile();            # Append to same file.
#
# Run slow code.
#
DB::finish_profile();            # Stop writing to file.

# NYTProf environment setup.
export PERL5OPT=-d:NYTProf
export NYTPROF='trace=1:start=no'
perl my_script.pl
unset PERL5OPT
unset NYTPROF

# Error when profiling
# Profile data incomplete, inflate error -5 ((null)) at end of input file
#
# Make sure not to run the nytprofhtml command in the same window as:
export NYTPROF='trace=1:start=no'


#############################################################
## Perl Modules - Devel::Peek
#############################################################

# Examine a data structure of variables in C code
perl -MDevel::Peek -le '$a=15; print Dump($a)'


#############################################################
## Perl Modules - Email::Outlook::Message
#############################################################

# Parse an outlook message .msg file
perl -MEmail::Outlook::Message -le 'print Email::Outlook::Message->new(shift)->to_email_mime->as_string' "$m"


#############################################################
## Perl Modules - Excel::Writer::XLSX
#############################################################

# Excel - Simple: Generate a blank xlsx file
perl -MExcel::Writer::XLSX -E "$wb = Excel::Writer::XLSX->new('my.xlsx'); $wb->close"

# Excel - Simple: Check for errors openning an excel file and write to a cell
# Also rename the worksheet
perl -MExcel::Writer::XLSX -E "$wb = Excel::Writer::XLSX->new('my.xlsx') or die qq($!\n); $ws = $wb->add_worksheet('my'); $ws->write('A1', 'Hello Excel'); $wb->close"

# Excel - Simple: Add a format to make a cell bold
perl -MExcel::Writer::XLSX -E "$wb = Excel::Writer::XLSX->new('my.xlsx') or die qq($!\n); $ws = $wb->add_worksheet('my'); $format = $wb->add_format; $format->set_bold; $ws->write(0, 0, 'Hello Excel', $format); $wb->close"

# Create a spreadsheet/excel with formulas using perl (only on lnxbr42)
perl -MExcel::Writer::XLSX -le '
   $wb=Excel::Writer::XLSX->new("new.xlsx");
   $ws=$wb->add_worksheet;
   $ws->write("A1","In Excel");
   $ws->write("B2",3);
   $ws->write("B3",4);
   $ws->write("B4","=B2+B3");
   $ws->write("B5","=SUM(B2:B4)");
   $wb->close
'

# Create a spreadsheet/excel with color formats using perl (only on lnxbr42)
perl -MExcel::Writer::XLSX -le '
   $wb=Excel::Writer::XLSX->new("new2.xlsx");
   $ws=$wb->add_worksheet;
   $format=$wb->add_format(color => 'red');
   $ws->write("A1","No Color");
   $ws->write("A2","Red Color", $format);
   $wb->close
'

# Create a spreadsheet/excel with color formats using perl (only on lnxbr42). same thing
perl -MExcel::Writer::XLSX -le '
   $wb=Excel::Writer::XLSX->new("new2.xlsx");
   $ws=$wb->add_worksheet;
   $ws->write("A1","No Color");
   $ws->write("A2","Red Color", $wb->add_format(color => 'red'));
   $wb->close
'


#############################################################
## Perl Modules - File::Copy
#############################################################

# Copy using perl
perl -MFile::Copy -lE 'copy("abc2","abc3")'


#############################################################
## Perl Modules - File::Tee
#############################################################

# Writing to multiple filehandles
# Bug: does not work with crontab
#
# Better to do this instead:
open STDOUT, "| tee -a $log" or die $!;
open STDERR, "| tee -a $log" or die $!;


#############################################################
## Perl Modules - FindBin
#############################################################

# Perl operator qw does not interpolate variables
# FindBin qw($bin)      same as:
# FindBin   '$Bin'
perl -le '$a="A"; print for qw/$a $b c/'


#############################################################
## Perl Modules - Getopt::Long
#############################################################

# Extract command line options using a library
perl -MGetopt::Long -MData::Dumper -le 'GetOptions(\%opts, "delim=s"); print Dumper \%opts' 5 3 02 .4f --delim=,

# Get the command line options (perl)
# Option can be used like this:
#  -r
#  -r VALUE
#
GetOptions(\%opts,
   "debug|s",
   "quiet|q",
   "recursive|r:s",                 # Takes optional string
);
for($opts{recursive}){
   if(defined){ $_ ||= "DEFAULT" }  # If blank, use default
   else       { $_ = 0 }            # Do not use option
}

# Pull out flags and data in Perl (command line options, function)
my $is_flag = qr/^ --? (\w[-\w]*) (?:= ([\w,]+) )? $/x;
for(splice @ARGV){
   if(/$is_flag/){ $flags{$1} = $2 // 1 }
   else          { push @data, $_       }
}


#############################################################
## Perl Modules - Hash::Util
#############################################################

# Perl bucket ratio (hash in scalar content)
perl -MHash::Util=bucket_ratio -le "%h=qw(a 1 b 2 c 3 d 4 e 5 f 6); print bucket_ratio %h"


#############################################################
## Perl Modules - Hook::LexWrap
#############################################################

# Wrap a subroutine and see the input and output
perl -MHook::LexWrap -le 'wrap 'abc', pre => sub{print "pre:  [@_[0..$#_-1]]"}, post => sub{print "post: [@{$_[-1]}]"}; sub abc{my($a,$b)=@_; $a+$b} print abc 2,3'

# Wrap a subroutine and see the input and output. modify results
perl -MHook::LexWrap -le 'wrap 'abc', post => sub{$_[-1] = 8}; sub abc{my($a,$b)=@_; $a+$b} print abc 2,3'


#############################################################
## Perl Modules - HTML::Tree
#############################################################

# Reduce Data::Dumper to the first layer of depth
perl -MHTML::Tree -MData::Dumper -le 'sub pr{my $d=Data::Dumper->new(\@_)->Sortkeys(1)->Terse(1)->Indent(1)->Maxdepth(1); print $d->Dump} $t=HTML::Tree->new_from_file("rakudo2.html"); $f=$t->look_down(qw/_tag td/); pr $_ for $f'

# Extract text from HTML
perl -MHTML::Tree -le '$t=HTML::Tree->new_from_file("rakudo2.html"); $f=$t->find(qw/tr td table/); print $f->as_text'

# Extract latest href download link from an html document
perl -MHTML::Tree -le '$t=HTML::Tree->new_from_file("rakudo.html"); print $_->attr("href") for ($t->look_down(class => "ext-gz"))[0]'
perl -MHTML::Tree -le '$t=HTML::Tree->new_from_file("rakudo.html"); print $t->look_down(class => "ext-gz")->attr("href")'


#############################################################
## Perl Modules - IPC::SysV
#############################################################

# Create a new SysV IPC stream
perl -MIPC::SysV=IPC_PRIVATE,IPC_CREAT,S_IRUSR,S_IWUSR -le 'print msgget(IPC_PRIVATE, IPC_CREAT | S_IRUSR | S_IWUSR)'


#############################################################
## Perl Modules - JavaScript::Minifier::XS
#############################################################

# Minify a javascript file
perl -MJavaScript::Minifier::XS=minify -e "open IN, 'operation-add.js'; open OUT, '>', 'operation-add.min.js'; {local $/; $d=<IN>} print OUT minify($d)"


#############################################################
## Perl Modules - JaSON
#############################################################

# Read a json file in perl
perl -MJSON -le "open FH, 'my.json'; local $/; $raw=<FH>; $d = from_json($raw)->{KEY}; print for @$d"


#############################################################
## Perl Modules - Lingua::EN::Tagger
#############################################################

# Add tags to text
perl -MLingua::EN::Tagger -le '$p=Lingua::EN::Tagger->new; print for $p->add_tags("I like food. I like food")'
perl -MLingua::EN::Tagger -le '$p=Lingua::EN::Tagger->new; print for $p->get_readable("I like food. I like food")'

# View natural language lexicon (on lnxbr42)
cd /usr/share/perl5/Lingua/EN/Tagger
perl -MData::Dumper -MStorable -le '$T=retrieve "pos_tags.hash";  print Dumper $T->{pp}'
perl -MData::Dumper -MStorable -le '$W=retrieve "pos_words.hash"; print Dumper $W->{I}'

# Find how likely a certain word is a particular part of speech
cd /usr/share/perl5/Lingua/EN/Tagger
perl -MStorable -le '$W=(retrieve "pos_words.hash")->{I}; $T=(retrieve "pos_tags.hash")->{pp}; print for reverse sort map{ ${$W->{$_}} * $T->{$_} . " $_" } keys $W'


#############################################################
## Perl Modules - Lock::File
#############################################################

# Simple module for locking a file. (exclusive,shared)
perl -MLock::File=lockfile -E 'my $lock = lockfile("my.lock7") or die $!; sleep 100000'
perl -MLock::File=lockfile -E 'my $lock = lockfile("my.lock7", {shared => 1}) or die $!; sleep 100000'


#############################################################
## Perl Modules - LWP
#############################################################

# Send a post request (LWP)
u="http://pythonscraping.com/pages/files/processing.php"
perl -MLWP -le '$u=shift; $ua=LWP::UserAgent->new; $ua->env_proxy;  $rc=$ua->post($u,{qw/^Crstname FIRST lastname LAST/}); print $rc->content' $u


#############################################################
## Perl Modules - LWP::UserAgent
#############################################################

# Get http request. practice using LWP::UserAgent
perl -MLWP::UserAgent -MData::Dumper -le '$u="http://www.google.com"; $ua=LWP::UserAgent->new; $ua->env_proxy; $r=$ua->get($u); print $r->header("Server")'


#############################################################
## Perl Modules - Math::Combinatorics
#############################################################

# Get permutations of lists (make a table).
perl -lE '$_="{0,1}"x3; say for glob'
perl -E 'say for glob "{A,B}{1,2}"'
perl -lE 'say for glob "{0,1}{0,1}{0,1}{0,1}"'
perl -MMath::Combinatorics=permute -lE 'say for map{"@$_"} permute(qw/a b c/)'


#############################################################
## Perl Modules - Math::Factoring
#############################################################

# Factoring a number to get the prime numbers
perl -MMath::Factoring=factor -E "say for factor 666"


#############################################################
## Perl Modules - Module::CoreList, corelist
#############################################################

# Find perl module
perl -MModule::CoreList -le 'print for Module::CoreList->find_modules("Class")'
cpan -l | grep -e '^Class'

# Find all available modules for a certain version
perl -MModule::CoreList -le 'print for Module::CoreList->find_modules(/5.010/)'

# Find find release of a perl module
corelist Data::Dumper

# Find all release versions of a perl module
corelist -a Data::Dumper


#############################################################
## Perl Modules - Module::Starter
#############################################################

# Create a new distribution in perl abd run it.
x2hs -X Example      # Pure Perl
h2xs -A -n Example   # XS
perl Makefile.PL
make
perl -Mblib -MExample2 -E 'Example2::print_hello()'

# Using -Mblib is similar to using:
perl -Iblib/lib -Iblib/arch -MExample2 -e 'Example2b::print_hello'

# Create a new distribution in perl.
module-starter --module=App::pod --author="AUTHOR" --email="EMAIL" --mb --verbose
#
perl Build.PL
perl Build
perl Build test
perl Build disttest
perl Build dist


#############################################################
## Perl Modules - Mojo
#############################################################

# Mojo DSL
  monkey_patch $caller,
    a => sub { $caller->can('any')->(@_) and return $ua->server->app },
    b => \&b,
    c => \&c,
    d => sub { $ua->delete(@_)->result },
    f => \&path,
    g => sub { $ua->get(@_)->result },
    h => sub { $ua->head(@_)->result },
    j => \&j,
    l => sub { Mojo::URL->new(@_) },
    n => sub (&@) { say STDERR timestr timeit($_[1] // 1, $_[0]) },
    o => sub { $ua->options(@_)->result },
    p => sub { $ua->post(@_)->result },
    r => \&dumper,
    t => sub { $ua->patch(@_)->result },
    u => sub { $ua->put(@_)->result },
    x => sub { Mojo::DOM->new(@_) };
}

# Download a PDF file using Perl
# Will not download if it is already up to date. (by etag)
perl -Mojo -E "my $q=chr 34; sub get_etag($tx){ $tx->result->headers->etag =~ s/^$q|$q$//gr; } my $ua = Mojo::UserAgent->new; my $url = Mojo::URL->new('https://hop.perl.plover.com/book/pdf/HigherOrderPerl.pdf'); my $f = $url->path->parts->[-1]; my $t = (stat($f))[9]; my $d = Mojo::Date->new($t); my $tx = $ua->head($url); my $etag = get_etag($tx); my $dir = Mojo::File->new('etag-cache')->make_path; my $path = $dir->child($etag); if(not -e $path){ my $tx = $ua->get($url); my $etag = get_etag($tx); $tx->result->save_to($f); open my $fh, '>', $path or die $! }"

# Fetch latest unicode characters (Windows)
perl -CSAD -Mojo -mcharnames -E "my $ua = Mojo::UserAgent->new; my $url = 'https://blog.emojipedia.org/whats-new-in-unicode-10/'; my $tx = $ua->get($url); die qq(Error getting) unless $tx->result->is_success; my $d = $tx->result->dom->find('ul:not([class]) li a')->map('text')->map(sub{ my $c = substr $_, 0, 1; my $ord = ord($c); $ord > 0x1F000 ? [ $c, $ord, charnames::viacode($ord) ] : () })->sort( sub{ $a->[1] <=> $b->[1] })->map(sub{ sprintf '%s (U+%05X) %s', $_->@* }) ; say for @$d"

# Fetch latest unicode characters (Linux)
perl -CSAD -Mojo -mcharnames -E 'my $ua = Mojo::UserAgent->new; my $url = "https://blog.emojipedia.org/whats-new-in-unicode-10/"; my $tx = $ua->get($url); die qq(Error getting) unless $tx->result->is_success; my $d = $tx->result->dom->find("ul:not([class]) li a")->map("text")->map(sub{ my $c = substr $_, 0, 1; my $ord = ord($c); $ord > 0x1F000 ? [ $c, $ord, charnames::viacode($ord) ] : () })->sort( sub{ $a->[1] <=> $b->[1] })->map(sub{ sprintf "%s (U+%05X) %s", $_->@* }) ; say for @$d'

# Make the client mojo page auto reload/refresh
plugin 'AutoReload';


#############################################################
## Perl Modules - Mojo::DOM
#############################################################

# Parsing HTML using regex vs Mojo::DOM
https://mojolicious.io/blog/2018/12/05/compound-selectors/

# Generate html tags using Mojo::DOM. (root,append)
perl -Mojo -E 'my $html = x(); $html->append_content("<a>"); $html->at("a")->attr("target" => "_blank"); say $html'
perl -MMojo::DOM -E 'my $html = Mojo::DOM->new; $html->append_content("<a>"); $html->at("a")->attr("target" => "_blank"); say $html'
# <a target="_blank"></a>

# Generate html tags using Mojo::DOM. (snippet)
perl -MMojo::DOM -E 'my $html = Mojo::DOM->new(qq(<a href="path" >)); $html->at("a")->attr("target" => "_blank"); say $html'
# <a href="path" target="_blank"></a>

# Generate html tags using Mojo::DOM. (conditional)
perl -MMojo::DOM -E 'my $html = Mojo::DOM->new(qq(<a href="path" >)); my $a = $html->at("a"); if(defined $a->attr("href")){ $a->attr("target" => "_blank") } say $html'
# <a href="path" target="_blank"></a>

# Difference between TAG:nth-child(N) and TAG:nth-of-type(N)
# nth-child - positional check first, then TAG check:
#
perl -Mojo -E 'my $dom = x(q(<ul class="clss"> <li>item1</li> <p>para</p> <li>item2</li> </ul>)); say $dom->at("ul > :nth-child(2)")'
# <p>para</p>
#
perl -Mojo -E 'my $dom = x(q(<ul class="clss"> <li>item1</li> <p>para</p> <li>item2</li> </ul>)); say $dom->at("ul > li:nth-child(2)")'
# undef

# Difference between TAG:nth-child(N) and TAG:nth-of-type(N)
# nth-of-type - TAG check first, then positional check.
# if the TAG is not specified, the first TAG found is used.
#
perl -Mojo -E 'my $dom = x(q(<ul class="clss"> <li>item1</li> <p>para</p> <li>item2</li> </ul>)); say $dom->at("ul > li:nth-of-type(2)")'
# <li>item2</li>
#
perl -Mojo -E 'my $dom = x(q(<ul class="clss"> <p>para1</p> <li>item1</li> <p>para2</p> <li>item2</li> </ul>)); say $dom->at("ul > :nth-of-type(2)")'
<p>para2</p>


#############################################################
## Perl Modules - Mojo::File
#############################################################

# Pretty print json data to a file
package Mojo::File {
   use Mojo::Base qw/ -strict -signatures /;
   use Mojo::JSON qw(j);
   use Encode qw/ encode /;
   sub spurt_json ( $self, $struct ) {
      my $string       = j $struct;
      my $_pretty_json = qx(echo '$string' | jq .);
      my $pretty_json  = encode( "UTF-8", $_pretty_json );
      $self->spurt( $pretty_json );
   }
}


#############################################################
## Perl Modules - Mojo::Parameters
#############################################################

# Access the contents of an array like a hash by key.
perl -MMojo::Util=dumper -E '@a=qw/a 1 b 2 c 3/; %h=@a; say dumper \%h'
#
# This might be more efficient for bigger lists.
perl -MMojo::Parameters -MMojo::Util=dumper -E '@a=qw/a 1 b 2 c 3/; $params = Mojo::Parameters->new(@a); say dumper $params->param("b")'
perl -MMojo::Parameters -MMojo::Util=dumper -E '@a=qw/a 1 b 2 c 3/; $params = Mojo::Parameters->new(@a); say dumper $params->every_param("b")'


#############################################################
## Perl Modules - Mojo::Promise
#############################################################

# Promise usage
perl -Mojo -E "my $p = Mojo::Promise->new; $p->then(sub($robot,$human){ say qq(robot: $robot); say qq(human: $human); }, sub{ say qq!Rejected with: @_!} )->catch( sub{say qq!Error: @_!} ); $p->resolve(qw/Bender Fry Leela/); $p->wait"

# Simple Mojo promise example
perl -MMojo::Promise -E "$p = Mojo::Promise->new; $p->then(sub{say 'OK'}); $p->resolve; $p->wait"
perl -MMojo::Promise -E "$p = Mojo::Promise->new; $p->then(sub{say 'OK'}, sub{say 'BAD'}); $p->resolve; $p->wait"
perl -MMojo::Promise -E "$p = Mojo::Promise->new; $p->then(sub{say 'OK'}, sub{say 'BAD'}); $p->reject; $p->wait"

# Simple Mojo promise example - timer (OK)/ timeout (BAD)
perl -MMojo::Promise -E "$p = Mojo::Promise->new; $p->then(sub{say 'OK'}, sub{say 'BAD'}); $p->timeout(1); $p->wait"
perl -MMojo::Promise -E "$p = Mojo::Promise->new; $p->then(sub{say 'OK'}, sub{say 'BAD'}); $p->timer(1); $p->wait"

# Chain of promises - short way, but not working for the 2nd level
perl -Mojo -MMojo::Promise -E "my $p = Mojo::Promise->new; $p->then(sub{say '1-OK'}, sub{say '1-BAD'})->then(sub{say '2-OK'}, sub{say '2-BAD'}); $p->reject; $p->wait"

# Chain of promises - long way
perl -Mojo -MMojo::Promise -E "my $p = Mojo::Promise->new; my $p2; $p2 = $p->then(sub{say '1-OK'; $p2->resolve}, sub{say '1-BAD'; $p2->reject}); $p2->then(sub{say '2-OK'}, sub{say '2-BAD'}); $p->reject; $p->wait"

# Using get_p (GET with a promise)
perl -Mojo -MMojo::Promise -E "my $ua = Mojo::UserAgent->new; $ua->get_p(shift)->then(sub{say qq(1-OK: @_)}, sub{say qq(1-BAD: @_)})->wait" mojolicious.org

# Create a list of promises and a top promise to watch them all
perl -MMojo::Promise -E "@p = map { my $p = Mojo::Promise->new; my $n = $_; $p->then(sub{say $n ** 2}, sub{ warn qq(Error in $n\n)}); $p } 1..10; $tp = Mojo::Promise->all(@p)->then(sub{say 'OK'}, sub{say 'NOK'}); $_->resolve for @p; $tp->wait"
#
# Reject a promise
perl -MMojo::Promise -E "@p = map { my $p = Mojo::Promise->new; my $n = $_; $p->then(sub{say $n ** 2}, sub{ warn qq(Error in $n\n)}); $p } 0..10; $tp = Mojo::Promise->all(@p)->then(sub{say 'OK'}, sub{say 'NOK'}); $p[4]->reject; $tp->wait"
#
# Try rejecting/approving
perl -Mojo -MMojo::Promise -E "my @p = map {my $n = $_; my $p = Mojo::Promise->new; $p->then(sub{say qq(P-OK: $n)}, sub{say qq(P-BAD: $n) }); $p } 0..2; my $hop = Mojo::Promise->all(@p)->then(sub{say 'OK'}, sub{say 'BAD'}); $p[$_]->reject for 0,1,2; $_->resolve for @p; $hop->wait"

# Mojo promise race - first one wins
perl -MMojo::Promise -E "@p = map { my $p = Mojo::Promise->new; my $n = $_; $p->then(sub{say $n ** 2}, sub{ warn qq(Error in $n\n)}); $p } 0..10; $race = Mojo::Promise->race(@p)->then(sub{say 'OK'}, sub{say 'NOK'}); $_->resolve for $p[4], @p; $race->wait"

# HigherOrder Promises
perl -Mojo -MMojo::Promise -E "my @p = map {Mojo::Promise->new} 1..3; my $hop = Mojo::Promise->new; $hop->all(@p)->then(sub{say qq(OK: @_)}, sub{say qq(BAD: @_)}); $hop->wait"
#
# Mojo::Promise::Role::HigherOrder - Not working
perl -MMojo::Promise -E "my @p = map {Mojo::Promise->new} 0..2; my $hop = Mojo::Promise->with_roles('+Any')->any(@p)->then(sub{say 'OK'}, sub{say 'BAD'}); $p[$_]->reject for 0,1,2; $_->resolve for @p; $hop->wait"
perl -MMojo::Promise -E "my @p = map {my $n = $_; my $p = Mojo::Promise->new; $p->then(sub{say qq(\nP-OK$n)}, sub{say qq(\nP-BAD$n) }); $p } 0..2; my $hop = Mojo::Promise->with_roles('+Any')->any(@p)->then(sub{say 'OK'}, sub{say qq(\nBAD)}); $p[$_]->reject for 0,1,2; $_->resolve for @p; $hop->wait"

# Check if a[href] urls in html files are accessbile
for file in *.xhtml; do echo; echo $file; my_get_ok $(perl -Mojo -E 'my $dom = x f(shift)->slurp; say for $dom->find("a[href]")->map("attr", "href")->each' "$file" | not -r '^\w+\.\w+$' | sort -u); done
my_html_links_check *.xhtml


#############################################################
## Perl Modules - Mojo::UserAgent
#############################################################

# Download a PDF file using Perl
perl -Mojo -E "my $ua = Mojo::UserAgent->new; my $url = Mojo::URL->new('https://hop.perl.plover.com/book/pdf/HigherOrderPerl.pdf'); my $f = $url->path->parts->[-1]; my $tx = $ua->get($url)->result->save_to($f)"

# Download a PDF file using Perl
# Will not download if it is already up to date. (by date)
perl -Mojo -E "my $ua = Mojo::UserAgent->new; my $url = Mojo::URL->new('https://hop.perl.plover.com/book/pdf/HigherOrderPerl.pdf'); my $f = $url->path->parts->[-1]; my $t = (stat($f))[9]; my $d = Mojo::Date->new($t); my $tx = $ua->get($url, {'If-Modified-Since' => $d}); say $tx->res->to_string"

# Create a Mojo Websocket and on message hooks
perl -Mojo -E "my $ua = Mojo::UserAgent->new; say r $ua->websocket_p('ws://172.17.17.1:80/get_jobs')->then(sub($tx){ my $p = Mojo::Promise->new; $tx->on(finish => sub($tx,$code,$reason){ say qq(Closed with code $code); $p->resolve;}); $tx->on(message => sub($tx,$msg){ say qq(Message: $msg); $tx->finish }); $p })->catch(sub($err){warn qq(Error: $err)})->wait"

# Show all the redirects
perl -Mojo -E "my @txs = Mojo::UserAgent->new->max_redirects(10)->head(shift); while(my $tx = $txs[0]->previous){ unshift @txs, $tx } say $_->req->url for @txs" mojolicious.org
perl -Mojo -E "my $tx = Mojo::UserAgent->new->max_redirects(10)->head(shift); say $_->req->url for $tx->redirects->@*, $tx" mojolicious.org


#############################################################
## Perl Modules - Mojo::Util
#############################################################

# steady_time and promises
perl -Mojo -MMojo::Util=steady_time -E "sub st($m){printf qq(%-20s: %s\n), steady_time, $m} st('Before'); my $ua = Mojo::UserAgent->new; for my $url(@ARGV){ st(qq(Trying: $url)); state $cnt = 0; my $label = $cnt++; $ua->get($url => sub{ st(qq(Finished: $url)) }) } st('After'); END{ st('END') }" https://www.perl.com https://www.mojolicious.org

#############################################################
## Perl Modules - Mojolicious::Plugin::Directory
#############################################################

# Similar to python's simple http server
python -m SimpleHTTPServer 8080
#
cpanm Mojolicious::Plugin::Directory
perl -Mojo -MCwd=getcwd -E 'a->plugin("Directory", root => getcwd())->start' daemon


#############################################################
## Perl Modules - Moose
#############################################################

# Override a method that is defined in a role (Moose)
$Self->meta->add_method(FinishHook => sub { say 'FINISH!!!' });

# Override a class method that is defined in a role (Moose,around)
# Approach 1 - get_method, add_method, execute.
#
+ my $Orig = $Meta->get_method($Method);
+ $Meta->add_method( $Method => sub {
+   my ($Self,%Param) = @_;
+   $Orig->execute($Self,%Param);
+   return 1;
+ });

# Override a class method that is defined in a role (Moose,around)
# Approach 2 - add_method_modifier.
#
+ add_method_modifier $Meta, 'around', [ $Method, sub {
+    my ($Orig,$Self,%Param) = @_;
+    $Self->$Orig(%Param);
+    return 1;
+ }];

# Override a class method that is defined in a role (Moose,around)
# Approach 3 - Moose::around meta.
#
+ # 'around' will not work since it uses currying and
+ # prepends the current class name.
+ # 'Moose::around' avoids currying.
+ Moose::around $Meta, $Method => sub {
+    my ($Orig,$Self,%Param) = @_;
+    $Orig->($Self,%Param);
+    return 1;
+ };

# Override a class method that is defined in a role (Moose,around)
# Approach 4 - Moose::around class.
#
+ Moose::around $Package, $Method => sub {
+    my ($Orig,$Self,%Param) = @_;
+    $Orig->($Self,%Param);
+    return 1;
+ };

# The basic Moose type hierarchy looks like this (perl,OOP):
Any
    Item
        Bool
        Maybe[`a]
        Undef
        Defined
            Value
                Str
                    Num
                        Int
                    ClassName
                    RoleName
            Ref
                ScalarRef[`a]
                ArrayRef[`a]
                HashRef[`a]
                CodeRef
                RegexpRef
                GlobRef
                FileHandle
                Object


#############################################################
## Perl Modules - O::Xref
#############################################################

# Debug a perl script. Find all usage of subroutines and variables
perl -MO=Xref fetch_excel.p | less


#############################################################
## Perl Modules - Pod::Usage
#############################################################

# Pull out a section from pod
perl -MPod::Usage=pod2usage -E "pod2usage(-input => `perldoc -l ojo`, -verbose => 99, -sections => '.*/x');"

# Pull out a sectin of perl documentation and store it in a variable
perl -MPod::Usage=pod2usage -E "open my $fh, '>', \my $out or die $!; pod2usage(-input => `perldoc -l ojo`, -verbose => 99, -sections => '.*/x', -output => $fh, exitval => 'NOEXIT'); say qq([$out])"


#############################################################
## Perl Modules - Safe
#############################################################

# Run code in a safer environment
perl -MSafe -le '$comp=Safe->new; $code=q(use v5.10; print "hello Safe!"); $comp->reval($code) or die $@'
	'require' trapped by operation mask at (eval 5) line 1.

# Permit actions to be done
perl -MSafe -le '$comp=Safe->new; $comp->permit("require"); $code=q(use v5.10; print "hello Safe!"); $comp->reval($code) or die $@'
	'print' trapped by operation mask at (eval 5) line 2.
perl -MSafe -le '$comp=Safe->new; $comp->permit(qw(require print)); $code=q(use v5.10; print "hello Safe!"); $comp->reval($code) or die $@'
	hello Safe!

# Find/View/see all Opcodes for Safe
perl -MOpcode=opdump -e opdump

# Find/View/see all Opcodes for Safe that include a string
perl -MOpcode=opdump -e 'opdump shift' item

# Find Opcode for safe that fints a specific attribute
perl -MOpcode=opdump -e 'opdump shift' ATTRIBUTE

# Run code to evaluate arithemetic
perl -MSafe -le '$comp=Safe->new; $comp->deny(qw(:default)); $comp->permit(qw(padany lineseq const add leaveeval subtract)); while(<>){chomp; $res=$comp->reval($_) or warn $@ and next; print "$_ = $res"}'


#############################################################
## Perl Modules - Set::Scalar
#############################################################

# Install library to work with sets
sudo apt-get install libset-scalar-perl

# Working with sets in perl (examples)
perl -MSet::Scalar -le '$s1=Set::Scalar->new(qw/1 2 3/); $s2=Set::Scalar->new(qw/2 4 6/); print for $s1-$s2'
perl -MSet::Scalar -le '$s=Set::Scalar; $s1=$s->new(qw/1 2 3/); $s2=$s->new(qw/2 4 6/); print for $s1-$s2'


#############################################################
## Perl Modules - Storable
#############################################################

# Create a deep clone of a reference.
perl -MStorable=dclone -E 'my $h={a => [1..2]}; my $h2 = dclone($h); say $_, " ", $_->{a} for $h, $h2'


#############################################################
## Perl Modules - Template (Toolkit,tt)
#############################################################

# Concatenation operator in template tookkit (tt)
Data.var1 _ Data.var2


#############################################################
## Perl Modules - Term::Animation
#############################################################

# Using a terminal animation framework
perl -MTerm::Animation -MCurses -E 'use v5.32; my $anim = Term::Animation->new; halfdelay(2); $anim->new_entity(shape => "<=0=>", position => [3,7,10], callback_args => [1,0,0,0], wrap => 1); while(1){ $anim->animate; my $in = getch(); last if $in eq "q" }'

# Using a terminal animation framework (with colors)
perl -MTerm::Animation -MCurses -E 'use v5.32; my $anim = Term::Animation->new; halfdelay(1); $anim->color(1); $anim->new_entity(shape => "<=0=>", position => [3,7,10], callback_args => [1,0,0,0], wrap => 1, default_color => "yellow"); while(1){ $anim->animate; my $in = getch(); last if $in eq "q" }'


#############################################################
## Perl Modules - Term::ANSIColor
#############################################################

# Proper way to color text in perl instead of hardcoding
# escape codes (which are not all the same on all devices).
perl -MTerm::ANSIColor -E 'say colored ($_,$_) for qw( RED YELLOW GREEN ON_BRIGHT_BLACK )'


#############################################################
## Perl Modules - Term::ProgressBar
#############################################################

# Progress bar example 1
perl -Mojo -MTerm::ProgressBar -CO -E "STDOUT->autoflush(1); my $ua = Mojo::UserAgent->new; $ua->on(prepare => sub($ua,$tx){ my($len,$bar); $tx->res->on(progress => sub($res){ return unless $len ||= $res->headers->content_length; my $prog = $res->content->progress; $bar //= Term::ProgressBar->new({name => 'Unicode', count => $len}); $bar->update($prog)  }); $tx->res->on(finish => sub($res){return unless $len; $bar->update($len); })  }); $ua->get('https://blog.emojipedia.org/whats-new-in-unicode-10/')"

# Progress Bar example 2
perl -MTerm::ProgressBar -E "$|++; @a=1..100; $bar = Term::ProgressBar->new({count => ~~@a}); $bar->update($_), select undef,undef,undef,0.05 for @a"
GetTerminalSize
# Progress Bar in Perl (more features shown here)
perl -MTerm::ProgressBar -E "$|++; $max=100_000; $progress = Term::ProgressBar->new({count => $max, name => 'File-1', term_width => 50, remove => 1}); $progress->minor(0); my $next_update = 0; for (0..$max){ my $is_power = 0; for (my $i = 0; 2**$i <= $_; $i++) { $is_power = 1 if 2**$i == $_; } $next_update = $progress->update($_) if $_ >= $next_update; } $progress->update($max) if $max >= $next_update; $progress->message('File-1: DONE')"


#############################################################
## Perl Modules - Term::ReadKey
#############################################################

# Get terminal width in perl
perl -MTerm::ReadKey= -E "my ($w) = GetTerminalSize(); say $w"

# Read input from the keyword/user without showing the password
perl -MTerm::ReadKey -le 'ReadMode(2); $pass .= $key while(ord($key = ReadKey(0)) !~ /^(?: 10|13 )$/x); ReadMode(0); print "Got [$pass]"'

# Read input from the keyword/user without showing the password (same, but using keywords)
perl -MTerm::ReadKey -le 'ReadMode(noecho); $pass .= $key while(ord($key = ReadKey(0)) !~ /^(?: 10|13 )$/x); ReadMode(restore); print "Got [$pass]"'
perl -MTerm::ReadKey -e 'ReadMode(2); while($c=ReadKey(0), ord($c) !~ /^(?:10|13)$/x){ $pass .= $c  } ReadMode(0); print "[$pass]\n"'

# Read input from the keyword/user without showing the password (same, but more compact)
perl -MTerm::ReadKey -le 'ReadMode(2); $pass = ReadLine(0); chomp $pass; ReadMode(0); print "Got [$pass]"'
perl -MTerm::ReadKey -le 'ReadMode(2); $_ = ReadLine(0); chomp; ReadMode(0); print "[$_]"'

# Read input from the keyword/user without showing the password (same, but on windows)
perl -MTerm::ReadKey -le "ReadMode 2; $pass = ReadLine 0; chomp $pass; ReadMode 0; print qq([$pass])"

# Read input from the keyword/user without showing the password. replace characters with a star "*"
perl -MTerm::ReadKey -e 'ReadMode(4); while($c=ReadKey(0),$o=ord($c),$o != 10 and $o != 13){ if($o == 127 || $o == 8){chop $p; print "\b \b"}elsif($o < 32){}else{ $p .= $c; print "*" }} ReadMode(0); print "[$p]\n"'
perl -MTerm::ReadKey -e 'ReadMode 3; while($c=ReadKey(0),$o=ord($c),$o != 10 and $o != 13){ if($o == 127 || $o == 8){chop $p; print "\b \b"}elsif($o < 32){}else{ $p .= $c; print "*" }} ReadMode 0; print "[$p]\n"'
perl -MTerm::ReadKey -e 'ReadMode 4; while($c=ReadKey(0),$o=ord($c),$o!=10){ if($o==127 or $o==8){chop $p; print "\b \b"}elsif($o < 32){}else{$p.=$c; print "*"}} ReadMode 0; print "[$p]\n"'


#############################################################
## Perl Modules - Text::CSV
#############################################################

# Write a csv file (super easy)
perl -MText::CSV_XS=csv -E "csv(in => [[qw/A B C/],[1,2,3]], out => 'my.csv')"

# Read certain lines of a CSV file
perl -l -MText::CSV -e '$csv=Text::CSV->new; open FH, "book1.csv"; while($a=$csv->getline(FH)){print $a->[0]}'

# CSV file into an array (Mike)
perl -l -MText::CSV_XS -e '$csv=Text::CSV_XS->new; open FH, "a.csv"; $a=$csv->getline_all(FH); print $a->[1][3]'


#############################################################
## Perl Modules - Tie::Array
#############################################################

# Tie a simple array variable
perl -MData::Dumper -MTie::Array -le 'tie @a, "Tie::StdArray"; @a=(1,3,4); print Dumper tied @a'


#############################################################
## Perl Modules - Tie::File
#############################################################

# Tie an array to a file
perl -MTie::File -le 'tie @file,"Tie::File","array.pl"; print $file[4]'


#############################################################
## Perl Modules - Tie::Hash
#############################################################

# Tie a simple hash variable
perl -MData::Dumper -MTie::Hash -le 'tie %h, "Tie::StdHash"; $h{age}=123; print Dumper tied %h'


#############################################################
## Perl Modules - Tie::Scalar
#############################################################

# Tie a simple scalar variable
perl -MData::Dumper -MTie::Scalar -le 'tie $n, "Tie::StdScalar"; $n=5; print Dumper tied $n'

# Tie to scalar (without template)
perl -le '{package P; sub TIESCALAR{my($c,$o)=@_; bless \$o,$c} sub FETCH{my($s)=@_; $$s} sub STORE{my($s,$v)=@_; $$s = $v} } tie $var, "P", 123; print $var; $var=42; print $var'


#############################################################
## Perl Modules - Tie::Watch
#############################################################

# Tie Watch. OOP interface that hides making packages for tied variables
perl -MTie::Watch -le 'my $v=1; Tie::Watch->new(-variable => \$v, -fetch => sub{my $s=shift; $v=$s->Fetch; $s->Store($v+1); $v}); print $v; print $v; print $v'

# Check when a variable is updated. (watcher)
perl -MTie::Watch -Mojo -le 'my $h={a => [1..2]}; say r $h; Tie::Watch->new( -variable => \$h->{a}, -store => sub{my ($s,$v) = @_; $s->Store($v); my $Scope = 0; while( my ($Pkg,$Line) = caller(++$Scope) ){ say "$Pkg:$Line" } }); sub func{$h->{a}=456} func(); say r $h'

# Check when a variable is updated. (watcher)
use Tie::Watch;
Tie::Watch->new(
   -variable => \$Self->{Cache}->{ $Param{Type} }->{ $Param{Key} },
   -store    => sub{
       my ($S,$Value) = @_;
       $S->Store($Value);
       my $Scope = 0;
       my $Limit = 5;
       while( my ($Package,$Line) = (caller(++$Scope))[0,2] ){
          next if $Package =~ /\ATie::/;
          say "* Store: $Package line $Line";
          last if $Scope >= $Limit;
       }
   },
);


#############################################################
## Perl Modules - Time::Moment
#############################################################

# Difference between with_offset_same_instant and with_offset_same_local.
# Instant form will use the time zone from the object (Probably what you want).
perl -MTime::Moment -E '$tm = Time::Moment->now; $tmi = $tm->with_offset_same_instant(0); $tml = $tm->with_offset_same_local(0); say "Normal:   $tm"; say "Instance: $tmi"; say "Local:    $tml"'
# Normal:   2022-03-10T18:44:46.882016+01:00
# Instance: 2022-03-10T17:44:46.882016Z
# Local:    2022-03-10T18:44:46.882016Z


#############################################################
## Perl Modules - Time::Piece
#############################################################

# Prefer using Time::Piece over DateTime if possible
#
# 1. Less dependencies:
cpanm --showdeps Time::Piece -q | wc -l   # 4
cpanm --showdeps DateTime -q | wc -l      # 35
#
# 2. Issues with using DateTime and cron.
# Could be due to also perlbrew trying a different
# library path (which I could not resolve).

# Print the currect time, the inputed time, and difference in seconds (accounts for timezone offset)
perl -MTime::Piece -le '$now=localtime; $t=Time::Piece->strptime("20170320 095200 -0400","%Y%m%d %H%M%S %z"); print $_->strftime," ",$_->tzoffset for $now,$t; print $now-$t'

# Compare the current time to a string (desired). Accounts for time zone
perl -MTime::Piece -le '$now=localtime; $now+=$now->tzoffset; print $now;  $t=Time::Piece->strptime("Mon Apr 17 14:36:02 2017","%a %b %d %H:%M:%S %Y"); print $now-$t'

# Compare the current time to a string (desired). Accounts for time zone (compact)
perl -MTime::Piece -le '$now=localtime; $now+=$now->tzoffset; print $now;  $t=Time::Piece->strptime("Mon Apr 17 14:36:02 2017","%c"); print $now-$t'

# Compare the curent time to a string. Show direrence in seconds between times
perl -MTime::Piece -le '$now=localtime; $now+=$now->tzoffset; $t=Time::Piece->strptime(shift,"%c"); print for $now,$t,$now-$t' "Mon Apr 17 14:36:02 2017"

# Print current time in about YYYYMMDD
perl -MTime::Piece -le "print localtime()->strftime('%Y%m%d')"

# Storage format for transfering/saving  timestamp
perl -MTime::Piece -E 'say localtime->strftime("%x %R")'
# Fri 06 Aug 2021 20:06       # Storage format
perl -MTime::Piece -E 'say localtime->strptime("Fri 06 Aug 2021 20:06", "%x %R")'
# Fri Aug  6 20:06:00 2021    # General format

# Set expiration date to start of tomorrow
perl -MTime::Piece -MTime::Seconds -E '$t = localtime; $t += ONE_DAY; say $t->truncate(to => "day")->strftime("%x %R")'
# Sat 07 Aug 2021 00:00

# Set expiration date to start of next week
perl -MTime::Piece -MTime::Seconds -E '$t = localtime; $t += ONE_DAY; $t += ONE_DAY until $t->wdayname eq "Sun"; say $t->truncate(to => "day")->strftime("%x %R")'
# Sun 08 Aug 2021 00:00


#############################################################
## Perl Modules - Time::Seconds
#############################################################

# Date arithmetic in Javascript (add 90 days to a date)
# Time::Seconds imports ONE_DAY
perl -MTime::Seconds -MTime::Piece -le "$now=localtime; $now+=$now->tzoffset; $now += ONE_DAY * 90; print $now->strftime('%Y-%m-%d')"

# Seconds to HMS (hhmmss)
use Time::Seconds;
my $time = Time::Seconds->new(time - $time0)->pretty;
#
perl -MTime::Seconds -E 'say Time::Seconds->new(time)->pretty;'
# 18845 days, 18 hours, 4 minutes, 21 seconds


#############################################################
## Perl Modules - Tk (General)
#############################################################

# Create a simple Tk window
perl -MTk -le '$mw=MainWindow->new; $mw->title("Hello"); $mw->Button(-text => "Done", -command => sub{exit})->pack; MainLoop'

# Create a simple grid window
perl -MTk -le '$m=MainWindow->new; $m->Button->grid($m->Button,$m->Button); $m->Button->grid($m->Button,$m->Button); MainLoop'

# Create a simple grid window with last button spanning several columns
perl -MTk -le '$m=MainWindow->new; $m->Button->grid($m->Button,$m->Button); $m->Button->grid($m->Button,"-", -sticky => "nsew"); MainLoop'

# Create a simple grid window with last button spanning several rows
perl -MTk -le '$m=MainWindow->new; $m->Button->grid($m->Button,$m->Button, -sticky => "nsew"); $m->Button->grid($m->Button,"^"); MainLoop'

# Create a simple grid window with last button removed/ignored/skipped
perl -MTk -le '$m=MainWindow->new; $m->Button->grid($m->Button,$m->Button); $m->Button->grid("x",$m->Button, -sticky => "nsew"); MainLoop'

# Have a button to disable another button
perl -MData::Dumper -MTk -wle '
   $mw     = MainWindow->new;
   $exit_b = $mw->Button(-text => "exit", -command => sub{exit})->pack(-ipadx => 20, -ipady => 10);
   $text   = "Disable Exit";
   $mw->Button(-textvariable => \$text, -command => sub{
      if( ($exit_b->configure(-state))[-1] eq "disabled" ){
         $exit_b->configure(-state => "normal");
         $text = "Disable Exit";
      }
      else{
         $exit_b->configure(-state => "disabled");
         $text = "Enable Exit";
      }
   })->pack;
   MainLoop;
'

# TODO: Check if Unigraph is perl tk

# Create Menu Buttons (PTk,bind method)
perl -MTk -le '$mw=MainWindow->new; $mw->Button(-text => "Exit", -command => sub{exit})->pack(-side => "bottom", -fill => "both", -expand => 1); $f=$mw->Frame(-relief => "ridge", -borderwidth => 2)->pack(-side => "top", -expand => 1, -fill => "both"); for(qw/File Edit Options Help/){$f->Menubutton(-text => $_)->pack(-side => "left", -fill => "both", -expand => 1)}; MainLoop'

# Perk Tk Event Types (PTk,bind method)
ButtonPress (or Button)
ButtonRelease
Circulate
Colormap
Configure
Destroy
Enter
Expose
FocusIn
FocusOut
Gravity
KeyPress (or Key)
KeyRelease
Leave
Map
Motion
Reparent
Unmap
Visibility

# Perl Tk Event Info Usage program
perl -MTk -le '$mw=MainWindow->new; $b=$mw->Button->pack(-ipadx => 60); $b->bind("<Key>", [sub{print "ARGV: @_[1..$#_]"}, Ev("k"), Ev("K"), Ev("N"), Ev("T")]); MainLoop'

# Perl Tk Event Info (PTk,bin methods,Ev)
#
# Coordinates (relative to window)
Ev('x')
Ev('y')
#
# Coordinates (relative to root of window)
Ev('X')
Ev('Y')
#
# Button Number (of mouse click)
Ev('b')
#
# Size of widget
Ev('h')     # height
Ev('w')     # width
#
# Keyboard Info
Ev('k')     # Physical Key Value  37   37
Ev('K')     # Letter              A    a
Ev("N")     # Decimal             65   97
#
# Event Type
Ev('T')     # KeyPress

# Perl Tk Event Info (PTk,bin methods,Ev)
# Stop events in callback.
return      # Exits only current sub
Tk::break   # Stops all callbacks for an event

# View order of bindings for a widget (PTk,bin methods,Ev)
print for $b->bindtags
print "$_: ", $b->bind($_) for $b->bindtags

# Order order of bindings for a widget (PTk,bin methods,Ev)
$b->bindtags("[all]")

# View the bindtags for (PTk):
# Class
# Install
# Toplevel
# All
perl -MTk -le '$b=MainWindow->new->Button->pack; $b->bind("<ButtonRelease-1>", sub{exit}); map {print $_; printf "   $_\n" for $b->bind($_)} $b->bindtags'

# Check if widget exists, if widget if packed (mapped,PTk)
perl -MTk -le '$mw=MainWindow->new; $b=$mw->Button(-text => "unpack", -command => sub{$b->packForget})->pack; $mw->Button(-text => "Check status", -command => sub{print for "",Exists($b), $mw->appname, $b->ismapped()})->pack; MainLoop'

# Track mouse movements (PTk)
perl -MTk -le '$mw=MainWindow->new; $mw->geometry("200x200+0+0"); $w=$mw->Label(-textvariable => \$t, -width => 20)->pack; $mw->bind("<Motion>", sub{$t=join ", ", $mw->pointerxy}); MainLoop'

# Track mouse movements (PTk)
# More positional values
perl -MTk -le '$w=tkinit; $w->geometry("200x200"); $w->Label(-textvariable => \$t, -justify => "left")->pack; $w->bind("<Motion>", sub{$t=sprintf "pointerxy:%s,%s\nxy:%s,%s\nroot:%s.%s\nvroothw:+%s,+%s\nvrootxy:%s,%s\nscreen:%s", $w->pointerxy, $w->x,$w->y, $w->rootx,$w->rooty,$w->vrootheight,$w->vrootwidth,$w->vrootx,$w->vrooty,$w->screen}); MainLoop'

# Add tab completion to an entry widget
perl -MTk -le '$mw=MainWindow->new; $e=$mw->Entry(-textvariable => \$t)->pack; $e->focus; $e->bind("<Tab>", sub{@a=glob "$t*"; $t=shift @a if @a; $e->selectionClear}); MainLoop'

# Bind Enter/Carriage Return key (PTk)
$e->bind("<Return>"

# Swap button (PTk)
perl -MTk -le '$mw=MainWindow->new; for(1..3){my $b=$mw->Button(-text => "B$_", -width => 20)->pack; $b->configure(-command => sub{ ($n)=grep{$b[$_] eq $b}0..$#b; return unless $n > 0; @b[$n,$n-1]=@b[$n-1,$n]; $_->packForget for @b; $_->pack for @b}); push @b,$b} MainLoop'

# Drag and swap buttons (PTk)
perl -MTk -le '$mw=MainWindow->new; my @b; sub id{my($n)=grep{$b[$_] eq $_[0]}0..$#b; $n} for(1..3){push @b, $mw->Button(-text => "B$_", -width => 20)->pack} $mw->bind("<ButtonRelease-1>",[sub{$m=id(shift); $n=id($mw->containing(@_)); @b[$m,$n]=@b[$n,$m]; $_->packForget, $_->pack for @b}, Ev("X"), Ev("Y")]); print for @b; print ""; MainLoop'

# Swap frames of buttons (PTk)
perl -MTk -le '$mw=MainWindow->new; my @b; sub id{my($n)=grep{$b[$_] eq $_[0]}0..$#b; $n} for my $fi(1..3){my $f=$mw->Frame->pack; push @b,$f; $f->Button(-text => "Btn - $fi - $_", -width => 20)->pack(-side => "left") for 1..3} $mw->bind("<ButtonRelease-1>",[sub{$m=id(shift->parent); $n=id($mw->containing(@_)->parent); print "$m <-> $n"; @b[$m,$n]=@b[$n,$m]; $_->packForget, $_->pack for @b}, Ev("X"), Ev("Y")]); print for @b; print ""; MainLoop'

# Notebook example 1. multiple pages/tabs (PTk)
perl -MTk -MTk::NoteBook -le '$nb=MainWindow->new->NoteBook->pack(-fill => "both", -expand => 1); @pgs = map { $nb->add("page$_", -label => "Page $_") } 0..5; $pgs[0]->Button(-text => "Button $_")->pack(-fill => "both") for 1..5; $pgs[1]->Label(-text => "Label $_")->pack(-fill => "both") for 1..5; MainLoop'

# Notebook example 2. multiple pages/tabs (PTk)
# Command when clicking a page/tab
perl -MTk -MTk::NoteBook -le '$nb=MainWindow->new->NoteBook(-font => "Courier 14 bold")->pack(-fill => "both", -expand => 1); @pgs = map { $nb->add("page$_", -label => "Page $_") } 0..20; $pgs[0]->Button(-text => "Button $_")->pack(-fill => "both") for 1..5; $pgs[1]->Label(-text => "Label $_")->pack(-fill => "both") for 1..5; $nb->pageconfigure("page1", -raisecmd => sub{print "raised"}); MainLoop'

# Notebook example 3. multiple pages/tabs (PTk)
# Page deletion
perl -MTk -MTk::NoteBook -le '$nb=MainWindow->new->NoteBook->pack(-fill => "both", -expand => 1); @pgs = map { $nb->add("page$_", -label => "Page $_") } 0..10; $nb->pagecget("page0", "-state"); $pgs[0]->Button(-text => "Button $_")->pack(-fill => "both") for 1..5; $nb->delete("page0"); MainLoop'

# Notebook example 4. multiple pages/tabs (PTk)
# Get page by name
perl -MTk -MTk::NoteBook -le '$nb=MainWindow->new->NoteBook->pack(-fill => "both", -expand => 1); @pgs = map { $nb->add("page$_", -label => "Page $_") } 0..10; $nb->pagecget("page0", "-state"); $pgs[0]->Button(-text => "Button $_")->pack(-fill => "both") for 1..5; $nb->page_widget("page3")->Label(-text => "Label$_")->pack for 1..5; MainLoop'

# Notebook example 5. multiple pages/tabs (PTk)
# 2 rows
perl -MTk -MTk::NoteBook -le '$nb=MainWindow->new->NoteBook->pack(-fill => "both", -expand => 1); $nb->add("page0$_", -label => "Page $_") for 1..5; map { my $nb = $_; $nb->add("page1$_", -label => "Page $_") for 6..10;   } map $_->NoteBook->pack, map $nb->page_widget($_), $nb->pages; MainLoop'

# Notebook example 6. multiple pages/tabs (PTk)
perl -MTk -MTk::NoteBook -le '$nb=MainWindow->new->NoteBook->pack; $nb->add("page0$_", -label => "Page $_") for 1..5; @pgs = map $nb->page_widget($_), $nb->pages; ($p,@rest)=@pgs; $nb1=$p->NoteBook->pack; $nb1->add("page1$_", -label => "Page $_") for 6..10; $nb->page_widget("page01")->Button(-text => "EXIT")->pack; MainLoop'

# Entry widget validation options (PTk)
perl -MTk -le 'MainWindow->new->Entry(-validate => "key", -validatecommand => sub{$_[1] =~ /\d/}, -invalidcommand => sub{ print "ERROR" })->pack->focus; MainLoop'

# Making Scrollbars (PTk)
# When text widget is scrolled its "-yscrollcommand" command is invoked. This calls $s->set(...)
# When the scrollbar is clicked on "-command" is invoked which calls $t->yview(...)
perl -MTk -le '$mw=MainWindow->new; $s=$mw->Scrollbar; $t=$mw->Text(-yscrollcommand => ["set" => $s]); $s->configure(-command => ["yview" => $t]); $s->pack(-side => "right", -fill => "y"); $t->pack(-fill => "both"); MainLoop'

# Scale widget example (PTk)
perl -MTk -le 'MainWindow->new->Scale(-from => 1, -to => 5, -tickinterval => 1, -showvalue => 0)->pack; MainLoop'

# Ballon widget example (PTk)
perl -MTk -MTk::Balloon -le '$mw=MainWindow->new; $b=$mw->Button(-text => "DO NOTHING")->pack; $mw->Balloon->attach($b, -msg => "button"); MainLoop'

# Ballon widget example (PTk)
perl -MTk -le '$w=tkinit; $bt=$w->Button(-text => "this does nothing")->pack; $w->Balloon->attach($bt, -msg => "really nothing"); MainLoop'

# Listbox example (PTk)
perl -MTk -le '$w=MainWindow->new; $lb=$w->Scrolled("Listbox", -scrollbars => "osoe")->pack; $lb->insert(0,1..10); $w->Button(-text => "SHOW", -command => sub{@s=$lb->curselection; print $lb->get(@s) if @s})->pack; MainLoop'

# Handle clicking the "X" button on a window to close (PTk)
perl -MTk -le '$w=MainWindow->new; sub e{print "safe exit"; $w->destroy} $w->protocol("WM_DELETE_WINDOW", \&e); $w->Button(-text => "EXIT", -command => \&e)->pack; MainLoop'

# Menu(bar) example (PTk)
perl -MTk -le '$w=MainWindow->new; $m=$w->Menu; $w->configure(-menu => $m); %h=map{$_ => $m->cascade(-label => "~$_")} qw/File Edit Help/; $h{File}->command(-label => "Exit", -command => sub{exit}); MainLoop'

# Menu(bar) example using -menuitems (PTk)
perl -MTk -le '$w=MainWindow->new; $m=$w->Menu; $w->configure(-menu => $m); %h=map{$_ => $m->cascade(-label => "~$_", -menuitems => [[checkbutton => "MY_CHECK"],[command => "MY_CMD", -command => sub{print "exit"}, -accelerator => "Ctrl-o"],[radiobutton => "MY_RADIO"],"",[cascade => "MY_CASCADE"]])} qw/File Edit Help/; MainLoop'

# Simple Menu(bar) example using -menuitems (PTk)
perl -MTk -le '$w=MainWindow->new; $m=$w->Menu; $w->configure(-menu => $m); $m->cascade(-label => "~File", -menuitems => [[command => "new", -accelerator => "Ctrl-n"],"",[command => "Open", -accelerator => "Ctrl-o"]]); MainLoop'

# Simple 2 Menu(bar) example using -menuitems (PTk)
perl -MTk -le '$w=MainWindow->new; $m=$w->Menu; $w->configure(-menu => $m); $m->cascade(-label => "~File", -menuitems => [[cascade => "new", -accelerator => "Ctrl-n", -menuitems => [map [command => $_],qw/PNG JPEG TIFF/], -tearoff => 0],"",[command => "Open", -accelerator => "Ctrl-o"]]); MainLoop'

# Color changing menu(bar) (PTk)
perl -MTk -le '$color="$red"; $w=MainWindow->new; $mi=[[cascade => "~Edit", -menuitems => [[cascade => "~Background", -menuitems => [map [radiobutton => $_, -variable => \$color, -command => [sub{my $c=shift; $w->configure(-background => $c); print "CHANGED TO [$c]"},$_]], qw/Red Blue Yellow Green/],   ]], ]]; $w->configure(-menu => $w->Menu(-menuitems => $mi)); MainLoop'

# Very primitive notebook (poor man's notebook) (PTk)
perl -MTk -le '$w=MainWindow->new; ($top,$bot)=map{$w->Frame->pack} 1..2; @b=map { $top->Button(-text => "B$_", -command => [sub{print shift}, $_])->pack(-side => "left") } 1..3; @f=map{$bot->Frame} 1..3; $f[0]->pack; $f[0]->Label(-text => "L1")->pack; $f[1]->Label(-text => "L2")->pack; $b[1]->configure(-command => sub{ $_->packForget for @f; $f[1]->pack }); MainLoop'

# Wait until variable is changes. Other button can still be pressed though. (PTk)
perl -MTk -le '$w=MainWindow->new; $w->Entry(-width => 20, -textvariable => \$t)->pack; $w->Button(-text => "PRINT", -command => sub{print "ABC"})->pack; $w->Button(-text => "PAUSE", -command => sub{$w->waitVariable(\$t); print "DONE"})->pack; MainLoop'

# Simple composite Mega-Widget based on a Toplevel (PTk)
perl -MTk -le '{package Tk::My; use base "Tk::Toplevel"; Construct Tk::Widget "My" } $w=MainWindow->new; $w->My; MainLoop'

# Define own bitmap
perl -MTk -le '$w=MainWindow->new; $p=pack("b5"x5,"..1..",".111.","11111",".111.","..1.."); $bm=$w->DefineBitmap(up => 5,5,$p); $w->Button(-width => 10, -height => 30, -bitmap => "up")->pack; MainLoop'

# Define own bitmap (fansy)
cat star.bm
..............................
..............................
..............................
..............1...............
..............1...............
.............111..............
.............111..............
............1.1.1.............
.......11...1.1.1...11........
.......11..1..1..1..11........
.........1.1..1..1.1..........
..........1...1...1...........
.........1.1..1..1.11.........
.......11...1.1.1....11.......
.....11......111.......11.....
...111111111111111111111111...
.....11......111.......11.....
.......11...1.1.1....11.......
.........1.1..1..1.11.........
..........1...1...1...........
.........1.11.1.11.1..........
.......11...1.1.1...11........
.......11...1.1.1...11........
.............111..............
.............111..............
..............1...............
..............1...............
..............................
..............................
..............................
perl -MTk -le '$w=MainWindow->new; $s=30; $p=pack("b$s"x$s,`cat start.bm`); $w->DefineBitmap(start => $s,$s,$p); $w->Button(-bitmap => "start")->pack; MainLoop'

# DirTree example (PTk)
perl -MTk -le 'MainWindow->new->Scrolled("DirTree")->pack(qw/-fill both -expand 1/); MainLoop'

# LabEntry example (PTk,label and entry in one)
perl -MTk -le 'tkinit->LabEntry(-label => "name", -textvariable => \$name, -labelPack => [qw/ -side left /], -width => 20)->pack; MainLoop'

# Clicking a button will send it to the top. Cycle through
perl -MTk -le '$w=tkinit; @b=map{$w->Button(-text => $_)->pack} a..c; $_->configure(-command => sub{$b[-1]->pack(-before => $b[0]); unshift @b, pop @b }) for @b; MainLoop'

# Show or hide widgets based on a checkbutton (advanced options)
perl -MTk -le '$w=tkinit; $b=$w->Button->pack(qw/ -side bottom /); $p=1; $w->Checkbutton(-text => "Pack", -variable => \$p, -command => sub{ if($p){ $i=$b->{packInfo}; $b->pack(@$i) } else { $b->{packInfo} = [$b->packInfo]; $b->packForget }  })->pack; MainLoop'

# Sleep/Wait (PTk)
$mw->after(3000)     # ms


#############################################################
## Perl Modules - Tk (Bind)
#############################################################

# Make Control-C binding (PTk)
perl -MTk -le '$b=tkinit->Button(-text => "Try Control-C"); $b->configure(-command => sub{$b->focus}); $b->pack->bind("<Control-Key-c>", sub{print "Hit C"}); MainLoop'

# Show the name an value of each pressed key (PTk)
perl -MTk -le '$e=tkinit->Entry->pack; $e->focus; $e->bind("<Key>", sub{my($w)=@_; my $E=$w->XEvent; printf "%s %s\n", $E->K, $E->N}); MainLoop'
#
# Simpler
perl -MTk -le '$e=tkinit->Entry->pack; $e->focus; $e->bind("<Key>", sub{my $E=shift->XEvent; printf "%s %s\n", $E->K, $E->N}); MainLoop'
#
# Using newer "Tk::event"
perl -MTk -le '$e=tkinit->Entry->pack; $e->focus; $e->bind("<Key>", sub{printf "%s %s\n", $Tk::event->K, $Tk::event->N}); MainLoop'

# Three (3) ways to get the widget reference of a binding (PTk)
perl -MTk -le '$b=tkinit->Button(-command => \&cb)->pack; $b->bind("<ButtonRelease-3>", \&cb); sub cb {print "\nargs: @_"; print "->W" . $Tk::event->W; print "widget " . $Tk::widget}; MainLoop'

# Find out value of keypress
perl -MTk -le 'tkinit->Entry->pack->bind("<KeyPress>", sub{$e=$Tk::event; print $e->K . " " . $e->N}); MainLoop'

#############################################################
## Perl Modules - Tk (Canvas)
#############################################################

# Take a canvas and create a postscript then a pdf
perl -MTk -le '$w=tkinit; $c=$w->Canvas->pack; $c->createLine(20,20,200,200,200,20); $b=$w->Button(-text => "Save", -command => sub{$c->postscript(-file => "tk.ps")})->pack; MainLoop'
ps2pdf tk.ps tk.pdf
xpdf tk.pdf


#############################################################
## Perl Modules - Tk (Tags)
#############################################################

# Text tags example (PTk)
perl -MTk -le '$t=tkinit->Text->pack; $t->tagConfigure("bold", -font => "Courier 24 bold"); $t->insert("end", "Normal Text\n"); $t->insert("end", "Bold Text\n", "bold"); MainLoop'

# Make select text bold (PTk)
perl -MTk -le '$w=tkinit; $t=$w->Text->pack; $t->tagConfigure("bold", -font => "bold"); $t->insert("end", "A Bunch of text"); $w->Button(-text => "BOLD", -command => sub{$t->tagAdd("bold", "sel.first", "sel.last")} )->pack; MainLoop'

# Check if a selection exists (PTk)
perl -MTk -le '$w=tkinit; $t=$w->Text->pack; $t->tagConfigure("bold", -font => "bold"); $t->insert("end", "A Bunch of text"); $w->Button(-text => "BOLD", -command => sub{$t->tagAdd("bold", "sel.first", "sel.last") if $t->tagRanges("sel")} )->pack; MainLoop'


#############################################################
## Perl Modules - Tk (Appendix B)
#############################################################

# Adjuster example (PTk,Appendix B)
perl -MTk -le '$w=tkinit; %def=qw/-fill both -expand 1/; $b=$w->Button(-text => "Button A")->pack(%def); $w->Adjuster(-side => "top", -widget => $b)->pack(qw/-fill x/); $w->Button(-text => "Button B")->pack(%def); MainLoop'

# Ballon Example (Ptk,Appendix B)
perl -MTk -le '$w=tkinit; $btn=$w->Button(-text => "Button A")->pack; $bl=$w->Balloon; $bl->attach($btn, -msg => "click me"); MainLoop'

# Bitmap Example (Ptk,Appendix B)

# BrowseEntry Example (Ptk,Appendix B)
#
# Simple
perl -MTk -MTk::BrowseEntry -le 'tkinit->BrowseEntry(-label => "label", -variable => \$v, -choices => [1..10], -browsecmd => sub{print "Clicked $v"})->pack; MainLoop'
#
# Insert additional values
perl -MTk -MTk::BrowseEntry -le '$b=tkinit->BrowseEntry(-label => "label", -variable => \$v, -choices => [1..10], -browsecmd => sub{print "Clicked $v"})->pack; $b->insert("end",20,30); MainLoop'

# Button Example (Ptk,Appendix B)

# Canvas Example (Ptk,Appendix B)
#
# Simple useless canvas
perl -MTk -le '$c=tkinit->Scrolled("Canvas")->pack; MainLoop'
#
# Click in canvas window will show x,y coordinates
perl -MTk -le 'sub print_xy { my($c,$x,$y)=@_; print "(x,y) = @{[ $c->canvasx($x) ]}, @{[ $c->canvasy($y) ]} "   } $c=tkinit->Scrolled("Canvas")->pack; $c->Subwidget("canvas")->CanvasBind("<Button-1>", [ \&print_xy, Ev("x"), Ev("y") ]); MainLoop'

# ColorEditor Example (Ptk,Appendix B)

# Dialog Example (Ptk,Appendix B)

# DirTree Example (Ptk,Appendix B)

# Entry Example (Ptk,Appendix B)

# ErrorDialog Example (Ptk,Appendix B)

# FileSelect Example (Ptk,Appendix B)

# Frame Example (Ptk,Appendix B)

# HList Example (Ptk,Appendix B)
perl -MTk -MTk::HList -le '$h=tkinit->HList(-indent => 20)->pack; $h->add(qw/A -text a/); $h->add(qw/A.B -text a->b/); MainLoop'

# Label Example (Ptk,Appendix B)

# LabEntry Example (Ptk,Appendix B)
# Learn how to use Text indices (demo)
perl -MTk -le '%def=qw/-side left/; $mw=tkinit; $t=$mw->Text->pack; ($i,$d)=map{my $v; $mw->LabEntry(-label => "$_:", -textvariable => \$v, -labelPack => [%def])->pack(%def); \$v} qw/Index Data/; $mw->Button(-text => "INSERT", -command => sub{$t->insert($$i,eval qq("$$d"))})->pack(%def, -expand => 1, -fill => "x"); $$i="1.0"; $$d="A1\\n"; MainLoop

# LabFrame Example (Ptk,Appendix B)

# ListBox Example (Ptk,Appendix B)

# MainWindow Example (Ptk,Appendix B)

# Menu Example (Ptk,Appendix B)

# MenuButton Example (Ptk,Appendix B)

# Message Example (Ptk,Appendix B)

# NoteBook Example (Ptk,Appendix B)

# Optionmenu Example (Ptk,Appendix B)

# Pane Example (Ptk,Appendix B)

# Photo Example (Ptk,Appendix B)

# ProgressBar Example (Ptk,Appendix B)

# Radiobutton Example (Ptk,Appendix B)

# ROText Example (Ptk,Appendix B)

# Scale Example (Ptk,Appendix B)

# Table Example (Ptk,Appendix B)

# Text Example (Ptk,Appendix B)

# TextUndo Example (Ptk,Appendix B)

# Tiler Example (Ptk,Appendix B)

# TList Example (Ptk,Appendix B)

# TopLevel Example (Ptk,Appendix B)

# Tree Example (Ptk,Appendix B)


#############################################################
## Perl Modules - Tk::TextString, Tk::TextStrings
#############################################################

# Tie Text widget to store input as an entry or label would in "-variable" (PTk)
perl -MTk -le '{package P; sub TIESCALAR{my($c,$o)=@_; bless \$o,$c} sub FETCH{my($s)=@_; $$s->get("1.0", "end")} sub STORE{my($s,$v)=@_; $$s->delete("1.0", "end"); $$s->insert("end", $v)} } $mw=MainWindow->new; $t=$mw->Text->pack; tie $v, "P", $t; $b=$mw->Button(-command => sub{print "[$v]"})->pack; MainLoop'

# Tie Text widget to -variable. Set value with button or entry (PTk)
perl -MTk -le '{package P; sub TIESCALAR{my($c,$o)=@_; bless \$o,$c} sub FETCH{my($s)=@_; $$s->get("1.0", "end")} sub STORE{my($s,$v)=@_; $$s->delete("1.0", "end"); $$s->insert("end", $v)} } $mw=MainWindow->new; $t=$mw->Text->pack; tie $v, "P", $t; $b=$mw->Button(-command => sub{print "[$v]"})->pack; $mw->Button(-command => sub{$v="ABC"})->pack; $mw->Entry(-textvariable => \$v)->pack; MainLoop'

# Example of new TextString Mega-Widget (PTk,tie,user module)
perl -MTk -MTk::TextString -w -le '$mw=MainWindow->new; $mw->TextString(-variable => \$v)->pack; $mw->Entry(-textvariable => \$v)->pack(-side => "left"); $mw->Button(-command => sub{print "[$v]"})->pack(-side => "left"); MainLoop'

# Scolled multiple text boxes through multiple -variables (PTk,tie,user module)
perl -MTk -MTk::TextString -w -le '%d=qw(-side left); $mw=MainWindow->new; @f=map{$mw->Frame->pack} 1..3; @t=map{my $v; $f[0]->TextString(-height => 2, -variable => \$v)->pack(%d); \$v} @f; $f[1]->Entry(-textvariable => $_)->pack(%d) for @t; $f[2]->Button(-command => [sub{my($r)=@_; print $$r},$_])->pack(%d) for @t; MainLoop'

# Scolled multiple text boxes through single -variable (PTk,tie,user module)
perl -MTk -MTk::TextStrings -w -le '%d=qw(-side left); $mw=MainWindow->new; @f=map{$mw->Frame->pack} 1..3; @t=map{$f[0]->TextStrings(-height => 2, -variable => \$v)->pack(%d); \$v} @f; $f[1]->Entry(-textvariable => $_)->pack(%d) for @t; $f[2]->Button(-command => [sub{my($r)=@_; print $$r},$_])->pack(%d) for @t; MainLoop'

# Can text widget and entry widget are synced (PTk, tie,user module)
perl -MTk -MTk::TextStrings -le '$mw=MainWindow->new; $mw->TextStrings(-height => 2, -variable => \$v)->pack; $mw->Entry(-textvariable => \$v)->pack; MainLoop'


#############################################################
## Perl Modules - Try::Tiny
#############################################################

# Simple approach to catching errors
# Try Catch return are subroutine based. Below return unexpectedly (at first) "BBB"
# WARNING: It has issues. Unpredictable syntax
perl -MTry::Tiny -lE 'sub try_me{ try{1/0}catch{say "Caught [$@]"; return "AAA"}; return "BBB" } $v=try_me; say $v'

# A better try/catch approach (only on lnxbr42)
# WARNING: It has issues. Highly dependent upon Perl changes
perl -MTryCatch -lE 'sub try_me{ try{1/0}catch{say "Caught [$@]"; return "AAA"}; return "BBB" } $v=try_me; say $v'


#############################################################
## Perl Modules - Unicode::Normalize
#############################################################

# Compose or decompose unicode strings.
perl -Mcharnames=:full -CO -MUnicode::Normalize -E 'say charnames::viacode ord for split //, NFD "\N{LATIN CAPITAL LETTER A WITH ACUTE}"'
# LATIN CAPITAL LETTER A
# COMBINING ACUTE ACCENT


#############################################################
## Perl Modules - XML::LibXML
#############################################################

# Parse and find specific nodes/elements in an xml file
# "//Page" means to look recursively down for a "Page" element
perl -MXML::LibXML -le '$d=XML::LibXML->load_xml(location => "my.xml"); print "$_\n\n" for $d->findnodes("//Page")'

# Parse xml file. Find all "PageTable" elements
# Select all PageTableProperty inside.
# Print out the value of the PageTableName   (Use @ to find an attribute instead of a value)
# Print out the value (using ->to_literal)
perl -MXML::LibXML -le '$d=XML::LibXML->load_xml(location => "my.xml"); for($d->findnodes("//PageTable")){ ($p)=$_->findnodes("PageTableProperty"); print map $_->to_literal, $p->findnodes("\@PageTableName") }' | head

# Parse xml file. Find all "PageTable" elements
# findvalue is like findnode and then to_literal. Use it when you expect a single node
perl -MXML::LibXML -le '$d=XML::LibXML->load_xml(location => "my.xml"); for($d->findnodes("//PageTable")){ ($p)=$_->findnodes("PageTableProperty"); print $p->findvalue("\@PageTableName") }'
#
# Same thing but using getAttribute() DOM method.
perl -MXML::LibXML -le '$d=XML::LibXML->load_xml(location => "my.xml"); for($d->findnodes("//PageTable")){ ($p)=$_->findnodes("./PageTableProperty"); print $p->getAttribute("PageTableName") }'
#
# Can also use the tied hash accessing approach $p->{ATTRIBUTE}
perl -MXML::LibXML -le '$d=XML::LibXML->load_xml(location => "my.xml"); for($d->findnodes("//PageTable")){ ($p)=$_->findnodes("PageTableProperty"); print $p->{PageTableName} }'

# Parse xml file. Find all "PageTable" elements
# Print only the actuator page
perl -MXML::LibXML -le '$d=XML::LibXML->load_xml(location => "my.xml"); for($d->findnodes("//PageTable")){ ($p)=$_->findnodes("./PageTableProperty"); $v=$p->findvalue("\@PageTableName"); print if $v eq "ACTUATOR" }'

# Process HTML using XML::LibXML
# Does not load badly formated files without these options:
#     recover
#     suppress_errors
perl -MXML::LibXML -le '$d=XML::LibXML->load_html(location => "index.html", recover => 1, suppress_errors => 1); print $d'

# XML Process big files. Save memory
perl -MXML::LibXML::Reader -le '$d=XML::LibXML::Reader->new(location => "xml"); printf "%-10s %-10s %-10s %-10s\n", $d->nodeType, $d->depth, $d->name, $d->getAttribute("code") while $d->read'

# Pull out parts of of a list
perl -MXML::LibXML -le '$d=XML::LibXML->load_html(location => "OSRS", recover => 1, suppress_errors => 1); @t = $d->findnodes(q(//table[@class="wikitable infobox"])); @t = grep { $_->findvalue(q(tr[th/a/@title="Members"]/td)) =~ /No/} @t; print for @t'


#############################################################
## Perl Modules - XML::Simple
#############################################################

# Read xml file and print out the structure
perl -MXML::Simple -MData::Dumper -le '$xs=XML::Simple->new; print Dumper($xs->XMLin("embraer.xml"))'

# Print the structure of an xml file while reading the input
perl -MXML::Simple -MData::Dumper -le '$d=XML::Simple::XMLin($ARGV[0]//die"\nSyntax: tool xmlfile\n\n"); print Dumper($d)'


#############################################################
## Perl Modules - YAML::XS
#############################################################

# Simple example of converting between yaml and a data structure.
perl -MYAML::XS -E '$yml = Dump [1..3]; $arr = Load $yml'


#############################################################
## Perl Book - Learning Perl Examples
#############################################################

# Exercise 2.1 (Learning Perl)
perl -le '$r=12.5; $pi=3.141592654; $c=2*$r*$pi; print $c'

# Exercise 2.2 (Learning Perl)
perl -le 'print "Enter radius: "; $r=<STDIN>; $pi=3.141592654; $c=2*$r*$pi; print $c'

# Exercise 2.3 (Learning Perl)
perl -le 'print "Enter radius: "; $r=<STDIN>; if($r < 0){ $r = 0 } $pi=3.141592654; $c=2*$r*$pi; print $c'

# Exercise 2.4 (Learning Perl)
perl -le 'print "Enter Num1: "; chomp($num1=<STDIN>); print "Enter Num2: "; chomp($num2=<STDIN>); print "$num1 * $num2 = ", ($num1 * $num2)'

# Exercise 2.5 (Learning Perl)
perl -le 'print "Enter String: "; chomp($string=<STDIN>); print "Enter num: "; chomp($num=<STDIN>); print $string x $num'


#############################################################
## Perl6 Programs (Rakudo)
#############################################################

# Setup/install/compile rakudo (perl6)
# 1. Get Latest
rm -f ~/rakudo/setup/index.html*
read -sp "Password: " PASSWORD
echo "$PASSWORD" | perl -ple 's/(\W)/ sprintf "%%%x", ord($1) /eg'
wget http://rakudo.org/downloads/star/ -P ~/rakudo/setup
ls ~/rakudo/setup/index.html | perl -MHTML::Tree -lne 'print HTML::Tree->new_from_file($_)->look_down(class => "ext-gz")->attr("href")'
basename `$LATEST`

# Setup/install/compile rakudo (perl6)
# 2. Download
read -sp "Password: " PASSWORD
echo "$PASSWORD" | perl -ple 's/(\W)/ sprintf "%%%x", ord($1) /eg'
wget http://rakudo.org/downloads/star/$LATEST -P ~/rakudo/setup

# Setup/install/compile rakudo (perl6)
# 3. Compile
tar -xvzf rakudo.tar.gz
cd rakudo
perl Configure.pl --backend=moar --gen-moar
make
make install

# Rational numbers issues with languages
ruby -e 'puts 0.1 + 0.2 == 0.3'
python -c 'print 0.1 + 0.2 == 0.3'
perl -E 'say 0.1 + 0.2 == 0.3 ? "true" : "false"'
perl6 -e 'say 0.1 + 0.2 == 0.3'
# Find out ip address of current bench
ip addr

# see all methods of an object
perl6 -e 'say "hi there".^methods'

# Generate fibonacci numbers
perl6 -e 'say (1,1,->$a,$b {$a+$b}...*)[^8]'
perl6 -e 'say (1,1,*+*...*)[^8]'

# Fibonacci numbers to at least 40
perl6 -e 'say (1,1, *+* ... * > 40)'

# Even fibonacci numbers up to 4 million
perl6 -e 'say grep * %% 2, (1,1, *+* ... ^ * > 4_000_000)'

# Sum of even fibonacci numbers up to 4 million
perl6 -e 'say [+] grep * %% 2, (1,1, *+* ... ^ * > 4_000_000)'

# Find the summation of numbers
perl6 -e 'say [+] 1..5'

# Find the summation of numbers (with intermediate steps)
perl6 -e 'say [\+] 1..5'

# Find the factorial of numbers
perl6 -e 'say [*] 1..5'

# Find the factorial of numbers (with intermediate steps)
perl6 -e 'say [\*] 1..5'

# Create factorial operator (!)
perl6 -e 'sub postfix:<!> {[*] 1..$^n}; say 5!'

# Create :=: operator (for sorting)
# Use rakudo-star-2017.01 for the interactive shell
perl6 -e 'sub infix:<:=:> ($a is rw, $b is rw) {($a,$b) = ($b,$a)}; my @a=(6,1,5); @a[0] :=: @a[1];  dd @a'

# Return first match (regex)
perl6 -e 'say ~$/ if "abc:def" ~~ /\w+/'

# Return all matches (regex)
perl6 -e 'say ~$/ if "abc:def" ~~ m:g/\w+/'

# Find largest prime factor (of n)
perl6 -e 'my $n=600_475_143; for 2,3,*+2...* {while $n %% $_ {$n div= $_; .say and exit if $_ > $n}}'

# Change named constructor into positional
perl6 -e 'class Point3D{has $.x; has $.y; has $!z; submethod BUILD(:$!x,:$!y,:$!z){say "Init"};  method get{$!x,$!y,$!z} }; my $a = Point3D.new(x=>23,y=>42,z=>2); .say for $a.get'

# Redefine/Create constructor for method new
perl6 -e 'class Point2D{has Numeric $.x; has Numeric $.y; method new($x,$y){$.bless(x=>$x,y=>$y)};  method get{$.x,$.y} }; my $a = Point2D.new(3,4); .say for $a.get'

# Run the debugger on a script
perl6debug sqrt.pl6

# Run the debugger on a one-liner
perl6debug -e '.say for 1..10'

# Debug a regular expression
perl6debug -e '"abc" ~~ /a(.+)c/

# Compare perl6 speeds (rakudo)
cd <RAKUDO_DIR>
perl6=`ls */perl6`
for p in $perl6 perl; do echo; echo "---------------------------------"; echo "$p"; time $p -e 'print join " ", grep /0/, (1..100)'; done
for p in $perl6 perl; do echo; echo "---------------------------------"; echo "$p"; time $p -e 'print 0.1 + 0.2 == 0.3'; done
echo


#############################################################
## Perlbrew
#############################################################

# Restore original perl environment
# https://stackoverflow.com/questions/25188575/switching-to-the-system-perl-using-perlbrew
perlbrew off           # only for this session (terminal)
perlbrew switch-off    # permanently

# Using the sheband line with perlbrew (-S to pass in args)
#!/usr/bin/env perl
#!/usr/bin/env -S perl -l


#############################################################
## PI - General
#############################################################

# No password when entering sudo commands (Linux,pi,debug)
vi /etc/sudoers
# Add this to bottom
pi 	ALL=(ALL) NOPASSWD:ALL

# No password when entering sudo commands (Linux,pi,debug)
sudo usermod -a -G GROUP_NAME USER
#
# Allow members of group sudo to execute any command
%sudo	ALL=(ALL:ALL) NOPASSWD:ALL

# autostart file location (pi)
sudo mount -o remount,rw /
vi /home/pi/.config/lxsession/LXDE-pi/autostart
sudo reboot

# Unable to write to /boot/config.txt (pi)
# Due to read only file system
# May need to mount a couple times (until "mount | grep boot" shows "rw")
sudo mount -o remount,rw /
sudo touch /forcefsck
sudo reboot


#############################################################
## PI - Configuration
#############################################################

# Get name of raspberry pi
cat /sys/firmware/devicetree/base/model
Raspberry Pi 3 Model B Plus Rev 1.3

# Check pi revision
cat /proc/cpuinfo
Code	Model	Revision	RAM	Manufacturer
a020d3	3B+		1.3			1GB	Sony UK
#
# Compare to:
https://www.raspberrypi.org/documentation/hardware/raspberrypi/revision-codes/README.md

# Find out the total on a linux machine (pi)
local ram=$(\grep MemTotal /proc/meminfo | perl -lne '($kb)=/(\d+)/; printf "%0.2fGB", $kb/1024/1024')


#############################################################
## PI - Network Interface
#############################################################

# Turn interface card off and on. (pi)
# Useful in cases where connection needs to be reset.
sudo ifconfig eth0 down && sudo ifconfig eth0 up

# Add a static IP address in Linux (pi,debug,Workarounds)
# Workaround for when DHCP does not work with the firewall
su 								 	# super user mode
mount -o remount,rw /				# mount the filesystem
vi /etc/network/interfaces			# update interfaces
	auto eth0						# Add these lines
	iface eth0 inet static
	        address 172.17.17.10
	        netmask 255.255.255.0
	        gateway 172.17.17.1
/etc/init.d/networking restart 		# restart the service
vi ~/webpage.sh
	#IP=$(dhcpcd --dumplease eth0 | grep routers | cut -d\' -f2)
	IP=172.17.17.1
reboot
#
The different keywords have the following meaning: (pi,debug,interfaces)
auto: the interface should be configured during boot time.
iface : interface
inet: interface uses TCP/IP networking.


#############################################################
## PI - Options
#############################################################

# Reduce blinking (pi)
sudo vi /boot/config.txt
/ hdmi_mode=82				# Original
# https://elinux.org/RPiconfig
82		1080p		60Hz	Original
83		1600x900        	Reduced blanking. Too small. Must scroll, plus keyboard is mostly gone)
84		2048x1152       	Reduced blanking. Double size. Unreadable
85		720p		60Hz	Good. But need to scroll

# Smart toggle (enable/disable) mouse cursor (pi)
# Remove/add "-nocursor" to this line:
# MUST first mount / then restart
sudo mount -o remount,rw /
sudo vi /etc/lightdm/lightdm.conf
/ xserver-command=X -nocursor
sudo reboot


#############################################################
## PI - Shortcuts
#############################################################

# Open Terminal on Linux (pi)
Control + Alt + T

# Maximize terminal window on Linux (debug)
Control + Alt + Up

# Switch between windows/terminal in Rasberry Pi (pi)
Alt + Tab

# Force a hard reboot that may cause a "Connection Reset by Peer" Error
sudo reboot -f
Alt + Druck + b

# Get control back of linux, save data and reboot (stuck,terminal)
#
# 1. Hold down the Alt and SysRq (Print Screen) keys.
# 2. While holding those down, type the following keys in order, several seconds apart: R E I S U B
# 3. Computer should reboot.
# unRaw      (take control of keyboard back from X),
#  tErminate (send SIGTERM to all processes, allowing them to terminate gracefully),
#  kIll      (send SIGKILL to all processes, forcing them to terminate immediately),
#   Sync     (flush data to disk),
#   Unmount  (remount all filesystems read-only),
# reBoot.


#############################################################
## PostgreSQL (psql)
#############################################################

# Install psql
sudo apt install postgresql postgresql-contrib postgresql-server-dev-13 gcc
sudo apt-get install libdbd-pg-perl
cpan DBD::Pg


#############################################################
## Powershell
#############################################################

# Regular Expression Named Capture in Powershell
"  dev   master * release/2.00" -match "release/(?<MAJOR>\d+)\.(?<MINOR>\d+)"
echo $Matches
echo $Matches.MAJOR
echo $Matches.MINOR


#############################################################
## Python General
#############################################################

# Zen of Python (motto)
python -c 'import this'
# The Zen of Python, by Tim Peters
#
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those


#############################################################
## Python Compare
#############################################################

# Increment a list of numbers (compare)
python -c 'L=map((lambda x:x+10),[1,2,3,4]); print L'
perl -le '@L=map{$_+10}(1,2,3,4); print "@L"'
perl -le '@L=map{$_+10} 1,2,3,4; print "@L"'
perl -le '@L=map{$_+10} 1..4; print "@L"'

# Get the ordinal values of a string (compare)
python -c 'res=list(map(ord,"spam")); print res'
python -c 'res=[ord(x) for x in "spam"]; print res'
perl -le '@L=map ord, split "", "spam"; print "@L" '
perl -le '@L=map{ord} split "", "spam"; print "@L" '

# Square all numbers in a list (compare)
python -c 'A=list(map((lambda x: x**2), range(10))); print A'
python -c 'A=[x**2 for x in range(10)]; print A'
perl -le '@A=map{$_**2}0..9; print "@A"'

# Square all even numbers
python -c 'A=list(map((lambda x: x**2), filter((lambda x: x%2 == 0), range(10)))); print A'
python -c 'A=[x**2 for x in range(10) if x%2 == 0]; print A'
perl -le '@A=map{$_**2} grep{$_ % 2 == 0} 0..9; print "@A"'

# Add 2D lists (compare)
python -c 'A=[x + y for x in [0,1,2] for y in [100,200,300]]; print A'
perl -le '@A=map{$x=$_; map{$x+$_}100,200,300 }0,1,2; print "@A"'
perl -le 'local $,="+"; @A=map eval, <{0,1,2}+{100,200,300}>; print "@A"'

# Add 3D lists (compare)
python -c 'A=[x + y + z for x in [0,1,2] for y in [100,200,300] for z in [1000,2000,3000]]; print A'
perl -le '@A=map{$x=$_; map{$y=$_; map{$x+$y+$_}1000,2000,3000  }100,200,300 }0,1,2; print "@A"'
perl -le 'local $,="+"; @A=map{eval}<{0,1,2}+{100,200,300}+{1000,2000,3000}>; print "@A"'
perl -le 'local $,="+"; @A=map eval, <{0,1,2}+{100,200,300}+{1000,2000,3000}>; print "@A"'

# Add 4D lists (compare)
python -c 'A=[x + y + z + aa for x in [0,1,2] for y in [100,200,300] for z in [1000,2000,3000] for aa in [10000,20000]]; print A'
perl -le '@A=map{$x=$_; map{$y=$_; map{$z=$_; map{$x+$y+$z+$_}10000,20000  }1000,2000,3000  }100,200,300 }0,1,2; print "@A"'
perl -le 'local $,="+"; @A=map eval, <{0,1,2}+{100,200,300}+{1000,2000,3000}+{10000,20000}>; print "@A"'

# Interate through list combinations
python -c 'A=[x+y for x in "spam" for y in "SPAM"]; print A'
perl -le '@A=<{s,p,a,m}{S,P,A,M}>; print "@A"'
perl -le '@A=<{@{[join ",",split //,"spam"]}}{@{[join ",",split //,"SPAM"]}}>; print "@A"'

# Max constant for using glob (permutations)
perl -MPOSIX -le 'print POSIX::sysconf(_SC_ARG_MAX)'

# Add 2D lists with conditionals (compare)
python -c 'A=[x+y for x in "spam" if x in "sm" for y in "SPAM" if y in ("P","A")]; print A'
perl -le '@A=map{$x=$_; map{$x.$_ }grep /[PA]/, split "", "SPAM" } grep /[sm]/, split "", "spam"; print "@A"'
perl -le '@a=join ",", grep /[sm]/, split "", "spam"; @b=join ",", grep /[PA]/, split "", "SPAM"; @A=<{@a}{@b}>; print "@A"'
perl -le '@A=<{@{[ join ",", grep /[sm]/, split "", "spam"  ]}}{@{[ join ",", grep /[PA]/, split "", "SPAM" ]}}>; print "@A"'
perl -le '@A=<{s,m}{P,A}>; print "@A"'

# Show even and odd lists (compare)
python -c 'A=[(x,y) for x in range(5) if x % 2 == 0  for y in range(5) if y % 2 == 1]; print A'
perl -le '@A=map{$x=$_; map{"($x,$_)"} grep{$_ % 2 == 1}0..4  }grep{$_ % 2 == 0}0..4; print "@A"'
perl -le '@A=<({@{[ join ",",grep{$_ % 2 == 0}0..4 ]}},{@{[ join ",",grep{$_ % 2 == 1}0..4 ]}})>; print "@A"'

# Extract the forward diagonal from a matrix (compare)
python -c 'M=[[1,2,3],[4,5,6],[7,8,9]]; A=[M[i][i] for i in range(len(M))]; print A'
perl -le '@M=([1,2,3],[4,5,6],[7,8,9]); @A=map{ $M[$_][$_] } 0..$#M; print "@A"'

# Extract the backward diagonal from a matrix (compare)
python -c 'M=[[1,2,3],[4,5,6],[7,8,9]]; A=[M[i][len(M)-1-i] for i in range(len(M))]; print A'
perl -le '@M=([1,2,3],[4,5,6],[7,8,9]); @A=map{ $M[$_][$#M-$_] } 0..$#M; print "@A"'

# Increment column in a matrix (compare)
python -c 'M=[[1,2,3],[4,5,6],[7,8,9]]; A=[row[1]+10 for row in M]; print A'
perl -le '@M=([1,2,3],[4,5,6],[7,8,9]); @A=map{ $_->[1]+10 } @M; print "@A"'

# Increment all columns in a matrix (compare)
python -c 'M=[[1,2,3],[4,5,6],[7,8,9]]; A=[[col+10 for col in row] for row in M]; print A'
perl -MData::Dumper -le '@M=([1,2,3],[4,5,6],[7,8,9]); @A=map{[map{ $_+10}@$_] } @M; print Dumper \@A'
perl -le '@M=([1,2,3],[4,5,6],[7,8,9]); @A=map{[map{ $_+10}@$_] } @M; print "@$_" for @A'

# Multiply matrices (compare)
python -c 'M=[[1,2,3],[4,5,6],[7,8,9]]; N=[[2,2,2],[3,3,3],[4,4,4]]; A=[M[row][col] * N[row][col] for row in range(3) for col in range (3)]; print A'
perl -le '@M=([1,2,3],[4,5,6],[7,8,9]); @N=([2,2,2],[3,3,3],[4,4,4]); @A=map{$row=$_; map{ $M[$row][$_] * $N[$row][$_] }0..2  }0..2; print "@A"'

# Multiply matrices preserving rows (compare)
python -c 'M=[ [1,2,3],[4,5,6],[7,8,9]]; N=[[2,2,2],[3,3,3],[4,4,4]]; A=[[col1 * col2 for (col1,col2) in zip(row1,row2)] for (row1,row2) in zip(M,N)]; print A'
perl -le '@M=([1,2,3],[4,5,6],[7,8,9]); @N=([2,2,2],[3,3,3],[4,4,4]); @A=map{$row=$_; [map{ $M[$row][$_] * $N[$row][$_] }0..2]  }0..2; print "@$_" for @A'


#############################################################
## Python Functions
#############################################################

# Keyword (Named) Arguments in Python
# Same definition
def myfunc(parm1, parm1):
    ...
myfunc(parm1=arg1, parm1=arg2)


#############################################################
## Python PIP
#############################################################

# Install a python package
setup_http_proxy
sudo pip install matplotlib --proxy $https_proxy

# Python package is not in the normal location. (Nathan)
# Add it to the include PATH
import sys; sys.path.append("/usr/lib/pyshared/python2.7/matplotlib")
import matplotlib

# Look up a python package
python -m pydoc <module>
perldoc <module>              # similar


#############################################################
## Python Regex
#############################################################

# Python offers two different primitive operations based on
# regular expressions: re.match() checks for a match only at
# the beginning of the string, while re.search() checks for
# a match anywhere in the string (this is what Perl does by
# default).
python -c 'import re; print(re.match("c", "abcdef"))'
python -c 'import re; print(re.search("c", "abcdef"))'

# Capture words in regex
python -c 'import re; m=re.search("(\w+) is (\d+)", "abc is 3"); print(m.groups())'
perl -le 'print for "abc is 3" =~ /(\w+) is (\d+)/'
perl -le 'print "abc is 3" =~ /(\w+) is (\d+)/'

# Allow free space in regex
python -c 'import re; print(re.search("(?x) c ", "abcdef"))'
perl -le 'print "abcdef" =~ / c /x'


#############################################################
## Python Strings
#############################################################

# Reverse string using python
python -c 'a="12345678"; b=a[::-1]; print [a,b]'

# Remove leading and trailing spaces
python -c "a = '  a   b   '; print('[{}]'.format(a.strip()))"
perl -le "$_ = '  a   b   '; s/^\s+//; s/\s+$//; print(qq([$_]))"

# Get number of lines in a file in python
sum(1 for line in open(file))

# Encode a url using python
python -c "from urllib.parse import urlencode; result = urlencode( {'':'159278 #01'}); print(result)"
159278+%2301
#
# Encode a string
python -c "from urllib.parse import quote; result = quote('159278 #01'); print(result)"
159278%20%2301
#
# Encode a string (%20 is +)
python -c "from urllib.parse import quote_plus; result = quote_plus('159278 #01'); print(result)"
159278+%2301

# Decode a url in Python
python -c "from urllib.parse import unquote; result = unquote('159278%20#01'); print(result)"
159278 #01
#
# (%20 is +)
python -c "from urllib.parse import unquote_plus; result = unquote_plus('159278+#01'); print(result)"
159278 #01


#############################################################
## Python Variable Types - General
#############################################################

# Different types of variables in python
string     = "abc"
string     = 'abc'
list       = ["a","b","c"]
dictionary = {"Name":"ABC", "Age":50, "Color":"Red"}
tuple      = ("a","b","c")                              # Immutable
set        = {"a","b","c"}                              # Unique


#############################################################
## Python Variable Types - Objecz
#############################################################

# See all methods of an object
python -c "import time; print(dir(time))"

# Loop through dictionary/hash in python (like each in perl)
python -c "h={'a':1, 'b':2}; print(h.items())"
perl -le "%h=('a',1, 'b',2); print qq($k: $v) while ($k,$v) = each %h"


#############################################################
## Python Virtual Environment
#############################################################

# Virtual environment in python (requirements.txt)
#
# Install as admin
pip install virtualenv
#
# Create environment folder
python -m venv env
#
# Activate it
env\Scripts\activate
#
# Install packages
python -m pip install --upgrade pip
pip install bottle
#
# Save requirements.txt
pip freeze > requirements.txt
#
# Save downloaded files locally
mkdir sdist
cd sdist
pip download -r ..\requirements.txt
#
# Close environment
deactivate
#
# Install requirements somewhere else
pip install -r requirements.txt --find-links sdist --no-index


#############################################################
## Python Modules - bottle
#############################################################

# Python bottle module routing options
self.app.get("/<f:path>")(lambda f: bottle.static_file(f, root=path))
self.app.get("/<file:path>")(lambda file: self.get_static_file(file,path))
#
def get_static_file(self,file,path):
    self.logger.debug("get_static_file(file:{},path={})".format(file,path))
    # Remove option timestamp/UID: version--UID--123.js
    file = re.sub(self.is_uid,'',file)
    return bottle.static_file(file, root=path)
#
#
The following filters are implemented by default and more may be added:
:int matches (signed) digits only and converts the value to integer.
:float similar to :int but for decimal numbers.
:path matches all characters including the slash character in a non-greedy way and can be used to match more than one path segment.
:re allows you to specify a custom regular expression in the config field. The matched value is not modified.


#############################################################
## Python Modules - datetime
#############################################################

# Get yyyymmmdd format in Python from a integer Epoch string
python -c "import datetime; import os; s=os.stat('version.js'); t=datetime.datetime.fromtimestamp(int(s.st_mtime)).strftime('%Y%m%d%H%M%S'); print(t)"
20210203102701

# Print current time in about YYYYMMDD
python -c "import datetime; print(datetime.date.today().strftime('%Y%m%d'))"

# Current timestamp as a string
python -c "from datetime import datetime; print(datetime.now(tz=None))"


#############################################################
## Python Modules - gevent
#############################################################

# Using gevent in a python webserver
#
import gevent.pywsgi
import geventwebsocket
import geventwebsocket.handler
class Server:
    def __init__(self,...):
        self.server = gevent.pywsgi.WSGIServer((address, port), self.app,
            handler_class=geventwebsocket.handler.WebSocketHandler)


#############################################################
## Python Modules - json
#############################################################

# Using json in a python webserver
#
import json
class Server:
    def info(self):
        try:
            return json.dumps(possible_endpoints)
        except KeyError:
            return bottle.HTTPError(404, "Error occurred")


#############################################################
## Python Modules - logging
#############################################################

# Log format to use for the logger
log_format = '%(asctime)s %(levelname)s %(module)s.%(funcName)s:%(lineno)d %(message)s'

# Using rotating logs in python (at midnight the log file changes)
import logging.handlers
file_handler = logging.handlers.TimedRotatingFileHandler(filename=log_file, when="midnight")


#############################################################
## Python Modules - os
#############################################################

# Python get the current working directory (dirname)
this_dir = os.path.dirname(os.path.realpath(__file__))


#############################################################
## Python Modules - SimpleHTTPServer
#############################################################

# View linux files from windows (debug,pi)
python -m SimpleHTTPServer 8080
http://172.17.17.10:8080/


#############################################################
## Python Modules - socket
#############################################################

# Create a port that can be connected to with netcat
/usr/bin/python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("localhost",4445));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'
nc -nlvp 4445


#############################################################
## Python Modules - sys
#############################################################

# Flushing output in Python
import sys
sys.stdout.flush()


#############################################################
## Python Modules - time
#############################################################

# Seconds since epoch
python -c "import time; print(time.time())"
python -c "import time; print(int(time.time()))"


#############################################################
## Python Modules - watchdog
#############################################################

# Python watchdog has a known bug which triggering 2 on_modified events per change.
import watchdog.observers
https://github.com/gorakhargosh/watchdog/issues/93


#############################################################
## Python Modules - winreg
#############################################################

# Get a subkey from a windows registry key
import winreg
def getLogPath(key,subKey):
    try:
        reg = winreg.OpenKeyEx(winreg.HKEY_LOCAL_MACHINE, key)
        val = winreg.QueryValueEx(reg, subKey)[0]
        return val
    except FileNotFoundError:
        return fallback


## Q


#############################################################
## RSnapshot
#############################################################

# Install rsnapshot
sudo apt install rsnapshot

# Update rsnapshot config
sudo vi /etc/rsnapshot.conf
#
# Make sure to use tab separators
snapshot_root   /media/<USER>/SRTO_BACKUP/BACKUP
no_create_root  1
#
retain  hourly  24
retain  daily   7
retain  weekly  4
retain  monthly 12
#
link_dest       1
#
backup /home/<USER>	timPC
backup /etc			timPC
backup /opt			timPC
backup /root		timPC

# Test rsnapshot configuration file
rsnapshot configtest

# Create crontab for rsnapshot
crontab -e
#
# min hr    dom   mon   dow   command
  0   *     *     *     *     /usr/bin/rsnapshot_runner.pl hourly
  50  23    *     *     *     /usr/bin/rsnapshot_runner.pl daily
  40  23    *     *     6     /usr/bin/rsnapshot_runner.pl weekly
  30  23    1     *     *     /usr/bin/rsnapshot_runner.pl montly

# Rsnapshot example
http://www.edwiget.name/2018/05/simple-rsnapshot-incremental-backups-to-removable-disks/#codesyntax_1


#############################################################
## RTCP (RBS,real time command processor)
#############################################################

# Show rtcp options (DES,DEBHAWK)
rtcp he
rtcp he options
rtcp he op2

# List fbs status
rtcp ls

# Real-time clock device (rtc,DES)
/dev/rrtc/McN
# M - is a controller number (0-3). corresponds to the CPU
# board on which the clock resides
# c - stands for clock
# N - specifies a real-time clock number (0-4 on the first CPU board,
#     and 0-2 on additional CPU boards)

# RTCP Commands (DES)
ats    Attach timing source to an FBS
chs    Change permissions for an FBS
cs     Configure an FBS
dts    Detach timing source from an FBS
rms    Remove an FBS
svs    Save scheduler configuration
vc     View minor cycle/major frame count
vr     View a rdevfs file configuration
vs     View scheduler configuration
rc     Start real-time clock
rd     Register a Coupled FBS device
sc     Stop real-time clock
stc    Set real-time clock values
gtc    Get real-time clock values
start  Start scheduling on an FBS
reg    Register a Closely-Coupled FBS timing device
resume Resume scheduling on an FBS
stop   Stop scheduling on an FBS
rmp    Remove a process from an FBS
rsp    Reschedule a process
sp     Schedule a process on an FBS
unreg  Unregister a Closely-Coupled FBS timing device
urd    Unregister a Coupled FBS device
vp     View processes on an FBS
pm     Start/stop performance monitoring
cpm    Clear performance monitor values
vcm    View or modify performance monitor timing mode
vpm    View performance monitor values
ex     Exit real-time command processor
he     Display help information

# RTCP Options (DES,rtcp he options)
-a               remove program from FBS and terminate
-b {F|R|O}       scheduling policy
-c cpu_bias      cpu bias (* = all CPUs) (default = current CPU)
-d name          devicename or filename
-e               EOC flag
-f frequency     number of minor cycles to next wakeup (default = 1)
-h {halt|nohalt} halt FBS on deadline violation (default = nohalt)
-i fpid          process fpid number  (default = -1)
-m start_cycle   1st minor cycle to wakeup  (default = 0)
-n proc_name     process name
-o {halt|nohalt} halt FBS on overrun flag (default = nohalt)
-p priority      process priority
-r {cycle|task}  deadline origin flag  (default = cycle)
-s scheduler     FBS scheduler key
-t {in|ex}       include or exclude interrupt time in pm monitor
-v parameter     process initiation parameter
-x {av|mi|ma|al} performance monitor display option (default = average)

# RTCP Options (DES,rtcp he opt2)
-C cycles/frame  number of minor cycles per major frame
-D duration      clock tick duration  (default = 10us)
-G gid           effective group ID for FBS  (default = current user)
-I permissions   permissions for FBS in octal  (default = 0600)
-L soft_limit    soft overrun limit  (default = 0)
-M progs/cycle   maximum number of processes per minor cycle
-N progs/fbs     maximum number of processes per FBS
-O clock_ticks   number of clock ticks per minor cycle
-P {ON|OFF}      enable/disable performance monitor (default = OFF)
-R {-1 | 0 | 1}  reset process flag  (default = 0)
-S delay         time to delay, in seconds
-T deadline      deadline microseconds (default = "Clear")
-U uid           effective user ID for FBS  (default = current user)
-W tick_count    #ticks before watchdog RTC takes over(special devices)

# RTCP syntax for a command (DES)
# rtcp he <command>
rtcp he ats
rtcp he start
rtcp he sp

# RTCP pass arguments to a process (DES)
# Use "--" to pass everything after to the process
# sys requires "-dt 1000" be passed to it.
rtcp sp -s 1 -n ~/run/sys -- -dt 1000

# Monitor rtcp status, which programs are attached, (DES)
# ipcx, simsec keys, and commands to rtcp "arg*"
watch -d -n1 -t "rtcp ls; rtcp vp -s 1 -c '*'; ipcx; ls -l /dev/keys/simsec; grep '' arg*"


#############################################################
## Ruby
#############################################################

# Check all of the ruby libraries for puppet
ruby -e 'puts $:' | while read n; do ll -d $n/*puppet* 2> /dev/null; done


#############################################################
## Selenium Testing
#############################################################

# Python script to run a simple selenium test
#
+ #!/usr/bin/python3
+
+ import time
+ from selenium import webdriver
+
+ driver = webdriver.Chrome()  # Optional argument, if not specified will search path.
+ driver.get('http://www.google.com');
+ time.sleep(2)
+
+ elem = driver.find_element_by_name('q')
+ elem.send_keys('ChromeDriver')
+ elem.submit()
+ time.sleep(2)
+
+ driver.quit()

# Perl script to run a simple selenium test
# Requires having the selenium to be already running:
java -Dwebdriver.chrome.driver=/usr/bin/chromedriver -jar /usr/local/lib/selenium/current.jar
#
+ #!/usr/bin/perl
+
+ use v5.10;
+ use Selenium::Remote::Driver;
+ use Selenium::Remote::WDKeys;;
+
+ my $driver = Selenium::Remote::Driver->new(
+    browser_name => 'chrome',   # Default is firefox
+ );
+
+ $driver->get('http://www.google.com');
+ $driver->pause(2000);
+
+ my $elem = $driver->find_element_by_name('q');
+ $elem->send_keys('ChromeDriver');
+ $elem->send_keys( KEYS->{enter} );
+ $driver->pause(2000);
+
+ $driver->quit;

# Check if selenium service is running
systemctl status selenium.service

# Install selenium-server-standalone
# https://tecadmin.net/setup-selenium-chromedriver-on-ubuntu/
#
# Step 1 – Prerequisites:
sudo apt install -y unzip xvfb libxi6 libgconf-2-4
sudo apt install default-jdk
#
# Step 2 – Install Google Chrome:
sudo curl -sS -o - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add
sudo bash -c "echo 'deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main' >> /etc/apt/sources.list.d/google-chrome.list"
sudo apt update
sudo apt install google-chrome-stable
#
# Step 3 – Installing ChromeDriver:
google-chrome --version
#
# Download same version:
# https://chromedriver.chromium.org/downloads
cd ~/Downloads
unzip chromedriver*.zip
#
# Move it:
sudo mv chromedriver /usr/bin/chromedriver
sudo chown root:root /usr/bin/chromedriver
sudo chmod +x /usr/bin/chromedriver
#
# Step 4 – Download Required Jar Files:


# Create selenium service
#
sudo cp ~/my/git/srto/selenium/setup/_etc_systemd_system_selenium.service /etc/systemd/system/selenium.service
sudo vi /etc/systemd/system/selenium.service
+ [Unit]
+ Description=Selenium Server
+
+ [Service]
+ EnvironmentFile=-/etc/default/selenium
+ User=<USER>
+ Group=<USER>
+ Environment=DISPLAY=:1
+ ExecStart=/usr/bin/java -Dwebdriver.chrome.driver=/usr/bin/chromedriver -jar /usr/local/lib/selenium/current.jar $SELENIUM_OPTS
+ SuccessExitStatus=143
+
+ [Install]
+ WantedBy=graphical.target

# Selenium service environment file
#
sudo cp ~/my/git/srto/selenium/setup/_etc_default_selenium /etc/default/selenium
sudo vi /etc/default/selenium
+ SELENIUM_OPTS="-role standalone -debug"

# Enable selenium service (runs on login)
sudo systemctl enable selenium.service
sudo systemctl start selenium.service

# Run selenium test using curl (for debug)
curl -X POST http://localhost:4444/wd/hub/session -d '{ "desiredCapabilities": { "browserName": "chrome" } }'
curl -X POST http://localhost:4444/wd/hub/session -d '{ "desiredCapabilities": { "browserName": "firefox" } }'


#############################################################
## SQLite3 Database
#############################################################

# Install sqlite on Unix (after in zipping the amalgamation file. make sure these 3 are present:
# shell.c, sqlite3.c, sqlite3.h). rename to a.out to sqlite3
# (database, sqlite3)
gcc shell.c sqlite3.c -lpthread -ldl

# View all the tables in a database (database, sqlite3)
sqlite3 my.db '.tables'

# Turn on column names on query results (database, sqlite3)
sqlite3 my.db '.explain on' 'select * from page_groups'

# Print database structure and data (database, sqlite3)
sqlite3 my.db '.dump'

# View current status/info (database, sqlite3)
sqlite3 my.db '.show'

# REFERENCES and FOREIGN KEYS are (database, sqlite3)
# used to ensure that the tables keys are valid since they
# are found in the foreign table.

# Output the results with a header and evenly spaced columns
sqlite3 my.db --header -column 'select * from my_table'

# Create a new database, table, and data (nathan)
sqlite3 my.db 'create table Users(name,date)'
sqlite3 my.db 'insert into Users values ("bob",20)'
sqlite3 my.db 'insert into Users values ("Joe",25)'
sqlite3 my.db '.explain on' '.width auto' 'select * from Users'

# Case Insensitive Search in SQL query
SELECT ... FROM ... WHERE ... ORDER BY name COLLATE NOCASE ASC LIMIT 5

# Master sqlite table (.tables)
if (table == "") {
    query = m_interface->prepare("SELECT name from sqlite_master");                         // .tables
}
# View the .schema
else if (haveVerbose) {
    query = m_interface->prepare("SELECT sql FROM sqlite_master WHERE name=:table");        // .schema
    query.bind(":table", table);
}
# View the columns
else {
    query = m_interface->prepare("SELECT name FROM PRAGMA_TABLE_INFO(:table)");             // column names
    query.bind(":table", table);

# Get all columns names from SQLite
sqlite3 my.db "PRAGMA table_info(myTable)"
#
sqlite3 my.db "SELECT name FROM pragma_table_info('myTable') ORDER BY name"

# Provide default for null values using COALESCE (sqlite3)
SELECT DISTINCT COALESCE(col,'NULL') FROM myTable ORDER BY col ASC

# SQLite if/else, concat(merge) columns(strings)
SELECT   name,
		 CASE WHEN var1 = 1 THEN 'x'  ELSE '-'  END ||
		 CASE WHEN var2 = 1 THEN '/x' ELSE '/-' END ||
		 CASE WHEN var3 = 1 THEN '/x' ELSE '/-' END ||
		 CASE WHEN var4 = 1 THEN '/x' ELSE '/-' END
		 AS var
FROM     myTable
ORDER BY name;

# SQL inner join to get a summary of possibilities
sqlite3 my2.db "SELECT DISTINCT col1,col2 FROM myTable AS INNER JOIN (SELECT col1 FROM tool_types GROUP BY col1) USING(col1) INNER JOIN (SELECT col FROM tool_types GROUP BY col) USING(col) ORDER BY col1,col ASC"

# Avoid using "NOT IN" (SQL)
http://www.dbatodba.com/sql-server/how-tos/typical-solutions-to-avoid-using-not-in-on-sql-server/
# NOT IN works, but as the number of records grows, NOT IN performs worse
# Fastest solution so far (Using LEFT JOIN)
#
# Final query
SELECT t1.name,t1.changed
FROM
	myTable1 AS t1
LEFT OUTER JOIN
	(SELECT * FROM myTable2 WHERE id='123') AS t2
ON t1.name=t2.uid
WHERE
	t2.changed IS NULL
	OR
	t1.changed!=t2.changed;

# Switch statement in SQLite3
SELECT
	CASE WHEN item IS NULL	THEN 'NULL'
		 WHEN item = 0		THEN '?'
		 WHEN item = 1		THEN 'Dummy'
		 WHEN item = 2		THEN 'Adapter'
		 ELSE				 	 item
	END AS item2
FROM
queue


#############################################################
## Sublime Editor
#############################################################

# Duplcate a line (sublime editor)
Control + Shift + D

# Vertical Column Edit (like vim,sublime editor)
Shift + Right Click

# Cut line (sublime editor)
Control + x

# Upper case the highlighted word (sublime editor)
Control + K + U

# Lower case the highlighted word (sublime editor)
Control + K + L


#############################################################
## Telegram
#############################################################

# Install telegram-send
sudo apt install pip
sudo pip install telegram-send


#############################################################
## Trello
#############################################################

# Make a hyperlink in Trello
# Create a link by putting:
#  1. The link text in brackets.
#  2. The URL in parentheses.
# With no space between ] and (
[this](Trello)


#############################################################
## Termux
#############################################################

# Add 2nd row to termux.
vi $HOME/.termux/termux.properties
#
+ # Ignore bell character
+ bell-character=ignore
+
+ # Only works on newer phones
+ # extra-keys = [ \
+ #  ['ESC','|','/','HOME','UP','END','PGUP','DEL'], \
+ #  ['TAB','CTRL','ALT','LEFT','DOWN','RIGHT','PGDN','BKSP'] \
+ # ]
+
+ extra-keys = [[ \
+  'ESC',   \
+  'TAB',   \
+  'UP',    \
+  'DOWN',  \
+  'LEFT',  \
+  'RIGHT', \
+  'CTRL',  \
+  'ALT',   \
+  'DEL'    \
+  ]]


#############################################################
## Ubuntu - Hard Drive Encryption - Detailed
#############################################################

# Ubuntu hard drive encryption.
# 1. Create the encrypted partition:
sudo cryptsetup luksFormat /dev/sda
#
# Verify header.
sudo cryptsetup luksDump /dev/sda

# Ubuntu hard drive encryption.
# 2. Map the encrypted container:
sudo cryptsetup luksOpen /dev/sda secret-container

# Ubuntu hard drive encryption.
# 2a. Wipe the partition (optional):
sudo shred -vfz /dev/mapper/secret-container

# Ubuntu hard drive encryption.
# 3. Create a filesystem in the mapped container:
sudo mkfs.ext4 /dev/mapper/secret-container

# Ubuntu hard drive encryption.
# SKIP FOR EXTERNAL HARD DRIVES
# 4. Update your /etc/crypttab file (used at system boot):
# Your crypttab should contain a line like
cryptHome     UUID=26a4b17a-aad3-436a-89f4-a68a4c4c371d    none    luks,timeout=30
# with the UUID of the device you just encrypted above
# (i.e. the /dev/sdXX device). You can find it out by using
# e.g. lsblk -f (it should say "crypto_LUKS" under FSTYPE in the output).

# Ubuntu hard drive encryption.
# SKIP FOR EXTERNAL HARD DRIVES
# 5. Update your /etc/fstab file (file system mounting:
# Finally, your fstab should contain a line like
/dev/mapper/cryptHome   /home/srto-backup       ext4    defaults        0       2
#
# to mount the decrypted partition in your filesystem.
# The mapped name (cryptHome) must match the one you
# defined in the crypttab. Replace username by the name of the actual user.
#
# You could also mount it under /home, but then you will have
# all user's home directories in one encrypted drive - that
# means all of them need to know the partition's password to open it on boot.

# Originally thought these were also necessary for an external hard drive.
# Appear to work without the lines.
#
sudo vi /etc/crypttab
# <name>        <device>            <password>      <options>
mnt-usb-crypt   UUID=<device-uuid>  /path/to/key    luks,noauto
#
# Need to run after updating cryptab:
sudo update-initramfs -u -k all
#
sudo vi /etc/fstab
#
# <file system>             <dir>       <type>  <options>                             <dump>    <pass>
/dev/mapper/mnt-usb-crypt   /mnt/usb    btrfs   defaults,noauto,x-systemd.automount   0         2

# Unable to mount the unencrypted harddrive.
# Error mentions mount: wrong fs type, bad option, bad superblock.
#
# See disks:
lsblk
#
# If you can see your drive thats good.
# Run this to see if the system can use it:
sudo fdisk -l
#
# Run this command to attempt to repair bad superblocks on the drive.
sudo xfs_repair /dev/mapper/srto_backup
#
# Mount again after repair is done:
sudo mount /dev/mapper/srto_backup /media/<USER>/SRTO_BACKUP

# Restore corrupted USB drive.
# Warning: could not erase sector 2: Input/output error.
sudo dd if=/dev/zero of=/dev/sdb bs=1M count=40
#
# Disk repair/recovery tool.
sudo apt install testdisk


#############################################################
## Ubuntu - Hard Drive Encryption - Simple
#############################################################

# Ubuntu hard drive encryption. (simple)
#
# Create the encrypted partition:
sudo cryptsetup -c aes-xts-plain -y -s 512 luksFormat /dev/DEVICE
#
# Map the encrypted container:
sudo cryptsetup luksOpen /dev/DEVICE srto_backup
#
# Wipe the partition (optional):
# Only if it has sensitive data already.
sudo shred -vfz /dev/mapper/secret-container
#
# Create a filesystem in the mapped container:
sudo mkfs.ext4 -L MY_BACKUP /dev/mapper/srto_backup
#
# Rename the drive label in gparted (optional)
sudo apt-get install gparted.
# open gparted.
# choose the thumbdrive from the dropdown in the top-right corner.
# unmount the volume (right-click on drive)
# right click and choose "label"
# click on green tick to apply changes.
#
# Find out ID by running
sudo fdisk -l
blkls /dev/<DEVICE>
#
# Or find UUID here for the device
ls -l /dev/disk/by-uuid/
#
# Can find the UUID in gparted.
#
# Add device to be auto decrypted
sudo vi /etc/crypttab
srto_backup UUID=e5dc6e53-2df1-40d8-baff-75ba4f1eacf4 none luks,noauto,size=256
#
# Need to run after updating cryptab:
sudo update-initramfs -u -k all
#
# Add device to be auto mounted
sudo vi /etc/fstab
srto_backup /media/SRTO_BACKUP auto nosuid,nodev,nofail,x-gvfs-show 0 2

# Close encrypted drive
sudo umount /dev/mapper/luks-ea444ab0-445e-4c5c-931b-27922bfa5510
sudo cryptsetup close luks-ea444ab0-445e-4c5c-931b-27922bfa5510
# file found here:
ll /dev/mapper/


#############################################################
## Ubuntu - Hard Drive Create and Delete
#############################################################

# Wipe an external hard drive (with Marco,ubuntu,hd)
#
# Find device here.
lsblk
#
# Remove signature.
sudo wipefs -a /dev/sdb
#
sudo cfdisk /dev/sdb

# Setup a new external hard drive (with Marco,ubuntu,hd)
lsblk    # To find out DEVICE name
sudo cryptsetup -c aes-xts-plain -y -s 512 luksFormat /dev/DEVICE
sudo cryptsetup luksOpen /dev/DEVICE srto_backup
sudo mkfs.ext4 -L MY_BACKUP /dev/mapper/srto_backup
sudo mount /dev/mapper/srto_backup /media/<USER>/SRTO_BACKUP


#############################################################
## Ubuntu - Evolution
#############################################################

# Completely remove ubunutu evolution services.
https://askubuntu.com/questions/315640/how-do-i-completely-remove-evolution
#
cd /usr/share/dbus-1/services
sudo cp org.gnome.evolution.dataserver.* /home/<USER>/my/git/srto/evolution/_usr_share_dbus-1_services/
sudo ln -snf /dev/null org.gnome.evolution.dataserver.Calendar8.service
sudo ln -snf /dev/null org.gnome.evolution.dataserver.
sudo ln -snf /dev/null org.gnome.evolution.dataserver.Sources5.service
sudo ln -snf /dev/null org.gnome.evolution.dataserver.UserPrompter0.service


#############################################################
## Ubuntu - Filesystem
#############################################################

# Show Hide/Hidden Files (Ubuntu)
Control + H

# Mount wired network connection (Ubuntu,linux)
# Useful is policykit-i is accidentally removed
sudo dhclient -v usb0


#############################################################
## Ubuntu - Filesystem - ZFS
#############################################################

# Create a new zpool
sudo fdisk -l 			# Find device path here

# Destroy (completely remove) a zpool
# WILL DELETE ALL DATA INSIDE
sudo zpool destroy brpool

# Unmount a busy device
umount -l /PATH/OF/BUSY-DEVICE
umount -f /PATH/OF/BUSY-NFS (NETWORK-FILE-SYSTEM)

# ZFS list snapshots
zfs list -r -t snapshot -o name,creation

# Send snapshot backup
sudo zfs send rpool/USERDATA/tim_e5bkz1@autozsys_zh25vd | sudo zfs receive brpool/USERDATA

# Send incremental backup
sudo zfs send rpool@june15b | sudo zfs receive -Fd brpool

# Mount external hard drive with ZFS
sudo zpool list 				# Show available pools
sudo zpool import 			# Shows the brpool name
sudo zpool import brpool	# Import brpool
sudo zpool list 				# Pool now added

# Create a Snapshot with a specific text
sudo zfs snapshot rpool/USERDATA/tim_e5bkz1@june15

# View mounting options for ZFS (zpool)
sudo zfs get 'mountpoint,mounted,canmount' brpool/USERDATA

# zpool status is SUSPENDED
sudo zpool clear brpool
sudo zpool clear -nFX brpool	# Or this


#############################################################
## Ubuntu - Flashdrive
#############################################################

# Make bootable flashdrive from iso file (ubuntu)
# Startup Disk Creator
# https://ubuntu.com/tutorials/create-a-usb-stick-on-ubuntu#3-launch-startup-disk-creator

# Automount external hard drive
vi /etc/fstab
UUID=E2B4CF51B4CF273F /media/MY_BACKUP auto nosuid,nodev,nofail,x-gvfs-show 0 2
#
# Find out ID by running
sudo fdisk -l
blkls /dev/<DEVICE>
#
# Or find UUID here for the device
ls -l /dev/disk/by-uuid/

# Backup PC in Ubuntu using timeshift (not for zfs)
https://linuxconfig.org/ubuntu-20-04-system-backup-and-restore

# Allow writing to flash drives
sudo chown $USER:$USER /media/<USER>-srto/ -R


#############################################################
## Ubuntu - Update Error
N#############################################################

# Problem: Did a partial upgrade,
# 	Ubuntu restarted to a black screen and a blinking cursor.
# Fix:
Control + Alt + F2	# At the same time
#
# Login to PC
#
# Finish upgrade
sudo apt update
sudo apt dist-upgrade
sudo startx


#############################################################
## Ubuntu - Drivers
#############################################################

# Reload sound drivers on Ubuntu
sudo alsa force-reload


#############################################################
## Ubuntu - Power
#############################################################

# Change Ubuntu from suspending when the lid is closed.
sudo vi /etc/systemd/logind.cong
#
# Do nothing (plus uncomment)
HandleLidSwitch=ignore
#
# Suspend
HandleLidSwitch=suspend
#
# Restart system daemon
sudo systemctl daemon-reload

# Check the battery charging threshold on Linux (Ubuntu)
cat /sys/class/power_supply/BAT0/charge_st*


#############################################################
## Ubuntu - X-Server
#############################################################

# On Ubuntu there are 2 X-Servers available during login:
   - Wayland
   - Xorg
# Wayland is newer and to use screen sharing (share,jitsi) in
   chrome enable this:
chrome://flags/#enable-webrtc-pipewire-capturer
# Xorg should be avoided since it can cause a black screen on lock screen
   (at least if an extra monitor is connected).


#############################################################
## VBA Regex
#############################################################

# Regex for validating input on database 
cat data | add_color -r '(?x) ^ (?! ^( (ALLENGINES|ASAPPLICABLE|PW\d+\w+-?\w+)(,|$))+ ((Except:)? (\d{6}-\d{6}|\d{6}) (,|$) )* $ ) .*'


#############################################################
## Vim Strings
#############################################################

# Example of using a multiline string in Vim
#
+ " Perl Data Dumper and other useful features all in one mapping.
+ function PerlDev()
+    let l:PERL_DEV = "
+       \\nuse v5.32;
+       \\nuse Mojo::Util qw(dumper);
+       \\nuse Carp       qw( croak confess carp cluck );
+       \\nsub WhoAmI { say '--> ' . (caller(1))[3] }
+       \\nsay 'var: ', dumper $var;
+       \\n$Self->HandleException('message'); # New    - Test/*
+       \\n$Selenium->HandleError('message'); # Legacy - script/*
+       \\n
+       \\n"
+
+    put =l:PERL_DEV
+ endfunction
+
+ nnoremap <leader>r :call PerlDev()<CR>


#############################################################
## Vim Quitting
#############################################################

# Exit, saving changes (Vim)
:x

# Exit as long as there have been no changes (Vim)
:q

# Exit and save changes if any have been made (Vim)
ZZ

# Exit and ignore any changes (Vim)
:q!


#############################################################
## Vim Variables
#############################################################

# Do substitution on a string or variable (vim)
let new_variable s = ubstitute("My::Long::Package", "::", "/", "g")
let old_variable = "My::Long::Package"
let new_variable = substitute(old_variable, "::", "/", "g")

# Check if a string or variable contains a pattern (vim)
echo "My::Package" =~ "::"       # 1
let var = "My::Package"
if var =~ "::"
   echo "Got a perl package"
endif


#############################################################
## Vim File Operations
#############################################################

# Check if a file is readable (vim,exists)
if filereadable(l:filename) == 1
   execute "edit" l:filename
else
   echohl WarningMsg | echo "File does not exist: " . l:filename | echohl None
endif


#############################################################
## Vim Funtions
#############################################################

# Prefix vim function arguments with a:
let l:filename = a:package_name


#############################################################
## Vim Custom Commands
#############################################################

# Create a custom command with arguments (vim)
+ function CustomEdit(package_name)
+    let l:filename = a:package_name
+
+    if l:filename =~ "::"
+       let l:filename = substitute(l:filename, "::", "/", "g")
+       let l:filename = l:filename . ".pm"
+    endif
+
+    if filereadable(l:filename) == 1
+       execute "edit" l:filename
+    else
+       echohl WarningMsg | echo "File does not exist: " . l:filename | echohl None
+    endif
+
+ endfunction
+
+ :command! -nargs=1 E call CustomEdit(<f-args>)


#############################################################
## Vim Inserting Text
#############################################################

# Insert before cursor (Vim)
i

# Insert before line (Vim)
I

# Append after cursor (Vim)
a

# Append after line (Vim)
A

# Open a new line after current line (Vim)
o

# Open a new line before current line (Vim)
O

# Replace one character (Vim)
r

# Replace many characters (Vim)
R

# Insert 50 characters (Vim)
50i-
50a-
50A-

# Append to the end of a word (Vim)
ea

# Join next line to current line (Vim)
J
3J       # join 3 lines (including current)

# Repeat last command (Vim)
.

# Insert a timestamp before each line labeled "SECTION" (Vim,read file,external,run)
:g/SECTION/-1 r !date

# View whitespace, line endings (Vim,hidden)
:set list

# Count the number of each of function call (DES,UI,Vim,variable)
# If there is a space before "\=i", "i" will not be interpreted.
# (same goes for "i++".
:let i=1
:g/myps()/ s!$! // ! | s/$/\=i/ | let i+=1            # In: ui.c
:g/myps(\d\+);/ s!\d\+!\=i! | let i+=1                # In: snvtb.c

# Insert 2 blank lines above "CREATE TABLE" line (Vim)
:g/\v^CREATE TABLE/ :norm 2O

# Append to an option or setting (Vim)
:set tags=abc
:set tags+=def

# Increase indentation (Vim,tab)
>>

# Decrease indentation (Vim,tab)
<<

# Move specific lines to the end of the file (Vim)
:g/item/ :move $

# Move specific lines to the end of the file (Vim)
# Plus next 2 lines
:g/item/ .,+2:move $

# Move current line to the start of file (Vim)
:move 0
:m 0


#############################################################
## Vim Motion
#############################################################

# Move left (Vim)
h

# Move down (Vim)
j

# Move up (Vim)
k

# Move right (Vim)
l

# Move to next word (Vim)
w

# Move to next blank delimited word (Vim)
W

# Move to the beginning of the word (Vim)
b

# Move to the beginning of blank delimited word (Vim)
B

# Move to the end of the word (Vim)
e

# Move to the end of Blank delimited word (Vim)
E

# Move a sentence back (Vim)
(

# Move a sentence forward (Vim)
)

# Move a paragraph back (Vim)
{

# Move a paragraph forward (Vim)
}

# Move to the begining of the line (Vim)
0

# Move to the end of the line (Vim)
$

# Move to the first line of the file (Vim)
1G

# Move to the last line of the file (Vim)
G

# Move to nth line of the file (Vim)
nG

# Move to nth line of the file (Vim)
:n

# Move forward to c (Vim)
fc

# Move back to c (Vim)
Fc

# Move to top of screen (Vim)
H

# Move to middle of screen (Vim)
M

# Move to botton of screen (Vim)
L

# Move to associated ( ), { }, [ ] (Vim)
%

# Go to start of word from anywhere in the word (Vim)
lb

# Select again the last visual selection (Vim)
gv


#############################################################
## Vim Deleting Text
#############################################################

# Delete character to the right of cursor (Vim)
x

# Delete character to the left of cursor (Vim)
X

# Delete to the end of the line (Vim)
D

# Delete current line (Vim)
dd

# Delete current line (Vim)
:d

# Delete text to beginning of line when in insert mode (Vim)
<Control> + u


#############################################################
## Vim Copy(Yank) and Paste Text
#############################################################

# Yank the current line (Vim)
yy

# Yank the current line (Vim)
:y

# Change to the end of the line (Vim)
C

# Change the whole line (Vim)
cc

# Put after the position or after the line (Vim)
p

# Put before the poition or before the line (Vim)
P

# Move block from "SECTION 1" to but not including "SECTION 2" (Vim)
# Move that block to right before "SECTION 3"
:g/SECTION 1/.,/SECTION 2/-1 move /SECTION 3/-1
#
# Approach in perl
perl -lne '$n=/SECTION 1/.../SECTION 2/; push @a,$_ and next if $n and $n !~ /E0$/; if(/SECTION 3/){print for @a}; print' vim_comp
perl -lne 'INIT{$"="\n"} $n=/SECTION 1/.../SECTION 2/; push @a,$_ and next if $n and $n !~ /E0$/; /SECTION 3/ and print "@a"; print' vim_com
# handles multiple such blocks
perl -lne 'INIT{$"="\n"} $n=/SECTION 1/.../SECTION 2/; push @a,$_ and next if $n and $n !~ /E0$/; /SECTION 3/ and print "@a" and undef @a; print' vim_comp

# Delete "SECTION 2" (end marker is "SECTION 3" exclusive (Vim)
:g/SECTION 2/,/SECTION 3/-1d
#
# Approach in perl
perl -lne '$a=/SECTION 2/.../SECTION 3/; print unless $a and $a !~ /E0$/' vim_comp


#############################################################
## Vim Markers
#############################################################

# Set marker c on this line (Vim)
mc

# Go to beginning of marker c line (Vim)
`c

# Go to first non-blank character of marker c line (Vim)
'c

# Same current deletion into buffer 'a' (Vim)
"add

# Paste current contents of buffer 'a' below (Vim)
"ap


#############################################################
## Vim Find/Search for strings
#############################################################

# Search forward for string (Vim)
/string

# Search back for string (Vim)
?string

# Search for next instance of string (Vim)
n

# Search for previous instance of string (Vim)
N

# Jump/Match between openning and closing parenthesis (Vim)
<Shift> + %

# Ignore case when searching (Vim)
:set ic

# Unignore case when searching (Vim)
:set noic


#############################################################
## Vim Find/Search and Replace for strings
#############################################################

# Make every after very magical (Vim,regex)
\v magical \V not_magical

# Replace pattern with string according to flags (Vim)
:s/pattern/string/flags

# Replace pattern with string ask for confirmation of each change (Vim)
:s/pattern/string/gc

# Replace pattern with string in entire file (Vim)
:%s/pattern/string/gc
:1,$s/pattern/string/gc

# Replace pattern with string in range (Vim)
:5,10s/pattern/string/gc

# Allow capturing groups (dollar variables) in substitutions (Vim, search and replace)
# \v for very magical mode
:%s/ \v([a-z]+)::/ <x>\1::/gc

# Positive lookahead (Vim)
# \v(pattern)@=
:%s/ \v([a-z_]+)\v(::)@=/ <x>\1/gc

# Format output from search and replace (Vim, substitution)
# as printf would do. Need to use submatch(1) instead of \1
s/\v(\S+)/submatch(1)/
:'<,'>s/\v(.* )\v(')@=/\=printf('%-60s',submatch(1))/c

# Word Boundary (Vim)
# \b \<
:%s/\<\v([cp]p[ab])@=/l/gc
:h \<

# Find how to use a specific variable (Vim)
:h \<

# Flag - Replace all occurences of pattern (Vim)
g

# Flag - Confirm replaces (Vim)
c

# Repeat last :s command (Vim)
&

# Non greedy search (Vim)
# Preceeding pattern range with "-"
:help non-greedy
{-}


#############################################################
## Vim Regular Expressions
#############################################################

# (dot) Any single character except newline (Vim)
.

# zero or more occurances of any character (Vim)
*

# Any single character specified in the set (Vim)
[...]

# Any single character not specified in the set (Vim)
[^...]

# Anchor - beginning of the line (Vim)
^

# Anchor - end of line (Vim)
$

# Anchor - begining of word (Vim)
\<

# Anchor - end of word (Vim)
\>

# Grouping - usually used to group conditions (Vim)
\(...\)

# Contents of nth grouping (Vim)
\n

# Beginning of file (Vim,regex,search)
/%^

# Go to the end of the match (Vim,regex,search)
/regex/e


#############################################################
## Vim Files
#############################################################

# file Write to file (Vim)
:w

# file Read file in after line (Vim)
:r

# Go to next file (Vim)
:n

# Go to previos file (Vim)
:p

# file Edit file (Vim)
:e

# Replace line with output from program (Vim)
!!program

# Open file in readonly mode (Vim)
vi -R file
view file

# Open another file in the same Vim session
:e file2

# Switch between files in Vim
:e#
<Control> + ^

# Write if newer and quit Vim
:x


#############################################################
## Vim Config
#############################################################

# Make vim config file (Vim)
touch ~/.vimrc

# Use boolean environmental variable in vimrc
if !$ON_VM
   echo "IF"
else
   echo "ELSE"
endif

# Use string environmental variable in vimrc
if $FOO == 'bar'
  " Vimscript to execute when the value of
  " the env variable FOO equals 'bar'.
else
  " Vimscript to execute otherwise.
endif

# Use syntax of the script (Vim)
:syntax on

# Use a more pleasant foreground color (Vim)
:color desert

# Color all matching items (Vim)
:set hlsearch

# Stop coloring all matching items (Vim)
:nohlsearch

# View options set by user (Vim)
:set

# View all options (Vim)
:set all

# Check the value/status of an option (Vim)
:set <option>?
:set ic?          # noignorecase

# Show full path, get the head, then the tail (Vim)
:echo expand("%:p:h:t")

# Toggle an option (Vim)
:set number!
:set number!

# View status of current file (filename, Vim)
Control + G


#############################################################
## Vim Abbreviations
#############################################################

# Create an abbreviation (Vim)
# Expands in insert mode after typing "TIM "
:ab TIM Time Is Money

# View all abbreviations set (Vim)
:ab

# View value for an abbreviation (Vim)
:ab TIM

# Remove abbreviation (Vim)
:unab TIM


#############################################################
## Vim Map Command Keys
#############################################################

# View mapped commands (Vim)
:map

# Create a mapping of commands for a particular key (Vim)
# Key 'q' will go down 5 lines and make a new line
:map q 5jo

# Reverse this and the following word (Vim,2 words,demo)
:map r wBdwelpBB

# Move word to the right (Vim)
:map gr "xdiwdwep"xpb

# Move word to the left (Vim)
:map gl lbgr

# Put html markers around a word (Vim)
:map + i<I>^[ea</I>^[

# Make the backslash a map leader (Vim,portable)
# Use leaders for global plugins.
:let mapleader = "\\"
:nnoremap <leader>d dd                 # Same as:
:nnoremap        \d dd

# Make the dash a map local leader (Vim,portable)
# Use local leaders for filetype plugins.
:let maplocalleader = "-"
:nnoremap <localleader>d yyp           # Same as:
:nnoremap             -d dd

# Create a multiline Vim mapping
nnoremap <leader>r O
   \<CR>use v5.32;
   \<CR>use Mojo::Util 'dumper';
   \<CR>use Carp qw( croak confess carp cluck );
   \<CR>say "var: ", dumper $var;
   \<CR><ESC>


#############################################################
## Vim Record Macros
#############################################################

# Record a new macro (Vim)
qa       # Start recording. Will be put in register "a".
...      # Run any commands.
q        # Stop recording.

# View recorded macros (Vim)
# ^[ is ESC key
:reg
:reg a

# Replay a macro (Vim,run)
@a

# Replay last macro (Vim,run)
@@

# Repeat movement and commands (Vim)
qq;.q       # next, repeat command
11@q        # run 11 times

# Number a list of lines (Vim)
:let @c=0      # set value of register (preload)
:let @n=0i^R=^Rc+1^M. ^[0"cywj^[       # will not work with control characters

# Run macro commands in parallel (Vim)
:let @a='0f.r)w~'    # load macro
<Shirt> + V + G      # Select current line to end
:normal @a           # run macro on lines

# Select desired lines in file and run macro on them (Vim,global)
:g /^sched_args/ :normal @c

# Append to existing register (Vim,typo)
qa       # start original macro
...      # commands
q        # stop recording
qA       # Captial means append to register "a"
...      # Fix typo
q        # End

# Indent the description section in primitives_doc file (Vim)
# This commands finds any problems
:g/^\v   Syntax:.*\n\n/ .+2,/^\v   [a-zA-Z]+:/-2p
#
# This will transform.
# 1. Find all "Syntax:" lines.
# 2. Assume next is blank, so start 2 lines down "+2".
# 3. Search for the next section and end 2 above that "-2".
# 4. Strip any leading space and replace with 6 spaces.
# 5. Strip trailing whitespace.
g/^\v   Syntax:.*\n\n/ .+2,/\v^   [a-zA-Z]+:/-2 s/^\v\s*(\S+)@=/      / | s/\s\+$//


#############################################################
## Vim Folding
#############################################################

# Manually fold a sectin (Vim)
v + <move_arrows> + zf

# Fold next 3 lines (Vim)
zf3j

# Allow folding of perl code (Vim)
let perl_fold=1

# Can put in rc file. related to folding. not sure (Vim)
:setlocal foldmethod=syntax
inoremap <F9> <C-O>za
nnoremap <F9> za
onoremap <F9> <C-C>za
vnoremap <F9> zf

# Close a fold (depends on cursor) (Vim)
zc

# Close all fold (depends on cursor) (Vim)
zC

# Open a fold (depends on cursor) (Vim)
zo

# Open all fold (depends on cursor)
zO

# Toggle/Alternate a fold (depends on cursor) (Vim)
za

# Toggle/Alternate all fold (depends on cursor) (Vim)
zA

# Open a single level of folds (depends on cursor) (Vim)
zr

# Open all more level of folds (seems similar to zA) (Vim)
zR

# Close a single level of folds (Vim)
zm

# Close all more level of folds (seems similar to zC) (Vim)
zM

# File should open unfolded (Vim)
set nofoldenable


#############################################################
## Vim Multiple Screens (Window/Split)
#############################################################

# Split screen horizontally (Vim,up and down)
<Control> + w + s

# Split screen vertically (Vim,left and right)
<Control> + w + v

# Move to the screen below (Vim,multiple)
<Control> + w + j

# Close all other screen (Vim,multiple)
<Control> + w + o

# View the window number of current screen (Vim)
:echo winnr()

# Go to a specific window (Vim,screen)
:1wincmd w
:wincmd w         # same
:2wincmd w

# Save all screens (Vim,multiple)
:wall
:wa

# Close all screens (Vim,multiple,quit)
:qall
:qa

# Rotate the windows horizontally (Vim,multiple,screens)
<Control> + w + r

# Show the current window number (Vim,multiple)
:echo winnr()

# Show the current buffer number (Vim,multiple)
:echo bufnr("%")

# Put current windows to the a side (Vim,multiple,screens)
<Control> + w + K # Up
<Control> + w + J # Down
<Control> + w + H # Left
<Control> + w + L # Right

# Load a buffer number (file) into the current window (Vim,multiple)
:hide buf<number>
:hide buf4

# Run command in every buffer (Vim,multiple screens)
:bufdo! %s/ABC/123/g

# Close all other windows (Vim,multiple screens)
:on
:on!
:only
:only!


#############################################################
## Vim Sessions (Save and Restore Display)
#############################################################

# Save current display (Vim,session)
:mksession ~/bin/vim/lwp.vim
:mks ~/bin/vim/lwp.vim

# Restore a select display (Vim,session)
vim -S ~/bin/vim/lwp.vim

# Save current display (Vim,session)
# Pressing "-s" will save the display
# Pressing "-r" will restore the last saved display


#############################################################
## Vim Tags
#############################################################

# Create a tags file (Vim)
sudo apt-get install exuberant-ctags
ctags <c_file>
ctags -f $tag -R $source --totals

# Create tags of all OMS functions  (Vim)
sudo apt-get install exuberant-ctags
ctags `find ~/omspp/trunk/ -type f -name "*.[ch]" -o -name "*.cpp"`
ctags -f $tag_file $(find $oms_tree -type f -name "*.[ch]" -o -name "*.cpp")

# Jump to the tag/function underneath the cursor (Vim)
<Control> + ]
:tag

# Search for a particular tag (Vim)
:ts <tag>

# Go to the next definition for the last tag (Vim)
:tn

# Go to the previous definition for the last tag (Vim)
:tp

# List all of the definitions of the last tag (Vim)
:ts

# Jump back up in the tag stack (Vim)
<Control> + o        # One jump in jump list
<Control> + t        # Can be many jumps


#############################################################
## Vim Tab Spacing (Indentation)
#############################################################

# Increase indentation (with autoindent set) (Vim)
<Control> + T

# Descrease indentation (with autoindent set) (Vim)
<Control> + D

# Indent the next 2 lines (Vim)
>2j

# Indent all the lines to the end of the file (Vim)
>G


#############################################################
## Vim Syntax
#############################################################

# Comment lines in vimrc should start with "
" this is a comment

# Name of file that is opened in vim
let _curfile = expand("%:t")

# Show line numbers in vim (vimrc)
set number

# Vim resource (vimrc) file. other features.
set nowrap
set cursorline
hi CursorLine term=bold cterm=bold guibg=Grey40
set cursorcolumn

# Do not go past the end of the file when searching (Vim)
set nowrapscan

# View the current file type of a Vim file
:set filetype?

# Check the file type (Vim,xterm,shell)
file ~/bin/enter_ui.sh

# Force the syntax to be a certain type in Vim
:set syntax=perl


#############################################################
## Vim Case Changing
#############################################################

# Toggle upp and lower case (Vim)
~

# Toggle case of the next three characters (Vim)
3~

# Toggle case of the next three words (Vim)
g~3w

# Toggle case of the current word (inner word - cursor anywhere in word (Vim)
g~iw

# Toggle case of all characters to end of line (Vim)
g~$

# Toggle case of the current line (Vim)
g~~
V~

# Uppercase the visually-selected text (Vim)
v
U

# Lowercase the visually-selected text (Vim)
v
u

# Change the current line to uppercase (Vim)
gUU
VU

# Change the current line to lowercase (Vim)
guu
Vu

# Change current word to uppercase (Vim)
gUiw

# Change current word to lowercase (Vim)
guiw

# Disable Caps Lock (Vim)
xmodmap -e "remove Lock = Caps_Lock" -e "keysym Caps_Lock = Escape"

# Enable Caps Lock (Vim)
xmodmap -e "keysym Escape = Caps_Lock" -e "add Lock = Caps_Lock"

# Other mappings for xmodmap (Vim,Shell)
vi /usr/include/X11/keysymdef.h


#############################################################
## Vim Script/Coding Structures (Functions
#############################################################

# Comparison in conditional (Vim,equal)
:if 1 == 1 | echo "TRUE" | else | echo "FALSE" | endif
# TRUE

# Comparison in conditional (Vim,equal,strings)
:if "abc" == "abc" | echo "TRUE" | else | echo "FALSE" | endif
# TRUE
# Comparison in conditional (Vim,equal,strings)
:if "abc" == "def" | echo "TRUE" | else | echo "FALSE" | endif
# FALSE

# Comparison in conditional (Vim,equal,strings)
:if "10abc" == "10def" | echo "TRUE" | else | echo "FALSE" | endif
# FALSE

# Comparison in conditional (Vim,equal,strings)
# Like perl. Uses leading numbers
:echo "10abc" + "10def"
# 20

# Comparison in conditional (Vim,equal,strings)
# Case sensitive ?
:if "abc" == "Abc" | echo "TRUE" | else | echo "FALSE" | endif
# FALSE
:set ignorecase
:if "abc" == "Abc" | echo "TRUE" | else | echo "FALSE" | endif
# TRUE
# Always use safer form ==? ==#
# ==?    - always case insensitive
# ==#    - always case sensitive
:if "abc" ==? "Abc" | echo "TRUE" | else | echo "FALSE" | endif
# TRUE
:if "abc" ==# "Abc" | echo "TRUE" | else | echo "FALSE" | endif
# FALSE


#############################################################
## Vim Functions
#############################################################

# Create a function (Vim)
# Must start with a capital letter
:function Abc()
:  echo "ABC"
:endfunction

# Define a function to return a value (Vim)
:function Abc()
:  return "ABC"
:endfunction

# Call a function (Vim)
# () are required.
:call Abc()

# Return a value from a function (Vim)
# :call will throw away the return value
# Use your function as an expresion instead.
:echo Abc()

# Create function inline (Vim)
# Not really friendly view.
:execute "function A()\necho \"ABC\"\nendfunction"

# Silence function redefinition with "!" (Vim)
:function! ABC()
:  echo "ABC"
:endfunction

# Return a sorted list (Vim)
function Sorted(l)
   let new_list = deepcopy(a:l)
   call sort(new_list)
   return new_list
endfunction
:let list = [3,6,1,2]
:echo Sorted(list)

# Save function reference in a scalar variable (Vim)
:let My_func = function("Sorted")
:let list = [3,6,1,2]
:echo Sorted(list)

# Higher order functions (Vim,pass function as parameter/argument)
function! Mapped(f,l)
   let new_list = deepcopy(a:l)
   call map(new_list, string(a:f) . '(v:val)')
   return new_list
endfunction
"
function! Sorted(l)
   let new_list = deepcopy(a:l)
   call sort(new_list)
   return new_list
endfunction
"
:let list = [[3,1,2],[23,12,3]]
:echo Mapped(function("Sorted"),list)

# Inside a map(), 'v:val' is the current item item in the list (Vim,function)
# Like $_ in perl


#############################################################
## Vim Plugins
#############################################################

# Setup plugin manager in Vim
# Download plug.vim
# Save here: ~/.vim/autoload/plug.vim

# Using plugins in vimrc
# Prepend in vimrc
#
call plug#begin('~/.vim/bundle')
Plug 'pbogut/fzf-mru.vim'
Plug 'ycm-core/YouCompleteMe'
Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': './install --all'  }
Plug 'junegunn/fzf.vim',
Plug 'airblade/vim-rooter'
Plug 'vim-perl/vim-perl', { 'for': 'perl', 'do': 'make clean carp dancer highlight-all-pragmas moose test-more try-tiny' }
call plug#end()

# Install plugin in vimrc file
:PlugInstall

# Vim plugin - Fuzzy search
:File


#############################################################
## Vim Other
#############################################################

# Join lines (Vim)
J

# Repeat last text-changing command (Vim)
.

# Undo last change (Vim)
u

# Undo all changes to line (Vim)
U

# Redo last command (Vim)
<Control> + r

# Diplay file name, number of lines (and percent) (Vim)
<Control> + g

# Type a control character in Vim
Control-V <RET>

# Convert binary to hex (Vim)
:%!xxd

# Comment a block of lines (Vim)
<Control> + v
# Scroll down with arrow keys
<Shift> + i
# Change first line to have a comment
ESC
# all other lines will have same change (comments added)

# Scroll down half a page (Vim)
<Control> + D

# Scroll up half a page (Vim)
<Control> + U

# Find documentaion for a lookahead (Vim)
:h \@

# View Vim variables (Vim)
:set

# History is not working (Vim)
# Check permissions of ~/.viminfo

# View man page (Vim,help)
:h

# Search for spaces (Vim)
/\s\+
# \+ since all are taken literally unless escaped

# If accidentally pressed <Control> + s (Vim)
# that will freeze the terminal. This is due to  "flow control"
# Do this to undo the effect:
<Control> + q
#
# To permanently disable this from occurring put this in .bashrc
stty -ixon

# Stop all output to terminal/xterm (Vim)
<Control> + s

# Restart output to terminal/xterm (Vim)
<Control> + q

# ERROR: the command is not available in this version (Vim)
sudo apt-get install vim

# Compare files (Vim)
vimdiff    file1 file2           # vertical split
vimdiff -o file1 file2           # horizontal split

# Open multiple files in split screens (Vim(
vim -O file1 file2               # vertical split
vim -o file1 file2               # horizontal split

# View history of searches (Vim)
q/

# View history of commands (Vim)
q:

# Open stream from STDIN (Vim)
echo "abc" | vi -


#############################################################
## Visual Basic Script (.vbs)
#############################################################

# Remove RSIGaurd process (.vbs)
Dim strComputer
DIm objWMIService
Dim colProcessList
Dim objProcess
strComputer = "."
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colProcessList = objWMIService.ExecQuery("SELECT * FROM Win32_Process WHERE Name = 'RSIGuard.exe'")
For Each objProcess in colProcessList
   objProcess.Terminate()
Next
#
# Same with perl
perl -e "kill -9,`tasklist`=~/RSIGuard\D+(\d+)/g"

# Convert .msg files to .txt files (extract text from outlook, .vbs)
Set ol  = CreateObject("Outlook.Application")
Set fso = CreateObject("Scripting.FileSystemObject")
inputString = "S:\controls\cert\<USER>\msg"
REM inputString = InputBox("Enter the full path to the .msg folder: ")
For Each f In fso.GetFolder(inputString).Files
  If LCase(fso.GetExtensionName(f)) = "msg" Then
      Set msg   = ol.CreateItemFromTemplate(f.Path)
      txt_path  = Replace(f.Path,".msg",".txt")
      txt_path  = Replace(txt_path," ","_")
      txt_path  = Replace(txt_path,"(","_")
      txt_path  = Replace(txt_path,")","_")
      If Not fso.FileExists(txt_path) Then
         Set txt   = fso.CreateTextFile(txt_path, True)
         txt.WriteLine(msg.Body)
      End If
  End If
Next
MsgBox "Done Converting!"



#############################################################
## Visual Studio (Windows 10)
#############################################################

# Fold all code in Visual Studio (Toggle Fold)
Control+M, Control+L

# Visual Studio 2015 Change encoding of a file
File -> “Advanced Save Options“
Select “Unicode (UTF-8 …“)

# Visual Studio column mode
Alt + Click and drag.


#############################################################
## Visual Studio Code
#############################################################

# Visual Studio Code (VSC) block edit (mode)
Shift + Alt + Click and Drag

# Visual Studio Code (VSC) bring up keybpard bindings
Control + Shift + P


#############################################################
## VLC
#############################################################

# Install support for creating soft subtitles in vlc videos (mp4)
sudo apt install gnome-subtitles
rm -fr ~/.cache/gstreamer-1.0/*     # If error opennig file.
gnome-subtitles


#############################################################
## Vue - General
#############################################################

# Vue shorthand (shortcuts)
@click = v-on:click
:value = v-bind:value

# Check Vue version
npm v vue

# Create Vue CLI app
vue create vue-first-app

# Run Vue server (start)
cd vue-first-app
npm run serve
#
# The npm run commands can be found in:
package.json /"scripts":
#
# Defaut script commands:
serve
build
lint

# Missing Node modules folder
npm install


#############################################################
## Windows Bugs
#############################################################

# Windows stuck in control mode (Tobias Wulf,windows bug)
Recovery: Most of the time, Ctrl + Alt + Del re-sets key status
to normal if this is happening. (Then press Esc to exit system screen.)
Another method: You can also press stuck key: so if you clearly see that
it is Ctrl which got stuck, press and release both left and right Ctrl .

# Why I have to press keys two times to get the ^ or ´ or ` (windows bug)
With this keyboard layout the ^ keystroke becomes a modifier to
enabling entering of special characters.
To get a single ^ character you will need to type ^+Space.


#############################################################
## Windows Command Prompt (DOS)
#############################################################

# Set an environmental variable (DOS)
setx <variable> <value>

# Unset an environmental variable (DOS)
setx <variable> ""

# Append path environmental variable (DOS)
setx path "new_dir_to_append"

# Change the width and height of a DOS window
mode con: cols=120 lines=20


#############################################################
## Windows - Drives
#############################################################

# Get mapped windows drives
net use

# Map windows drives
net use k: \\path /persistent:yes


#############################################################
## Windows - Excel
#############################################################

# Get last row in an excel column
=MATCH(TRUE,INDEX($K$3:$K$22="",0),0)-1

# Show excel formulas
Ctrl + `

# Insert the current date
Ctrl + :

# Insert the current time
Ctrl + Shift + :

# Drag excel column
Ctrl + r

# Drag excel row
Ctrl + d


#############################################################
## Windows - Filesystem
#############################################################

# /etc/hosts on Windows
C:\Windows\System32\drivers\etc

# Check if a program on Windows is 32 or 64 bit (objdump,stat,file)
Control + Shift + ESC
-> More Details
-> "Details" tab
Right Click
Select Columns
Platform
#
# Another way
"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.21.27702\bin\Hostx64\x64\dumpbin" /headers hinstall.exe | findstr machine

# Find windows start location folder (autostart scripts)
Windows + R
type:
	shell:startup
    shell:common startup

# Delete a deeply nested folder on Windows
cd bad_dir
mkdir empty
robocopy empty bad_dir /mir 	:: mirror blank directory over nested
rmdir empty bad_dir

# Question:
# What differences are between Authenticated Users, SYSTEM, Administrators
# (ADMIN\Administrators), and Users (ADMIN\Users) (Windows 10)
#
# Answer:
# They are all default users and groups Windows uses to maintain
# permissions, typically for security purposes.
#
# Authenticated Users is a pseudo-group (which is why it exists, but is not
# listed in Users & groups), it includes both Local PC users and Domain users.
#
# SYSTEM is the account used by the operating system to run services,
# utilities, and device drivers. This account has unlimited power and access
# to resources that even Administrators are denied, such as the Registry's SAM.
#
# Administrators can do just about everything a user would want to do with
# Windows, typically this includes the first user you create with windows.
# You are probably a member of this group.
#
# Users are accounts with lower permissions, and typically require an Administrator
# to enter their password to do anything that would bring up a UAC console in
# Windows. You can create accounts with these permissions (I do it for my
# guest account) with the "Add Remove User Accounts" menu in the Control Panel.

# Find out who have a file opened
# Need to have this setup one time (as admin)
openfiles.exe /local on
# restart PC


#############################################################
## Windows - Outlook
#############################################################

# Windows Outlook.
# Monospaced font
Courier New


#############################################################
## Windows - Registry
#############################################################

# Registry file location on windows 10
C:\Users\<USER>\NTUSER.DAT

# Script to update the windows registry
#
@echo off
echo.
cd ..
reg add HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\MY_PATH /t REG_SZ /v AppPath /d %cd% /f
echo.
echo AppPath = %cd%
echo.
pause

# Dump windows 10 registry to a file (query,view,search)
reg export "HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\MY_PATH" my.reg
reg export "HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\MY_PATH" my.reg /y

# Enable Restore Points in Windows 10
Win + r
Type: regedit
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows NT\SystemRestore
Double - Click "DisableSR"
1	- Disabled
0	- Enabled
#
# Restart PC for changes to take effect.

# Add the "Open command window here" option back to windows 10 commamd prompt (registry,DOS)
# when doing right click.
#
# Go to the regestry
Win + r
type: regedit
#
# For these paths:
Computer\HKEY_CLASSES_ROOT\Directory\shell\cmd
Computer\HKEY_CLASSES_ROOT\Directory\background\shell\cmd
#
# Update permissions:
	- Right-click the PowerShell (folder) key, and click Permissions.
	- Click the Advanced button.
	- On "Advanced Security Settings," click the Change link next to "Owner".
	- Type your account name in the provided field, click Check Names to verify
		you're typing the account name correctly, and click OK.
	- Check the Replace owner on subcontainers and objects option.
	- Click Apply.
	- Click OK.
	- On "Permissions," select the Administrators group.
	- Under "Permissions for Administrators," select Allow for the Full Control option.
	- Click Apply.
	- Click OK.
#
# Show option:
	- Inside the cmd (folder) key, right-click the HideBasedOnVelocityId DWORD,
		and click Rename.
	- Change the DWORD name from HideBasedOnVelocityId to ShowBasedOnVelocityId,
		and press Enter.
#
# Hide option (undo the change):
	- rename the DWORD from from ShowBasedOnVelocityId to HideBasedOnVelocityId


#############################################################
## Windows - Variables
#############################################################

# Get windows script directory (DOS,pwd,windows vars)
echo %~dp0

# Start in currect script directory (windows vars)
cd /d %~dp0


#############################################################
## Windows Commands - ipconfig
#############################################################

# Internet not working on Windows
# Disable all adapters, but Ethernet 2.
# Then:
ipconfig /renew
ipconfig /release
# Enable the adapters again.


#############################################################
## Windows Commands - net
#############################################################

# See which folders are being shared on windows 10
net share


#############################################################
## Windows Commands - netstat
#############################################################

# Special Addresses
netstat -ano -p tcp | findstr 8080
# Address 0.0.0.0   allows access by another machine.
# Address 127.0.0.1 allows faking a server by using the loopback adapter.


#############################################################
## Windows Commands - putty
#############################################################

# Launch all benches and watch the date (Putty,xterm)
#
# @REM='
# @echo off
# mode CON: COLS=120 LINES=30
#
# set file=H:/kog.dat
# perl -lE "$f='%file%'; -e $f and exit; print qq(Enter your password: ); chomp($p=<STDIN>); open FH, qq(>$f); print FH $p; system qq(attrib +h $f) "
# set /P pass=< %file%
#
# echo Opening Exceed
# start /B "Exceed" "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Open Text Exceed 14 x64\Exceed.lnk"
#
# echo Opening Putty
# perl -x -l -S "%0" "%pass%"
# echo Everything is opened. Close this Window.
# exit /b
# ';
#
#
# #!perl
#
# #-----------------------------------------------------
# # SUBS
# #-----------------------------------------------------
#
# sub make_file {
# 	my ($n,$x,$y) = @_;
# 	my $file = "run$n.txt";
# 	open FH, ">", $file or die $!;
# 	print FH q(echo -e '\e[8;1;30t');		# Size
# 	print FH "echo -e '\\e[3;$x;${y}t'";	# Placement
# 	print FH "/home3/timp/watchdate";
# 	close FH;
# 	$file;
# }
#
# sub make_cmd {
# 	my ($user,$_,$pass,$file) = @_;
# 	my $cmd = qq(start "Putty" "$ENV{PWPROD}\\wnt\\putty\\putty.exe" -X -ssh $user\@lnxbr$_ -pw $pass -m "$file" -t&);
# 	$cmd;
# }
#
#
# my ($pass) = @ARGV;
#
#
# #-----------------------------------------------------
# # new
# #-----------------------------------------------------
# my @benches = grep { not / 40 | 49 /x  } 21..70;
# my $COLS    = 3;
# my $ROWS    = @benches / $COLS;
# my $Xoffset = 300;
# my $x       = $Xoffset;
# my $y       = 0;
# my $height  = 50;
# my $width   = 270;
# my $cnt     = 0;
# my $y2;
# my $user    = "timp";
#
# $ROWS++ if $ROWS > int($ROWS);
#
# for(@benches){
# 	my $file = make_file($_,$x,$y);
# 	my $cmd  = make_cmd($user,$_,$pass,$file);
# 	# print  $cmd;
# 	system $cmd;
#
# 	$y += $height;
# 	$cnt++;
# 	if($cnt >= $ROWS){
# 		$y2 //= ($y + $height);
# 		$x  += $width;
# 		$y   = 0;
# 		$cnt = 0;
# 	}
# }
#
# #-----------------------------------------------------
# # user
# #-----------------------------------------------------
#
# @benches = qw/24 36 42 43/;
# $x = $Xoffset;
# $y = $y2;
# $user = "<USER>";
# for(@benches){
# 	my $file = make_file($_,$x,$y);
# 	my $cmd  = make_cmd($user,$_,$pass,$file);
# 	# print  $cmd;
# 	system $cmd;
# 	$y += $height;
# }
#
#
# #-----------------------------------------------------
# # admin
# #-----------------------------------------------------
#
# @benches = qw/24 36 42 43/;
# $x += $width;
# $y  = $y2;
# $user = "<USER>";
# for(@benches){
# 	my $file = make_file($_,$x,$y);
# 	my $cmd  = make_cmd($user,$_,$pass,$file);
# 	# print  $cmd;
# 	system $cmd;
# 	$y += $height;
# }
#
#
#
# __END__
#


#############################################################
## Windows Commands - sc
#############################################################

# Service commands
::
:: Add new service
sc.exe create MyProgram binPath="C:\Program Files (x86)\Windows Resource Kits\Tools\srvany.exe"
sc config MyProgram start=auto
sc.exe config MyProgram obj= "me@home.com" password= ""
::
:: Remove a service
sc.exe delete MyProgram
::
:: Start a service
sc.exe start MyProgram
::
:: Stop a service
sc.exe stop MyProgram


#############################################################
## Windows Commands - schtasks
#############################################################

# TASK_INSTALL.bat (Scheduler)
# Manually create task.xml in task scheduler, then export
cd /d %~dp0
python.exe task_create_xml.py
schtasks /CREATE /TN MyProgram /XML task.xml /RU %USERNAME% /RP
DEL /F task.xml

# TASK_SHOW.bat (Scheduler)
schtasks /QUERY /TN Statusmonitor /V /FO LIST

# TASK_UNINSTALL.bat (Scheduler)
schtasks /DELETE /TN Statusmonitor /F


#############################################################
## Windows Commands - start
#############################################################

# Start a window minimized
start "TITLE" /D "START_PATH" /MIN PERL MY.PL


#############################################################
## Windows Commands - tasklist
#############################################################

# Kill any process (like notepad). Put this in a .bat file
@perl -e "kill -9, `tasklist`=~/Notepad\S*\s+(\d+)/gi"

# Kill any process. like previous, but can be more descriptive
@tasklist /v /fo list | perl -00ane "kill -9, /PID:\s+(\d+)/ if /Image Name:\s+Notepad/i"


#############################################################
## Windows Commands - taskkill
#############################################################

# Stop a running program
taskkill /F /IM python.exe


#############################################################
## Windows Commands - where
#############################################################

# Find the location of a program in Windows (whereis, which)
where cdd


#############################################################
## XMLint
#############################################################

# Install xmllint
sudo apt install libxml2-utils


#############################################################
## XLST (Xalan-Java Program, org.apache.xalan.xslt.Process)
#############################################################

# Common Options (Xalan-Java,org.apache.xalan.xslt.Process)
# -XSLTC (use XSLTC for transformation)
# -IN inputXMLURL
# -XSL XSLTransformationURL
# -OUT outputFileName
# -V (Version info)
# -EDUMP [optional filename] (Do stackdump on error.)
# -XML (Use XML formatter and add XML header.)
# -TEXT (Use simple Text formatter.)
# -HTML (Use HTML formatter.)
# -PARAM name expression (Set a stylesheet parameter)
# -MEDIA mediaType (use media attribute to find stylesheet associated with a document)
# -FLAVOR flavorName (Explicitly use s2s=SAX or d2d=DOM to do transform)
# -DIAG (Print overall milliseconds transform took)
# -URIRESOLVER full class name (URIResolver to be used to resolve URIs)
# -ENTITYRESOLVER full class name (EntityResolver to be used to resolve entities)
# -CONTENTHANDLER full class name (ContentHandler to be used to serialize output)
# -SECURE (set the secure processing feature to true)

# Options for Xalan-Java Interpretive (Xalan-Java,org.apache.xalan.xslt.Process)
# -QC (Quiet Pattern Conflicts Warnings)
# -TT (Trace the templates as they are being called)
# -TG (Trace each generation event)
# -TS (Trace each selection event)
# -TTC (Trace the template children as they are being processed)
# -TCLASS (TraceListener class for trace extensions)
# -L (use line numbers for source document)
# -INCREMENTAL (request incremental DTM construction by setting
#     http://xml.apache.org/xalan/features/incremental to true)
# -NOOPTIMIMIZE (request no stylesheet optimization proccessing by setting
#     http://xml.apache.org/xalan/features/optimize to false)
# -RL recursionlimit (assert numeric limit on stylesheet recursion depth)

# Options for Xalan-Java Compiled (XSLTC) (Xalan-Java,org.apache.xalan.xslt.Process)
# -XO [optional transletName] (assign the name to the generated translet)
# -XD destinationDirectory (specify a destination directory for translet)
# -XJ jarfile (package translet classes into a jar file of name <jarfile>)
# -XP package (specify a package name prefix for all generated translet classes)
# -XN (enable XSL template inlining into one big method)
# -XX (turn on additional debugging message output)
# -XT (use translet to transform if possible)

# xsl "<xsl:apply-templates />" with no selection
# In the absence of a select attribute, the xsl:apply-templates instruction
# processes all of the children of the current node, including text nodes


#############################################################
## XPath
#############################################################

# Xpath in Chrome console
$x('//body//h2')

# Xpath . is a shorthand for text():
$x('//tr[contains(@class, "MyClass")]/td/span[contains(@id, "-Title")]/span[contains(text(),"MyText")]')
$x('//tr[contains(@class, "MyClass")]/td/span[contains(@id, "-Title")]/span[contains(.,"MyText")]')

# XPath in Javascript code
elem = document.evaluate('//span[@id="MyID"]', document, null, XPathResult.ANY_TYPE, null).iterateNext();
elem = $x('//span[@id="MyID"]')[0]
#
# Same as css selector:
elem = document.querySelector('span[id="MyID"]')

# Xpath vs Css Selector Examples
my $css1   = 'span[id="MyId"]';
my $xpath1 = '//span[@id="MyId"]';
my $css2   = '.MyClass input[type="checkbox"][name="MyName"]';
my $xpath2 = '//*[contains(@class, "MyClass")]//input[@type="checkbox"][@name="MyName"]';


## Y


#############################################################
## Zrepl
#############################################################

# Install zrepl on Ubuntu
sudo apt update && sudo apt install curl gnupg lsb-release
ARCH="$(dpkg --print-architecture)"
CODENAME="$(lsb_release -i -s | tr '[:upper:]' '[:lower:]') $(lsb_release -c -s | tr '[:upper:]' '[:lower:]')"
curl https://zrepl.cschwarz.com/apt/apt-key.asc | sudo apt-key add -
echo "deb [arch=$ARCH] https://zrepl.cschwarz.com/apt/$CODENAME main" | sudo tee /etc/apt/sources.list.d/zrepl.list
sudo apt update
sudo apt install zrepl


#############################################################
## New and Unsorted Commands
#############################################################
