8/2/16

notes

- git
  which git  # /usr/bin/git
  /applications/xcode.app/contents/developer/usr/bin/git version  # 2.37.1
  
  q  # quit
  
# git commit --amend --author "John Marquez <john@dev.com>"
  
  
  # delete the last commit (revert)
  # http://christoph.ruegg.name/blog/git-howto-revert-a-commit-already-pushed-to-a-remote-reposit.html
  
# git reset  HEAD^ --hard
  
  
  # config
  git help config
  git config  --list  # -l
  git config  --unset  branch.foo.remote
  git config  --unset  branch.foo.merge
  git config  --global user.name
  git config  --global user.email
  git config  --global user.name   "john"
  git config  --global user.email  "john@dev.com"
  
  
# git gc  # cleanup
  
  
  git branch  -r                        # list remote branches
# git branch  -r  -d  origin/demo       # delete remote branch
# git remote  prune  origin  --dry-run  # delete all stale remote-tracking branches
  
  git branch  -m <oldname> <newname>    # rename from any branch
  git branch  -m           <newname>    # rename current branch
  
  
  git status
  git status  --short  # -s
  
  
  git log  -n3  dev/app/lib.mm  # git log for file, last n commits, filename is case sensitive
  
  git log  -n2                # Sun Oct 5 12:00:00 2014 -0600
  git log  -n2  --date=local  # Sun Oct 5 12:00:00 2014
  git log  -n2  --date=short  # 2014-10-05
  git log  -n2  --date=iso    # 2014-10-05 12:00:00 -0600
  
  git log  --name-status
  git log  --name-status  --author=kbcat  --merges     -n2
  git log  --name-status  --author=kbcat  --no-merges  -n3  dev/app/file.c
  git log  --name-status                  --no-merges  -n3
  git log  --name-only
  git log  --stat
  
  git log  -n3  --pretty=format:"%cd  %h%n%s%n-------"  --date=local  # Sun Oct 5 12:00:00 2014
  git log  -n3  --pretty=format:"%cd  %h%n%s%n-------"  --date=iso    # 10-05 12:00:00
      | sed -e 's/2014-//'
      | sed -e 's/ -0600//'
  
  git log  --abbrev-commit
  git log  --abbrev-commit  --pretty=oneline
  git log  --abbrev-commit  --pretty=oneline  --author=kbcat
  git log  --abbrev-commit  --pretty=oneline  --author=kbcat  dev/app/file.c
  git log  --abbrev-commit  --pretty=oneline                  dev/app/file.c
  
  git log  --diff-filter=A  --name-status   # Added
  git log  --diff-filter=D  --name-status   # Deleted
  git log  --diff-filter=M  --name-status   # Modified
  git log  --diff-filter=R  --name-status   # Renamed
  
  git log  --diff-filter=AD  --name-status  # Added or Deleted
  
  git log --before="2017-01-01"
  
  git log  --grep="bug"  # match commit message
  git log  -Sfoo         # find string occurrences +-
  
  
  git show  HEAD
  git show  HEAD~
  git show  HEAD~2
  git show  HEAD~3
  
  git show  f000000
  git show  f000000  dev/app/file.c
  git show  --name-status  f000000
  
  git show  --pretty="format:"  --name-only             # last commit
  git show  --pretty="format:"  --name-only  f000000    # commit
  git show  --pretty="format:"  --name-only  stash@{0}
  
  
  # show all commits in feature branch that are not in main branch
  git log  main..dev/fb
  git log  main..dev/fb  --no-merges
  
  
  # add files
  git add  -A             # stage all
  git add  .              # stage mod and new
  git add  -u             # stage mod and del
  git add  dev/app/lib.*  
  
  
  git checkout -b fb1
  git checkout stash
  git checkout stash@{1}     dev/app/file.c
  git checkout stash@{1}  -- dev/app/file.c
  
  git checkout f000000       dev/app/file.c
  
  git checkout -b temp stash@{1}
  
  
  git cherry-pick               f000000
  git cherry-pick  --no-commit  f000000  # -n
  git cherry-pick  --edit       f000000  # -e


  git tag  -a  v1.0  -m "..."
  git tag  -l                   # list all tags, default shows 1 line of tag message
  git tag  -l  -n3  v1.0        # show 3 lines of tag message
  git show  v1.0
  git push  origin  [tagname]
  git push  origin  v1.0


  # update
  git remote  show  origin
  git fetch
  git pull


  git diff             stash                  # diff working dir w/stash
  git diff  dev        stash@{1}              # diff dev branch w/stash
  git diff             stash@{1}      file.c  # diff file in working dir w/stash
  git diff  stash@{1}  stash@{0}              # diff stash 1 w/stash 0, most recent last
  git diff  stash@{1}  stash@{0}      file.c  # diff file between stash 1 and stash 0
  git diff  f000000    f000001     -- file.c  # diff file between commit x and commit y

  git diff  --staged


  // git diff stash script, swift 5
  for x in (1...20).reversed() {

      let stashData = "stash@{\(x)} stash@{\(x - 1)}"

      print("cl git diff        \(stashData)   --name-only")
      print("#  git stash drop  stash@{\(x)}\n")
  }


      cl git diff        stash@{10} stash@{9}   --name-only
      #  git stash drop  stash@{10}

      cl git diff        stash@{9} stash@{8}   --name-only
      #  git stash drop  stash@{9}

      cl git diff        stash@{8} stash@{7}   --name-only
      #  git stash drop  stash@{8}

      cl git diff        stash@{7} stash@{6}   --name-only
      #  git stash drop  stash@{7}

      cl git diff        stash@{6} stash@{5}   --name-only
      #  git stash drop  stash@{6}

      cl git diff        stash@{5} stash@{4}   --name-only
      #  git stash drop  stash@{5}

      cl git diff        stash@{4} stash@{3}   --name-only
      #  git stash drop  stash@{4}

      cl git diff        stash@{3} stash@{2}   --name-only
      #  git stash drop  stash@{3}

      cl git diff        stash@{2} stash@{1}   --name-only
      #  git stash drop  stash@{2}

      cl git diff        stash@{1} stash@{0}   --name-only
   #  cl git diff        stash@{1} stash@{0}                # kb: up, L+W
      #  git stash drop  stash@{1}


      # do not drop stash zero


  # interactive rebase, to edit/squash commits
# git rebase  -i  HEAD~2  # opens vim
# git rebase  -i  HEAD~3
# git rebase  -i  HEAD~4
# git rebase  -i  HEAD~5
# git rebase  -i  HEAD~6

# git rebase  --continue
# git rebase  --abort


# git stash  save  "backup"
  git stash  list
  git stash  list  --date=local
  git stash  show                # file list
# git stash  pop/apply

  # show stash sha1 hash
  git reflog stash


  git blame              dev/app/file.c
  git blame  -L 100,110  dev/app/file.c


  # --------------------------------------
  - git workflow example 1
    
    clear; git status
    
    git init                                     # initialized empty Git repository in /users/a/dev/app/.git/
    git add file1.txt
    git commit -m "..."
    git log
    git add .
    git commit -m "..." >> ~/gitCommitLog.txt
        
        10 files changed, 20 insertions(+), 1 deletion(-)
        create mode 100644 .gitignore
        create mode 100644 HEAD
        create mode 100644 c/lib.c
        create mode 100644 c/lib.h
        create mode 100644 file2.txt
    
    
  # --------------------------------------
  - git workflow example 2
    
    WORKING_FOLDER=~/dev/app/
    mkdir -p "$WORKING_FOLDER"
    cd "$WORKING_FOLDER"
    
    ls -alt
    git init
    git status    # On branch main
    
    touch .gitignore
    echo .DS_Store > .gitignore
    git add .gitignore
    git add --all
    
    git commit -m "new"
    git log  --name-status
    
  # --------------------------------------
  - git workflow example 3, GitHub
    
    1. init, setup, and commit into local git repo
    2. create repo on GitHub
    3. push repo to GitHub
    
    # test github connection
    ssh -T git@github.com    # Hi expressionsoftware! You've successfully authenticated, but GitHub does not provide shell access.
    
    
    git init
    touch .gitignore
    echo .DS_Store > .gitignore
    git add .gitignore
    
    git commit -m "new"
    
    # ...
    
    
    # github repo url
    ssl:  git@github.com:expressionsoftware/foo.git
    http: https://github.com/expressionsoftware/foo.git
    
    # add remote and push
    git remote add origin git@github.com:expressionsoftware/foo.git
    
    git push -u origin main --porcelain --verbose  # include -u (--set-upstream) on first push only
    git push -u origin dev
    
    git push    origin main
    git push    origin dev
    git push                   # current branch
                               # fatal: The current branch dev has no upstream branch.
                               # To push the current branch and set the remote as upstream, use
    
                               # git push --set-upstream origin dev
    
    
    # clone
    git clone git@github.com:expressionsoftware/foo.git         # creates folder, default folder name, same as repo name, "foo"
    git clone git@github.com:expressionsoftware/foo.git foobar  # creates folder "foobar"
    git clone git@github.com:expressionsoftware/foo.git .       # current empty folder
    
    
  # --------------------------------------
  - .gitignore file
    .cfusertextencoding
    .ds_store
    .fontconfig/
    .gitignore~
    .lesshst
    .trash/
    .viminfo
    .xauthority
    *~*
    *.exe
    xcuserdata/
    # -----------------
    app/temp.cpp
    temp file 1.txt
    # -----------------
    # wildcards
    # * wildcard requires full path
    app/images/*png
    *~
    *.swp
    # ignore all directories and files in a directory
    tmp/**/*
  
  
- brew
  /usr/local/bin/brew -v  # 4.0.4
  
  /usr/local/cellar
  
  man brew
  brew help
  brew home
  brew doctor
  
  brew analytics
  brew analytics off
  
  brew list
  brew list -1  # one entry per line
  
# brew update  # update hb
  
  brew outdated  # list outdated packages
  
  brew upgrade $FORMULA
# brew upgrade           # upgrade all
  
  brew cleanup -n        # show cleanup
  brew cleanup $FORMULA
