Linux

Android and Java

Common Programs
Web

Medicine



Git and GitHub


Overview

A repository, often called a repo, is a directory of files. Every directry under source conntrol is a complete independant repository, and can function even without network access.

The basic structures are:

When sharing work with other users, there is no special "central" repository. All repositories are equal in the eyes of git. Instead of checking an updated file into a source control central server, with Git you push or pull commits from one repository to another. In practice, one repository may be treated specially, like a central master, but that is outside of git. Different organizations may use different policies for identifying or protecting different special repositories.

GitHub is a web-based server where people can exchange and share a source tree. You can push your local repository to the server, and can pull repositories from the server to your local repository. It also lets people chat and read each other's source code. You do not need GitHub to use Git, but you do use git to interact with GitHub. Git does everything on the local computer, and GitHub is a web service that allows sharing between different git users. Git can also work with other similar services.

Login to GitHub at https://github.com and create a Free account.
WARNING! Use the same email you used for the local repository!

The git cheat sheet (in English) https://training.github.com/downloads/github-git-cheat-sheet.pdf

Some handy tutorials

Installation

Creating repositories

Each directory of source code requires a separate repository.

Modifying and Committing Files

The states of a file are: Tracked ---> Modified ---> Staged ---> Committed/Tracked
A key idea in git is that changes are not stored as diffs, but rather as stand-alone snapshots.

If you are only working on a local storage (no GitHub or BitBucket or other remote store) then you are done. Your changes are saved. If you delete the working copy of the file, then do a "git reset --hard HEAD" the file will be restored.

If you want to use GitHub, then you ALSO need to do the next steps.

Next make a branch. In git, a branch is a reference to a commit. This becomes important when you have several commits in a directory, each with different set of snapshots of files. You use branch names to reference each commit. In practice, this means you specify a branch name to the command that changes the current working environment to reference a particlar commit.

Now, push a branch to Github git push origin my-new-branch Here, "origin" is just a special keyword that means the remote URL associated with this repository Or, you can try this, but I have to enter SSH public key passcodes which takes extra configuration. git push git@github.com:git/git.git yourbranchname

Now you can log into GitHub and create a pull request, examine the diff, and merge it into the main branch.

Getting Updates

In a directory that is a clone of a repository on GitHub git pull origin master

To dischard all local changes and replace the directory with the remote repository git reset --hard HEAD git pull

To restore the state of a file from your local repository git checkout However, if you deleted a file, then you will have to name it to restore it from the local repository. git checkout myFileName

Status Commands

To see what has changed but not been committed in the working directory git status

To see which branch you are currently working on git branch

To see what remote repository git remote -v

To see what has been changed and committed in the past: git log

To see what changes are changed but not yet staged. Shows the differences between the working directory and the index. Note, if all changes are staged but not yet committed then "git diff" will show nothing. git diff git diff [fileName] git diff [tag name]

The changes are in the current staged commit. These files have been added to the index and staged for a commit. These are the changes between the index and the HEAD (which is the last commit on this branch). git diff --staged

Shows the changes between the index and the HEAD (which is the last commit on this branch). git diff --cached

Shows all the changes between the working directory and HEAD (which includes changes in the index). This shows all the changes since the last commit, whether or not they have been staged for commit or not. git diff HEAD

Delete/Undo Changes




User customizations for the Epic EMR

These are some hints for customizing your Epic electronic medical record work environment. Note, however, that it seems that Epic is sooooo customizeable that no two hospitals that use Epic work exactly the same. Each may have different versions of Epic with different features turned on, but also each may have done different site-specific customizations. Below are some thoughts on how to tweak Epic on an Indiana University system in 2017.


Creating Templates

You can create "smart phrases" which can be inserted into any note. A smartPhrase is basically a macro, that can expand to any text string, from a single character to an entire document. I make a smart phrase that I insert into a blank note that is the skeleton for different typical notes I write.

You load a SmartPhrase into a document by typing .phraseName where "phraseName" is the name you gave your phrase. The period "." before the name teels Epic this is a SmartPhrase to expand.

To create a new SmartPhrase

  • Go to the top window in Epic and open the "Personalize" menu and select the "My SmartPhrases" menu item. This will open a tab that is labelled "Workbench".
  • Click the "New" button in the toolbar inside the Workbench tab. This will open an editor.
  • Enter your name in the top small text box
  • Enter
  • Click "Accept" to save your smartphrase.

Your SmartPhrase text can include variables, that pull in data from the patient chart. This lets the SmartPhrase text to include data specific to each patient. As a result one SmartPhrase can include other nested SmartPhrases. You expand the top-level SmartPhrase by typing .xxx where xxx is the name of the SmartPhrase. The SmartPhrase body may include string like @yyy@ where yyy is the name of the nested SmartPhrase. So, the expanded text for SmartPhrase yyy appears somewhere in the body of the expanded text for SmartPhrase xxx.

Some of my favorite SmartPhrases are:

Patient identifiers:

  • Mr/Mrs: @M@
  • Names: @NAME@ @LNAME@
  • Age: @AGE@
  • Sex: @SEX@
  • DOB: @DOB@
  • MRN: @MRN@
  • AUTHOR: @ME@
  • he/she @HE@
  • He/She @CAPHE@
  • His/her @HIS@
  • His/Her @CAPHIS@
  • him/her @HIM@
  • Him/Her @CAPHIM@

Medical History:

  • CURRENT PROBLEM LIST: @PROB@
  • PAST MEDICAL HISTORY: @PMH@
  • PAST SURGICAL HISTORY: @PSH@
  • FAMILY HISTORY: @FAMHX@
  • TOBHX @TOBHX@
  • ALCHX @ALCHX@
  • DRUGHX @DRUGHX@
  • CURRENT HOSPITAL MEDICATIONS: @MEDS@
  • CURRENT OUTPATIENT MEDICATIONS: @MEDSCURRENT@
  • ALLERGIES: @ALLERGY@

Vitals:

  • @TMAX(24)@
  • @SBPMAX(24)@
  • @DBPMAX(24)@
  • VITAL SIGNS: @VS@

Lab Values are a bit tricky. I cannot as yet find a way to pull in just a number, like "136" for a sodium. Epic seems to only support expanding the data into a formatted table with lots of other related information, like the date. All lab values use the same SmartPhrase

LABBRIEF

LABBRIEF will take parameters, which specify which particular labs to use. For example, this SmartPhrase will include Sodium and Potassium:

@LABBRIEF[NA:1,K:1@

Some useful lab names you can pass to LABBRIEF are:

CMP Lab parameters to LABBRIEF

  • NA
  • K
  • CL
  • CO2
  • BUN
  • CREATININE
  • GFR
  • GLU
  • GLUFASTING
  • ALB
  • TBILI
  • PROT
  • ALT
  • AST
  • ALP

CBC Lab parameters to LABBRIEF

  • WBC
  • HGB
  • PLT
  • MCV

CBC Lab parameters to LABBRIEF

  • CREATUR - Urine Creatinine in mg/dL
  • PROTUR - Urine Protein
  • ALBUMINUR - Urine Albumin
  • UREAUR - Urine Urea
  • NAUR - Urine Sodium
  • CLUR - Urine Chloride
  • KUR - Urine Potassium



Here is my template for the top of an clinic note.

===========================================================
NEPHROLOGY CLINIC NOTE:

@M@ @LNAME@ is a @AGE@ @SEX@ with pmh Chronic Kidney Disease Stage xxx who returns to nephrology clinic for a regular followup. 

Since @HIS@ last clinic visit, @HE@ has been feeling well since his last clinic visit, with no hospitalizations or ER visits.

@CAPHE@ denies use of NSAIDS and has been compliant with all medications.


REVIEW of SYSTEMS:
General: No fevers, no dizziness, no weakness, no fatigue
Cardiovascular: no chest pain, no palpitations, no edema
Pulmonary: no shortness of breath, no cough, no change in sputum production
Gastrointestinal: no nausea, no vomiting, no diarrhea, no constipation, no abdominal pain
Genitourinary: no nocturia, no dysuria, no urinary hesitancy, no hematuria, no partial voiding
Dermatologic: no rashes
All other review of systems are negative


ACTIVE PROBLEMS: 
@PROB@ 

CURRENT MEDICATIONS:
@MEDSCURRENT@

ALLERGIES:
@ALLERGY@ 


PHYSICAL EXAMINATION:
Vital Signs:  @VS@ 
General: Alert and oriented, no acute distress
HEENT: Pupils equal and round. No oral lesions. eyes are anicteric
Cardiovascular: Regular rhythm, no murmurs or rubs. No JVD, no lower extremity edema
Respiratory: Clear to auscultation bilaterally without wheezes or crackles. Good air movement, non-labored breathing
Abdomen: Soft, non-distended, non-tender, normal bowel sounds
Neurologic: No asterixis. Alert and oriented x3. Speech is clear and coherent. Face and limb movements are symmetric
Dermatologic: No rashes


LABORATORY DATA: Laboratory data and imaging was reviewed in the medical record.

@LABBRIEF(NA:1,K:1,CL:1,CO2:1,BUN:1,CREATININE:1,GFR:1,GLU:1,GLUFASTING:1,ALB:1,TBILI:1,PROT:1,ALT:1,AST:1,ALP:1)@
@LABBRIEF(WBC:1,HGB:1,PLT:1,MCV:1)@
@LABBRIEF(PROTUR:1,CREATUR:1,ALBUMINUR:1,UREAUR:1,NAUR:1,CLUR:1,KUR:1)@


ASSESSMENT AND PLAN:

#) Chronic kidney disease. Stage 
The original causes of the CKD are xxxxxx.
Today, serum Cr is xxxxx, which is within the range of approx xxxxx. 
@CAPHIS@ renal disease is stable with no signs of progression. 
Urine Prot/Cr ratio is xxxxx, suggesting approximately xxxx grams daily proteinuria. They are already on an ACE/ARB (Lisinopril).
Serum CO2 is stable at xxxxx, so there is no indication for bicarbonate supplementation.
We will continue to control @HIS@ renal disease by managing risk factors including diabetes and hypertension.
@CAPHE@ was counselled to avoid NSAIDs and IV Contrast

#) Hypertension
BP = 
The current regimen is 

#) Mineral Bone Disease
PTH 
Calcium and Phos are both stable and within normal limits.
Meds:

#) Anemia of Chronic Renal Disease
Hgb = xxxxx, no indication for ESA.
Meds: 


PLANS FOR NEXT CLINIC APPOINTMENT:


SUMMARY OF CHANGES IN THIS CLINIC APPOINTMENT:
- Return to clinic in 

Staff: Dr. Decker
Dawson Dean (312-1226)



Here is my template for the top of an impatient note. I then use NoteBuilder to generate the plan

===========================================================
SUBJECTIVE:
@M@ @LNAME@ is a @AGE@ @SEX@ who presented with


REVIEW of SYSTEMS:
General: No fevers, no dizziness, no weakness, no fatigue
Cardiovascular: no chest pain, no palpitations, no edema
Pulmonary: no shortness of breath, no cough, no change in sputum production
Gastrointestinal: no nausea, no vomiting, no diarrhea, no constipation, no abdominal pain
Genitourinary: no nocturia, no dysuria, no urinary hesitancy, no hematuria, no partial voiding
Dermatologic: no rashes
All other review of systems are negative


CURRENT MEDICATIONS:
@MEDS@

ALLERGIES:
@ALLERGY@ 


PHYSICAL EXAMINATION:
Vital Signs:  @VS@ 
General: Alert and oriented, no acute distress
HEENT: Pupils equal and round. No oral lesions. eyes are anicteric
Cardiovascular: Regular rhythm, no murmurs or rubs. No JVD, no lower extremity edema
Respiratory: Clear to auscultation bilaterally without wheezes or crackles. Good air movement, non-labored breathing
Abdomen: Soft, non-distended, non-tender, normal bowel sounds
Neurologic: No asterixis. Alert and oriented x3. Speech is clear and coherent. Face and limb movements are symmetric
Dermatologic: No rashes


LABORATORY DATA: Laboratory data and imaging was reviewed in the medical record.

@LABBRIEF(NA:1,K:1,CL:1,CO2:1,BUN:1,CREATININE:1,GFR:1,GLU:1,GLUFASTING:1,ALB:1,TBILI:1,PROT:1,ALT:1,AST:1,ALP:1)@
@LABBRIEF(WBC:1,HGB:1,PLT:1,MCV:1)@
@LABBRIEF(PROTUR:1,CREATUR:1,ALBUMINUR:1,UREAUR:1,NAUR:1,CLUR:1,KUR:1)@


ASSESSMENT AND PLAN:



GDB

GDB in Emacs

A good tutorial is http://tedlab.mit.edu/~dr/gdbintro.html
  • Control-x 2 - Split the screen
  • Esc-X gdb - Start gdb
  • Esc-X gud-gdb - Start GUD gdb
  • {program name} - type this at the "Run gdb" prompt in the mini-buffer
  • Optionally, type "set args xxxx" to the prompt, which will set the command line arguments to xxxx.


GDB Commands

See the manual for more information.
  • file - Load a new program
  • r - Run the current program
  • k - Kill the current debugged process
Execution
  • s - Step Into
  • n - Step Over
  • c - Continue
  • jump lineNum - Jump to lineNum in the current file
  • fin - Run until the current function finishes
Stack
  • bt - Print the call stack
  • f n - Set the current stack frame to frame #n
  • p {var name} - Print the value of the named variable
Breakpoints
  • b {proc name or lineNum} - Set a breakpoint at the entry to the named procedure. If this is a lineNum then it assumes the current file being debugged.
  • d {num} - Delete breakpoint number
  • info break - List breakpoints



gprof (GNU Profiler)

Using gprof

  • Compile with -pg flag
  • run the program as you normally would. This creates a gmon.out file
  • gprof {programName} gmon.out > prof.txt



Microsoft Excel

Making a Cell whose value is defined by an expression

Select the cell, and type the expression in the fx (function) text box. Start the string with "=" to tell Excel that this is a formula and not a string value.

Example:
=(L2 / (K2 + L2)) * 100

The parameters refer to cells. These take the form of where is a letter and is a number. A "$" symbol in front of either the column or letter means it is absolute address, which is independent of the location of the cell making the reference. No "$" means that this address is relative to the cell making the reference. This can have several combinations:

Type Description Example
Absolute A specific cell independent of location of the referencing cell $A$1
Absolute Column, Relative Row A cell in a specific column, and in a row relative to the referencing cell $A1
Absolute Row, Relative Column A cell in a specific row, and in a column relative to the referencing cell A$1
Relative A cell in a relative row and column to the referencing cell A1

Once you have a cell with a formula, you can select it and drag the outline to fill a column or row. This will put that expression in every cell in the region. Assuming that hte formula uses relative cell references, this means every cell will have a value dependent on relative cells in its own row or column.

NOTE: The first cell uses relative addresses with specific constant names, like "A3" and so on. When you copy this to other cells, Excel will first convert the specific names (like "A3") to relative positions (like, one column to the left and two rows up) and then put the appropriate relative positions in each new cell. So, you define the pattern with a specific example and then Excel generalizes this and makes new specific constants for each new cell.

Besides algebraic expressions, there are a few built-in functions that are handy.

  • SUM(A1:A3)
  • AVERAGE(A1:A3)
  • MAX(A1:A3)
  • MIN(A1:A3)

Creating a series of auto-fill data in rows or columns
  1. Click a cell, which should show a dark frame around the cell, with a box in the lower right corner. Select the box, and drag it to expand the region to a row or column or block of cells.
  2. Select the "Home" tab, then click the "Fill" combo box, then select the "Series..." item. This lets you control how data is filled in the selected region.

Counting the Number of rows that Meet a Condition

=CountIf(range, criteria)
where

  • Range is a range of cells, like "A2:A7"
  • Criteria is a quoted algebraic relation, like ">=2001"

Some examples

  • =CountIf(A2:A7, ">=2001")

Some extensions

  • Combine several COUNTIF expressions in a SUM expression



Booting Linux on a new laptop
Unfortunately, new computers come out of the box configured to boot the pre-installed software (often, Windows) and it's hard to change the boot order, let alone boot from a USB drive. It's harder now than in the good old days when you would just insert a floppy or later a CD and hit the power button.
  • Boot and enter the boot manager. On my Dell laptops, this means holding the F12 key during the boot process, while F2 will boot into the BIOS Manager. Make sure you do a full boot, (from powerOff) and not a resume from sleep mode. Here is a good list of hotkeys for different manufacturers
  • Turn off Secure Boot. This is usually under the "Security" menu.
  • Turn off "UEFI" mode. The alternative on a Dell is called "Legacy" boot mode, and on Toshiba it's "CSM" boot. I cannot get things to work with UEFI, and there may be a solution but I am not going to work on that problem. There is a very good page on UEFI that describes this more. Basically, however, I just turn off UEFI and boot from the good old legacy BIOS.
  • In non-UEFI boot mode, you can select the order that different devices are queried for a boot sector. Move the USB device up in the list so it appears before the Hard drive. For some reason, my Dell will let me use the "+" key to move a list item up, but the "-" key does nothing.



A few personal things for installing and configuring Linux

This it is Fedora-specific, which uses yum. Debian and Ubuntu systems will use an alternate system, apt-get.


Yum
yum is a wrapper for the RedHat package manager (rpm) which works on Fedora or Red Hat systems. It runs as root. Here are the common yum commands:

  • yum update
  • yum list <package name>
  • yum list updates
  • yum list recent
  • yum list installed
  • yum search <name> - looks for a string in package names and descriptions
  • yum info <package name>
  • yum install <package name>
  • yum remove <package name>


  • Install the software On Fedora:
    sudo dnf install git-all
    On non-Linux systems, download Git - http://git-scm.com/downloads

  • Create a user
    • git config --global user.name "John Doe"
    • git config --global user.email myEmail
    • git config --global core.editor emacs
    Installing KeePass on Fedora
    Once I started using a password manager I wondered how I lived without one. But, I prefer to keep a local file that is password protected rather than a cloud-based service. A local file has a big inconvenience that I can't use it from a laptop while working or travelling. But, really, I don't want to be accessing financial or similar web sites from a coffee shop wifi. Keeping a local file means you first have to break into my house and then break into my computer and then break the file encryption to get my passwords. Sure, that's possible, but it adds another level of security which I prefer. I just fear that web-based password managers are too tempting a target and may some day be broken, particularly by a state agency.

    There are lot of password managers, and I used to use PasswordSafe because of its association with Bruce Schneier. However, that is not supported in the latest Fedora, so I changed to KeePass and am happy with it as well.

    I installed KeePass XC" through Fedora Software manager. There is also https://keepass.info/

    Installing Google Drive for Python on Fedora

    Installing exfat File System support on Fedora
    This is the file system used for camera flash drives and similar devices.
        $> su
        #> yum install exfat-utils.x86_64
        #> dnf install fuse-exfat
    
    Disable Bell in shell windows Edit the "/etc/inputrc" to add the line:
    set bell-style none
    
    Prusa Slicer

    To install:
    The instructions are here
    The GitHub page is here

    xclip

    To install:

    • yum install xclip
    Blender

    To install:

    Thunderbird Email

    To install:
    On Fedora, I just search for Thunderbird in the software catalog, and this will show a way to install it.

    Adding email accounts:

    • Click Preferences > Account Settings
    • From the Account Actions drop-down (bottom left corner), select Add Mail Account
    • Enter your email account information
    • Click Continue
    • Select IMAP
    • Click DONE
    Installing VLC Media Player on Fedora
    See https://www.videolan.org/vlc/download-fedora.html This requires Fedora 22 and later.
    This uses rpmfusion, and installs from rpmfusion-free-release-stable.noarch.rpm
    This also uses DNF, which is another package manager for all Linux distributions that use rpm.
        $> su
        #> dnf install https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm
        #> dnf install vlc
    

    To play local DVD movies, you need to separately install the libdvdcss package. You can find precompiled .rpm packages or Debian install packages for libdvdcss on https://www.rpmfind.net/linux/rpm2html/search.php?query=libdvdcss.

    Installing Zoom on Fedora
    See https://support.zoom.us/hc/en-us/articles/204206269-Installing-Zoom-on-Linux

    Installing Git on Fedora
    sudo dnf install git-all
    On non-Linux systems, download Git - http://git-scm.com/downloads

  • Create a user
    • git config --global user.name "John Doe"
    • git config --global user.email myEmail
    • git config --global core.editor emacs

  • To view users
    git config --list

    Installing PrivateInternetAccess VPN on Fedora
    See https://www.privateinternetaccess.com/helpdesk/guides/desktop/linux/fedora-openvpn-setup
    In a teminal, run
    • sudo -i
    • dnf -y install wget unzip python NetworkManager-openvpn-gnome util-linux coreutils
    • wget https://www.privateinternetaccess.com/installer/pia-nm.sh
    • ./pia-nm.sh



    Transmission
    In a teminal, run
    • sudo -i
    • yum install transmission



    Sample ~/.bashrc - A few common shortcuts that are actually a mix of some uxix and DOS commands.
    
    ################################################################################
    # .bashrc
    #
    ################################################################################
    
    ########################################
    # Source global definitions
    if [ -f /etc/bashrc ]; then
    	. /etc/bashrc
    fi
    
    ########################################
    # Global Shell Variables
    export DD_ROOT="/home/ddean/ddRoot"
    export DD_BUILD_ROOT="${DD_ROOT}/code"
    
    ########################################
    # User specific aliases and functions
    alias cls='clear'
    alias r='cd ${DD_ROOT}'
    alias ..='cd ..'
    alias more='less'
    
    ########################################
    # Prompt
    PS1='\w> '
    
    ########################################
    # Path. This is originally set in .bash_profile but expanded here
    # for the command line
    PATH=$HOME/ddRoot/tools:$PATH
    
    ########################################
    # Filename colors
    # eval "dircolors -b ~/.setFileColorsrc
    
    cd /home/ddean/ddRoot
    
    


    My personal setup "to-do" list
    • Use the Software Package tool to get the latest system updates

    • Use the Software Package tool to install "Gnome Tweak"

    • Use the Software Package tool to install Emacs

    • Go through Tweak and Settings tools

    • Copy ddRoot and latest Archive directories from a recent backup

    • Copy .emacs and .bashrc from ddRoot/tools to the home directory

    • Install Chrome from https://www.google.com/chrome/browser/desktop/index.html

    • Configure Chrome (homePage, font size, show Home button, newTab page)

    • yum install ftp

    • yum install dvd+rw-tools

    • yum install gcc

    • yum install gcc-c++

    • yum install glibc-static

    • yum install libstdc++-static

    • dnf install https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm

    • dnf install vlc

    • Download the appropriate libdvdcss package from https://www.rpmfind.net/linux/rpm2html/search.php?query=libdvdcss
      • cd to the Downloads directory
      • dnf install ./the-downloaded-libdvdcss package

    • Edit the "/etc/inputrc" to add the line: set bell-style none

    • Install a VPN, I use privateinternetaccess, so this is specific to their software. Different VPN's will have different installation steps.
      • dnf -y install wget unzip python NetworkManager-openvpn-gnome util-linux coreutils
      • wget https://www.privateinternetaccess.com/installer/pia-nm.sh
      • chmod ugo+x ./pia-nm.sh
      • ./pia-nm.sh
        Note, this will prompt you for the user name.
      • Enable the VPN in Settings, and that will prompt you for the password.
    • Install Password Managers (keepassXC and Seahorse)
      • Install keePassXC from the Software Manager
      • Install seahorse from the Software Manager

    • Install and edit public keys. (see my private notes in the tools dir for that)

    • Install support for my Backup to Google Drive. This requires installing Python libraries used by my Python scripts.
      • Install pip - go to https://pypi.org/project/pip/
      • sudo -i
      • pip install --upgrade pip
      • pip install --upgrade google-api-python-client
      • pip install oauth2client

    • Automate backups with cron
      • dnf install cronie cronie-anacron
      • If cron is not running, use this to configure it to run at boot:
        systemctl enable crond.service
      • Add this line to /etc/crontab
        0 2 * * * ddean /home/ddean/ddRoot/tools/offsiteBackup.sh

    • Install exfat File System
      • yum install exfat-utils.x86_64
      • dnf install fuse-exfat

    • Install startup scripts
      • cp ~/ddRoot/tools/ddean.desktop ~/.config/autostart/ddean.desktop
      • chmod ugo+x ~/.config/autostart/ddean.desktop
    • XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    • Set up Evolution email client
      • Copy emailArchive to local ~/ directory
      • Go through View menu options (Preview=Vertical, Uncheck group by threads)
      • Go through menu Edit>Preferences
      • Setup gmail
        • Select the menu "Edit>Accounts" and then expand the list item for your email account, then expand the list item for "Mail Accounts" and then select the list item for your email account and click the "Edit" button.
        • In the edit dialog, select "Receiving Email" and change the imap.googlemail.com to imap.gmail.com
        • In the edit dialog, select "Sending Email" and change the smtp.googlemail.com to smtp.gmail.com
      • Create an account for Local Archived files
        • Select the menu item File>New>Mail Account
        • For the General Dialog, FillName=Local Archive emailAddress=emailArchive@dawsondean.com
        • For the Receiving Email Dialog, accountType="Standard Unix mbox spool directory" spoolDirectory=[local archive dir]
        • For the Receiving Options Dialog, deselect all options, these messages have already been filtered and saved.
        • For the Sending Email Dialog, serverType=None
        • For the Account Summary Dialog, name="Local Archive"

    • Octave (open source Matlab work-alike)
      • dnf install octave

    • Pinta (paint)
      • yum install pinta

    • Install numpy and pytorch
      • sudo -i
      • python3 -m pip install numpy
      • python3 -m pip install https://download.pytorch.org/whl/cpu/torch-1.0.1.post2-cp36-cp36m-linux_x86_64.whl
      • python3 -m pip install tables
      • python3 -m pip install opencv-python
      • python3 -m pip install matplotlib
      • python3 -m pip install sklearn
      • sudo -i
      • dnf install python3-tkinter

    • Brother Printer
    Startup Scripts I added a command to the file "~/.config/autostart". In my case, for easier backup on Linux and Windows, I added a call to a shellscript I keep in my local account, but you can do anything else.

    Here is the file I put in my autostart directory

    #!/bin/sh
    /home/ddean/ddRoot/tools/loginScript.sh
    

    Here is the file I put in my own directory

    #!/bin/sh
    ###############################################
    # Login Script
    ###############################################
    emacs &
    emacs &
    thunderbird &
    google-chrome --new-window /home/ddean/ddRoot/HomePage/main.html &
    



    Installing and configuring Emacs

    A few common shortcuts that I personally prefer. The blessing/curse of emacs is that it is so customizable, everyone ends up with a slightly different solution. These are what I have come up with so far, but I am also still trying to tweak it to make it more to my liking. Still, you may not like these design choices.

    When testing a .emacs file, you can always use "M-x load-file" and then enter the file name. This will reload the config file without quitting and restarting the program.

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;;
    ;; Emacs Customization
    ;; Tips and tricks from many sources, collected by Dawson Dean
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Font Size and Type
    ;;
    ;; The height is 1/100th of a point, so 100 is a 10pt font.
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    (set-default-font "DejaVu Sans Mono")
    (set-face-attribute 'default nil :height 100)
    
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Text Colors
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    (set-face-foreground 'font-lock-string-face "black")
    (set-face-foreground 'font-lock-comment-face "dark green")
    (set-face-foreground 'font-lock-comment-delimiter-face "dark green")
    (set-face-foreground 'font-lock-function-name-face "black")
    (set-face-foreground 'font-lock-variable-name-face "black")
    (set-face-foreground 'font-lock-keyword-face "dark blue")
    (set-face-foreground 'font-lock-type-face "black")
    (set-face-foreground 'font-lock-constant-face "black")
    (set-face-foreground 'font-lock-builtin-face "black")
    (set-face-foreground 'font-lock-preprocessor-face "black")
    
    ;; The color of the mark region
    (set-face-attribute 'region nil :background "#BFEFFF")
    ;; Blue:    0000FF
    ;; Orange:  FFA000
    
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Custom Key Bindings
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    ;; Ctrl-Z is undo.
    (global-set-key (kbd "C-z") 'undo)
    (global-set-key (kbd "C-Z") 'undo)
    
    ;; Ctrl-/ will goto-line
    ;; This is totally unique to me, nobody else agrees on this. Lots of people
    ;; seem to like "Esc-g g" but that's still too many keystrokes for me.
    (define-key global-map (kbd "C-/") 'goto-line)
    
    ;; I sometimes have the Control key held down while doing other things.
    (define-key global-map (kbd "") (kbd ""))
    (define-key global-map (kbd "") [Double-Mouse-1])
    
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Basic Editing
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    ;; Shift-click will extend the mark region
    (define-key global-map (kbd "") 'mouse-save-then-kill)
    
    ;; Typing will replace the currently selected text.
    (delete-selection-mode 1)
    
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Syntax Table Hacking
    ;; http://www.emacswiki.org/emacs/EmacsSyntaxTable
    ;;
    ;; Word operations will not treat "_" as a word-break in C++. This puts
    ;; the character "_" (which is quoted with ? so it is ?_) in the "word"
    ;; class of characters (which is identified by "w").
    ;; Really, we just want to evaluate this:  (modify-syntax-entry ?_ "w")
    ;; But we add a hook so our customization is not clobbered every time
    ;; the symbol table is edited.
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    (add-hook 'text-mode-hook (lambda () (modify-syntax-entry ?_ "w")))
    (add-hook 'c-mode-hook (lambda () (modify-syntax-entry ?_ "w")))
    (add-hook 'c++-mode-hook (lambda () (modify-syntax-entry ?_ "w")))
    (add-hook 'html-mode-hook (lambda () (modify-syntax-entry ?_ "w")))
    (add-hook 'xml-mode-hook (lambda () (modify-syntax-entry ?_ "w")))
    (add-hook 'java-mode-hook (lambda () (modify-syntax-entry ?_ "w")))
    (add-hook 'js-mode-hook (lambda () (modify-syntax-entry ?_ "w")))
    (add-hook 'js2-mode-hook (lambda () (modify-syntax-entry ?_ "w")))
    (add-hook 'abbrev-mode-hook (lambda () (modify-syntax-entry ?_ "w")))
    
    
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Select the entire buffer
    ;; This was copied (with some small changes) from:
    ;; https://www.gnu.org/software/emacs/manual/html_node/eintr/mark_002dwhole_002dbuffer.html
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    (defun mark-whole-buffer()
           "Select the entire buffer"
           (interactive)
           (message "mark-whole-buffer!")
            ;; Put point at beginning 
           (push-mark (point))
            ;; Put the mark at end of buffer.
           (push-mark (point-max) nil t)
           (goto-char (point-min))
    ) ;; defun
    (global-set-key (kbd "C-S-A") 'mark-whole-buffer)
    
    
    
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; CUA Mode
    ;;
    ;; This makes Ctl-x cut, Ctl-v paste, and Ctl-C copy.
    ;; This is what you use in Web browsers, so it makes sense for all applications to
    ;; share a common convention.
    ;; http://www.emacswiki.org/emacs/CuaMode
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    (cua-mode t)
    (transient-mark-mode 1) ;; Default in Emacs 23 and later. Selected region is only active when highlighted
    ;;(setq cua-auto-tabify-rectangles nil) ;; Don't tabify after rectangle commands
    ;;(setq cua-keep-region-after-copy t) ;; Standard Windows behaviour
    
    
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;;
    ;; Searching: Find, Find-And-Replace, Grep 
    ;;
    ;; As I switched back to emacs after years on Microsoft's Visual Studio, I realized
    ;; that I use search to navigate around a buffer more than Ctl-V and Esc-V or similar
    ;; things. Here are some functions to find the next and previous instance of the
    ;; currently selected text.
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Find the next instance of the selected text
    (defun forward-search-selection (beg end)
        "Search for the current selection"
        ;; This tells elisp to call this command with the point and mark
        ;; as arguments parameters bound to beg and end
        (interactive "r")
    
        ;; Save the current selection to a local variable.
        ;; We want to deactivate the mark, so save a private copy first.
        (let (
              (selection (buffer-substring-no-properties beg end))
             )
            ;;(message "selection:%s" selection)
        
            ;; De-activate the current mark region. We will change the mark later
            (deactivate-mark)
    
            ;; Find the next instance of the string.
            ;; https://www.gnu.org/software/emacs/manual/html_node/eintr/search_002dforward.html#search_002dforward
            ;; search-forward takes 4 arguments:
            ;;      The search pattern
            ;;      Optional - limit of search. nil means end of buffer
            ;;      Optional - how to handle failed search. nil means print a message.
            ;;                   t means return a result
            ;;      Optional - How many instances to find
            (when (search-forward selection nil t)
                ;; If search-forward returned true, then it found a match.
                ;; Select the match. This is nice for user feedback but it also
                ;; lets another search-forward find the next occurrence.
                (setf
                    (mark) (match-beginning 0)
                    (point) (match-end 0))
            ) ;; when
        ) ;; let
    ) ;; forward-search-selection
    (define-key global-map (kbd "") 'forward-search-selection)
    
    
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Find the previous instance of the selected text
    (defun reverse-search-selection (beg end)
        "Search for the current selection"
        ;; This tells elisp to call this command with the point and mark
        ;; as arguments parameters bound to beg and end
        (interactive "r")
    
        ;; Save the current selection to a local variable.
        ;; We want to deactivate the mark, so save a private copy first.
        (let (
              (selection (buffer-substring-no-properties beg end))
             )
          
            ;; De-activate the current mark region. We will change the mark later
            (deactivate-mark)
    
            ;; Find the prev instance of the string.
            ;; This works like search-forward except it runs in reverse
            ;; search-backward takes 4 arguments:
            ;;      The search pattern
            ;;      Optional - limit of search. nil means end of buffer
            ;;      Optional - how to handle failed search. nil means print a message.
            ;;                   t means return a result
            ;;      Optional - How many instances to find
            
            (when (search-backward selection nil t)
                ;; If search-forward returned true, then it found a match.
                ;; Select the match. This is nice for user feedback but it also
                ;; lets another search-forward find the next occurrence.
                (setf
                    (mark) (match-end 0)
                    (point) (match-beginning 0))
            ) ;; when
        ) ;; let
    ) ;; reverse-search-selection
    (define-key global-map (kbd "") 'reverse-search-selection)
    
    
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Replace Text
    
    ;; Replace the next instance of the selected text
    (defun forward-replace-selection (beg end)
        "Search for the current selection"
        ;; This tells elisp to call this command with the point and mark
        ;; as arguments parameters bound to beg and end
        (interactive "r")
    
        ;; Save the current selection to a local variable.
        ;; We want to deactivate the mark, so save a private copy first.
        (let (
              (selection (buffer-substring-no-properties beg end))
             )
            ;; (message "forward-replace-selection:%s" selection)
        
            ;; De-activate the current mark region. We will change the mark later
            (deactivate-mark)
    
            (let (
                (replaceStr (read-from-minibuffer "Replacement: "))
                )
                ;;(message "replaceStr:%s" replaceStr)
    
                ;; Go to the start of the buffer.
                ;; search-forward will only start at the current position.
                (goto-char (point-min))
    
                ;; https://www.gnu.org/software/emacs/manual/html_node/elisp/Search-and-Replace.html
                (while (search-forward selection nil t)
                    ;; https://www.gnu.org/software/emacs/manual/html_node/elisp/Replacing-Match.html
                    ;; replace-match replacement &optional fixedcase literal string subexp
                    ;; fixedcase says to not change the case of the replacement text
                    ;; to match the text being replaced.
                    (replace-match replaceStr t))
            ) ;; let
    
        ) ;; let
    ) ;; forward-replace-selection
    (define-key global-map (kbd "C-r") 'forward-replace-selection)
    
    
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Grep
    
    ;; Find the next instance of the selected text
    (defun grep-selection (beg end)
        "Grep for the current selection"
        ;; This tells elisp to call this command with the point and mark
        ;; as arguments parameters bound to beg and end
        (interactive "r")
    
        ;; Save the current selection to a local variable.
        ;; We want to deactivate the mark, so save a private copy first.
        (let (
              (pattern (buffer-substring-no-properties beg end))
             )
            (message "ddGrep:%s" pattern)
        
            ;; De-activate the current mark region. We will change the mark later
            (deactivate-mark)
    
            ;; grep-find is a built-in emacs elisp function.
            ;; See: https://www.gnu.org/software/emacs/manual/html_node/emacs/Grep-Searching.html#Grep-Searching
            ;; See: https://www.gnu.org/software/emacs/manual/html_node/emacs/Grep-Searching.html
    
            ;; The options are the normal command line grep options.
            ;; Here, I use:
            ;;  -e, --regexp=PATTERN      use PATTERN for matching
            ;;  -i, --ignore-case         ignore case distinctions
            ;;  -n, --line-number         print line number with output lines
            ;;  -H, --with-filename       print file name with output lines
            ;;  -R, --recursive           like --directories=recurse, and also follow all symlinks
            ;;
            ;; Some useful topns which are not used now, but may be used later
            ;;  -w, --word-regexp         force PATTERN to match only whole words
            ;;  -x, --line-regexp         force PATTERN to match only whole lines
            ;;  -m, --max-count=NUM       stop after NUM selected lines
            ;;  -h, --no-filename         suppress the file name prefix on output
            ;;  -o, --only-matching       show only the part of a line matching PATTERN
            ;;  --include=FILE_PATTERN    search only files that match FILE_PATTERN
            ;;  -L, --files-without-match print only names of FILEs with no selected lines
            ;;  -l, --files-with-matches  print only names of FILEs with selected lines
            ;;  -T, --initial-tab         make tabs line up (if needed)
            ;;  -B, --before-context=NUM  print NUM lines of leading context
            ;;  -A, --after-context=NUM   print NUM lines of trailing context
            ;;  -C, --context=NUM         print NUM lines of output context
            (grep (concat "grep -i -n -H -R -e \"" (shell-quote-argument pattern) "\" /home/ddean/ddRoot/code"))
        ) ;; let
    ) ;; grep-selection
    (define-key global-map (kbd "") 'grep-selection)
    
    
    
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;;
    ;; Parens and Braces
    ;;
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Find the matching (open or close) paren
    ;; This was copied (with some small changes) from:
    ;; https://www.gnu.org/software/emacs/manual/html_node/efaq/Matching-parentheses.html
    (defun find-match-paren (arg)
        "Go to the matching paren if on a paren; otherwise insert %."
        (interactive "p")
        (cond
                ((looking-at "\\s(") (forward-list 1) (backward-char 1))
                ((looking-at "\\s)") (forward-char 1) (backward-list 1))
    
                ((looking-at "\\s[") (forward-list 1) (backward-char 1))
                ((looking-at "\\s]") (forward-char 1) (backward-list 1))
        ) ;; cond
    ) ;; defun
    (define-key global-map (kbd "C-]") 'find-match-paren)
    
    ;; Make braces act like parens, and match opens and closes
    (modify-syntax-entry ?{ "(}")
    (modify-syntax-entry ?} "){")
    
    
    
    
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;;
    ;; Tabs and Indentation
    ;;
    ;; http://www.emacswiki.org/emacs/IndentationBasics
    ;; https://stackoverflow.com/questions/344966/improved-tab-in-emacs
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    ;; Tabs are space characters, not a tab character.
    (setq-default indent-tabs-mode nil)
    
    (global-set-key (kbd "TAB") 'tab-to-tab-stop)
    (setq default-tab-width 4)
    (setq tab-width 4)
    
    ;; tab-width is used when DISPLAYING tabs, while tab-stop-list 
    ;; is needed to determine tab stops when you ADD tabs.
    ;; From emacs documentation, "The variable tab-stop-list controls these positions. The default value is nil, which means a tab stop every 8 columns."
    ;;;(setq-default c-basic-offset 4)
    (setq tab-stop-list (number-sequence 4 200 4))
    
    ;; Be careful. If you set this to newline-and-indent, then emacs
    ;; will autoindent no matter what you set the autoindent options to.
    ;;(global-set-key (kbd "RET") 'newline-and-indent)
    (global-set-key (kbd "RET") 'newline)
    
    ;; Don't use tabs to indent code.
    ;;;(setq-default indent-tabs-mode nil)
    
    ;; Stop emacs from trying to second-guess what it thinks I want.
    (when (fboundp 'electric-indent-mode) (electric-indent-mode -1))
    ;;(setq-default electric-indent-inhibit t)
    
    ;; Pasting a newline does not cause an indent.
    (global-set-key "\C-j" 'newline)
    
    
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;;
    ;; Indenting and Un-Indenting
    ;;
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    (defun shift-region (distance)
      (let ((mark (mark)))
        (save-excursion
          (indent-rigidly (region-beginning) (region-end) distance)
          (push-mark mark t t)
          ;; Tell the command loop not to deactivate the mark
          ;; for transient mark mode
          (setq deactivate-mark nil))))
    
    (defun shift-right ()
      (interactive)
      (shift-region 4))
    
    (defun shift-left ()
      (interactive)
      (shift-region -4))
    
    ;; C-[ is equivalent to the escape key on US English keyboards
    ;; Changing  C-[ will break things like Esc-x
    (global-set-key (kbd "C-]") 'shift-right)
    (global-set-key (kbd "C-.") 'shift-right)
    (global-set-key (kbd "C-,") 'shift-left)
    
    
    
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Backup Files
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    (setq backup-directory-alist `(("." . "~/emacsBackupFiles")))
    
    (setq delete-old-versions t
      kept-new-versions 1
      kept-old-versions 1
      version-control t)
    
    ;; This will turn off all backup files.
    ;; (setq make-backup-files nil)
    
    
    
    
    
    






    vi editor

    I used emacs until I went into IDE's. Now that I am back to some linux programming, here are some tips for those times when I do a bit of VI (like when you are running as root and need an editor for a config file).

    • Run vi - "vi fileName"

    • Enter insert mode - Type "i <RET>". Now any further text you type is entered into the file as data. You can use the arrow keys to move around the file. This command leaves command mode.

    • Leave insert mode - Type the <ESC> key. Now you are back in command mode.

    • Save changes and exit vi - ":wq <RET>" Type this in command mode

    • Exit vi withOUT saving changes - ":q! <RET>" Type this in command mode

    • Search for the next occurrence after the cursor of some pattern - "/pattern <RET>" Type this in command mode

    • Search for the previous occurrence after the cursor of some pattern - "?pattern <RET>" Type this in command mode

    • Find the next occurrence of the pattern - "n <RET>" Type this in command mode

    • Save the current file - ":w <RET>" Type this in command mode

    • Save the current file to a new file - ":w fileName <RET>" Type this in command mode



    Emacs Common Things

    For some reason, I always forget these things.

    • Conditional-Search-Replace M-% string RET newstring RET
      Then, <Space> to replace the current instance, <DEL> to skip the current instance, <RET> to stop search without any more replacements



    Burning DVDs on Linux

    I use an online backup service, but I still like to burn my home directory to a DVD every few days. It lets me make my own offsite backups, as well as shuttle my home directory between machines and between Linux and Windows. I know I might be able to use some online service for that, but with more complexity, with a monthly subscription fee, with challenges in portability across operating systems, with a dependency on a third party company that may change their UI or features or costs, and with my data sitting on somebody else's computer which may be secure but is also an inviting target for hackers. On Windows, I just used Roxio, but on Linux, here is a quick and dirty solution. I wrote scripts to do this, so I just run the script to burn an image:

    This uses growisofs, which requires you install

        yum install dvd+rw-tools
    
    Burning a data DVD with a tree of files
        su
        mkisofs -J -R -o /your-temp-directory-name/foo.iso -root your-top-level-dir-name  /your-home-dir
        growisofs -dvd-compat -Z /dev/cdrom=/your-temp-directory-name/foo.iso 
        rm -rf /your-temp-directory-name/foo.iso
    
    Restoring a Directory from a DVD
        su
        umount /dev/cdrom
        mount -t iso9660   /dev/cdrom   your-temp-directory-name
        rm -r -I   your-home-dir
        cp -r your-temp-directory-name   your-home-dir
        chown -R   your-user:your-group   your-home-dir
        chmod -R   u+rwx  your-home-dir
        umount /dev/cdrom
    
    Note, these must run as root.
    Burning VOB files to a Video DVD
    There are several alternatives.
    • mkisofs -dvd-video -o mydvd.iso -udf /path/to/filedir/
      This will not skrink, so the .iso file will be 8gb
    • genisoimage -dvd-video -v -o DVD.iso DVD



    Compiling Linux programs with static libraries

    Linux has adopted the philosophy that programs should be dynamic linked. There are both legal reasons for this (the libraries are built under GPL) and practical. However, suppose you want to compile a program, and then run your program on servers provided by web hosting companies. Your program must be compiled with exactly the same version of the runtime libc as is available on the hosting servers. Do hosting companies guarantee that? Of course not. So, instead your program must be compiled with static libraries. That is the problem I am trying to solve, and here are some notes.

    • Compile your programs with static linking. The compiler uses the flag -static. There are some other flags that I have seen discussed, but in practice I don't need them. These include the flags -Wl -Bstatic, where -Wl sends a flag to the linker and -Bstatic is the static link flag

    • Install the static libraries
      • yum install glibc-static
      • yum install libstdc++-static

    • Key networking system calls do not seem to work for a statically linked program. Specifically, you cannot lookup a network address if you are statically linked because getaddrinfo and even gethostname do not work. It seems that the name resolution library runs different code depending on host-specific preferences, like whether to use DNS or other network infrastructure. So, rather than writing 1 program that can call out to different local name resolver services (like, via a local pipe or system call), the C library is hard-compiled with the diffreent sources. This means that libc cannot call gethostbyname in a portable way. Instead, you must dynamically link with the local glibc on each different machine. If you really need to run the static glibc, then you cannot use this call.



    Installing and configuring mySQL

    Installation

    I use Fedora, which uses dnf and yum, and the best guide I found (granted after only a cursory look) is at www.if-not-true-then-false.com/2010/install-mysql-on-fedora-centos-red-hat-rhel


    Installing and configuring Apache
    See https://fedoraproject.org/wiki/Apache_HTTP_Server
    • Install Apache
      • su
      • dnf install httpd
      • To have the server start at each boot: systemctl enable httpd.service
      • To start the server now: systemctl start httpd.service
    • Configuration
      • GUI Configuration tool: /usr/bin/system-config-httpd
      • Manual edit config files. emacs /etc/httpd/conf/httpd.conf



    Using CSS "position" attributes for HTML Layout


    Many HTML elements may use CSS to control where they are positioned on a page. This is done with a "position" attribute, that may have two values: "absolute" or "relative". For example:

    • style="position:absolute; left:0px; top:0px;"
    • style="position:relative; left:0px; top:0px;"

    These can be confusing, because they use the terms "absolute" and "relative" to place an element in a position in relation to the "normal position of that element in the HTML layout", and NOT necessarily in relation to another element. So, the browser first lays out an HTML document, which assigns every element in the document to a position on the page. This initial position is referred to as the element's position in the "document flow". Once the browser has completed this initial layout step, then the CSS position attributes may override each element's position and place the element in a different place.

    "Relative" means place the element at some offset in relation to where it would normally go in the HTML laytout. So, for example, if a typical HTML page would place an element at x=100,y=200, and the element had an attribute

    • style="position:relative; left:50px; top:75px;"
    then the element would be placed at x=150,y=275.

    "Absolute" means place the element at some "absolute" position, and just ignore where it would normally go in the HTML laytout. So, for example, if a typical HTML page would place an element at x=100,y=200, and the element had an attribute

    • style="position:absolute; left:50px; top:75px;"
    then the element would be placed at x=50,y=75.

    However, the confusing part is that an "absolute" coordinate is still in relation to somethng. It may be in relation to the bottom-left corner of the HTML page, but it may also be in relation to a containing element, like a div element. So, "position:absolute" means an absolute position compared to the flow of the document but still relative to the position of the parent HTML element that contains the element being moved.


    Installing Raspberry Pi

    Installation with Linux

    • Run lsblk to see which devices are NOT the SD card. This will print a list of devices.
    • Plug an SD card into the linux box - I use a USB-SD-reader.
    • Run "lsblk" again. The USB HDMI is cometimes sdb, but beware. That can differ with different devices.
    • sudo -i
    • parted /dev/sdb - or whatever the device name of the SD card is.
      • (parted) mklabel msdos
      • (parted) mkpart primary fat32 1MiB 100%
      • (parted) set 1 boot on
    • mkfs.vfat /dev/sdb1
    • Ctrl-D
    • Download the latest noobs OS software from downloads.raspberrypi.org/noobs
    • Mount the device. One way to do this is to open Files, which will automount the new device.
    • cd ~/Downloads
    • unzip NOOBS_v2_8_2.zip -d /run/media/userName/xxxxxx - where userName is your name and XXXX is the volume name of the SD drive
    • Plug in the SD card, a USB mouse, a USB Keyboard, a HDMI monitor into the Pi and connect a powersupply.
    • Plug the power supply in, and the Pi should boot. It will install an OS from your SD card
    Some handy references:

    Copying Files from Linux to a Pi

    • Configure the Pi to accept SSH connections.
      • sudo systemctl enable ssh
      • sudo systemctl start ssh
      Or, try this:
      • On desktop, select menu "Preferences>Raspberry Pi Configuration"
      • Select the Interfaces tab
      • Select "Enabled" next to SSH
      • Select the "OK" button, and the Pi will reboot
    • On the Pi, open a terminal window and run "ifconfig". Next to the wlan0 entry, get the IP address
    • To copy from Linux to Pi: scp file.txt pi@xxx.xxx.xxx.xxx:destinationDir/
    • To copy from Pi to Linux: scp file.txt pi@xxx.xxx.xxx.xxx:
    Some handy references:

    Cross-compiling on Linux and Running on Pi

    I am not doing this yet. Currently, I am just maintaining source code on my dev box and copying it to a Pi and compiling it there.
    • yum install apt-get install git rsync cmake
      Note that ia32-libs is no longer supported.
    Some handy references:


    Android Studio

    Installation on Linux

    • On linux, I needed to install some directories first. For Fedora, this required these installs
              yum install compat-libstdc++-296.i686 compat-libstdc++-33.i686 ncurses-libs.i686 compat-libstdc++-33.x86_64 zlib.i686 bzip2-libs.i686
              yum install adb
              dnf install android-tools
      

    • Download and install the Android Development environment. See https://developer.android.com/studio/install.html. This will have instructions for Windows and Linux.

    • On Fedora, unzip the downloaded directory, which makes an "android-studio" directory. Then run the installer from the command line from , by running "~/android-studio/bin/studio.sh". I also run the "~/android-studio/bin/studio.sh" to launch the application after it has been installed (really, installation is just done the first time you start the app).

    Running Android-Studio and Loading a Project

    This assumes you installed the directory "android-studio" in your home directory. If you put it somewhere else, then change the "~" to the parent of your installed directory.
    • ~/android-studio/bin/studio.sh
    • In the "Welcome to Android Studio" window, there is a list of projects on the left side of the window. Click the project to load.

    Common Problems

    • Cannot Upgrade - No space left on device
      On linux, I often get errors when upgrading AndroidStudio. This is because the downloaded upgrade file is copied into /tmp, and that is often only the size of physical memory. If you have several SDK's, then upgrading all of them will download an 8g or more archive file, and that is too big to fit in a small /tmp. To fix this, try first pruning the SDK's you use, and then increase the size of /tmp. As root, edit the /etc/fstab file to change the line for the /tmp file system:
          tmpfs /tmp tmpfs defaults,size=3g 0 0
      
      You will need to reboot.

    Hello World

    This creates and runs a simple "Hello, World" app, and is drawn from https://developer.android.com/training/basics/firstapp/index.html
    • In the "Welcome to Android Studio" window, click the link "Start a new Android Studio project". This will open a dialog box where you provide basic information.

      • Enter the app name and your domain, and click "next"

      • In the "Target Android Devices" screen, select "Phone and Tablet" and click "next"

      • In the Add an Activity to Mobile screen, select Empty Activity and click "next"

      • In the "Customize the Activity" screen, keep the default values and click "Finish"

    • The first time you run on a physical device, you will need to do some setup.

      • Connect the device to your machine with a USB cable

      • Open the "Settings" app on the device

      • (Only on Android 8.0 or higher) select "System". On my older (ver 4.4) test phone, I select the "More" tab.

      • Scroll to the bottom and select "About Device" or "About Phone".

      • Scroll to the bottom and tap Build number 7 times.

      • Return to the previous screen to find Developer options near the bottom.

      • Open Developer options, and then scroll down to find and enable USB debugging.

      You may have to change the SDK to fit your device. Be careful to change only the "Min Sdk"

      • Select the menu "File>Project Structure". This opens an options dialog.

      • Select the "app" entry, below the "Modules" section, in the table-of-contents on the left side

      • Select the "Flavors" tab

      • Select the "Min Sdk Version" and "Target Sdk Version" combo boxes

      Some common problems:

      • I was getting an error:
        com.android.ddmlib.AdbCommandRejectedException: insufficient permissions for device
        See [http://developer.android.com/tools/device.html] for more information.
        Error while Installing APK
        

        Android-studio points you to the web page, "https://developer.android.com/studio/run/device" which does not help. It seems the problem is not with the device, but the development system. Specifically, you need to install a file that allows the PC to access the connected phone.

        First, you can manually list all devices connected to use with the command:

        > sudo lsusb
        

        This has a list of devices, one per line, and each includes two hex values separated by a colon (for example: 18d1:4e22). This is the manufacturerID:deviceID you need to tell the system to handle. These need to be included in a configuration file names, "/etc/udev/rules.d/51-android.rules" If this file does not exist, you must create it (as root).

        I found a template rules file on https://github.com/M0Rf30/android-udev-rules
        This has a rules file with vendor andd device id's for many popular phones. I simply copied the 51-android.rules file to my /etc/udev/rules.d dir and rebooted.

      • If you get an error like "com.android.ddmlib.AdbCommandRejectedException: device unauthorized." then your phone may have cached connection state for a different computer.
        • Revoke the old device permissions on your phone. Go to Settings > Developer options > Revoke USB debugging authorizations

        • Disconnect the phone from the USB, then plug it back in.

    • The first time you run in an emulator you will have to do some installation. Note, you need a CPU which runs SSSE3. I have tried to setup system images that do not require VM support, but still cannot make it work.
      • You have to download the necessary system images

        • In Android Studio, open "Android SDK Manager". It may be in the "Tools" menu or the "Tools -> Android -> SDK Manager" sub-menu

        • Click the "Show Details" or "Show Package Details" checkbox

        • Chose platforms/packages you want to download. For older non-Intel x64 systems, select "ARM EABI v7a System Image" or "ARM 64 v8a System Image"

        • Install the images

      • When installing SDK's or AVD's you may hit an error, "No space left on device Error". In my case, it was because my /tmp file system was too small. It appears that Android Studio creates large temporary files in /tmp when it unzips downloaded images. You could try to just do a "rm -r -I *" in the /tmp directory and try again. However, I find that some of the large zip files are bigger than /tmp will allow. So, in the end, I had to change the /tmp size in my /etc/fstab file. I do this only when downloading and installing the images, and then comment out the line when I am done so it does not take too much of my ram for the /tmp file system.

        • As root, add the following line to the end of the /etc/fstab
                  none    /tmp   tmpfs size=8G   0   0
                  

        • Reboot or remount for the changes to take effect

      • If, like me, you get an error that says, "An error occurred while creating the AVD. See idea.log for details", you may ask yourself, "Where are the logs? How do I fix this?"

        • The log files are in a directory, /home/>yourUserName</.AndroidStudio2.3/system/log on linux and C:\Users\yourid\.AndroidStudioPreview\system\log on windows. Be careful, depending on the version of Android Studio you are using, the "AndroidStudio2.3" directory may have a different version number suffix.

        • You may need to install additional libraries onto your system. For example, on Linux I had to run "yum install libgcc_s.so.1". Look in the idea.log file. In my case, I had an error like "WARN - Vdmanager.AvdManagerConnection - error while loading shared libraries: libgcc_s.so.1"

    • The first time you run, you may have to create an emulator

      • In Android Studio, open the "Android AVD Manager" from the menu "Tools" or a submenu "Tools -> Android -> AVD Manager"

      • Create an emulator

    • Select the "Run App" item in the "Run" menu. Or, click the green triangle "Play" but on on the toolbar

    • In the "Select Deployment Target" window, Select an existing device, or click "Create New Virtual Device"

      • To create a new device:

      • In the "Select Hardware" window, select the device you want to emulate, and click "next"

      • In the "Select Image" window, select the system software you want to emulate, and click "next". You may have to first dsownload some system images.

      • In the "Android Virtual Device (AVD)" window, review your choices and click "Finish"

  • In the Select Deployment Target window, select your device or emulator and click OK. Android Studio installs the app and runs it.

    Adding A Button

    • Edit the "activity_main.xml" file. This may initially display the XML but you can select the "Design" tab at the bottom of the XML text to show the palette.
    • Drag a button fromt he palette side-bar to the GUI
    • Select the button, and in the right-hand sidebar, edit the properties. Specifically, you may want to edit
      • ID - the ID used to refer to this button from code.
      • Text - the text displayed on the button
    • Select the MainActivity.java text. You will now add some text code to register and declare an event handler for the button.

    General Android Studio Tips

    • If you add code that uses a system type that is defined in a library that has not been imported, you will get an error, "Cannot resolve symbol".
      Select the undeclared type and press Alt + Enter (or Option + Return on Mac) and you will get a popup menu to select which library to import. The system will then insert the appropriate "import" statements at the top of your file.

    Editing an App's GUI in Android Studio

    • On the left vertical border of Android Studio are several tabs, that select main windows.
      • Project - This is a tree of objects in the app, including Java code, Resources, and more
      • Structure
      • Capture
      • Build Variants

    • Select the Project window, and then select the XML that defines the UI layout. For a simple app, this will be in the "app > res > layout > activity_main.xml" section of the Project tree. This will open an editor for manipulating the GUI. This creates several window panes
      • Palette - prototypes of View objects you can drag into the editor

      • Component Tree - the Views and ViewLayout objects that are in your GUI

      • The main GUI editor. Above this window pane is a toolbar with an icon of a blue square with a drop shadow on its corner (like a diamond). This selects the view of the GUI.
        • Design - previews what the UI will look like.

        • Blueprint - Displays an editor that allows you to add new Views and move or resize Views.
        In Blueprint mode, when you select an object in the View pane, then a configuration window pane with the attributes for that View object should appear on the right.

    • To delete an item from the UI, select its entry in the "Component Tree" and hit Delete-key

    • To add an item, select the item in the "Palette" window pane on the left. This is a 2-level hierarchical view, so first select the category in the left half of the pane (for example, category "Text") and then specific object (for example, "TextView") in the right half of the pane.

    • Drag the item you selected in the palette to the layout window in the large pane in the center of the screen. You can use the mouse to directly manipulate any View, such as resizing or moving it. Click and drag squares in the corners to resize the View. Click and drag circles inthe middle of the border edges to move the View.

    • To set the text in a View object, select the object in the layout window. This should open an "Attributes" window pane (in my installation, this is on the right). Select the "text" property, delete the contents of the property and then click the "..." button to the right of the text edit box. This opens a modal dialog that allows you to select a "string" resource which will be used for the View's text.

    • Create string resources in the Strings editor.
      • In the Project Window, select "app > res > values > strings.xml" and double click it.

      • Click the "Open Editor" link (not a tool bar icon)

      • To add a new string, click the green "+" toolbar icon. This opens a dialog box where you can enter the "key" and value for the resource.

    • Layout

      Layout uses constraints rather than absolute positions, because a single GUI will have to run on many different devices with different screen dimensions.

      • A Constraint between the edge of a view and the border of the app. Select the ViewObject and in the properties pane you can select the left, right, top or bottom margin to the edge of the app. You can also configure the View object to have a fixed size or else scale to fit the width or height of the App.

      • A constraint between 2 Views. Click one View object, then click the square the pops up to the lower left of the View object. This square is the "Edit Baseline" control. Select the Edit Baseline and then drag a connection to another View object. This will put the 2 View objects on the same horizontal baseline.

      • Chain constraints. Select one view, then shift-select a second view. Then right click either view, and in the context menu select "Chain > horizontal" or "Chain > vertical". This will force the Views to be in a horizontal or vertical line

    Adding new code to an App in Android Studio

    • Adding a new file of source code

      In Java, typically each class is in its own file, so the most natural way to add new code in Android is to add a new class.

      Select the menu "File>New>Java Class" and then follow the prompts. This will create a new file in the "projectName/app/src/main/java/com/yourDomainName/projectName/className.java" subdirectory under your App project directory. Where:

      • "projectName" is the name of your project
      • "yourDomainName" is the name of your domain
      • "className" is the name of your domain
      I prefer to select the ".java" tab to view the project structure in an outline editor window pane, and then right click the appropriate secion of the project under the app>java>... section. This will create a new class file under a specific Java package within the app.

      The new file will contain an empty class definition, to which you can add methods. The file should also contain a code that says it belongs to the same package.

      package com.yourDomainName.projectName;

      I find I can edit the files in any editor (such as emacs) and Android Studio will always read the latest version of the file on disk.

    • Calling your code from the GUI

      You first need an instance of your class.

      • Declare the variable in the main activity class.
        myClass g_GlobalCommand;
      • Create an instance of this class when the app starts. One easy place to do this is the onCreate() methods for the activity.
        g_GlobalCommand = new myClass();
        Now you should be able to call methods on the class from anywhere.

    • Setting the function to run when you click a button

      Your function needs to be public, return void, and take a single parameter of type View. As an example:

        
          // Called when the user taps a button
          public void
          onButtonClick(View buttonView) {
              // Do something in response to button
          } // onButtonClick
      

      Set the "onClick" attribute of the View object. To do this, go into the layout editor, and select the View object to display its properties (in a window pane on the right side of the screen). There is a property labelled "onClick" that selects from a pull-down menu of callback methods you have declared in the code as of the last compile. Select the appropriate function.

    • Change the string in an object (ie, change "Hello World!" to "I have Changed!")

      Get the attribute of the View object. To do this, you may need to go into the layout editor, and select the View object to display its properties (in a window pane on the right side of the screen). There is a property labelled "ID" at the top of the list of properties. You may need to provide a value.

      Get a reference to the View object using its ID.

        
          EditText editText = (EditText)findViewById(R.id.edit_text);
          editText.setText("I have changed!!!");
      

    • Open a new Activity
      This uses "Intent" objects - which are declaring an App state change. These can be created any time, and really it is like making a systm call to Android, but you do so by creating an Intent system object and then invoking a method on it.
      Intent intent = new Intent(this, DisplayMessageActivity.class);
      EditText editText = (EditText) findViewById(R.id.editText);
      String message = "extra param";
      intent.putExtra(EXTRA_MESSAGE, message);
      startActivity(intent);  
      
      The contstructor to the Intent object takes 2 parameters
      • A context (we use "this" because the Activity is a subclass of a context)
      • The ID of the new activity class
      Additionally, this also passes an additional parameter to the startup code for the new activity. This is optional but useful. To do this, you will need to declare the EXTRA_MESSAGE constant in the class
      public static final String EXTRA_MESSAGE = "com.dawsondean.myfirstapp.MESSAGE";  
      

      Next create a new activity class. In Android Studio, look at the Project window pane, and right-click the app folder and select "New > Activity > Empty Activity" action. This will open a dialog box where you configure the new Activity. When you hit the "Finish" button, this will create an xml file for the Activity GUI, and also a Java file for the Activity code.

      Declare the hierarchy of the activities in the AndroidManifest.xml file. To do this, open the file by double clicking "app > manifests > AndroidManifest.xml" in the project window pane. Now add the following to the DisplayMessageActivity tag

      
          
          
      
      
      This will tell Android to put in a navigation button in the DisplayMessageActivity activity to go back to the parent activity.

    • Get the contents of a text edit control
          EditText editText = (EditText) findViewById(R.id.editText);
          String message = editText.getText().toString();
      
      
      
      



    Android Debugger

    Starting the Debugger

    Use the "Debug 'app'" command in the "Run" menu.
    • Setting a Breakpoint - Open the source code file, and click on the left column. A red dot should appear on the left margin of the line with the new breakpoint.
    • Step Into - F7
    • Step Over - F8
    • Resume - F9



    Java Programming


    Install the SDK from Oracle: http://www.oracle.com/technetwork/java/javase/downloads/index.html
    A good Tutorial is: https://introcs.cs.princeton.edu/java/11hello/

    Hello World

     
    // The public class name must match the file name
    // However, if there is no public class, then the file name and class names do not have to match.
    // Even if there is a public class, you may have any number of non-public classes and they can have any name.		
    public class HelloWorld {
        //////////////////////////////////////////
        public static void
        main(String[] args) {
          System.out.println("Hello, World!");
        } // main()
    } // class HelloWorld
    
    To Compile: javac HelloWorld.java To Run: java HelloWorld

    Packages

    These define a named scope, usually at the file granularity. Put somethinig like this at the start ofo a file: package com.dawsondean.medicalDevices.scopeNamee;

    Built-In Types

    6 Primitives: char, int, float, boolean, byte short, long, double 6 Boxed Primitives: Integer, Float, Collection Interfaces Collection - unorodered group of things, may have duplicates Set - unorodered group of things, no duplicates List - Like an array. Inddexed by an integer 0 .... length-1 Map - A group of name/value pairs Collection Base Types (Implementations) ArrayList - implements list LinkedList - implements list HashSet - implements set HashMap - implements Map TreeMap - implements Map Generics are like template types in C++. Basically, it is a macro for types. List Bundle - This is a map that maps string keys to values of different built-in types. It supports the "Parseable" interface so can be marshalled across an IPC.
     
    Iterators
      for (iterator iter = list.iterator(); iter.hasNext();) {
        string s = iter.next();
      }
    
    for (string s: list) {
     }
    

    Interfaces and Classes

    These are like pure virtual base classes in C++
     
    public interface MyAPI {
      void foo();
    }
    
    extends - subclass a parent class
    implements - implement an interface
    	
    public class CMyClass implements MyAPI, YourAPI  extends MyBaseClass
      @override
      public void foo() {
      }
    
    }
    
    Note that all method bodies are inline. You can only extend one base class but you can implement any number of interfaces Common Classes Object - basetype of all casses. Any synchronization methods work on a type Object so it may alsoo be used to make a concrete instance String

    Anonymous Classes

     
      fooSetListener (
    		  new CListenerClass () [
    					 public void myCallback(int foo) {
    					       // Do something.
    					 } // myCallback
    		         } // CListenerClass
    		  );
    
    An anonymous class can only access "final" variabales that are defined in the surrounding scope. The life of the anonymous class may extend beyond the life of the parent scope, which may happen often if an anonymous class is a callback.

    Keywords

    static On a Variable: A global variable, not associated with a specific object instance. Variables are by default dynamic. On a Method: A global method, not associated with a specific object instance. Methods are by default dynamic. On a Class: Class name scope is global. Classes are by default static, A static class does NOT havee access to instance variables of enclosing class final On a Variable: Cannot be changed after initialized On a Method: On a Class: Cannot be subclassed dynamic This is the opposite of static. On a Variable: Associated with a specific object instance. Variables are by default dynamic. On a Method: Associated with a specific object instance. Methods are by default dynamic. On a Class: Class name scope is local to a block of code. A dynamic class may access instance variables of enclosing class. Classes are by default static private On a Variable: - Only visible to the class that contains it, not to subclasses On a Method: - Only visible to the class that contains it, not to subclasses On a Class: package On a Variable: - Visible to the class that contains it, and any other classes in the same package, like "friend" classes in C++ On a Method: - Visible to the class that contains it, and any other classes in the same package, like "friend" classes in C++ On a Class: protected On a Variable: - Only visible to the class that contains it and any subclasses On a Method: - Only visible to the class that contains it and any subclasses On a Class: public: On a Variable: Visible to any code in any package On a Method: Visible to any code in any package On a Class: The class that contains the "main" function for the program

    Exceptions

     
    try {
        // do something
      } catch (Exception e) {
        // do soething
      }
    
    public void Foo() throws Exception {
      throw new Exception();
    }
    

    Worker Threads

     
    public class myThreadClass implements Runnable {
        @override
        public void run() {
          // do something
        }
    } myThreadClass
    
    To fork:
     
    myThreadClass worker = new myThreadClass();
    Thread t = new Thread(worker);
    t.start();
    
    The synchronized keywork is like Monitor methods in Mesa - it can only have one active call in all threads.
     
    class  CMyClass {
      privaate Object m_Lock = new Object();
    				       
       public synchronized void foo1() {
         // Do Something
       }
    
       public void foo2() {
         synchronized(this);
         // Do Something
       }
    
       public void foo3() {
         synchronized(m_Lock);
         // Do Something
       }
    }
    
    Other synchronization primitives Thread.sleep(1000); // static methodds, sleeps for n ms this.notifyAll(); // wakee up all threads blocked on this thread yourRunnableObject.wait(); // block on a Runnable object calldd "yourRunnableObject"
     	
    public static final class CMyAsyncWorker extends AsyncTask   {
        private final m_LocalVar;
    
        ///////////////////////////////////////////////////////
        public
        CMyAsyncWorker(int foo) {
          m_LocalVar = foo;
        } // CMyAsyncWorker
    
        ///////////////////////////////////////////////////////
        // Runs on parent thread
        @override protected void
        onPreExecute() {
        } // onPreExecute
    
        ///////////////////////////////////////////////////////
        // Runs on worker thread
        @override protected workerResult
        doInBackground(workerParam param) {
          workerResult x;
          return(x);
        } // doInBackground
    
        ///////////////////////////////////////////////////////
        // Runs on parent thread
        @override protected void
        onProgressUpdate(progressParam param) {
        } // onProgressUpdate
    
        ///////////////////////////////////////////////////////
        // Runs on parent thread
        @override protected void
        onPostExecute(workerResult param) {
        } // onPostExecute
    
    
        ///////////////////////////////////////////////////////
        // Runs on parent thread
        @override protected void
        onProgressUpdate(progressParam param) {
        } // onProgressUpdate
    
    } // CMyAsyncWorker
    
    To fork the thread:
     
        new CMyAsyncWorker(31).execute(workerParam);
    
    Note: each instance of a AsyncTask can only be executed once. To update progress counter threadObject.publishProgress(param); Java threads can be a subtype of "Looper" which is a worker thread ad a job queue

    Static Analyzers

    - FindBugs


    Android Programming


    App Components

    Applications are made of high level components 1. Activity - A unit of interaction, typically one view or tool or screen withinn an app. It is a unit of execution, and may be started or stopped at any time during an app's lifetime
     
    public class MyActivity extends Activity {
        private final String myTag = this.getClass().getSimpleName();
        private final String restoreTag = ", can restore state";
        private final String myState = "MyStateXML";
    
          ///////////////////////////////////////////////////////
          @override public void
           onCreate(Bundle savedState) {
                super.onCreate(savedState);
    
                // Use resource definitions to build the View tree for the default view
                setContentView(R.Layaout.main);
    
                // If we are being reactivated, rather than initializing for the first time, then restore any state
                // we saved when we were last suspended.
                if (null != savedState) {
                     myState = savedState.getString("value");
                }
    
                Log.i(myTag, "onCreate");          
           } // onCreate
    
          ///////////////////////////////////////////////////////
          @override public void
           onRestart() {
                super.onRestart();
                Log.i(myTag, "onRestart");
           } // onRestart
    
          ///////////////////////////////////////////////////////
          // The activity is starting
          @override public void
           onStart() {
                super.onRestart();
                Log.i(myTag, "onStart");
           } // onStart
    
          ///////////////////////////////////////////////////////
          // The activity will interact with the user
          @override public void
           onResume() {
                super.onResume();
                Log.i(myTag, "onResume");
           } // onResume
    
          ///////////////////////////////////////////////////////
          // The activity will stop interacting with the user
          @override public void
           onPause() {
                super.onPause();
                Log.i(myTag, "onPause");
           } // onPause
    
          ///////////////////////////////////////////////////////
          // The activity is now invisible
          @override public void
           onStop() {
                super.onStop();
                Log.i(myTag, "onStop");
           } // onStop
    
          ///////////////////////////////////////////////////////
          // The activity is being shutdown
          @override public void
           onDestroy() {
                super.onDestroy();
                Log.i(myTag, "onDestroy");
           } // onDestroy
    
    } // MyActivity
    
    Activity objects may be suspended and deleted any time the system needs more resources. Each activity must be able to save and restore its state at any time so deleting/recreating an activity is invisible to the user. 2. Intent - is a message to start an activity, and also passes initial parameters tot he activity initializiation. A single intent may cause one or more activities to start 3. Service - Implements background tasks but has no UI, like a Unix daemon process. 4. ContentProvider - provides a data stream, from either local or remote data. For example, the local contacts list is accessed through a local ContentProvider. Each ContentProvider supports a REST model, and provides basic methods: insert() query() update() delete() A "ContentResolver" will find the content provider that supplies a particular type of data.
     
        Cursor cur = getContentResolver().query(
                                            android.provider.ContactsContract.Data.CONTENT_URI,
                                            new String() { android.provider.ContactsContract.Data._IO, android.provider.ContactsContract.Phone.NUMBER },
                                            null,
                                            null,
                                            null);
    
    The URI that describes a content provider is of the form content:///path/id 5. Appliciation - The top-level class, but it is more of a plain container and does not provide much functionality of its own. View Class Override the method onSaveInstavceState to save specific state
     
    public class MyActivity extends Activity {
    
       private static class MyWidget extends View {
          public MyWidget() [ }
          @override protected void onMeasure(int w, int h) { }
          @override protected void onDraw(Canvas canvas) { }
       } // MyWidget
    
    
       @override protected void onCreate(Bundnle state) { }
    } // MyActivity
    

    Serialization

    When any Activity is suspended, its state is serialized to a persistent object called a "Bundle". Each Activity is seperately serializzable.
     
    public class CMyClass extends Activity {
    
        private static class CAppState implements serializable {
        }
        private CAppState m_AppState;
        
        ///////////////////////////////////////////////////////
        // Override an Activity method
        @override public void
        onCreate(Bundle savedAppState) {
          super.onCreate(savedAppState);
    
          // If savedAppState is null,  then this is the first initialization
          if (null == savedAppState) {
    	m_AppState = new CAppState;
          } else {
    	m_AppState = (CAppState) savedAppState.getSerializable(APP_STATE);
          }      
        } // onCreate
    
    
        ///////////////////////////////////////////////////////
        // Override an Activity method
        @override protected void
        onSaveInstanceState(Bundle outState) {
          super.onSaveInstanceState(outState);
          outState.putSerializable(APP_STATE, m_AppState);
        } // onSaveInstanceState
    
        ///////////////////////////////////////////////////////
        // Override an Activity method
        @override protected void
        onRestoreInstanceState(Bundle savedAppState) {
          super.onRestoreInstanceState(savedAppState);
    
          m_AppState = (CAppState) savedAppState.getSerializable(APP_STATE);
        } // onSaveInstanceState
    
    } // CMyClass
    
    Additionally, Java objects can implement the "Parceable" interface that supports fast efficient marshalling for IPC. This implements a WriteToParcel method, as well as a CREATOR objest that is a special constructor that takes a marshalled state and unmarshalls a runtime object. It also has get/set methods for all state variables

    Project Directory

     
    myApp
       |
       | - AndroidManifest.xml
       |
       | - src/
       |      Source code, as .java files
       |
       | - bin/
       |      Compiled classes, .class files
       |
       | - gen/
       |     Compiler generated source code
       | 
       | - res/
             |
             | - layout/
             |
             | - drawable/
             |       Images, drawable XML
             |
             | - raw/
             |      Data files to be loaded as streams
             |
             | - values/
             |     XML files containing strings and numbers
    
    You may further specify several layouts, each for a different device or configuration. For example, res/layout/main.xml may be augmented with: res/layout-land/main.xml // Landscape screen res/layout-port/main.xml // Portrait screen You can also have different configurations for screen size, pixel density, language, region, docking state, and more Android resolves the same constant "layout/main.xml" to the specific layout option using the current system state.

    Resources

    Java reads .xml files in res/ directory and stores the compiled data in the bin/ dir All resources are accessed at runtime with an object of class "Context" The Activity class and Service class both extend the Context class, so all activities and services have access to context methods. The getResources method in the parent Context class will return a runtime context object. For example: String s = this.getResoources().getString(...); So, how do you identify individual resources at runtime? Java generates a runtime class, names "R", at cocmpile time, and R contains all resource names. Really, this is just like a bunch of constants, but it is accessed through static members of a public and globally available class. So, for example: String s = this.getResoources().getString(R.string.hello_world);

    Manifest Files

    This is an XML file that declares activities, content providers and other coponents of an App. It also declares required permissions for running the app so a usere may decide whether to use an App.
    <!-- Package is the default package. versionCode and versionName describe the app, not Android itself  -->
    <?xml encoding="utf-8" ?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.dawsondean.medicalDevices.scopeNamee;"
           android:versionCode="1"
           android:versionName="1.0">
    
        <!--  Permissions required by this app   -->
        <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    
        <application .android:icon="@drawable/icon"
                               android: label="@string/app_name"
                               android:debuggable="true>
        </application>
    
    
        <activity android:name=".MainConsole"
                               android: label="Main Console">
        </activity>
    
    
        <provider android:name=".MainConsole"
                               android: authorities="xxxxxxxxxx">
        </provider>
    
    
        <service android:name=".MainConsole"
                               android: label="Main Console">
        </service>
    
    
        <receiver android:name=".MainConsole"
                               android: label="Main Console" />
    
        <uses-sdk android:minsdkVersion="7" />
    </manifest>
    

    .apk files

    This is the final binary package that will be delivered to users The apkbuilder application will generate one of these from a compiled source tree you run the apk file in an emulator or else upload to the store or a web server.

    Libraries

    Here are some of the key Android libraries android.view android.graphics android.widget android.text android.app android.content android.databases android.telephone android.webkit java.lang java.util All of the built in classes like collections javax Not part of the required Java spec but common and useful Contaians XML libraries org.apachee.http The apache http client org.w3c.dom org.xml.sax org.xmlpull org.json

    Publishing an App to the Android Store

    Sign your binary with a public/private key pair. This does not have to come from a signing authority, like verisign, but cana be self-generated. Any debug build will by default use a special debug key, so it is automatically signed for fast development testing. These keys are in the ~/.android/debug.keystore file. You use the "keytool" command to inspect this, and keytool is part of JDK. For example, run "keytool -list -keystore debug.keystore". The password to this keystore is by default "android". 1. You can then create a private key with keytool: "keytool -genkey -v -keystore my-release-key.keystore -alias -keyalg RSA -keysize 2048 -validity 50000" 2. Use a key to sign an app. Usually in the IDE. In Eclipse, this is File/Export menu. This will create an .apk file 3. Sign up as an official Android Developer http://market.android.com/publish/signup This is a 25$ fee and needs you to login with a gmail password 4. Upload an app http://market.android.com/publish/Home#AppEditorPlace To be paid for an App, sign up for a "merchant account". To use Google Maps data, you need a separate Google Maps API Key that is linked with the key you use to sign your app.

    Views

    View comes from the MVC Model Model - the engine of an app View - The display to show state to the user Controller - the user input that drives program actions A view is like a window in Windows. There is a tree of views, each is a rectangle of screen real estate. Views can contnain child views, the rectangle of a child view is clipped by its parent. Views are used to make buttons and controls. Internal tree nodes are often called "container views" and leafs are often informally called widgets because they implement both view and controller roles. All leaf nodes are subclasses of android.view.View All container views are subclasses of android.view.ViewGroup, which in turn is a subclass of View LinearLayout is a class of container views that arrange children in a line, either a single row or column. Each app has a single FIFO EventQueue, which is a sequential queue of events generated by user actions and other UI activity (for example, Redraw is an event) The Android base classes will implement the main event loop, andd pull events off the head of the queue and call the appropriate callback method. All UI components may override the default callbacks so they will be called for specific events. The UI is single threaded.

    Programattically Creating a Tree of Views in a App

     
    private LinearLayout  root;
    
    @override public void
    onCreate(savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        LinearLayout.LayoutParaams containenrParams
            = new LinearLayout.LayoutParaams(
                               ViewGroup.LayoutParaams.FILL_PARENT,
                               ViewGroup.LayoutParaams.WRAP_CONTENT,
                               0.0F);,
    
        LinearLayout.LayoutParaams widgetParams
            = new LinearLayout.LayoutParaams(
                               ViewGroup.LayoutParaams.FILL_PARENT,
                               ViewGroup.LayoutParaams.FILL_PARENT,
                               1.0F);
    
        root = new LinearLayout(this);
        root.setOrientation(LinearLayout.VERTICAL);
        root.setBackgroundColor(Color.LTGRAY);
        root.setLayoutParams(containenrParams);
    
        LinearLayout l1 = new LinearLayout(this);
        l1.setOrientation(LinearLayout.HORIZONTAL);
        l1.setBackgroundColor(Color.LTGRAY);
        l1.setLayoutParams(containenrParams);
        root.addview(l1);
    
        EditText tb = new EditText(this);
        tb.setText(R.string.defaultText);
        tb.setFocusable(false);
        tb.setLayoutParams(widgetParams);
        l1.addView(tb);
    
        Button b = new Button(this);
        b.setText(R.string.labelRed);
        b.setTextColor(Color.RED);
        b.setLayoutParams(widgetParams);
        l1.addView(b);
    
        setContentView(root);
    } // onCreate
    

    Creating a Tree of Views in a App With Resources

     
          private LinearLayout  g_RootView;
          private EditText  g_TextBox;
          private Button  g_Button;
    
          @override public void
           onCreate(savedInstanceState) {
                super.onCreate(savedInstanceState);
    
                // Create a tree of views from a resource 
                setContentView(R.Layaout.main);
    
                // Get UI components
                g_RootView = (LinearLayout) findViewById(R.id.root);
                g_Button = (Button) findViewById(R.id.myButton);
                g_TextBox = (EditText) findViewById(R.id.myText);
    
                // Create and register a callback.
                Button.OnClickListener listenet =  new Button.OnClickListener() {
                                @override public void
                               onClick(View arg0) {
                                    // Do some work here
                               } // onClick
                        } // End of anon class
                g_Button.setOnClickListener(listener);
    
                // Listen for taps - user finger events on the touch-sensitive screen.
                // NOTE: Trackball events are handled differently - they are converted to D-pad keystrokes
                // Touch events are a lot like mouse clicks, with separate events for DOWN, MOVE, UP
                // For efficiency, not all events may be reported. But a MOVE event may batch together several coordinates into a single event.
                // The method can call event.getHistoricalX(index), and event.getHistoricalY(index) and more to get all intermediate drag positions 
                // since the last time it was callled.
                View.OnTouchListener listener2 = new View View.OnTouchListener{ 
                               @override public boolean
                               onTouch(View v, MotionEvent event) {
                                    // Do some work here
                               } // onTouch
                        } // End of anon class
                g_RootView.setOnTouchListener(listener2);
    
           } // onCreate
    

    Event Listeners

    Each View class defines event processing methods, like OnTouch and OnKey. These are built-intoo the View class. You may define a View subclass that overrides these methods. Additionally, every view object may ALSO have a listener object, that sees events first. The listener may process events before the View object. This lets you intercept events even if you do not implement or subclass the View. Each event method in the listener returns a boolean (true/false) that tells the framework whether the event has been consumed. If there is no listener or else the listener method returns false, then the framework will pass the event on to the View.

    Touch Events

    The same OnTouch callback can be used to handle several types of touch events.
     
    onTouch(View v, MotionEvent event) {
        switch (event.getAction()) { 
        ///////////////////////////////////////
        case MotionEvent.ACTION_DOWN:
            break;
    
        ///////////////////////////////////////
        case MotionEvent.ACTION_UP:
            break;
    
        ///////////////////////////////////////
        case MotionEvent.ACTION_MOVE:
            break;
        } // switch
    
        return(true);
    } // onTouch
    
    Information about a single event comes from the event object event.getX() event.getY() event.getPressure() event.getSize() Additionally, several events may be batches in a single MOVE event. This will describe each point in the path of movement event.getHistoricalX(index) event.getHistoricalY(indnex) event.getHistoricalPressure(indnex) event.getHistoricalSize(indnex) Additionally, a single event may descrbe several pointers, such as when you zoom with 2 fingers event.getX(pointerIndex) event.getY(pointerIndex) event.getPressure(pointerIndex) event.getSize(pointerIndex) This tells you how many pointers are active. event.getPointerCount(); But, the same pointer may show up at different indexes for different events. In this case, use the pointerId to find which index will access it. To get the id of a particular index index = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK; index = index >> MotionEvent.ACTION_POINTER_INDEX_sHIFT; pointerId = event.getPointerId(index); Then for every event, to get the index of a particular id index = event.findPointerIndex(pointerId);

    Key Events

     
    View.OnKeyListener listener2 = new View View.OnKeyListener{ 
                  @override public boolean
                   onKey(View v, int keyCode, MotionEvent event) {
                       switch (event.getAction()) { 
                            ///////////////////////////////////////
                            case KeyEvent.ACTION_DOWN:
                               break;
    
                            ///////////////////////////////////////
                            case KeyEvent.ACTION_UP:
                               switch (keyCode) {
                                   case KeyEvent.KEYCODE_SPACE:
                                        break;
                               }
                               break;
    
                           ///////////////////////////////////////
                           case KeyEvent.ACTION_MULTIPLE:
                              event.getRepeatCount();
                               break;
                           } // switch
    
                           return(true);
                        } // onKey
                    } // End of anon class
                g_RootView.setOnKeyListener(listener2);
    

    Focus Events

    This handles selecting/deselecting a selected control withinn a view.
     
    View.OnFocusChangeListener listener2 = new View View.OnFocusChangeListener{ 
                  @override public boolean
                   onFocusChange(View v, boolean hasFocus) {
                       return(true);
                    } // onFocusChange
         } // End of anon class
    g_RootView.setOnFocusChangeListener(listener2);
    
    You can also call widget.requestFocus(); to select a specific widget.. Focus is best for text edit widgets. You do *NOT* have to focus a button before clicking it.

    Multithreading and Handlers

    This is a thread-safe way of calling another thread in a way that is synchronized with that thread's event queue. For example, this is very handy to call the main UI thrad from another worker thread. On the UI thread, call this: private final Handler myHandler = new Hanadler(); On the worker thread call this:
     
    private final Runnable myRunnable;
    myRunnable = new Runnable() {
       public void
       run() {
         // Do something.
       } // run()
    }; // myRunnable anon class
    myHandler.post(myRunnable);
    
    A Handler object is associated with the thread on which it is created. For example, if it is created on the UI thread then iti is associated with the UI thread. It may be invoked (via a post method) from any thread. Post takes a runnable object aand will execute that object on the associated thread. For example, call post(myObj) frorm a worker thread and then myObj is run on the UI thread and is synchronized witht he event queue of the UI thread.

    Menus

    The old style of a single optionMenu is being deprecated in favor of the newer model of an action bar. You can create a single menu that is compatible with a task bar. In the View subclass, override the following:
     
      @override
      public boolean
      OnCreateOptionsMenu(Menu menu) [
          getMenuInflater().inflate(R.menu.simple_menu, menu);
          return(true);
      } // OnCreateOptionsMenu
      
      @override
      public boolean
      OnOptionsItemSelected(MenuItem menuItem) [
          switch(menuItem.getItemId()) {
              case R.id.menu_clear:
                  break;
          } // switch
          return(true);
      } // OnOptionsItemSelected
    

    Fragments

    Views may be swapped out, so one is always visible, but this forms a simple card-stack like interface. A fragment is a persistently visible view, so it can be a side-bar. Fragments are similar to views, and have similar event handler callbacks. Fragments are loaded by an XML specification, just like vieiws, with setContentView(r.layout.myFragment); Fragments have callbacks onSaveInstanceState just like views Fragments can be added to ViewGroup and Layout objects, so it acts like a view. But it outlives a particular ViewGroup However... Fragments are not Contexts Fragments have a lifecycle tied to an Activity, not a specific view. In the XML declaration, a fragment will specify a class name that implements that class. The class must be publicly visible within the application AND the class must subclass the "Fragment" class, not Activity or View The subclass should NOT have a constructor - do the initializataion later in response to an early event An object instance of the class will be created when the fragment XML isi loaded
     
    public class MyFrag extends Fragment {
        //////////////////////////////
        public void
         onCreate(Bundle state) {
             super.onCreate(state);
             // Do init here that would normally be done in a constructor method.
       } // onCreate
    
    
        //////////////////////////////
        public View
        onCreateView(LayoutInflator inflator, ViewGroup container, Bundle b) {
          View view inflator.inflate(R.layout.myLayout, container, false);  // Must pass false
    
          // Init the view
          
          return(view);
        } // oCreateView
    }  // MyFrag
    
    Note, you create the view separately than when the fragment is created. The contnainer will eventually be the parent to the inflated fragment view (calaled a shard). BUT, the fragment owns the inflated view, so it is dispplayed in the parent container but it may have a lifespan that outlives the parent container. It is not tied to the parent contnainer. The object instance of the fragment object may either be created byt he system when the xml formata is loaded or else explicitly. But, never replace a fragment that is created by an XML init with one that is explicitly created - their lifetimes are different and this will lead to dangling references. Each Activity has a single Fragment Manager, which finds Fragments. This is used to ensure a fragment is only created once, but also to allow sendingn IPC messages to a fragment. FragmentManager fragMgr = getFragmentManager(); xxx myFrag = frgMgr.findFragmentByTaga(MY_FRAG_NAME_STRING); Fragments also allow a caller to call setArguments and getArguments on a newly created fragment. This lets you pass in initialization state, like a Bundle, to a fragment so it can use it when the fragment OnCreate is eveentually called.. You can also group operations on fragments into a single atomic transaction by calling FragmentManager fragMgr = getFragmentManager(); FragmentTransaction xact - fragManager.beginTransaction(); ... xact.commit();

    Custom Widgets

    A widget is a subclass of android.view.View, and is usually a leaf node in the tree of containers andn views. A widget implements the calalbacks for drawing and handling user input like touches. For Drawing, a widget must implement the layout and rendering callbacks.

    Layout

    The systm wiil periodically re-layout the UI, whenever conditions like landscape/portrait change. Widgets can also request the system re-layout the widget anytime their state or presentation changes. The widget or the system triggers layout by calling requestLayout(view) on a widget or parent contaiiner view. Each widget then implements the onMeasure method, which is called by the layout manager code in the parent container view. onMeasure may be called several times, each time is asking for desired width and height of the widget onMeasure takes 2 args, the width andd height spec. The widget calls MeasureSpec.getMode and MeasureSpec.getSize on these parameters to parse them The size if a size in pixels and the spec is one of: MeasureSpec.EXACTLY, MeasureSpec.AT_MOST, MeasureSpec.UNSPECIFIED The spec lets a parent ask for different constraints, whether it wants an exacly or max size. The widget returns a desired width and height by setting height and width properties, which is really just member vars. Don't set these directly, call setMeasuredDimension(); Android will raise an excepetion if onMeasure returns but setMeasuredDimension has not been called. The default implementation of on Measure will call setMeasuredDimension with width and height dependning on the mode passed in by the caller MeasureSpec.EXACTLY - Use the sizes suggested by the called MeasureSpec.AT_MOST - Use the sizes suggested by the called MeasureSpec.UNSPECIFIED - Use valur returned by getSuggestedMinimumWidth and getSuggestedMinimumHeieght Once the parent container has chosen a suze for each child widget, it will call onLayout on each childl widget and pass in the actual width and height. Note, a widget may not get the width or height it requested. The widget uses this to configure its state. Alternatively, the widget can examaine the ClipRect on Draw, since that is also set to the final dimensions of the widget.
     
     public class MyWidget extends View {
    
        //////////////////////////////////////////
        public MyWidget(arg1) {
           // Constructor
       }
    
        //////////////////////////////////////////
       // Request screen space from the parent UI element. This method mmay be called several times, and
       // may not get the space it requests. The final allocated size will be passed to OnLayout (which usually only 
       // container views implememnt) and is also sete in the view clipRect before onDraw. Examine the view clip rect
       // in onDraw to see the actual size.
       @override
        protected void
        onMeasure(int widthSpec, int heightSpec) {
            setMeasuredDimension(getSuggestedMinimumWidth(), getSuggestedMinimumheight());
       }  // onMeasureSpec
    } // MyWidget
    

    Drawing

    To force a redraw, call view.invalidate(); This queues a draw event and then the system will eventually call the onDraw() method for the widgets. Basic Drawing Data Structures 1. Canvas Maintains the clip rectangle and scales drawing. It is a parameter to OonDraw(); It is a subclass of android.graphics.Canvas. Basic methods include drawing a line or geometric shapes, drawing text, Canvas also supports matrix operations to scale or rotate or stretch a canvas. Besides 2D operatioins, these can be used to implemment 3D views. Canvas also lets you save and restore the configuratioin of drawing, so you can draw a background with one style, then save the state, draw the foreground using a different style, then restore the state and draw more background in the original background style. 2. Paint The drawing implememnt - contnrools color, brush size, transparency, font, text size and more onDraw will create one of these when needed. It is a subclass of android.graphics.Paint Paint objects may have seveeral attributes includingn shadow effects, shaders (which transition a pain from one color into another color), 3. Bitmap It is a subclass of android.graphics.Bitmap This is usually maintainend in internal state of a Canvas. You may expllicitly manipulate them if you want to dod double buffering or caching previously-rendered bitmaps. On Init:
     
    private Bitmap myBitmap;
    myBitmap = Bitmap.createBitmap(
    			    getMeasuredWidth(),
    			    getMeasuredHeight(),
    			    Bitmap.Configi.ARGB_8888);
    Canvas tempCanvas =new Canvas(myBitmap);
    myDraw(tempCanvas);
    
    On draw:
     
    canvas.drawBitmap(myBitmap, 0, 0, new Paint());
    
    You can also load constant bitmaps from resources to draw them. BitmapDrawable myRsrcBitmap = resource.Resources.geteDrawable() 4. Drawable A pattern to be drawn, like a rectangle or circle. It is a subclass of android.graphics.Drawable
     
     public class MyWidget extends View {
        public MyWidget(arg1) {}
       @override protected void onMeasure(int widthSpec, int heightSpec) { }
    
        //////////////////////////////////////////
       @override
        protected void
        onDraw(Canvas canvas) {
            ??? setBackground()???
            canavas.drawColor(Color.WHITE);
    
            Paint myPaint = new Paint();
    
            myPaint.setColor(Color.GREEN);
            myPaint.setStrokeWidth(10);
            canvas.drawLine(1, 2, 101, 102, myPaint);
    
            canvas.drawText("Hello, world", startX, startY, myPaint);
    
       }  // onDraw
    } // MyWidget
    
    A widget can also override the isOpaque() method. If it returns true, then the system will not try to draw any part of the screen occluded by the widget. This helps performance.

    Drawables

    You can also subclass a Drawable, and then have the View call Draw() on your Drawable subclass.
        
     public class MyDrawable extends Drawable {
        public MyDrawable(arg1) {}
    
        //////////////////////////////////////////
       @override
        protected void
        draw(Canvas canvas) {
       }  // draw
    
        //////////////////////////////////////////
       @override
        protected int
        getOpacity() {
            return(PixelFormat.TRANSLUCENT);
       }
    
        //////////////////////////////////////////
       @override
        protected void
        setAlpha(int value) {
        }
    
        //////////////////////////////////////////
       @override
        protected void
        setColorFilter(ColorFilter value) {
        }
        
    } // MyDrawable
    
    A view then calls
     
          drawable.draw(canvas);
    
    Note that a Drawable implements draw() not onDraw because it is not an explicit part of the event processing - it is a graphics primitive. Moreover, the caller can apply any transformation to the canvas before passing it to the Drawable object, so the same Drawable can be used for any arbitraty stretch, scale, skew, 3D rotate or other perspectivie. A Drawable's position is set in instance variables, there is not a way to specify the coordinates when the drawable is rendered. Drawables do not negotiate their size with measure/layout methods.

    Animation

    There are 3 ways to do animation: 1. You can specify an animation to transition between one View and another Call the View mthod StartAnimation(Animation myAn) which takes an Animation objectc. The Animation object may be a default implementation or a custom subclass, and it implements a method applyTransformation that will create a matrix transformation object that will convert one frame of the animation sequencne into another. Successively applying transformations will makee a scene spin or skew or shrink or grow. 2. Background Animation. Create an AnimationDrawable object, which is a subclass of Drawable. As a Drawable, it can be drawn on the screen, but you don't do that explicitly. Instead, ALWAYS use the View setBackground method. 3. SurfaceView This is raw full animation. A SurfaceView class is a subclass of View and is a node in the View tree. Really, this creattes a section of screen that another thread can draw on, so a worker thread runninng on a GPU can animate this.

    OpenGL

    This has been supported since Honeycomb. This uses GLSurfaceView objects, which are passed to a GPU to execute a section of OpenGL code. There are callbacks that the OpenGL interpreter will invovke to alert the Android GUI that the size or shape of the FLSurfaceView has changed.