# brew cleanup           # cleanup all

  brew info    bash           # 5.2.15
  brew install bash           # /usr/local/cellar/bash/*/bin/bash

  brew info    curl           # 7.87
  brew install curl           # /usr/local/cellar/curl/*/bin/curl

  brew info    erlang         # 25.2.2
  brew install erlang         # /usr/local/cellar/erlang/*/bin/erl

  brew info    git            # 2.39.2
  brew install git            # /usr/local/cellar/git/*/bin/git

  brew info    go             # 1.19.5
  brew install go             # /usr/local/cellar/go/*/bin/go
  
  
  brew info    haskell-stack  # 2.9.3, GHCi 9.4.4
  brew install haskell-stack  # /usr/local/cellar/haskell-stack/*/bin/stack
  
  brew info    cabal-install  # 3.8.1
  brew install cabal-install  # /usr/local/Cellar/cabal-install/3.8.1.0
  
  brew info    ghc@9.2        # 9.2.6
  brew install ghc@9.2        # /usr/local/Cellar/ghc@9.2/9.2.6
  
  
  brew info    java           # 19.0.2
  brew install java           # /usr/local/Cellar/openjdk/19.0.2/bin/java
  
  brew info    leiningen      # 2.10
  brew install leiningen      # /usr/local/cellar/leiningen/*/bin/lein
  
  brew info    make           # 4.4
  brew install make           # /usr/local/Cellar/make/*/bin/gmake
  
  brew info    maven           # 3.9
  brew install maven           # /usr/local/Cellar/maven/3.9.0
  
  brew info    node.js        # 19.7
  brew install node.js        # /usr/local/cellar/node/*/bin/node

  brew info    python3        # 3.10.10
  brew install python3        # /usr/local/cellar/python/*/bin/python3

  brew info    rsync          # 3.2.7
  brew install rsync          # /usr/local/cellar/rsync/*/bin/rsync

  brew info    rust           # 1.67.1
  brew install rust           # /usr/local/cellar/rust/*/bin/rustc

  brew info    scala          # 3.2.2
  brew install scala          # /usr/local/cellar/scala/*/bin/scala
  
  brew info    vapor          # 18.6
  brew install vapor          # /usr/local/cellar/vapor/*/bin/vapor
  
  
- antlr
  antlr4                                                # ANTLR Parser Generator 4.12
  java -jar /usr/local/lib/antlr-4.12.0-complete.jar    # ..
  
  jar  tf   /usr/local/lib/antlr-4.12.0-complete.jar    # toc
  
# antlr4 Hello.g4                  -o ./build/java      # gen java
# antlr4 Hello.g4 -Dlanguage=Swift -o ./build/swift     # gen swift
  
# javac build/java/Hello*.java     -d build/class       # compile java to class
# cd build/class
# grun Hello r1 -tokens                                 # -gui -tokens -tree
                                                        # input string to parse, enter, L+D to enter EOF
  
# grun is an alias to antlr test rig
# java org.antlr.v4.gui.TestRig Hello r1 -tokens        # -gui -tokens -tree
                                                        # -gui launches TestRig java applet, Parse Tree Inspector gui window
                                                        # quit TestRig to exit grun, back to shell
  
  
  // file: NS.g4
  // nested namespace antlr grammar
  // 
  grammar NS;
  
  ns: nsgroup (nsgroup)*
  ;
  
  nsgroup: 'namespace' nsname? nsbody
  ;
  
  nsname: ID
  ;
  
  nsbody: '{' (nsgroup)? '}' |    // nested namespace
          '{' natext* '}'    |    // unnested text
          '{' '}'                 // unnested empty
  ;
  
  natext: (.)+? | UNKNOWN ((.)+? | UNKNOWN)*
  ;
  
  UNKNOWN : (PUNC | DIGITS)
  ;
  
  PUNC: ([.,;:/-] | ADDOP | MULOP)+
  ;
  
  ID: [a-zA-Z]+
  ;
  
  WS: [ \n]+ -> skip
  ;
   
  fragment ADDOP: [\\+]
  ;
  
  fragment MULOP: [\\*]
  ;
  
  fragment ESC: '\\'
  ;
  
  fragment DIGITS: DIGIT (DIGIT)*
  ;
  
  fragment DIGIT: [0-9]
  ;
  
  
  // valid namespace grammar
  // 
     namespace { }
     namespace foo { }
     namespace foo { namespace { } }                  // nested
     namespace foo { namespace bar { } }              // nested
     namespace foo { int x; namespace bar { } }       // nested
     namespace a { } namespace b { } namespace c { }
     namespace foo { xxx }
     namespace foo { 123 }
     namespace foo { // }
     namespace foo { ... }
     namespace foo { 1   2   3 }
     namespace foo { 1 + 2 + 3 }
     namespace foo { x + y }
  
  
  // namespace foo { }
  // output
  // tokens:
    [          |                            |
    [ @0    0:8='namespace'  <'namespace'> 1:0  ]
    [ @1  10:12='foo'        <ID>          1:10 ]
    [ @2  14:14='{'          <'{'>         1:14 ]
    [ @3  16:16='}'          <'}'>         1:16 ]
    [ @4  17:16='<EOF>'      <EOF>         1:17 ]
    ]
  
  // walker
  // 
    enter method  line  token      display     type    ctx text
    enterNs          1  namespace  'namespace'    1    'namespacefoo{}'
    enterNsgroup        namespace  'namespace'    1    'namespacefoo{}'
    enterNsname         foo        ID             6    'foo'
    exitNsname          foo        ID             6    'foo'
    enterNsbody         {          '{'            2    '{}'
    exitNsbody          }          '}'            3    '{}'
    exitNsgroup         }          '}'            3    'namespacefoo{}'
    exitNs              }          '}'            3    'namespacefoo{}'
  
  
  // namespace foo { namespace bar { } }    // nested
  // output
  // tokens:
     [          |                            |
     [ @0    0:8='namespace'  <'namespace'> 1:0  ]
     [ @1  10:12='foo'        <ID>          1:10 ]
     [ @2  14:14='{'          <'{'>         1:14 ]
     [ @3  16:24='namespace'  <'namespace'> 1:16 ]
     [ @4  26:28='bar'        <ID>          1:26 ]
     [ @5  30:30='{'          <'{'>         1:30 ]
     [ @6  32:32='}'          <'}'>         1:32 ]
     [ @7  34:34='}'          <'}'>         1:34 ]
     [ @8  35:34='<EOF>'      <EOF>         1:35 ]
     ]
  
  // walker
  // 
     enter method  line  token      display     type    ctx text
     enterNs          1  namespace  'namespace'    1    'namespacefoo{namespacebar{}}'
     enterNsgroup        namespace  'namespace'    1    'namespacefoo{namespacebar{}}'
     enterNsname         foo        ID             6    'foo'
     exitNsname          foo        ID             6    'foo'
     enterNsbody         {          '{'            2    '{namespacebar{}}'
     enterNsgroup        namespace  'namespace'    1    'namespacebar{}'
     enterNsname         bar        ID             6    'bar'
     exitNsname          bar        ID             6    'bar'
     enterNsbody         {          '{'            2    '{}'
     exitNsbody          }          '}'            3    '{}'
     exitNsgroup         }          '}'            3    'namespacebar{}'
     exitNsbody          }          '}'            3    '{namespacebar{}}'
     exitNsgroup         }          '}'            3    'namespacefoo{namespacebar{}}'
     exitNs              }          '}'            3    'namespacefoo{namespacebar{}}'
  
  
  
  
  # separate lexer and parser
# antlr4 XLexer.g4 XParser.g4                            -o ./build/java
# javac build/java/XLexer*.java build/java/XParser*.java -d build/class
# cd build/class
# grun X ruleX -tokens demo.h
  
  
  // TestXListener.java
  // 
  public class TestXListener {
      
      public static void main(String[] args) throws Exception {
          XListener x = new XListener();
          x.parse();
      }
      
  }
  
  // XListener.java
  // 
  import java.util.*;
  import org.antlr.v4.runtime.*;
  import org.antlr.v4.runtime.tree.*;

  public class XListener extends XBaseListener {
      
      XLexer            lexer;
      XParser           parser;
      ParseTree         tree;
      CommonTokenStream tokenStream;
      
      String file = "foo.h";
      
      
      public void parse() throws Exception {
          CharStream input = CharStreams.fromFileName(file);
          
          lexer       = new XLexer(input);
          tokenStream = new CommonTokenStream(lexer);
          parser      = new XParser(tokenStream);
          
          parser.removeErrorListeners();  // remove ConsoleErrorListener
          parser.addErrorListener(new XParseErrorListener());
          
          tree = parser.ruleX();  // rule name to process
          
          int errorCount = parser.getNumberOfSyntaxErrors();
          if (errorCount > 0) {
              System.out.println("\nParser Error Count: " + parser.getNumberOfSyntaxErrors() + "\n");
          }
          
          // sim to grun -tokens but wo hidden channel tokens, comments #include #define
          // re s:, \[
          //    r:\n[
          System.out.println("\ntokens: " + tokensWithDisplayName(tokenStream.getTokens()) + "\n");
          
          
          // walker header
          System.out.println("enter method                            line    token             type      ctx text");
          
          ParseTreeWalker.DEFAULT.walk(this, tree);
      }
      
      
      String tokensWithDisplayName(List<Token> list) {
          String tokens = list.toString();
          System.out.println("debug raw tokens: " + tokens);
          
          Iterator<Token> it = list.iterator();
          while (it.hasNext()) {
              Token t = it.next();
              int type = t.getType();
              String displayName = parser.getVocabulary().getDisplayName(t.getType());
              
              tokens = tokens.replace(("<" + type + ">"),
                                      ("<" + displayName + ">"));
          }
          
          return tokens;
      }
      
      @Override
      public void enterClassName(XParser.ClassNameContext ctx) {
          System.out.println("enterClassName    " + ctx.start.getLine() + ", " + ctx.start.getText() + ", " + ctx.start.getType() + ", '" + ctx.getText() + "'");
      }
      
  }
  
  
  // XParseErrorListener.java
  // 
  import java.util.*;
  import org.antlr.v4.runtime.*;

  public class XParseErrorListener extends BaseErrorListener {
      
      @Override
      public void syntaxError(Recognizer<?, ?> recognizer,
                              Object offendingSymbol,
                              int line,
                              int charPositionInLine,
                              String msg,
                              RecognitionException e) {
          
          List<String> stack = ((Parser)recognizer).getRuleInvocationStack();
          Collections.reverse(stack);
          
          System.err.println("\nParser Error");
          System.err.println("rule stack: " + stack);
          System.err.println("line " + line + ":" + charPositionInLine + " at " + offendingSymbol + ": " + msg);
      }
      
  }
  
  
  // foo.h
  // 
  namespace Foo {
      
      class Bar;
      
      struct Data {
          int val;
          Bar lib;
      };
      
  }
  
  
  // output
  // tokens:
     [              |                               |
     [ @0        0:8='namespace'   <'namespace'>   1:0  ]
     [ @1      10:12='Foo'         <Identifier>    1:10 ]
     [ @2      14:14='{'           <'{'>           1:14 ]
     [ @3      25:29='class'       <'class'>       3:4  ]
     [ @4      31:33='Bar'         <Identifier>    3:10 ]
     [ @5      34:34=';'           <';'>           3:13 ]
     [ @6      45:50='struct'      <'struct'>      5:4  ]
     [ @7      52:55='Data'        <Identifier>    5:11 ]
     [ @8      57:57='{'           <'{'>           5:16 ]
     [ @9      67:69='int'         <'int'>         6:8  ]
     [ @10     71:73='val'         <Identifier>    6:12 ]
     [ @11     74:74=';'           <';'>           6:15 ]
     [ @12     84:86='Bar'         <Identifier>    7:8  ]
     [ @13     88:90='lib'         <Identifier>    7:12 ]
     [ @14     91:91=';'           <';'>           7:15 ]
     [ @15     97:97='}'           <'}'>           8:4  ]
     [ @16     98:98=';'           <';'>           8:5  ]
     [ @17   105:105='}'           <'}'>          10:0  ]
     [ @18   106:105='<EOF>'       <EOF>          10:1  ]
     ]
  
  // walker
  // 
  // enter method              line  token      display     type    ctx text
     enterTranslationUnit         1  namespace  'namespace'   48    'namespaceFoo{classBar;structData{intval;Barlib;};}<EOF>'
     enterNamespaceDefinition     1  namespace  'namespace'   48    'namespaceFoo{classBar;structData{intval;Barlib;};}'
     enterNsHead                  1  namespace  'namespace'   48    'namespaceFoo'
                                     Foo        Identifier   132    
     enterNsKey                   1  namespace  'namespace'   48    'namespace'
     enterNsName                  1  Foo        Identifier   132    'Foo'
                                                                    
     enterDeclarationseq          3  class      'class'       21    'classBar;structData{intval;Barlib;};'
     enterDeclaration             3  class      'class'       21    'classBar;'
     enterDeclSpecifier           3  class      'class'       21    'classBar'
     enterClassKey                3  class      'class'       21    'class'
     enterClassName               3  Bar        Identifier   132    'Bar'
                                                                    
     enterDeclaration             5  struct     'struct'      66    'structData{intval;Barlib;};'
     enterDeclSpecifier           5  struct     'struct'      66    'structData{intval;Barlib;}'
     enterClassHead               5  struct     'struct'      66    'structData'
     enterClassKey                5  struct     'struct'      66    'struct'
     enterClassName               5  Data       Identifier   132    'Data'
                                                                    
     enterMemberSpecification     6  int        'int'         45    'intval;Barlib;'
                                                                    
     enterMemberdeclaration       6  int        'int'         45    'intval;'
                                     val        Identifier   132    
     enterTypeSpecifier           6  int        'int'         45    'int'
     enterMemberDeclarator        6  val        Identifier   132    'val'
                                                                    
     enterMemberdeclaration       7  Bar        Identifier   132    'Barlib;'
                                     lib        Identifier   132    
     enterTypeSpecifier           7  Bar        Identifier   132    'Bar'
     enterClassName               7  Bar        Identifier   132    'Bar'
     enterMemberDeclarator        7  lib        Identifier   132    'lib'
                                                                    
     exitNamespaceDefinition     10  }          '}'           90    'namespaceFoo{classBar;structData{intval;Barlib;};}'
     exitTranslationUnit         10  <EOF>      EOF           -1    'namespaceFoo{classBar;structData{intval;Barlib;};}<EOF>'
  
  
- bash
# exit  # exit bash 4

  # date format
  date +%H:%M:%S             # 22:52:01
  date '+%m-%d-%y %H:%M:%S'  # 08-28-16 20:19:53
  date '+%m-%d-%y.%H%M%S'    # 08-28-16.201953

  echo $BASH          # /bin/bash
  echo $BASH_VERSION  # 3.2.57(1)-release
                      # 4.4.5(1)-release

  bash --version      # 3.2.57(1)-release
                      # 4.4.5(1)-release

  echo $HOME          # /users/a
  echo $HOSTNAME      # h9000
  echo $RANDOM        # 10273, (0-32767)

  echo $PATH  # /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
  PATH="${PATH}:/users/a/dev/scala/bin"
  export PATH
  echo $PATH

  echo -e "foo\nbar"

  for x in {1..10}
  do
      echo $x
  done

  # bash array
  declare -a data=("foo" "bar" "...")
  for x in "${data[@]}"
  do
      echo $x
  done

  cal
  cal    2017
  cal 10 2017
  cal -y


  # --------------------------------------
  # .zshrc
  # .bash_profile
  
  # set min prompt
  export PS1='$ '
  
  # alias
  alias czs='cat ~/.zshrc'
  
  alias  cl='clear;'
  alias xfc='~/applications/fileCompare'          # xfc f1 f2, do not use fc, a built-in command, see: man zshbuiltins or man fc
  alias  od='/usr/bin/opendiff'                   # filemerge, od f1 f2
  alias ovs='open -a Visual\ Studio\ Code.app'    # open visual studio code
  alias oxc='open -a Xcode'                       # open xcode
  alias lss='ls -al'
  alias lsv='ls -al /volumes'
  
  alias antlr4='/usr/local/Cellar/openjdk/19.0.2/bin/java -Xmx500M -cp "/usr/local/lib/antlr-4.12.0-complete.jar:$CLASSPATH" org.antlr.v4.Tool'
  alias   grun='/usr/local/Cellar/openjdk/19.0.2/bin/java -Xmx500M -cp "/usr/local/lib/antlr-4.12.0-complete.jar:$CLASSPATH" org.antlr.v4.gui.TestRig'
  
  
  # git alias
  alias gb='    git branch;'
  alias gbr='   git branch -r;'                   # show remote branches
  alias gcem='  git config --global user.email;'  # john@dev.com
  alias gds='   git diff stash;'
  alias gl='    git log --name-status;'
  alias glm='   git log --name-status --author=john;'
  alias glp='   git log --abbrev-commit --pretty=oneline;'
  alias glpm='  git log --abbrev-commit --pretty=oneline --author=john;'
  alias gmt='   git mergetool;'
  alias gp='    git pull;'
  alias gs='    git status;'
  alias gsl='   git stash list;'
  alias gsll='  git stash list --date=local;'
  alias gslno=' git stash list --name-only;'


  function filehashlog() {
      set -x
      filehash $1
      set +x
  }

  function filehash() {
      openssl sha1 $1
  }

  function fhash() {
      filehash $1 | egrep -o "\b([a-z0-9]+)$"
  }

  function fcomp() {
      local fh1=$(fhash $1)
      local fh2=$(fhash $2)

      printf "file compare sha1 hash\n%s = %s\n%s = %s\n\n" $fh1 $1 $fh2 $2

      if [ $fh1 == $fh2 ]
      then
          printf "files are equal\n"
      else
          printf "files are NOT equal\n"
      fi
  }
  
  
  # file open chrome
  # foc f.c
  #
  function foc() {
      open "$1" -a Google\ Chrome.app
  }
  
  # file open preview
  # fop a.png
  # 
  function fop() {
      open "$1" -a preview
  }
  
  # file open safari
  # fos f.c
  #
  function fos() {
      open "$1" -a Safari.app
  }
  
  # file open text edit
  # fote f.txt
  # 
  function fote() {
      open "$1" -a textedit
  }
  
  # file open visual studio code
  # fovs f.c
  #
  function fovs() {
      open "$1" -a Visual\ Studio\ Code.app
  }
  
  # file open xcode
  # foxc f.c
  # 
  function foxc() {
      open "$1" -a xcode
  }


  # --------------------------------------
  # !/bin/bash
  # backup copy file w/timestamp script
  # bash backupFileScript "file 1.txt"

  if (($# == 1))  # one param
  then
      vTimestamp=$(date "+_%m%d%y_%H%M%S.txt")
      vBackupFilename=$1$vTimestamp

      echo "file:   $1"                # file 1.txt
      echo "backup: $vBackupFilename"  # file 1.txt_100713_203059.txt

      # quote for filename space chars
      cp "$1" "$vBackupFilename"
  else
      printf "user error\n1 filename param is required\n"
      echo "params: ${#}"
  fi

  # --------------------------------------
  # !/bin/bash
  # 2013 Mac CPU Architecture Script
  # bash cpuScript "intel core i7"
  # returns CPU architecture, either 32 or 64 bit, based on processor name
  # http://support.apple.com/kb/HT3696

  # bug param count wrong for string w/spaces
  # bash cpuScript $(system_profiler SPHardwareDataType | grep -i 'processor name:' | sed -e 's/ *Processor Name: *//')
  # params: 3
  # version 2.0
  # 64-bit CPU Intel

  # fix wrap command-substitution $() in double quotes to send 1 string param
  # bash cpuScript "$(system_profiler SPHardwareDataType | grep -i 'processor name:' | sed -e 's/ *Processor Name: *//')"
  # params: 1
  # version 2.0
  # 64-bit CPU Intel Core i7

  echo "params: ${#}"

  ver="2.0"
  echo "version $ver"

  # lowercase
  v1=$(echo $1 | tr '[:upper:]' '[:lower:]')

  case $v1 in
    "intel core solo"|"intel core duo") echo "32-bit CPU $1"
                                        ;;
    *)                                  echo "64-bit CPU $1"
                                        ;;
  esac

  # --------------------------------------
  
  bash base conversions
  int to binary  echo 'obase=2;  256' | bc       # 100000000
  int to hex     echo 'obase=16; 256' | bc       # 100
  int to hex     printf '%x\n'   256             # 100
  int to octal   echo 'obase=8;  256' | bc       # 400
  binary to int  echo 'ibase=2; 100000000' | bc  # 256
  hex to int     echo $((0x100))                 # 256
  hex to int     echo 'ibase=16; 100' | bc       # 256
  hex to int     printf '%d\n' 0x100             # 256
  octal to int   echo 'ibase=8; 400' | bc        # 256
  
  
- bc calculator
  echo 2+2 | bc
  bc     # bc 1.06
  bc -h  # help
  2 + 2  # ...
  quit
  
  
- clojure (leiningen)
  /usr/local/bin/lein -v  # Leiningen 2.10 on Java 19.0.2 OpenJDK 64-Bit Server VM
  
  lein -h
  quit
  L D  quit
  (quit)
  
  lein repl  ;;Clojure 1.11.1
  quit
  
  (+ 1 2 3 4 5 6 7 8 9 10)  ;;55
  (def nums [1 2 3 4 5 6 7 8 9 10])
  (apply + nums)  ;;55
  
  (for [x [:a :b], y (range 5) :when (odd? y)] [x y])  ;;([:a 1] [:a 3] [:b 1] [:b 3])
  
  (doseq [x [:a :b], y (range 5) :when (odd? y)] (prn x y))  ;;:a 1
                                                               :a 3
                                                               :b 1
                                                               :b 3
                                                               nil
  
  (def a 42)
  a        ;;42
  (+ a)    ;;42
  (+ a 2)  ;;44
  (/ a 2)  ;;21
  (* a 2)  ;;84

  (take 10 (range))                 ;;(0 1 2 3 4 5 6 7 8 9)
  (map inc (take 10 (range)))       ;;(1 2 3 4 5 6 7 8 9 10)
  (map #(+ % 2) (take 10 (range)))  ;;(2 3 4 5 6 7 8 9 10 11)
  
  
- curl
  curl -V  # 7.79.1
  curl http://curl.haxx.se/docs/manpage.html
  curl http://www.gutenberg.org/cache/epub/2600/pg2600.txt -o "~/downloads/tolstoyWarAndPeace.txt"  # download file
  curl http://a.com/a.jpg                                  -o  ~/downloads/a.jpg
  
  
  # http get
  curl                          \
  -H "Accept: text/html"        \
  -H "Content-Type: text/html"  \
  -H "Cookie: foo=1"            \
  -o "~/downloads/a.com.txt"    \
  -v                            \
  https://a.com
  
  
  # http post json body w/certificate
  curl                                 \
  -H "Accept: application/json"        \
  -H "Content-Type: application/json"  \
  -H "Content-Length: 17"              \
  -H "Cookie: foo=1"                   \
  -H "Cookie: bar=1"                   \
  --cert /etc/ssl/certs/file.crt       \
  --key  /etc/ssl/certs/file.key       \
  -X POST                              \
  -d '{ "foo" : "bar" }'               \
  -v                                   \
  https://a.com
  
  
  # http get raw github source file
  curl                                     \
  -H "Accept: application/vnd.github.raw"  \
  -H "Content-Type: text/plain"            \
  -o "~/downloads/Date.swift"              \
  -v                                       \
  https://raw.githubusercontent.com/expressionsoftware/Lib/main/Sources/Lib/Date.swift
  
  
- erlang
  /usr/local/bin/erl +V  # Erlang (SMP,ASYNC_THREADS,HIPE) (BEAM) emulator version 6.3
  /usr/local/bin/erlc -help
  
  erl     # Erlang/OTP 17 [erts-6.3.1] [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
  help().
  
  LG      switch command
  LG h|?  help
  LG i    interrupt
     c    connect
  LG q    quit
  
  q().    quit
  
  code:root_dir().  %"/usr/local/cellar/erlang/17.4/lib/erlang"
  erlang:loaded().  %loaded erlang modules, current and/or old code, including preloaded modules
  erlang:memory().
  erlang:system_info(process_limit).  %262144
  
  os:version().    %{14,1,0}
  os:cmd("date").  %"Sat Jan 10 05:39:56 MST 2015\n"
  
  io:format("hello Erlang!~n").
  
  self().
  process_info(self()).
  process_info(self(), links).
  
  processes().
  length(processes()).
  
  pwd().
  ls().
  cd("/users/a/erlang").
  
  P1 = list_to_pid("<0.281.0>").  %<0.281.0>
  is_pid(P1).  %true
  
  b().   %var bindings
  f().   %forget all vars
  f(X).  %forget X var
  
  string:concat(string:concat("foo", " "), "bar").  %"foo bar"
  io:format("~s~n", ["foo bar"]).  %foo bar
  io:format("~w~n", ["foo bar"]).  %[102,111,111,32,98,97,114]
  
  Sq = fun(X) -> X * X end.
  Sq(8).  %64
  math:sqrt(64).  # 8.0
  math:pi().      %3.141592653589793
  
  now().                                                  %{1420,849205,145416}  timestamp from 1-1-1970 GMT
  time().                                                 %{17,20,5}
  erlang:localtime().                                     %{{2015,1,9},{17,20,5}}
  erlang:localtime_to_universaltime(erlang:localtime()).  %{{2015,1,10},{0,20,5}}
  
  T = lists:seq(0, 9).  %[0,1,2,3,4,5,6,7,8,9]
  T.
  length(T).  %10
  
  AbcSha512 = crypto:hash(sha512, "abc").  %<<221,175,53,161,147,97,122,186,204,65,115,73,174,32,65,
                                              49,18,230,250,78,137,169,126,162,10,158,238,230,75,...>>
  is_binary(AbcSha512).  %1
  binary_to_list(AbcSha512).
  length(binary_to_list(AbcSha512)).  %64
  lists:foreach(fun(B) -> io:format("~w ", [B]) end, binary_to_list(AbcSha512)).
  binary:last(AbcSha512).  %159
  io:format("~s~n", [[io_lib:format("~2.16.0B ",[X]) || <<X:8>> <= AbcSha512 ]]).
  
  L1 = ["foo", "bar", "foo", "foo++", "FOO", "abc"].
  lists:foreach(fun(X) -> io:format("~s~n", [X]) end, L1).
  lists:foreach(fun(X) -> io:format("~s~n", [X]) end, lists:sort(L1)).  %FOO
                                                                         abc
                                                                         bar
                                                                         foo
                                                                         foo
                                                                         foo++

  %guid, 2^82 unique
  make_ref().  %#Ref<0.0.0.393>
  
  
- # grep  # regex
# grep -ri -e 'foo'       --include '*cpp*'
# grep -ri -E '\[\]'    . --include=*.h
# grep -ri -E 'min|max' .

# fgrep -ri 'foo' .                   # all files
# fgrep -ri 'foo' . --include='*.h'
# fgrep -i  'foo' /users/a/file.txt

  -n --line-number
  -l --files-with-matches
  -c --count
  
  
- haskell
  ghci
  :?  help
  :q  quit
  -- haskell comment
  
  :show paths
  current working directory:  /users/a
  module import search paths: .
  
  
- java
  which java  # /usr/bin/java
  
  java -help
  java -version  # openjdk version "19.0.2" 2023-01-17
                 # OpenJDK Runtime Environment Homebrew build 19.0.2
                 # OpenJDK 64-Bit Server VM
  
  echo $CLASSPATH
  echo $JAVA_HOME
  
  javac -help
  javac Hello.java
  java  Hello
  
  java -X
  
  jar --help
  jar tf foo.jar  # toc
  
  
  https://www.java.com/releases
  
  
- # less text viewer
  less -?  # --help
  less -V  # --version
  -i  # --ignore-case  # ignore case in searches that do not contain uppercase
  -I  # --IGNORE-CASE  # ignore case in searches and patterns
  /regex search string
  less iPhone.storyboard
  q  # quit
  
  
- LLDB
  http://lldb.llvm.org/lldb-gdb.html
  
    help
    # comment
    p @import Foundation
    p sizeof(int)
    p width
    po foo
    po @"foo".length

    po FooType $x = (FooType)1  # cast int to enum Foo

    po [0x00000000 description]

    po node.position  # (x = 0, y = 0, z = -10)
    po node.rotation  # (x = 1, y = 0, z = 0, w = 6.28318548)

    po type(of: self.view)
    po self.view.superclass
    po [self.view class]
    po [self.view superclass]

    po cell.contentView.subviews

    po _stdlib_getDemangledTypeName(x)  # Swift.Array<Swift.Int>

    p @import UIKit
    po view.bounds.size.width
    po indexPath.row
    po indexPath.section
    po [refreshControl actionsForTarget:self forControlEvent:UIControlEventValueChanged]

    p self.view.frame
    p (CGRect)[self.view frame]

    po $arg1  # use w/exception breakpoint

    po [NSUserDefaults.standardUserDefaults dictionaryRepresentation]

    po Thread.callStackSymbols

    po request.allHTTPHeaderFields

    expr width = 25
    expr debugFlag = true  # reset

    fr v
    frame variable s  # (__NSCFString *) s = 0x0 @"foo"
    frame variable k  # (__NSCFConstantString *) k = 0x0 @"bar"
    frame variable d  # (__NSDictionaryI *) d = 0x0 4 key/value pairs
  
    
- maven
  mvn -h
  mvn -v  # 3.9  # Maven home: /usr/local/Cellar/maven/3.9.0/libexec
  
  
- node.js
  /usr/local/bin/node -v  # v19.7
  
  node --help
  node -e "require('repl').start({ignoreUndefined: true})"
  node helloNode.js
  
  # repl
  .break
  .clear
  .exit
  .help
  .save session.js
  .load session.js
  
  LC  terminate current command, twice to exit
  LD  exit
  
  a = [1, 2, 3]; a.forEach(function(x){ console.log(x); });
  
  
  //--------------------------------------
  // node web server, min
  // https://localhost:8443
  // touch web/public/favicon.ico
  
  var _fs    = require('fs'),
      _https = require('https'),
      _url   = require('url')
  
  // lib
  
  _https.createServer(httpsOptions, function(req, res) {
      const url     = _url.parse(req.url, true)
      const fullUrl = fullUrlFunc(req, url.pathname)
      
      console.log("\nrequest url:", fullUrl)
   // console.log('request headers:', req.headers)
      
      const response = '{ "hello" : "Node" }'  //
      
      res.writeHead(200, { 'Content-Type' : 'application/json' })
      res.end(response)
      
  }).listen(8443)
  
  //--------------------------------------
  // node web server
  
  const _fs    = require("fs"),
        _https = require("https"),
        _path  = require("path"),
        _url   = require("url"),
        
        rootDir = "web/public"
  
  // lib
  
  function serveFile(res, path) {
      const file    = rootDir + path
      const fileExt = fileExtension(file)
      
      console.log("serve file:", file)
      
      _fs.readFile(file, function(err, data) {
          if (fileExt == "css") {
              res.writeHead(200, { "Content-Type" : "text/css" })
          }
          else if (fileExt == "js") {
              res.writeHead(200, { "Content-Type" : "text/javascript" })
          }
          else {
              res.writeHead(200, { "Content-Type" : "text/html" })
          }
          
          res.write(data)
          res.end()
      })
  }
  
  function serveTextFile(res, path) {
      const file = rootDir + path
      
      console.log("serve text file:", file)
      
      _fs.readFile(file, function(err, data) {
          res.writeHead(200, { "Content-Type" : "text/plain" })
          res.write(data)
          res.end()
      });
  }
  
  function response_404(res, fullUrl) {
      res.statusCode    = 404
      res.statusMessage = "Not found"
      const html = '<!doctype html><html><head><title>404</title><meta charset=utf-8><link href="/style.css" rel="stylesheet"></head><body style="margin: 40px 60px 50% 60px;"><h1>Error</h1><br/><h2>Status Code: 404<br/>Resource not found: ' + fullUrl + '</h2></body></html>';
      res.end(html)
  }
  
  function fileExists(path) {
      const relPath = "./" + rootDir + path
      
      if (fs.existsSync(relPath)) {
          return true
      }
      
      return false
  }
  
  function fileExtension(file) {
      const basename = _path.basename(file)
      const firstDot = basename.indexOf(".")
      const lastDot  = basename.lastIndexOf(".")
      const fileExt  = _path.extname(basename).replace(/\.([a-z0-9]+).*/i, "$1")  // css, htm
      
      if (firstDot === lastDot) {
          return fileExt
      }
      
      return basename.slice(firstDot, lastDot) + fileExt
  }
  
  _https.createServer(httpsOptions, function(req, res) {
      const url     = _url.parse(req.url, true)
      const fullUrl = fullUrlFunc(req, url.pathname)
      
      console.log("\nrequest url:", fullUrl)
   // console.log('request headers:', req.headers)
      
      if (url.pathname == "/") {
          serveFile(res, "/index.htm")
      }
      else if (fileExists(url.pathname) === false) {
          response_404(res, fullUrl)
      }
      else if (url.pathname.toLowerCase().includes("/source/")) {
          serveTextFile(res, url.pathname)
      }
      else {
          serveFile(res, url.pathname)
      }
      
  }).listen(8443)
    
  //--------------------------------------
  // node web server lib
  
  var httpsOptions = {
      key:  fs.readFileSync("/etc/ssl/localhost/localhost.key.rsa"),
      cert: fs.readFileSync("/etc/ssl/localhost/localhost.crt")
  }
  
  function fullUrlFunc(req, fullUrl) {
      return (req.connection.encrypted ? "https://" : "http://") + req.headers.host + fullUrl
  }
  
  
- openssl
  SHA File Hash
  https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/openssl.1ssl.html
# openssl sha512 file
  # SHA512(/Users/j19/file)= ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f
  
  
- # pbcopy
  # use w github setup
# pbcopy < ~/.ssh/id_rsa.pub    # Public Key, share
# pbpaste
  
  
- ps – process status
  ps aux
  ps aux <pid>
  
  
- python

  python  -V  # 2.7.16  /usr/bin/python
  python3 -V  # 3.9.6   /usr/local/bin/python3
  python3 -V  # 3.9.6   /usr/local/bin/python3 -> /usr/local/cellar/python3/3.9.6/bin/python3

  python3 --help
  python3 -c "print('foo')"

  quit()  # LD

  pip3 -V  # pip 9.0.1   /usr/local/lib/python3.6/site-packages (python 3.6)
           # pip 19.2.3  /applications/xcode.app/contents/developer/library/frameworks/python3.framework/versions/3.8/lib/python3.8/site-packages/pip (python 3.8)


  sorted(['a', 'c', 'b'])           # ['a', 'b', 'c']
  sorted(['a', 'c', 'B'])           # ['B', 'a', 'c']
  sorted(['', ' ', '.', '/', '_'])  # ['', ' ', '.', '/', '_']
  sorted(['a', 'a.', 'a/', 'a_'])   # ['a', 'a.', 'a/', 'a_']
  sorted([1, 10, 9, 2, 20, 3])      # [1, 2, 3, 9, 10, 20]


  for x in [' ', '.', '/', '_']:
      print('\'{}\' = {}'.format(x, ord(x)))  # ' ' = 32
                                                '.' = 46
                                                '/' = 47
                                                '_' = 95


  # --------------------------------------
  # python file hash script, fileHash.py
  import hashlib
  def getFileHash(filePath):
      md5 = hashlib.md5()
      sha1 = hashlib.sha1()
      sha224 = hashlib.sha224()
      sha256 = hashlib.sha256()
      sha384 = hashlib.sha384()
      sha512 = hashlib.sha512()

      with open(file, 'rb') as f:
          for chunk in iter(lambda: f.read(8192), b''):  # b'' = bytes literal
              md5.update(chunk)
              sha1.update(chunk)
              sha224.update(chunk)
              sha256.update(chunk)
              sha384.update(chunk)
              sha512.update(chunk)

      print('md5: ' + md5.hexdigest())
      print('sha1: ' + sha1.hexdigest())
      print('sha224: ' + sha224.hexdigest())
      print('sha256: ' + sha256.hexdigest())
      print('sha384: ' + sha384.hexdigest())
      print('sha512: ' + sha512.hexdigest())

  print('file hash')
  file = input('enter filename: ')  # /users/a/file.txt
  getFileHash(file)

  # --------------------------------------
  # example
  python3 ~/fileHash.py

  # file hash
  # enter filename: /users/a/file.txt  # abc

  # md5:    900150983cd24fb0d6963f7d28e17f72
  # sha1:   a9993e364706816aba3e25717850c26c9cd0d89d
  # sha224: 23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7
  # sha256: ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
  # sha384: cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7
  # sha512: ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f

  # --------------------------------------
  # python azure blob storage sdk
  # http://azure.microsoft.com/en-us/documentation/articles/storage-python-how-to-use-blob-storage/
  # http://azure.microsoft.com/en-us/documentation/articles/python-how-to-install/
  # https://pypi.python.org/pypi/azure

  pip3 search azure
  pip3 install azure
  ls -l /usr/local/lib/python3.5/site-packages

  from azure.storage.blob import BlobService
  blob_service = BlobService(account_name='__', account_key='__')

  blob_containers = blob_service.list_containers
  for bc in blob_containers():
      print(bc.name)

  blobs = blob_service.list_blobs('blobs')
  for b in blobs:
      print(b.name)

  # upload blob
  blob_service.put_block_blob_from_path('blobs',
                                        'foo.txt',
                                        '/users/a/temp.txt',
                                        x_ms_blob_content_type='application/txt')

  # uploaded blob url
  http://foo.blob.core.windows.net/blobs/foo.txt

  blob_service.delete_blob('blobs', 'foo.txt')
  
  
- R
  /library/frameworks/r.framework/resources/r --version
  
  R.Version()
  R.Version()$version   # 4.2.2 (2022-10-31)"
  R.Version()$nickname  # Innocent and Trusting
  
  ?help  # q
  quit()
  
  Sys.getenv()
  
  ls()
  ?ls
  ls(pattern = "^m.*")
  
  ?rm
# rm(m1)
# rm(list = ls())  # remove all
  
  x = "foo"
  nchar(x)  # length 3
  
  ?matrix
  ?vector
  
  
- ruby
  /usr/bin/ruby -v  # 2.6.10p210 (2022-04-12 revision 67958) [universal.x86_64-darwin21]
  ruby --help
  
  
- # sed substitute replace
  sed -e s/foo/BAR/  file.txt
  sed -e s/foo/BAR/g file.txt
  
  # split
  echo foo bar bam | sed 's/ /\n/g'
  # foo
  # bar
  # bam
  
  # --------------------------------------
  # sed script html encode file
  sed -f script.txt file.txt
  sed -f script.txt file.txt > file.txt.out
  s/\&/\&amp;/g
  s/</\&lt;/g
  s/>/\&gt;/g
  s/"/\&quot;/g
  s/'/\&#39;/g

  # --------------------------------------
  # sed script html decode file
  s/\&amp;/\&/g
  s/\&lt;/</g
  s/\&gt;/>/g
  s/\&quot;/"/g
  s/\&#39;/'/g
  
  
- SSH Keys
# man ssh-keygen
# man ssh-agent
# man ssh-add
  
# ls -al ~/.ssh/
# ls -al /Users/*/.ssh/
  
# ls ~/.ssh/id_rsa.pub    # Public Key, share
# ls ~/.ssh/id_rsa        # Private Key, do not share
# ls ~/.ssh/config
  
# cat ~/.ssh/id_rsa.pub  # Public Key, share
# cat ~/.ssh/id_rsa      # Private Key, do not share
# cat ~/.ssh/config
  
  
  ## Generate an SSH Key Pair
  
# ssh-keygen -t rsa -b 4096 -C "email@foo.com"
  
  
  ## Add SSH Private Key to ssh-agent
  
# eval "$(ssh-agent -s)"      # Start the ssh-agent in the background
# ssh-add -K ~/.ssh/id_rsa    # Add your SSH Private Key to the ssh-agent and store your passphrase in the keychain
                              
                              # Enter passphrase for /Users/a/.ssh/id_rsa:
                              # Identity added:      /Users/a/.ssh/id_rsa (email@foo.com)
  
  
  
  # Copy SSH Public Key and add to GitHub account, one-time setup
  
  
- translate
  delete carriage return chars ^M
# tr -d '\r' <  /users/a/bookmarks.html  >  /users/a/bookmarks_2.html
  
- translate regex replacement, lowercase uppercase
  echo "Foo Bar 123" | tr 'A-Z' 'a-z'  # foo bar 123
  echo "Foo Bar 123" | tr 'a-z' 'A-Z'  # FOO BAR 123
  echo 'Foo Bar 123' | tr '0-9' '#'    # Foo Bar ###

  # lowercase
  echo "Foo" | tr '[:upper:]' '[:lower:]'

  # uppercase
  echo "Foo" | tr '[:lower:]' '[:upper:]'
  
  
- vim
  # 9.0.1023
  
# vim f.txt
  
  :help
  :q           # quit, exit, escape from :help
  esc          # normal mode
  
  .            # repeat command
  b            # move 1 word back
  dd           # delete line
  dw           # delete word under cursor
  i            # insert mode
  u            # undo
  w            # move 1 word forward
  
  :open f.txt
  :w    f.txt  # save
  :x           # save (if changed) and quit
  
  :split           # h
  :vertical split  
  L+w w            # nav windows
  L+w q            # close current window, split
  
  :ls
  :colorscheme torte  # b, zellner w
  
  
- line word count
  wc -lw main.storyboard


- macOS
  - connected servers/volumes
    ls -1   /volumes/
    ls -Alt /volumes/serverName/folder/

  - apps
    ls -1 /applications

    open -a /applications/textEdit.app 'file.txt'
    open -a /applications/xcode.app    'file.txt'

    - run app executable from command line
    # ./app

    - fileMerge diff app
      opendiff file1 file2

  - diff
    compare directories
    diff -rq   ./dir1  ./dir2  # show files that are diff
    diff -rqs  ./dir1  ./dir2  # show files that are same

  - defaults read/write plist
    - view app bundle info
      defaults read demo.app/info.plist CFBundleIdentifier  # com.foo.demo
      defaults read demo.app/info       CFBundleVersion

      defaults read /users/a/Library/Developer/CoreSimulator/Devices/*/Data/Containers/Bundle/Application/*/.com.apple.mobile_container_manager.metadata.plist  MCMMetadataIdentifier  # com.foo.demo

    - show hidden files
      defaults read  com.apple.finder AppleShowAllFiles
      defaults write com.apple.finder AppleShowAllFiles YES  # NO
    # killall Finder

  - plutil read/write plist
    plutil -p            info.plist
    plutil -convert xml1 info.plist -o -  # print plist as xml

  - config vars
    getconf DARWIN_USER_CACHE_DIR  # /var/folders/a0/aaa000/C/

  - file flags
    ls -lO
    chflags   uchg file  # lock
    chflags nouchg file  # unlock

    chflags -R   uchg /dir  # lock
    chflags -R nouchg /dir  # unlock

  - extended attributes
  # ls -l ~/downloads/                                      # list file or dir, extended attributes are indicated by an @ char at the end of the ownership and permissions info
  # -rw-r--r--@  1 apaak  staff  1024 Sep 12 10:00 foo.app

    xattr                         ~/downloads/foo.app
  # xattr -p com.apple.quarantine ~/downloads/foo.app  # print attribute, file quarantine
  # xattr -d com.apple.quarantine ~/downloads/foo.app  # delete attribute
  # xattr -c                      ~/downloads/foo.app  # delete all attributes, clear
  # xattr -rc                     ~/downloads          # delete all attributes from dir and files

  - change file modes
    u user   (owner)
    g group
    o other
    a all    (everyone, ugo)

  # chmod 700   ~/downloads/foo.app
  # chmod u=rwx ~/downloads/foo.app
  # chmod o-rwx ~/downloads/foo.app

    u   g   o    octal
    rwx rwx rwx  mode
    100 000 000  400    r   user
    100 100 100  444    r   all
    110 000 000  600    rw  user
    111 000 000  700    rwx user

  - file commands
    # set file create modified date
    touch -t 201701020000 /users/a/file

    # copy file
  # cp file1.txt file2.txt

    # copy folder
  # cp -npR ~/temp ~/backup                    # mac
  # cp -nR  ~/temp /volumes/10.0.0.100/backup  # win
    
    # cut
  # echo "a1 a2 a3 ax\nb1 b2 b3 b4 b5" | cut -f 1     -w
  # echo "a1 a2 a3 ax\nb1 b2 b3 b4 b5" | cut -f 1,3   -w   # output is tab delimited
                                                           # a1	a3
                                                           # b1	b3
  # echo "a1 a2 a3 ax\nb1 b2 b3 b4 b5" | cut -f 1-4   -w
  # echo "a1 a2 a3 ax\nb1 b2 b3 b4 b5" | cut -f 1-5   -w
  # echo "a1 a2 a3 ax\nb1 b2 b3 b4 b5" | cut -f 1-10  -w

  # echo "a0;a1 a2\nb0  b1 b2; b3"     | cut -f 1 -d ';'  # a0
                                                          # b0  b1 b2
    
    
    # rename/move file
  # mv file1.txt file2.txt

    # batch file rename w/sed regex, test w/echo
  # ls * | sed -e 'p;s/foo/bar/' | xargs -n2 echo  # mv

    # remove file
  # rm tempFile.txt

    # remove folder
  # rm -dfr tempFolder

    # create parent intermediate folders path
  # mkdir -p ~/dev/c

    # sort file
  # sort file1.txt -o file2.txt

    # list files
    ls -lt    ~/temp
    ls -ltT   ~/temp  # seconds
    ls -1lhRt ~/temp
    ls -l
    ls -1             # file names
    ls -1R            # file names, recursive
    ls * | xargs -n1

    du -ach ~/Library/Developer/Xcode/DerivedData/*/Build/Products/Debug/cocoa.app

    # file search, default recursive
  # sudo find /  -iname '*.app'

  # find .  -iname '*.h'
  # find .  -iname '*.txt'  -depth 1     # top level files
  # find .  -iname '*.txt'  -maxdepth 2  # all files up to max depth
  # find .  -iname '*.txt'  -depth 2     # only depth 2 files
  # find ~  -iname 'java'
  # find ~/Library/Developer/Xcode/DerivedData/*/Build/Products/Debug/cocoa.app -type f

    # find and delete files
  # find .  -iname '.ds_store'  -type f
  # find .  -iname '.ds_store'  -type f  -exec rm  {} \;
  # find .  -iname '.ds_store'  -type f  -print0 | xargs -0  rm


    # find and delete git folders
  # find .  -iname '.git'   -type d                                    # find only
  # find .  -iname '.xgit'  -type d  -print0 | xargs -0       rm -dfr
  # find .  -iname '.xgit'  -type d  -print0 | xargs -0  sudo rm -dfr

    # delete git folders
  # rm -dfr .xgit

  - unzip
    https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/unzip.1.html
    
    
  - lipo
    lipo /users/a/lib.a -info  # Non-fat file: /users/a/lib.a is architecture: x86_64
    
    
  - make
    brew: GNU "make" has been installed as "gmake"
    gmake -v  # GNU Make 4.4, Built for x86_64-apple-darwin21.6.0
    
    gmake c_lean                  # WARN "clean" deletes executable and .o files
    gmake build  --file=Makefile
    
    
  - nm
    # display name list (symbol table)
    # llvm symbol table dumper
    
    nm --help
    nm --version                                  # apple llvm 14
    nm --defined-only             /users/a/lib.a
    nm --defined-only --demangle  /users/a/lib.a
    
    #    /Library/Developer/CommandLineTools/usr/bin/llvm-nm
    # cd /Library/Developer/CommandLineTools/usr/bin/
    #                                              ./llvm-nm -version  # apple llvm 14
    
    
  - otool
    # object file display tool
    
    otool -h  /users/a/lib.a
    otool -D  /users/a/lib.a
              Archive : /users/a/lib.a
                        /users/a/lib.a(fooClass.o):
    

- macOS
- crash reports
  - iOS
    Xcode -> Window -> Devices and Simulators (CS 2)
    View Device Logs
    
    or
    1. Catalina: Sync device with Finder Locations
         Mojave: Sync device with iTunes
    2. open    ~/Library/Logs/CrashReporter/MobileDevice
    3. ls -alt ~/Library/Logs/CrashReporter/MobileDevice/iphone/*.crash
  
  
- disk util
  diskutil list
  diskutil cs list
  diskutil info /volumes/vol1
  diskutil eraseVolume  JHFS+  untitled_usb_drive  "/volumes/a usb drive"
  
  - create macOS bootable install usb drive
    diskutil eraseVolume  JHFS+  untitled_usb_drive  "/volumes/usb drive to erase and use"
    
    sudo "/Applications/Install macOS 12 Beta.app/contents/resources/createinstallmedia"      --volume /volumes/untitled_usb_drive  # Monterey
    sudo "/Applications/Install macOS High Sierra.app/contents/resources/createinstallmedia"  --volume /volumes/untitled_usb_drive  --applicationpath "/Applications/Install macOS High Sierra.app"
    
    - use bootable install usb drive
      reboot, hold the Option key while booting to launch the Startup Manager, select the usb drive as the startup disk to begin install
  
  
- ip address
  ifconfig
  ifconfig | grep "inet "
  
  - spoof mac address
    get current mac address and interface name with Option + Click on Wifi icon in menu toolbar
    use your actual interface name, eg en0, en1, en2
  # networksetup -getmacaddress en0
  # sudo ifconfig en0 ether 00:00:00:00:00:00
  
  
- network setup
  networkSetup -getComputername
  networkSetup -printCommands
  networkSetup -listAllNetworkServices
  networkSetup -getInfo wi-fi  # wifi network service, ip address
  https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man8/networksetup.8.html
  
  
- sound processing
  # afinfo soundFile.m4a
  # afConvert -f caff -d aac soundFile.m4a soundFile.caf
  
  
- sysctl hw.machine  # hw.machine: x86_64
  
  
- system diagnostics
# sudo sysdiagnose xcode
  /var/tmp/sysdiagnose_2013.10.13_15-00-00-MDT_Xcode.tar.gz  # output
  https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/sysdiagnose.1.html
  
  
- system_profiler
  system_profiler -listDataTypes
  system_profiler SPStorageDataType
  system_profiler SPSoftwareDataType  # System Software Overview
  
  System Version:  macOS 13.2 (22D49)
  Kernel Version:  Darwin 22.3
  Boot Volume:     Vol
  Boot Mode:       Normal
  Time since boot: 1 day 4:04
  Computer Name:   dadoes
  User Name:       rick deckard (rickdeckard)
  
  system_profiler SPHardwareDataType
  system_profiler SPHardwareDataType | grep -i 'processor name:' | sed -e 's/ *Processor Name: *//'
  https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man8/system_profiler.8.html
  
  
- versions
    14    Sonoma         
    13    Ventura        2022
    12    Monterey       
    11    Big Sur        2020
    10.15 Catalina       
    10.14 Mojave         2018
    10.13 High Sierra    
    10.12 Sierra         2016  macos
    10.11 El Capitan           
    10.10 Yosemite       2014  
    10.09 Mavericks            
    10.08 Mountain Lion  2012  os x
    10.07 Lion                 
    10.06 Snow Leopard   2010  
    10.05 Leopard              
    10.04 Tiger          2008  mac os x
  
  
- xcode 
  # beta, bash script
  for _ in {1..10}
  do
      killall ReportCrash
      killall SourceKitService
      killall "Interface Builder Cocoa Touch Tool"
  done
  
  
- xcodebuild
  xcodebuild -help
  /usr/bin/xcodebuild -showBuildSettings
  xcodebuild -showsdks
  xcodebuild -dry-run -project app.xcodeproj
  xcodebuild -list -project app.xcodeproj
  xcodebuild -showBuildSettings -project app.xcodeproj
  
  # xcodebuild -showBuildSettings -project app.xcodeproj | less
  
  
- xcode-select
  xcode-select -h
  
  sudo xcode-select --switch /Applications/Xcode-Beta.app
  xcode-select -p  # /Applications/Xcode-Beta.app/Contents/Developer
  
    
- xcrun --show-sdk-path --sdk iphoneos  # /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.4.sdk
  xcrun --show-sdk-path --sdk macosx    # /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk
  xcrun --show-sdk-path --sdk watchos   # /Applications/Xcode.app/Contents/Developer/Platforms/WatchOS.platform/Developer/SDKs/WatchOS4.3.sd
  
  xcrun simctl
  xcrun simctl terminate booted  com.expressionSoftware.app
  xcrun simctl launch    booted  com.apple.Preferences       # launch iOS settings
# xcrun simctl delete unavailable                            # delete devices that are not supported by the current Xcode SDK
  
  xcrun swift-demangle __TFC4Demo6MainVC5debugfT_T_  # Demo.MainVC.debug ()()

8/1/16

Xcode Keyboard Shortcuts

v11.3

KEYS
  cmd  command/apple C
  ctl  control       L
  opt  option/alt    O
  shf  shift         S
  ent  enter         E
  del  delete        D
  spc  space         _
  clk  click         K


FILE
  C T|N   new tab/file...
  CS T|N  new window/new project...
  CL N    new workspace...
  COS N   new playground
  CO N    new group
  C O     open...
  CS O    open quickly..., file or symbol name
  C >     open hidden files, toggle in file-open dialog (CS .)
  CO A    add files
  C W     close tab
  CS W    close window
  CLO W   close other windows
  CL W    close current file, back to previous file
  CO W    close workspace
  C S     save
  CS S    duplicate..., save as...
  CSO S   save as...
  CO S    save all
  CL S    create snapshot...


NAVIGATE
  C `       next window
  C ~       previous window (CS `)
  C {|}     previous/next tab
  CL left   back
  CL right  forward
  CL up     toggle header/source file, jump to next counterpart
  L /       next placeholder //<##>
  L ?       previous placeholder (LS /) //<#placeholder 2#>
  C L       line number, goto
  CL J      definition, (cmd + click)
  CS L      selection
  C J       editor
  CO `      focus next area
  CO ~      focus previous area (COS `)
  CO <      open in... (COS ,)
  CO ,      open in assistant editor
  CS J      reveal in project navigator


JUMP BAR
  L 1  grouped files, recent, unsaved, includes, storyboard outlets
  L 2  previous history
  L 3  next history
  L 4  project
  L 5  folder files
  L 6  function list, code comment tags, storyboard view controller scene

  JUMP BAR CODE COMMENT TAGS
  // TODO: ...
  // FIXME: ...
  // MARK: m1
  // ???: wtf
  // !!!: foo


EDIT
  C Z    undo
  CS Z   redo
  CO V   special paste
  COS V  paste and preserve formatting
  CD     delete to beginning of line
  L D    delete forward, cursor stationary
  L K    delete to end of line, paragraph
  CL_    emoji & symbols


FIND
  C F    find
  CO F   find and replace
  CS F   find in workspace
  COS F  find and replace in workspace
  C G    find next
  CS G   find previous
  C E    use selection for find
  CS E   use selection for replace
  CO J   filter in navigator
  CO L   filter in library


FORMAT
  CLS T  show fonts


EDITOR
show editor only                                              C   enter
----------
canvas                                                        CO  enter
assistant                                                     CLO enter
layout >
----------
show completions                                              L_  (esc)
show code actions                                             CS A
edit all in scope                                             CL E
refactor >
----------
selection >
    select all symbols
    split selection by lines
    balance delimiters
    select column up                                          LS up
    select column down                                        LS down

structure >
    re-indent                                                 L I
    shift right                                               C ]
    shift left                                                C [
    move line up                                              CO [
    move line down                                            CO ]
    comment selection, toggle                                 C /
    add documentation                                         CO /

code folding >
    fold                                                      CO  left
    unfold                                                    CO  right
    unfold all
    fold methods & functions                                  COS left
    unfold methods & functions                                COS right
    fold comment blocks                                       CLS left
    unfold comment blocks                                     CLS right

syntax coloring >
    default for file type
    none

font size >
    increase                                                  C +
    decrease                                                  C -
    reset                                                     CL 0

theme >
----------
minimap                                                       CLS M
authors                                                       CLS A
----------
invisibles
----------
show last change for line
create code snippet
----------
jump to definition                                            CLK
select block of text                                          OK
move cursor to start of file                                  C up
move cursor to end of file                                    C down
move cursor to start of line                                  C left   (L A)
move cursor to end of line                                    C right  (L E)
move cursor left one word                                     O left
move cursor right one word                                    O right
center selection in visible area                              L L
cycle thru code completion                                    L .
cycle backward thru code completion, reverse                  L >  (LS .)
  

PRODUCT
  C B|R|.  build/run/stop
  CS K     clean
  COS K    clean build folder
  CS R     build for running
  CS I     build for profiling
  CL R     run without building
  C I      profile
  CS B     analyze
  CL [|]   select previous/next scheme, workspace project
  C <      edit scheme (CS ,)
  CLO U    test, xctest
  CLO G    test again


DEBUG
  F6|F7|F8  step over/into/out
  CL Y      toggle pause, continue
  CL C      continue to current line
  C K       clear console
  CO K      reload console
  L F6|F7   step over/into instruction
  LS F6|F7  step over/into thread
  C \       add breakpoint at current line
  C Y       toggle activate breakpoints
  CS M      view memory


VIEW
editor >
    focus
    
    show related items                                       L 1
    show previous history                                    L 2
    show next history                                        L 3
    show top level items                                     L 4
    show group files                                         L 5
    show document items                                      L 6

show code review, hide, toggle                               COS enter
----------
change editor orientation
reset editor sizes
reset assistant selection                                    COS Z
----------
navigators >
    show project navigator                                   C 1
    show source control navigator                            C 2
    show symbol navigator                                    C 3
    show find navigator                                      C 4
    show issue navigator                                     C 5
    show test navigator                                      C 6
    show debug navigator                                     C 7
    show breakpoint navigator                                C 8
    show report navigator                                    C 9
    
    show navigator, hide, toggle                             C 0

debug area >
    activate console                                         CS C
    show debug area, hide, toggle                            CS Y

inspectors >
    show file inspector                                      CO 1
    show history inspector                                   CO 2
    show quick help inspector                                CO 3
    
    show inspectors                                          CO 0

show library                                                 CS L
----------
hide toolbar                                                 CO T
hide tab bar
show all tabs                                                CS \
----------
enter full screen, exit, toggle                              CL F


VIEW - UTILITIES
  CO 0  toggle utilities
  CO 1  show file inspector
  CO 2  show history inspector
  CO 3  show quick help inspector
        show identity inspector
             dae node inspector
  CO 4  show attributes inspector
  CO 5  show size inspector
  CO 6  show connections inspector
  CO 7  show bindings inspector, cocoa storyboard
             sknode inspector, sprite kit
  CO 8  show view effects inspector, cocoa storyboard

  CLO 1  show file template library
  CLO 2  show code snippet library
  CLO 3  show object library
  CLO 4  show media library
  CS 0   documentation & api reference
  CS 1   welcome to xcode
  CS 2   devices


IOS SIMULATOR
  C 1|2|3|4|5   scale 100/75/50/33/25%
  C left|right  rotate left/right
  CS H          home
  C K           toggle software keyboard
  CS K          connect hardware keyboard
  C S           save screen shot
  C T           slow animations
  CS M          simulate memory warning
  C /           open system log...


INTERFACE BUILDER
  C D       duplicate control
  C =       size to fit content, select control first
  C _       add horizontal guide, drag off top/bottom to remove
  C |       add vertical guide, drag off left/right to remove, pipe char
  C [|]     align left/right edges, select controls first
  C +|-     zoom
  C LRUD    scroll
  LS click  control popup menu


SOURCE CONTROL
  CO C|X  commit.../pull...


FILE MERGE
  C A  select all diffs, then left or right to select entire file rev


OS
  L F2    select menu bar, file, edit, (ctl + fn + F2)
  CS /    help menu (C ?)
  L F3    select dock
  C `     select next window
  CS `    select previous window (C ~)
  CS 3    save screenshot to file
  CS 4    save selected area to file
  CS 5    onscreen capture controls, use to set screenshot size etc, enter or capture to save screenshot to file
  CLS 3   copy screenshot to clipboard
  CLS 4   copy selected area to clipboard
  C ,     preferences...
  CO_     system preferences emoji & symbols
  C L     system preferences show all
  CO F5   accessibility options
  CO =    zoom in (enable zoom in accessibility)
  CO _    zoom out
  CO 8    toggle zoom
  C M     minimize
  C H     hide
  CO H    hide others
  CS G    finder goto folder /etc
  C K     finder connect to server
  O       finder image zoom full size
  T       target disk mode w/thunderbolt cable, hold T on startup
  CO esc  force quit applications
  CL pwr  reboot
  OS K     apple logo char

3/21/15

iOS Scene Kit Jet

The Scene Kit 3D Jet in flight with clockwise roll, in iPad airspace.
Trailing transparent snapshots are 3D model clones of the jet at variable intervals.
Use SCNView allowsCameraControl to zoom and rotate the entire scene, including models, for different points of view.

* The 3D Jet ship mesh is part of the default Xcode Scene Kit project.





@import SceneKit;
@import GLKit;


@interface ESJet: NSObject

    @property (nonatomic) SCNNode * node;
    @property (nonatomic, assign) CGFloat velocity;
    @property (nonatomic, assign) BOOL roll;
    @property (nonatomic, assign) CGFloat rollRate;


    -(void)update:(NSTimeInterval)aTime isVisible:(BOOL)aVisible;

    -(instancetype)init;
    -(instancetype)initWithNode:(SCNNode *)aNode zPosition:(int)aZPosition;
@end


@implementation ESJet

    -(void)update:(NSTimeInterval)aTime isVisible:(BOOL)aVisible;
    {
        CGFloat nextZPosition = self.velocity;

     // NSLog(@"jet position: %@", NSStringFromGLKVector3(SCNVector3ToGLKVector3(self.node.position)));

        if (aVisible)
        {
            NSLog(@"jet visible");
        }
        else
        {
            //when jet flys off right-side of screen, reposition on left
            NSLog(@"...");
            nextZPosition = -(self.node.position.x * 1.95);
        }

        GLKVector3 nextFramePosition = GLKVector3Make(0, 0, nextZPosition);
        GLKMatrix4 transform = SCNMatrix4ToGLKMatrix4(self.node.transform);
        self.node.transform = SCNMatrix4FromGLKMatrix4(GLKMatrix4TranslateWithVector3(transform, nextFramePosition));


        if (self.roll)
        {
            //rotate jet ~ 1 degree per frame on X axis
            GLKQuaternion rot = GLKQuaternionMakeWithAngleAndAxis((M_1_PI * self.rollRate), 1, 0, 0);
            GLKQuaternion orientation = GLKQuaternionMultiply(rot, GLKQuaternionMake(self.node.orientation.x,
                                                                                     self.node.orientation.y,
                                                                                     self.node.orientation.z,
                                                                                     self.node.orientation.w));

            self.node.orientation = SCNVector4Make(orientation.x, orientation.y, orientation.z, orientation.w);
        }
    }

    -(instancetype)init
    {
        if (self = [super init])
        {
            self.velocity = 0.33f;
            self.rollRate = (self.velocity * 0.364);
        }

        return self;
    }

    -(instancetype)initWithNode:(SCNNode *)aNode zPosition:(int)aZPosition
    {
        if ([self init])
        {
            self.node = aNode;
            [self.node removeAllActions];

            //rotate jet 90 degrees on Y axis, facing right edge of screen
            GLKQuaternion rot = GLKQuaternionMakeWithAngleAndAxis(M_PI_2, 0, 1, 0);
            self.node.orientation = SCNVector4Make(rot.x, rot.y, rot.z, rot.w);
            self.node.position = SCNVector3Make(0, 0, aZPosition);
        }

        return self;
    }
@end


@interface GameViewController: UIViewController<SCNSceneRendererDelegate>
@end

@implementation GameViewController
{
    SCNScene * skScene;
    SCNView * skView;
    SCNNode * cameraNode;

    NSMutableArray * nodeSnapshots;
    NSDate * frameTimer;

    ESJet * jet;
}

    -(void)viewDidLoad
    {
        //default project code here...

        skScene = scene;
        skView = scnView;
        skView.delegate = self;
        skView.playing = YES;

        nodeSnapshots = [NSMutableArray array];

        jet = [[ESJet alloc] initWithNode:ship zPosition:-20];
        jet.roll = YES;
    }

    //SCNSceneRendererDelegate
    -(void)renderer:(id<SCNSceneRenderer>)aRenderer updateAtTime:(NSTimeInterval)time
    {
                void (^cloneNode)() = ^
                { 
                    dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
                    dispatch_async(q, ^
                                   {
                                       SCNNode * clone = [jet.node clone];
                                       clone.opacity = 0.20f;
                                       [nodeSnapshots addObject:clone];
                                       [skScene.rootNode addChildNode:clone];
                                   });
                };

                void (^cloneNodeOnTimer)(float) = ^(float interval)
                {
                    if ((frameTimer == nil) || (frameTimer.timeIntervalSinceNow <= -interval))
                    {
                        frameTimer = [NSDate date];
                        cloneNode();
                    }
                };


        //SCNSceneRenderer protocol
        BOOL nodeIsVisible = [aRenderer isNodeInsideFrustum:jet.node withPointOfView:cameraNode];

        if (nodeIsVisible)
        {
            cloneNodeOnTimer(0.6f);
        }
        else
        {
            skView.playing = NO;
            jet.node.hidden = YES;

            if (nodeSnapshots.count > 0)
            {
                //remove transparency from last cloned node
                ((SCNNode *)[nodeSnapshots lastObject]).opacity = 1.0;
            }
        }


        [jet update:time isVisible:nodeIsVisible];
    }

    //tap any node to render new scene
    -(void)handleTap:(UIGestureRecognizer*)gestureRecognize
    {
        CGPoint tp = [gestureRecognize locationInView:skView];

        NSArray * hitTestResults = [skView hitTest:tp options:nil];
        if (hitTestResults.count > 0)
        {
            [nodeSnapshots enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL * stop)
            {
                [(SCNNode *)obj removeFromParentNode];
            }];

            [nodeSnapshots removeAllObjects];

            jet.node.hidden = NO;
            skView.playing = YES;
        }
    }

3/15/15

iOS Gradient View with Clipped Path

Custom gradient view with support for 3 shapes: default, circle, circle-outline.
Copy path with CGPathCreateCopyByStrokingPath, clip, then draw gradient.




//swift

import UIKit

class ViewController: UIViewController
{
    override func viewDidLoad()
    {
        super.viewDidLoad()

        var gv = [ESGradientView]()
        var x = 100
        for i in 0...5
        {
            var g = ESGradientView()
            g.frame = CGRect(x:x, y:200, width:100, height:100)
            g.gradientColors = i < 3 ? g.gradientColors : [UIColor.redColor().CGColor, UIColor.blackColor().CGColor]
            gv.append(g)
            self.view.addSubview(g)
            x += 110
        }

        gv[1].shape = .Circle
        gv[2].shape = .CircleOutline
        gv[4].shape = .Circle
        gv[5].shape = .CircleOutline
        gv[5].circleOutlineWidth = 1
    }
}


class ESGradientView: UIView
{

    enum Shape
    {
        case Default, Circle, CircleOutline
    }

    var shape = Shape.Default
    var circleOutlineWidth:Int = 4
    var gradientColors = [UIColor.redColor().CGColor, UIColor.blueColor().CGColor]
    var gradientLocations:[CGFloat] = [0, 1]
    var gradientEndOffset:CGFloat = 20


    override func drawRect(rect: CGRect)
    {
        var context = UIGraphicsGetCurrentContext()

        if (shape == .Circle)
        {
            let path = getCirclePath(1)
            path.addClip()
        }
        else if (shape == .CircleOutline)
        {
            let path = getCirclePath(circleOutlineWidth + 2)
            var pathRef = CGPathCreateCopyByStrokingPath(path.CGPath, nil, CGFloat(circleOutlineWidth), kCGLineCapRound, kCGLineJoinRound, 1)
            UIBezierPath(CGPath: pathRef).addClip()
        }

        var gradient = CGGradientCreateWithColors(CGColorSpaceCreateDeviceRGB(), gradientColors, gradientLocations)
        let gradientEndPoint = CGPointMake(bounds.width - gradientEndOffset, bounds.height - gradientEndOffset)
        CGContextDrawLinearGradient(context, gradient!, CGPointZero, gradientEndPoint, UInt32(kCGGradientDrawsAfterEndLocation))
    }   

    func getCirclePath(inset:Int) -> UIBezierPath
    {
        let center = CGFloat(bounds.width * 0.5)
        let radius = CGFloat(center * CGFloat(100 - inset) * 0.01)
        let centerPoint = CGPointMake(center, center)
        var cp = UIBezierPath(arcCenter:centerPoint, radius:radius, startAngle:0, endAngle:CGFloat(M_PI * 2), clockwise:true)

        return cp
    }
}

3/7/15

We Can Has WWDC Session Videoz Descriptions?

Javascript to show all WWDC session video descriptions.
Expands sessions to show descriptions and view search matches. *
To use, copy and paste script into browser console and then call show() function.

var sessions = $$('li.session')

function show()
{
    toggle('session active');
}

function hide()
{
    toggle('session');
}

function toggle(css)
{
    for (var i = 0; i < sessions.length; i++)
    {
        sessions[i].className = css;
    }
}

WWDC
2014
2013
2012
2011
2010


* Usability clue for Apple Web Dev Team
"We can't wait to show you."

2/28/15

iOS Draw Along Bezier Quad Curve Path


//swift

var bp = UIBezierPath()
let startPoint = CGPointMake(200, 400)
let endPoint = CGPointMake(500, 400)
let controlPoint = CGPointMake(350, 150)
bp.moveToPoint(startPoint)
bp.addQuadCurveToPoint(endPoint, controlPoint:controlPoint)

var vp = CAShapeLayer()  //debug visual path
vp.path = bp.CGPath
vp.fillColor = UIColor.clearColor().CGColor
vp.strokeColor = UIColor.darkGrayColor().CGColor
vp.lineWidth = 1.0
self.view.layer.addSublayer(vp)

    //http://en.wikipedia.org/wiki/Bezier_curve#Quadratic_B.C3.A9zier_curves
    func getBezierQuadXY(t:CGFloat, p0:CGFloat, p1:CGFloat, p2:CGFloat) -> CGFloat 
    {
        return ((1-t) * (1-t)) * p0 + 2 * (1-t) * t * p1 + t * t * p2
    }

    func addNode(pathPercent:CGFloat)
    {
        var node = CALayer()
        node.frame = CGRectMake(0, 0, 20, 20)
        node.cornerRadius = 10.0
        node.borderColor = UIColor.darkGrayColor().CGColor
        node.borderWidth = 1.0
        let p = CGPointMake(getBezierQuadXY(pathPercent, startPoint.x, controlPoint.x, endPoint.x),
                            getBezierQuadXY(pathPercent, startPoint.y, controlPoint.y, endPoint.y))
        node.position = p
        self.view.layer.addSublayer(node)
    }

addNode(0.5)
addNode(0.7)
addNode(0.8)
addNode(0.89)
addNode(1.0)

2/24/15

iOS Autolayout Constraints on Stacked Views



The containing view (gray border) vertically resizes to fit child views.
Containing view is hidden when child view heights total 0.

5 screenshots
1. View layout before applying constraints
2. 3 child views, heights 100
3. Green view height 0
4. Green and blue view height 0
5. Red view height 20, green view height 40


@implementation ViewController
{
    UIView * cv;  //container view, clear w/gray border
    UIView * tv;  //top view, red
    UIView * mv;  //middle view, green
    UIView * bv;  //bottom view, blue

    NSDictionary * bindings;
    NSMutableArray * verticalConstraints;
}

-(void)viewDidLoad
{
    [super viewDidLoad];

    [self createControls];
    [self setupConstraints];
}

-(void)setupConstraints
{
    self.view.translatesAutoresizingMaskIntoConstraints = NO;
    cv.translatesAutoresizingMaskIntoConstraints = NO;
    tv.translatesAutoresizingMaskIntoConstraints = NO;
    mv.translatesAutoresizingMaskIntoConstraints = NO;
    bv.translatesAutoresizingMaskIntoConstraints = NO;

    bindings = NSDictionaryOfVariableBindings(cv, tv, mv, bv);
    verticalConstraints = [NSMutableArray array];

    [self setupHorizontalConstraints];
    [self setupVerticalConstraints];
}

-(void)setupHorizontalConstraints
{
    NSMutableArray * hConstraints = [NSMutableArray array];
    
    //container view
    [hConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-20-[cv(200)]"
                                                                              options:0
                                                                              metrics:nil
                                                                                views:bindings]];
    //top view
    [hConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[tv]-|"
                                                                              options:0
                                                                              metrics:nil
                                                                                views:bindings]];
    //match middle view w/top view
    [hConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[mv(tv)]"
                                                                              options:0
                                                                              metrics:nil
                                                                                views:bindings]];
    //match bottom view w/top view
    [hConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[bv(tv)]"
                                                                              options:0
                                                                              metrics:nil
                                                                                views:bindings]];
    [self.view addConstraints:hConstraints];
}

-(void)setupVerticalConstraints
{
    [self.view removeConstraints:verticalConstraints];
    [verticalConstraints removeAllObjects];

    [verticalConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[cv]-20-|"
                                                                                     options:0
                                                                                     metrics:nil
                                                                                       views:bindings]];
    //view heights, container vertical margin
    NSDictionary * metrics = @{ @"th" : @(tv.frame.size.height),
                                @"mh" : @(mv.frame.size.height),
                                @"bh" : @(bv.frame.size.height),
                                @"cm" : @(tv.frame.size.height + mv.frame.size.height + bv.frame.size.height > 0 ? 8 : 0) };

    [verticalConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-cm-[tv(th)][mv(mh)][bv(bh)]-cm-|"
                                                                                     options:NSLayoutFormatAlignAllCenterX
                                                                                     metrics:metrics
                                                                                       views:bindings]];
    [self.view addConstraints:verticalConstraints];
}

//init controls w/temp width and position for general layout, before implementing constraints
-(void)createControls
{
    int vWidth  = 100;
    int vHeight = 100;
    int cHeight = vHeight * 3;

    cv = [[UIView alloc] initWithFrame:CGRectMake(20,  20, vWidth, cHeight)];
    tv = [[UIView alloc] initWithFrame:CGRectMake(10,   0, vWidth, vHeight)];
    mv = [[UIView alloc] initWithFrame:CGRectMake(10, 100, vWidth, vHeight)];
    bv = [[UIView alloc] initWithFrame:CGRectMake(10, 200, vWidth, vHeight)];
    
    cv.layer.borderColor = [UIColor lightGrayColor].CGColor;
    cv.layer.borderWidth = 1;

    tv.backgroundColor = [UIColor redColor];
    mv.backgroundColor = [UIColor greenColor];
    bv.backgroundColor = [UIColor blueColor];

    [self.view addSubview:cv];
    [cv addSubview:tv];
    [cv addSubview:mv];
    [cv addSubview:bv];
}


-(void)hideView:(UIView *)aView
{
    aView.frame = CGRectMake(0, 0, aView.frame.size.width, 0);
    [self setupVerticalConstraints];
}

-(void)resizeView:(UIView *)aView height:(int)aHeight
{
    aView.frame = CGRectMake(0, 0, aView.frame.size.width, aHeight);
    [self setupVerticalConstraints];
}

-(void)showView:(UIView *)aView
{
    aView.frame = CGRectMake(0, 0, aView.frame.size.width, 100);
    [self setupVerticalConstraints];
}