text:
<repo_name>W21C/Open-Source-IoT-Hand-Hygiene-Innovation<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/reference/tools/index.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

		<title>Tools \ Processing 3+</title>

		<link rel="icon" href="./img/favicon.ico" type="image/x-icon" />
		<link rel="shortcut icon" href="./img/favicon.ico" type="image/x-icon" />

		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
		<meta name="Author" content="Processing Foundation" />
		<meta name="Publisher" content="Processing Foundation" />
		<meta name="Keywords" content="Processing, Sketchbook, Programming, Coding, Code, Art, Design" />
		<meta name="Description" content="Processing is a flexible software sketchbook and a language for learning how to code within the context of the visual arts. Since 2001, Processing has promoted software literacy within the visual arts and visual literacy within technology." />
		<meta name="Copyright" content="All contents copyright the Processing Foundation, <NAME>, <NAME>, and the MIT Media Laboratory" />

		<link href="../css/style.css" rel="stylesheet" type="text/css" />

				<form name="search" action="//www.google.com/search" method="get" >

<input type="hidden" name="as_sitesearch" value="processing.org" />
				       <input type="text" name="as_q" value="" size="20" class="text" />
						<input type="submit" value=" " />

				</form>

					Language

					Libraries

					Tools

					Environment

Tools. Extend the capability of the Processing Environment (PDE) beyond the core functionality.

	The following tools are included with the Processing software. Select the tool you want
	to use from the Tools menu of the Processing Environment. These tools are open source; the
	code is distributed with Processing.

Color Selector

Simple interface for selecting colors as RGB, HSB, and Hex values.

Movie Maker

Creates a QuickTime movie from a sequence of images. Options include setting the
    size, frame rate, and compression, as well as an audio file.

Archive Sketch

Archives a copy of the current sketch in .zip format. The archive is placed in
    the same directory as the sketch.

Create Font

Converts fonts into the Processing font format and adds to the current sketch.
      Opens a dialog box which give options for setting the font, its size, if
      it is anti-aliased, and if all characters should be generated.

Contributions

	Contributed tools must be downloaded individually. Select "Add Tool..." from the Tools menu
	to select a Tool to download.

 	Contributed tools are developed, documented, and maintained by members of the Processing
 	community. For feedback and support, please post to the
 	Forum. For development discussions post to the
 	Libraries and Tool
 	Development topic. Instructions for creating your own tool are on the
 	Processing GitHub site.

		A complete list of tools can be found
		online.

Processing was initiated by <NAME> and <NAME>. It is developed by a small team of volunteers.

                    © Info

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Visualization Code/HandWashing/HandWashing.pde

// -----------------------------
// IMPORTS
// -----------------------------

import processing.serial.*;
import java.awt.Frame;
import mqtt.*;

import java.io.File;
import java.util.Date;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.awt.event.KeyEvent;

// -----------------------------
// DECLARATIONS
// -----------------------------

ArrayList<TheHand> hands;
TheHand tempHand;
Sanitizer[] sanitizers = new Sanitizer[7];

PFont large, medium, small;
PImage eculogo;
PImage w21clogo;
PShape handImg;

int numReadings = 50; //keeps track of how many readings you'd like to take before writing the file.
int readingCounter = 0; //counts each reading to compare to numReadings.
String pumpName;
String fileName;
String SerialIn;
int batteryFlag = 1;

Calendar calendar;
java.util.Date date;

// -----------------------------
// GLOBAL VARIABLES
// -----------------------------

// Display State
int halfTimeOut = 5;
int fullTimeOut = 15;
int drawState = 1;
int subDrawState = 1;
boolean drawHands = true;

// Hand Counts

int allHandsThisDay   = 0;
int numHandsThisDay[]   = new int[7];

// Colours
int bgColor = 0;

color[] palette = {
  color(255, 245, 0, 201),    // Yellow
  color(255, 0, 153, 201),   // Magenta
  color(102, 255, 0, 201),    // Green
  color(0, 153, 255, 201),  // Blue
  color(204, 0, 255, 201),  // Purple
  color(255, 102, 0, 201),   // Orange
  color(245,51,71,201)
};

color dropShadowColor = color(7, 89, 164);   // PSD
color textColor = color(255, 255, 255);

// XY
int newX = width/2;
int newY = height/2;
int prevX = width/2;
int prevY = height/2;

// Time / Date / Text / Label Position
int datePositionX, datePositionY;
int timePositionX, timePositionY;
int textPositionX, textPositionY;

int dailyLabelPositionX, dailyLabelPositionY;
int weeklyLabelPositionX, weeklyLabelPositionY;
int monthlyLabelPositionX, monthlyLabelPositionY;

// Chart
int baseLineX, baseLineY;
int divStartX, divEndX;
int divOneY, divTwoY, divThreeY;

// Time
String theHour;
String theMin;
String theSec;
String theMeridiem;
String time;

// Date
String theDate;
String theYear;
String theMonth;
String theDay;

// Timer
int start;
int count = 0;
int tempSec = 0;
int tempMin = 0;
int lastMin = 0;
int maxTempCount = 60;
int maxVerticalHands = 10;

//Germ implementation variables

int germSize = 60;
int germIndex = 0;
ArrayList<TheSplat> splatter;
TheSplat tempSplat;
String splatSVG = "Shapes/Germs/splat.svg";
int splatterStart;
int tempSplatSec;
int maxTempSplatCount = 10;

//THEME SVG's

String[] theme = new String[7];
color[] themePalette = new color[7];

String[] africanAnimals = {

  "Shapes/Africa/elephant.svg",
  "Shapes/Africa/lion.svg",
  "Shapes/Africa/giraffe.svg",
  "Shapes/Africa/antelope.svg",
  "Shapes/Africa/gorilla.svg",
  "Shapes/Africa/hippo.svg",
  "Shapes/Africa/cheetah.svg"
};

/* Source:

Elpahant: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/african-elephant
Antelope: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/antelope
Gorilla: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/gorilla
Lion: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/african-lion
Giraffe: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/giraffe
Hippo: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/hippopotamus
Cheetah: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/cheetah

*/

String[] canadianAnimals = {

  "Shapes/Canada/bear.svg",
  "Shapes/Canada/moose.svg",
  "Shapes/Canada/wolf.svg",
  "Shapes/Canada/beaver.svg",
  "Shapes/Canada/bison.svg",
  "Shapes/Canada/hare.svg",
  ""

};

/* Source:

Bear: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/grizzly-bear?tag=57390
Beaver: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/beaver
Bison: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/bison
Hare: Anastasiia. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/arctic-hare
Moose: Anastasiia. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/moose-deer
Wolf: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/wolf

*/

String[] oceanCreatures = {

  "Shapes/Ocean/dolphin.svg",
  "Shapes/Ocean/jellyfish.svg",
  "Shapes/Ocean/seahorse.svg",
  "Shapes/Ocean/cuttlefish.svg",
  "Shapes/Ocean/octopus.svg",
  "Shapes/Ocean/shark.svg",
  ""

};

/* Source:

Cuttlefish: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/cuttlefish
Dolphin: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/dolphin
Jellyfish: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/jellyfish
Octopus: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/giant-octopus
Seahorse: Public domain
Shark: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/tiger-shark

*/

String[] dogs = {

  "Shapes/Dogs/bulldog.svg",
  "Shapes/Dogs/running-dog.svg",
  "Shapes/Dogs/boxer.svg",
  "Shapes/Dogs/cocker-spaniel.svg",
  "Shapes/Dogs/lab.svg",
  "Shapes/Dogs/poodle.svg",

  ""

};

/* Source:

Boxer: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/boxer-dog-sitting
Bulldog: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/french-bulldog?tag=57353
Cocker Spaniel: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/cocker-spaniel?tag=57353
Lab: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/labrador
Poodle: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/standard-poodle?tag=57353
Running Dog: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/dog-running

*/

String[] insects = {

  "Shapes/Insects/bee.svg",
  "Shapes/Insects/butterfly.svg",
  "Shapes/Insects/praying-mantis.svg",
  "Shapes/Insects/dragonfly.svg",
  "Shapes/Insects/grasshopper.svg",
  "Shapes/Insects/wasp.svg",
  ""

};

/* Source:

Bee: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/honeybee
Butterfly: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/small-tortoiseshell-butterfly
Dragonfly: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/dragonfly
Grasshopper: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/grasshopper
Praying Mantis: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/praying-mantis
Wasp: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/wasp

*/

String[] transport = {

  "Shapes/Transport/helicopter.svg",
  "Shapes/Transport/tow-truck.svg",
  "Shapes/Transport/trail-bike.svg",
  "Shapes/Transport/sport-bike.svg",
  "Shapes/Transport/fire-engine.svg",
  "Shapes/Transport/airbus.svg",
  //"Shapes/Transport/tractor.svg",
  " "

};
/* Source:

Airbus: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/airbus-a350
Tractor: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/tractor
Helicopter: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/helicopter
Sport Bike: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/sportbike
Tow Truck: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/tow-truck
Trail bike: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/trail-bike
Fire Engine: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/fire-engine

*/

String[] fantasy = {

 "Shapes/Fantasy/dragon.svg",
 "Shapes/Fantasy/unicorn.svg",
 "Shapes/Fantasy/phoenix.svg",
 "Shapes/Fantasy/witch.svg",
 "Shapes/Fantasy/merman.svg",
 "Shapes/Fantasy/fairy.svg",
 ""

};

/* Source:

Merman: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/merman
Dragon: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/dragon
Fairy: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/fairy
Phoenix: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/phoenix
Witch:<NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/flying-witch
Unicorn: <NAME>. Creative Commons Attribution-Share Alike 4.0 License. Online: http://www.supercoloring.com/silhouettes/unicorn-0

*/

String[] dinos = {
 "Shapes/Dinosaurs/puertasaurus.svg",
 "Shapes/Dinosaurs/raptor.svg",
 "Shapes/Dinosaurs/triceratops.svg",
 "Shapes/Dinosaurs/ankylosaurus.svg",
 "Shapes/Dinosaurs/parasaurolophus.svg",
 "Shapes/Dinosaurs/tRex.svg",
 ""

};
//Dinosaur SVG's made by <NAME>

String[] germs = {

  "Shapes/Germs/eColi.svg",
  "Shapes/Germs/cDiff.svg",
  "Shapes/Germs/staph.svg",
  "Shapes/Germs/hPylori.svg",
  "Shapes/Germs/TB.svg",
  "Shapes/Germs/ebola.svg",
  "Shapes/Germs/strep.svg",
  "Shapes/Germs/germ2.svg",
  "Shapes/Germs/germ3.svg",
  "Shapes/Germs/germ2.svg",
  "Shapes/Germs/germ4.svg",
  "Shapes/Germs/germ5.svg",
  ""

};
//Germ SVG's made by <NAME>

//THEME COLOR PALETTES

color[] paletteAfrica = {
  color(255, 200, 0, 201),
  color(255, 120, 0, 201),
  color(255, 40, 0, 201),
  color(255, 160, 0, 201),
  color(255, 80, 0, 201),
  color(255, 0, 0, 201),
  color(255, 0)
};

color[] paletteCanada = {

  color(0, 150, 0, 201),
  color(0, 150, 80, 201),
  color(0, 150, 160, 201),
  color(0, 150, 40, 201),
  color(0, 150, 120, 201),
  color(0, 150, 200, 201),
  color(255, 0)

};

color[] paletteOcean = {

  color(40, 0, 150, 201),
  color(120, 0, 150, 201),
  color(200, 0, 150, 201),
  color(80, 0, 150, 201),
  color(160, 0, 150, 201),
  color(0, 0, 150, 201),
  color(255, 0)
};

color[] paletteDogs = {

  color(80, 255, 140, 201),
  color(170, 80, 255, 201),
  color(255, 80, 85, 201),
  color(80, 110, 255, 201),
  color(240, 255, 80, 201),
  color(255, 160, 80, 201),
  color(255, 0)
};

color[] paletteInsects = {

  color(15, 200, 220, 201),
  color(120, 15, 220, 201),
  color(125, 220, 15, 201),
  color(220, 15, 15, 201),
  color(15, 35, 220, 201),
  color(220, 190, 15, 201),
  color(255, 0)
};

color[] paletteTransport = {

  color(220, 15, 15, 201),
  color(15, 35, 220, 201),
  color(220, 190, 15, 201),
  color(15, 200, 220, 201),
  color(120, 15, 220, 201),
  color(125, 220, 15, 201),
  color(255, 0)
};

color[] paletteGerms = {
  color(232, 114, 23, 201),
  color(232, 65, 23, 201),
  color(23, 232, 25, 201),
  color(200, 232, 23, 201),
  color(232, 191, 23, 201),
  color(23, 115, 232, 201),
  color(232, 23, 100, 255)
};

color[] paletteFantasy = {
  color(245, 221, 101, 201),
  color(101, 205, 245, 201),
  color(245, 101, 101, 201),
  color(245, 101, 212, 201),
  color(120, 101, 245, 201),
  color(101, 245, 117, 201),
  color(255, 0)
};

color[] paletteDinos = {
  color(237, 177, 12, 201),
  color(237, 240, 12, 201),
  color(237, 140, 12, 201),
  color(12, 237, 0, 201),
  color(100, 237, 0, 201),
  color(200, 237, 0, 201),
  color(255, 0)
};

// -----------------------------
// SETUP
// -----------------------------

void setup() {

  // SCREEN
  fullScreen();
  surface.setResizable(true);
  smooth();

  // FONT
  large  = loadFont("Fonts/Knockout-HTF49-Liteweight-96.vlw");
  medium = loadFont("Fonts/Knockout-HTF49-Liteweight-72.vlw");
  small  = loadFont("Fonts/Knockout-HTF49-Liteweight-48.vlw");

  // LOGOS
  eculogo = loadImage("Logos/EmilyCarr_White_Logo_Large.png");
  w21clogo = loadImage("Logos/W21C Logo.png");

  //TITLE POSITIONS
  textPositionX = int(width * .15);
  textPositionY = int(height * .15);
  datePositionX = int(width - (width * .15));
  datePositionY = int(height *.20);
  timePositionX = int(width - (width * .15));
  timePositionY = int(height * .15);

  dailyLabelPositionX = int(width / 2);
  dailyLabelPositionY = int(height - (height * .15));
  weeklyLabelPositionX = int(width / 2);
  weeklyLabelPositionY = int(height - (height * .15));
  monthlyLabelPositionX = int(width / 2);
  monthlyLabelPositionY = int(height - (height * .15));

  // HANDS
  hands = new ArrayList<TheHand>();

  //MQTT IMPLEMENTATION
  client = new MQTTClient(this);
  client.connect("mqtt://MQTT_Username:MQTT_Password@Broker_IP", "processing1");
  //client.connect("mqtt://IP_Address", "Client_Name"); // Use this line instead of the preveious when you have not set a username or password for your MQTT broker
  client.subscribe("pumpID");

  //GERM IMPLEMENTATION
  useGerms = false; // Determines whether the complex germ theme is used upon starting code
  if(useGerms == true){
    splatter = new ArrayList();
    CreateGermArray();
  }
  if(useGerms == true){
     splatterStart = millis();
  }

  AssignTheme();

  // Calendar
  getCalendar();

  // Misc
  start = millis();
  ellipseMode(CENTER);

  println("");
  println("---- End Of Setup ----");
  println("");

} /* End Of Setup() */

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Interaction/Tickle/Tickle.pde
/**
 * Tickle.
 *
 * The word "tickle" jitters when the cursor hovers over.
 * Sometimes, it can be tickled off the screen.
 */

String message = "tickle";
float x, y; // X and Y coordinates of text
float hr, vr;  // horizontal and vertical radius of the text

void setup() {
  size(640, 360);

  // Create the font
  textFont(createFont("SourceCodePro-Regular.ttf", 36));
  textAlign(CENTER, CENTER);

  hr = textWidth(message) / 2;
  vr = (textAscent() + textDescent()) / 2;
  noStroke();
  x = width / 2;
  y = height / 2;
}

void draw() {
  // Instead of clearing the background, fade it by drawing
  // a semi-transparent rectangle on top
  fill(204, 120);
  rect(0, 0, width, height);

  // If the cursor is over the text, change the position
  if (abs(mouseX - x) < hr &&
      abs(mouseY - y) < vr) {
    x += random(-5, 5);
    y += random(-5, 5);
  }
  fill(0);
  text("tickle", x, y);
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Transform/RotateXY/RotateXY.pde
/**
 * Rotate 1.
 *
 * Rotating simultaneously in the X and Y axis.
 * Transformation functions such as rotate() are additive.
 * Successively calling rotate(1.0) and rotate(2.0)
 * is equivalent to calling rotate(3.0).
 */

float a = 0.0;
float rSize;  // rectangle size

void setup() {
  size(640, 360, P3D);
  rSize = width / 6;
  noStroke();
  fill(204, 204);
}

void draw() {
  background(126);

  a += 0.005;
  if(a > TWO_PI) {
    a = 0.0;
  }

  translate(width/2, height/2);

  rotateX(a);
  rotateY(a * 2.0);
  fill(255);
  rect(-rSize, -rSize, rSize*2, rSize*2);

  rotateX(a * 1.001);
  rotateY(a * 2.002);
  fill(0);
  rect(-rSize, -rSize, rSize*2, rSize*2);

}
<file_sep>/Data and System Management/requirements.txt
Click==7.0
cycler==0.10.0
dominate==2.3.5
Flask==1.1.1
Flask-Bootstrap==3.3.7.1
Flask-SQLAlchemy==2.4.0
Flask-WTF==0.14.2
itsdangerous==1.1.0
Jinja2==2.10.1
kiwisolver==1.1.0
MarkupSafe==1.1.1
matplotlib==3.1.1
numpy==1.16.4
paho-mqtt==1.4.0
pyparsing==2.4.0
python-dateutil==2.8.0
six==1.12.0
SQLAlchemy==1.3.5
visitor==0.1.3
Werkzeug==0.15.4
WTForms==2.2.1
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/src/processing/mode/java/JavaBuild.java
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
Part of the Processing project - http://processing.org

Copyright (c) 2012-19 The Processing Foundation
Copyright (c) 2004-12 <NAME> and <NAME>
Copyright (c) 2001-04 Massachusetts Institute of Technology

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

package processing.mode.java;

import java.io.*;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DefaultLogger;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.ProjectHelper;

import processing.app.Base;
import processing.app.Language;
import processing.app.Library;
import processing.app.Messages;
import processing.app.Mode;
import processing.app.Platform;
import processing.app.Preferences;
import processing.app.Sketch;
import processing.app.SketchCode;
import processing.app.SketchException;
import processing.app.Util;
import processing.app.exec.ProcessHelper;
import processing.core.PApplet;
import processing.core.PConstants;
import processing.data.StringList;
import processing.data.XML;
import processing.mode.java.pdex.SourceUtils;
import processing.mode.java.preproc.PdePreprocessor;
import processing.mode.java.preproc.PreprocessorResult;
import processing.mode.java.preproc.SurfaceInfo;

public class JavaBuild {
  public static final String PACKAGE_REGEX =
    "(?:^|\\s|;)package\\s+(\\S+)\\;";

  protected Sketch sketch;
  protected Mode mode;

  // what happens in the build, stays in the build.
  // (which is to say that everything below this line, stays within this class)

  protected File srcFolder;
  protected File binFolder;
  private boolean foundMain = false;
  private String classPath;
  protected String sketchClassName;

  /**
   * This will include the code folder, any library folders, etc. that might
   * contain native libraries that need to be picked up with java.library.path.
   * This is *not* the "Processing" libraries path, this is the Java libraries
   * path, as in java.library.path=BlahBlah, which identifies search paths for
   * DLLs or JNILIBs. (It's Java's LD_LIBRARY_PATH, for you UNIX fans.)
   * This is set by the preprocessor as it figures out where everything is.
   */
  private String javaLibraryPath;

  /** List of library folders, as figured out during preprocessing. */
  private List<Library> importedLibraries;

  public JavaBuild(Sketch sketch) {
    this.sketch = sketch;
    this.mode = sketch.getMode();
  }

  /**
   * Run the build inside a temporary build folder. Used for run/present.
   * @return null if compilation failed, main class name if not
   * @throws RunnerException
   */
  public String build(boolean sizeWarning) throws SketchException {
    return build(sketch.makeTempFolder(), sketch.makeTempFolder(), sizeWarning);
  }

  /**
   * Preprocess and compile all the code for this sketch.
   *
   * In an advanced program, the returned class name could be different,
   * which is why the className is set based on the return value.
   * A compilation error will burp up a RunnerException.
   *
   * @return null if compilation failed, main class name if not
   */
  public String build(File srcFolder, File binFolder, boolean sizeWarning) throws SketchException {
    this.srcFolder = srcFolder;
    this.binFolder = binFolder;

    // run the preprocessor
    String classNameFound = preprocess(srcFolder, sizeWarning);

    // compile the program. errors will happen as a RunnerException
    // that will bubble up to whomever called build().
    if (Compiler.compile(this)) {
      sketchClassName = classNameFound;
      return classNameFound;
    }
    return null;
  }

  public String getSketchClassName() {
    return sketchClassName;
  }

  /**
   * Build all the code for this sketch.
   *
   * In an advanced program, the returned class name could be different,
   * which is why the className is set based on the return value.
   * A compilation error will burp up a RunnerException.
   *
   * Setting purty to 'true' will cause exception line numbers to be incorrect.
   * Unless you know the code compiles, you should first run the preprocessor
   * with purty set to false to make sure there are no errors, then once
   * successful, re-export with purty set to true.
   *
   * @param buildPath Location to copy all the .java files
   * @return null if compilation failed, main class name if not
   */
  public String preprocess(File srcFolder, boolean sizeWarning) throws SketchException {
    return preprocess(srcFolder, null, new PdePreprocessor(sketch.getName()), sizeWarning);
  }

  /**
   * @param srcFolder location where the .java source files will be placed
   * @param packageName null, or the package name that should be used as default
   * @param preprocessor the preprocessor object ready to do the work
   * @return main PApplet class name found during preprocess, or null if error
   * @throws SketchException
   */
  public String preprocess(File srcFolder,
                           String packageName,
                           PdePreprocessor preprocessor,
                           boolean sizeWarning) throws SketchException {
    // make sure the user isn't playing "hide the sketch folder"
    sketch.ensureExistence();

//    System.out.println("srcFolder is " + srcFolder);
    classPath = binFolder.getAbsolutePath();

    // figure out the contents of the code folder to see if there
    // are files that need to be added to the imports
    StringList codeFolderPackages = null;
    if (sketch.hasCodeFolder()) {
      File codeFolder = sketch.getCodeFolder();
      javaLibraryPath = codeFolder.getAbsolutePath();

      // get a list of .jar files in the "code" folder
      // (class files in subfolders should also be picked up)
      String codeFolderClassPath =
        Util.contentsToClassPath(codeFolder);
      // append the jar files in the code folder to the class path
      classPath += File.pathSeparator + codeFolderClassPath;
      // get list of packages found in those jars
      codeFolderPackages =
        Util.packageListFromClassPath(codeFolderClassPath);

    } else {
      javaLibraryPath = "";
    }

    // 1. concatenate all .pde files to the 'main' pde
    //    store line number for starting point of each code bit

    StringBuilder bigCode = new StringBuilder();
    int bigCount = 0;
    for (SketchCode sc : sketch.getCode()) {
      if (sc.isExtension("pde")) {
        sc.setPreprocOffset(bigCount);
        bigCode.append(sc.getProgram());
        bigCode.append('\n');
        bigCount += sc.getLineCount();
      }
    }

    // initSketchSize() sets the internal sketchWidth/Height/Renderer vars
    // in the preprocessor. Those are used in preproc.write() so that they
    // can be used to add methods (settings() or sketchXxxx())
    //String[] sizeParts =
    SurfaceInfo sizeInfo =
      preprocessor.initSketchSize(sketch.getMainProgram(), sizeWarning);
    if (sizeInfo == null) {
      // An error occurred while trying to pull out the size, so exit here
      return null;
    }
    //System.out.format("size() is '%s'%n", info[0]);

    // Remove the entries being moved to settings(). They will be re-inserted
    // by writeFooter() when it emits the settings() method.
    // If the user already has a settings() method, don't mess with anything.
    // https://github.com/processing/processing/issues/4703
    if (!PdePreprocessor.hasSettingsMethod(bigCode.toString()) &&
        sizeInfo != null && sizeInfo.hasSettings()) {
      for (String stmt : sizeInfo.getStatements()) {
        // Don't remove newlines (and while you're at it, just keep spaces)
        // https://github.com/processing/processing/issues/3654
        stmt = stmt.trim();
        int index = bigCode.indexOf(stmt);
        if (index != -1) {
          bigCode.delete(index, index + stmt.length());
        } else {
          // TODO remove once we hit final; but prevent an exception like in
          // https://github.com/processing/processing/issues/3531
          System.err.format("Error removing '%s' from the code.", stmt);
        }
      }
    }

    PreprocessorResult result;
    try {
      File outputFolder = (packageName == null) ?
        srcFolder : new File(srcFolder, packageName.replace('.', '/'));
      outputFolder.mkdirs();
      final File java = new File(outputFolder, sketch.getName() + ".java");
      try {
        final PrintWriter writer = PApplet.createWriter(java);
        try {
          result = preprocessor.write(writer, bigCode.toString(), codeFolderPackages);
        } finally {
          writer.close();
        }
      } catch (RuntimeException re) {
        re.printStackTrace();
        throw new SketchException("Could not write " + java.getAbsolutePath());
      }
    } catch (antlr.RecognitionException re) {
      // re also returns a column that we're not bothering with for now
      // first assume that it's the main file
//      int errorFile = 0;
      int errorLine = re.getLine() - 1;

      // then search through for anyone else whose preprocName is null,
      // since they've also been combined into the main pde.
      int errorFile = findErrorFile(errorLine);
      errorLine -= sketch.getCode(errorFile).getPreprocOffset();

      String msg = re.getMessage();

      if (msg.contains("expecting RCURLY") || msg.contains("expecting LCURLY")) {
        for (int i = 0; i < sketch.getCodeCount(); i++) {
          SketchCode sc = sketch.getCode(i);
          if (sc.isExtension("pde")) {
            String s = sc.getProgram();
            int[] braceTest = SourceUtils.checkForMissingBraces(
                SourceUtils.scrubCommentsAndStrings(s) + "\n", 0, s.length()+1);
            if (braceTest[0] == 0) continue;

            // Completely ignoring the errorFile/errorLine given since it's
            // likely to be the wrong tab. For the same reason, I'm not showing
            // the result of PApplet.match(msg, "found ('.*')") on missing
            // LCURLY.
            throw new SketchException(braceTest[0] > 0
              ? "Found an extra { character without a } to match it."
              : "Found an extra } character without a { to match it.",
              i, braceTest[1], braceTest[2], false);
          }
        }
        // If we're still here, there's the right brackets, just not in the
        // right place. Passing on the original error.
        throw new SketchException(
            msg.replace("LCURLY", "{").replace("RCURLY", "}"),
            errorFile, errorLine, re.getColumn(), false);
      }

      if (msg.indexOf("expecting RBRACK") != -1) {
        System.err.println(msg);
        throw new SketchException("Syntax error, " +
                                  "maybe a missing ] character?",
                                  errorFile, errorLine, re.getColumn(), false);
      }

      if (msg.indexOf("expecting SEMI") != -1) {
        System.err.println(msg);
        throw new SketchException("Syntax error, " +
                                  "maybe a missing semicolon?",
                                  errorFile, errorLine, re.getColumn(), false);
      }

      if (msg.indexOf("expecting RPAREN") != -1) {
        System.err.println(msg);
        throw new SketchException("Syntax error, " +
                                  "maybe a missing right parenthesis?",
                                  errorFile, errorLine, re.getColumn(), false);
      }

      if (msg.indexOf("preproc.web_colors") != -1) {
        throw new SketchException("A web color (such as #ffcc00) " +
                                  "must be six digits.",
                                  errorFile, errorLine, re.getColumn(), false);
      }

      //System.out.println("msg is " + msg);
      throw new SketchException(msg, errorFile,
                                errorLine, re.getColumn(), false);

    } catch (antlr.TokenStreamRecognitionException tsre) {
      // while this seems to store line and column internally,
      // there doesn't seem to be a method to grab it..
      // so instead it's done using a regexp

//      System.err.println("and then she tells me " + tsre.toString());
      // TODO not tested since removing ORO matcher.. ^ could be a problem
      String locationRegex = "^line (\\d+):(\\d+):\\s";
      String message = tsre.getMessage();
      String[] m;

      if (null != (m = PApplet.match(tsre.toString(),
              "unexpected char: (.*)"))) {
        char c = 0;
        if (m[1].startsWith("0x")) {     // Hex
          c = (char) PApplet.unhex(m[1].substring(2));
        } else if (m[1].length() == 3) { // Quoted
          c = m[1].charAt(1);
        } else if (m[1].length() == 1) { // Alone
          c = m[1].charAt(0);
        }
        if (c == '\u201C' || c == '\u201D' || // “”
            c == '\u2018' || c == '\u2019') { // ‘’
          message = Language.interpolate("editor.status.bad_curly_quote", c);
        } else if (c != 0) {
          message = "Not expecting symbol " + m[1] +
              ", which is " + Character.getName(c) + ".";
        }
      }

      String[] matches = PApplet.match(tsre.toString(), locationRegex);
      if (matches != null) {
        int errorLine = Integer.parseInt(matches[1]) - 1;
        int errorColumn = Integer.parseInt(matches[2]);

        int errorFile = 0;
        for (int i = 1; i < sketch.getCodeCount(); i++) {
          SketchCode sc = sketch.getCode(i);
          if (sc.isExtension("pde") &&
              (sc.getPreprocOffset() < errorLine)) {
            errorFile = i;
          }
        }
        errorLine -= sketch.getCode(errorFile).getPreprocOffset();

        throw new SketchException(message,
                                  errorFile, errorLine, errorColumn);

      } else {
        // this is bad, defaults to the main class.. hrm.
        String msg = tsre.toString();
        throw new SketchException(msg, 0, -1, -1);
      }

    } catch (SketchException pe) {
      // RunnerExceptions are caught here and re-thrown, so that they don't
      // get lost in the more general "Exception" handler below.
      throw pe;

    } catch (Exception ex) {
      // TODO better method for handling this?
      System.err.println("Uncaught exception type:" + ex.getClass());
      ex.printStackTrace();
      throw new SketchException(ex.toString());
    }

    // grab the imports from the code just preprocessed

    importedLibraries = new ArrayList<>();
    Library core = mode.getCoreLibrary();
    if (core != null) {
      importedLibraries.add(core);
      classPath += core.getClassPath();
      javaLibraryPath += File.pathSeparator + core.getNativePath();
    }

    for (String item : result.extraImports) {
      // remove things up to the last dot
      int dot = item.lastIndexOf('.');
      // http://dev.processing.org/bugs/show_bug.cgi?id=1145
      String entry = (dot == -1) ? item : item.substring(0, dot);

      if (item.startsWith("static ")) {
        // import static - https://github.com/processing/processing/issues/8
        int dot2 = item.lastIndexOf('.');
        entry = entry.substring(7, (dot2 == -1) ? entry.length() : dot2);
      }

      Library library = mode.getLibrary(entry);

      if (library != null) {
        if (!importedLibraries.contains(library)) {
          importedLibraries.add(library);
          classPath += library.getClassPath();
          javaLibraryPath += File.pathSeparator + library.getNativePath();
        }
      } else {
        boolean found = false;
        // If someone insists on unnecessarily repeating the code folder
        // import, don't show an error for it.
        if (codeFolderPackages != null) {
          String itemPkg = entry;
          for (String pkg : codeFolderPackages) {
            if (pkg.equals(itemPkg)) {
              found = true;
              break;
            }
          }
        }
        if (ignorableImport(entry + '.')) {
          found = true;
        }
        if (!found) {
          System.err.println("No library found for " + entry);
        }
      }
    }

    // Finally, add the regular Java CLASSPATH. This contains everything
    // imported by the PDE itself (core.jar, pde.jar, quaqua.jar) which may
    // in fact be more of a problem.
    String javaClassPath = System.getProperty("java.class.path");
    // Remove quotes if any.. A messy (and frequent) Windows problem
    if (javaClassPath.startsWith("\"") && javaClassPath.endsWith("\"")) {
      javaClassPath = javaClassPath.substring(1, javaClassPath.length() - 1);
    }
    classPath += File.pathSeparator + javaClassPath;

    // But make sure that there isn't anything in there that's missing,
    // otherwise ECJ will complain and die. For instance, Java 1.7 (or maybe
    // it's appbundler?) adds Java/Classes to the path, which kills us.
    //String[] classPieces = PApplet.split(classPath, File.pathSeparator);
    // Nah, nevermind... we'll just create the @!#$! folder until they fix it.

    // 3. then loop over the code[] and save each .java file

    for (SketchCode sc : sketch.getCode()) {
      if (sc.isExtension("java")) {
        // In most cases, no pre-processing services necessary for Java files.
        // Just write the the contents of 'program' to a .java file
        // into the build directory. However, if a default package is being
        // used (as in Android), and no package is specified in the source,
        // then we need to move this code to the same package as the sketch.
        // Otherwise, the class may not be found, or at a minimum, the default
        // access across the packages will mean that things behave incorrectly.
        // For instance, desktop code that uses a .java file with no packages,
        // will be fine with the default access, but since Android's PApplet
        // requires a package, code from that (default) package (such as the
        // PApplet itself) won't have access to methods/variables from the
        // package-less .java file (unless they're all marked public).
        String filename = sc.getFileName();
        try {
          String javaCode = sc.getProgram();
          String[] packageMatch = PApplet.match(javaCode, PACKAGE_REGEX);
          // if no package, and a default package is being used
          // (i.e. on Android) we'll have to add one

          if (packageMatch == null && packageName == null) {
            sc.copyTo(new File(srcFolder, filename));

          } else {
            if (packageMatch == null) {
              // use the default package name, since mixing with package-less code will break
              packageMatch = new String[] { "", packageName };
              // add the package name to the source before writing it
              javaCode = "package " + packageName + ";" + javaCode;
            }
            File packageFolder = new File(srcFolder, packageMatch[1].replace('.', File.separatorChar));
            packageFolder.mkdirs();
            Util.saveFile(javaCode, new File(packageFolder, filename));
          }

        } catch (IOException e) {
          e.printStackTrace();
          String msg = "Problem moving " + filename + " to the build folder";
          throw new SketchException(msg);
        }

      } else if (sc.isExtension("pde")) {
        // The compiler and runner will need this to have a proper offset
        sc.addPreprocOffset(result.headerOffset);
      }
    }
    foundMain = preprocessor.hasMethod("main");
    return result.className;
  }

  /**
   * Returns true if this package isn't part of a library (it's a system import
   * or something like that). Don't bother complaining about java.* or javax.*
   * because it's probably in boot.class.path. But we're not checking against
   * that path since it's enormous. Unfortunately we do still have to check
   * for libraries that begin with a prefix like javax, since that includes
   * the OpenGL library, even though we're just returning true here, hrm...
   */
  protected boolean ignorableImport(String pkg) {
    if (pkg.startsWith("java.")) return true;
    if (pkg.startsWith("javax.")) return true;
    if (pkg.startsWith("javafx.")) return true;

    if (pkg.startsWith("processing.core.")) return true;
    if (pkg.startsWith("processing.data.")) return true;
    if (pkg.startsWith("processing.event.")) return true;
    if (pkg.startsWith("processing.opengl.")) return true;

    return false;
  }

  protected int findErrorFile(int errorLine) {
    for (int i = sketch.getCodeCount() - 1; i > 0; i--) {
      SketchCode sc = sketch.getCode(i);
      if (sc.isExtension("pde") && (sc.getPreprocOffset() <= errorLine)) {
        // keep looping until the errorLine is past the offset
        return i;
      }
    }
    return 0;  // i give up
  }

  /**
   * Path to the folder that will contain processed .java source files. Not
   * the location for .pde files, since that can be obtained from the sketch.
   */
  public File getSrcFolder() {
    return srcFolder;
  }

  public File getBinFolder() {
    return binFolder;
  }

  /**
   * Absolute path to the sketch folder. Used to set the working directry of
   * the sketch when running, i.e. so that saveFrame() goes to the right
   * location when running from the PDE, instead of the same folder as the
   * Processing.exe or the root of the user's home dir.
   */
  public String getSketchPath() {
    return sketch.getFolder().getAbsolutePath();
  }

  /** Class path determined during build. */
  public String getClassPath() {
    return classPath;
  }

  /** Return the java.library.path for this sketch (for all the native DLLs etc). */
  public String getJavaLibraryPath() {
    return javaLibraryPath;
  }

  /**
   * Whether the preprocessor found a main() method. If main() is found, then
   * it will be used to launch the sketch instead of PApplet.main().
   */
  public boolean getFoundMain() {
    return foundMain;
  }

  /**
   * Get the list of imported libraries. Used by external tools like Android mode.
   * @return list of library folders connected to this sketch.
   */
  public List<Library> getImportedLibraries() {
    return importedLibraries;
  }

  /**
   * Map an error from a set of processed .java files back to its location
   * in the actual sketch.
   * @param message The error message.
   * @param filename The .java file where the exception was found.
   * @param line Line number of the .java file for the exception (0-indexed!)
   * @return A RunnerException to be sent to the editor, or null if it wasn't
   *         possible to place the exception to the sketch code.
   */
  public SketchException placeException(String message,
                                        String dotJavaFilename,
                                        int dotJavaLine) {
    int codeIndex = 0; //-1;
    int codeLine = -1;

//    System.out.println("placing " + dotJavaFilename + " " + dotJavaLine);
//    System.out.println("code count is " + getCodeCount());

    // first check to see if it's a .java file
    for (int i = 0; i < sketch.getCodeCount(); i++) {
      SketchCode code = sketch.getCode(i);
      if (code.isExtension("java")) {
        if (dotJavaFilename.equals(code.getFileName())) {
          codeIndex = i;
          codeLine = dotJavaLine;
          return new SketchException(message, codeIndex, codeLine);
        }
      }
    }

    // If not the preprocessed file at this point, then need to get out
    if (!dotJavaFilename.equals(sketch.getName() + ".java")) {
      return null;
    }

    // if it's not a .java file, codeIndex will still be 0
    // this section searches through the list of .pde files
    codeIndex = 0;
    for (int i = 0; i < sketch.getCodeCount(); i++) {
      SketchCode code = sketch.getCode(i);

      if (code.isExtension("pde")) {
//        System.out.println("preproc offset is " + code.getPreprocOffset());
//        System.out.println("looking for line " + dotJavaLine);
        if (code.getPreprocOffset() <= dotJavaLine) {
          codeIndex = i;
//          System.out.println("i'm thinkin file " + i);
          codeLine = dotJavaLine - code.getPreprocOffset();
        }
      }
    }
    // could not find a proper line number, so deal with this differently.
    // but if it was in fact the .java file we're looking for, though,
    // send the error message through.
    // this is necessary because 'import' statements will be at a line
    // that has a lower number than the preproc offset, for instance.
//    if (codeLine == -1 && !dotJavaFilename.equals(name + ".java")) {
//      return null;
//    }
//    return new SketchException(message, codeIndex, codeLine);
    return new SketchException(message, codeIndex, codeLine, -1, false);  // changed for 0194 for compile errors, but...
  }

  /**
   * Export to application via GUI.
   */
  protected boolean exportApplication() throws IOException, SketchException {
    // Do the build once, so that we know what libraries are in use (and what
    // the situation is with their native libs), and also for efficiency of
    // not redoing the compilation for each platform. In particular, though,
    // importedLibraries won't be set until the preprocessing has finished,
    // so we have to do that before the stuff below.
    String foundName = build(true);

    // (already reported) error during export, exit this function
    if (foundName == null) return false;

    // if name != exportSketchName, then that's weirdness
    // BUG unfortunately, that can also be a bug in the preproc :(
    if (!sketch.getName().equals(foundName)) {
      Messages.showWarning("Error during export",
                           "Sketch name is " + sketch.getName() + " but the sketch\n" +
                           "name in the code was " + foundName, null);
      return false;
    }

    File folder = null;
    for (String platformName : PConstants.platformNames) {
      int platform = Platform.getIndex(platformName);

      // Can only embed Java on the native platform
      boolean embedJava = (platform == PApplet.platform) &&
        Preferences.getBoolean("export.application.embed_java");

      if (Preferences.getBoolean(JavaEditor.EXPORT_PREFIX + platformName)) {
        final int bits = Platform.getNativeBits();
        final String arch = Platform.getNativeArch();

        if (Library.hasMultipleArch(platform, importedLibraries)) {
          // Don't try to export 32-bit on macOS, because it doesn't exist.
          if (platform != PConstants.MACOSX) {
            // export the 32-bit version
            folder = new File(sketch.getFolder(), "application." + platformName + "32");
            if (!exportApplication(folder, platform, "32", embedJava && (bits == 32) && ("x86".equals(arch) || "i386".equals(arch)))) {
              return false;
            }
          }
          // export the 64-bit version
          folder = new File(sketch.getFolder(), "application." + platformName + "64");
          if (!exportApplication(folder, platform, "64", embedJava && (bits == 64) && "amd64".equals(arch))) {
            return false;
          }
          if (platform == PConstants.LINUX) {
            // export the arm versions as well
            folder = new File(sketch.getFolder(), "application.linux-armv6hf");
            if (!exportApplication(folder, platform, "armv6hf", embedJava && (bits == 32) && "arm".equals(arch))) {
              return false;
            }
            folder = new File(sketch.getFolder(), "application.linux-arm64");
            if (!exportApplication(folder, platform, "arm64", embedJava && (bits == 64) && "aarch64".equals(arch))) {
              return false;
            }
          }
        } else { // just make a single one for this platform
          folder = new File(sketch.getFolder(), "application." + platformName);
          if (!exportApplication(folder, platform, "", embedJava)) {
            return false;
          }
        }
      }
    }

    return true;  // all good
  }

  /**
   * Export to application without GUI. Also called by the Commander.
   */
  protected boolean exportApplication(File destFolder,
                                      int exportPlatform,
                                      String exportVariant,
                                      boolean embedJava) throws IOException, SketchException {
    // TODO this should probably be a dialog box instead of a warning
    // on the terminal. And the message should be written better than this.
    // http://code.google.com/p/processing/issues/detail?id=884
    for (Library library : importedLibraries) {
      if (!library.supportsArch(exportPlatform, exportVariant)) {
        String pn = PConstants.platformNames[exportPlatform];
        Messages.showWarning("Quibbles 'n Bits",
                             "The application." + pn + exportVariant +
                             " folder will not be created\n" +
                             "because no " + exportVariant + " version of " +
                             library.getName() + " is available for " + pn, null);
        return true;  // don't cancel all exports for this, just move along
      }
    }

    /// prep the output directory

    mode.prepareExportFolder(destFolder);

    /// figure out where the jar files will be placed

    File jarFolder = new File(destFolder, "lib");

    /// where all the skeleton info lives

    /// on macosx, need to copy .app skeleton since that's
    /// also where the jar files will be placed
    File dotAppFolder = null;
    String jvmRuntime = "";
    String jdkPath = null;
    if (exportPlatform == PConstants.MACOSX) {
      dotAppFolder = new File(destFolder, sketch.getName() + ".app");

      File contentsOrig = new File(Platform.getJavaHome(), "../../../../..");

      if (embedJava) {
        File jdkFolder = new File(Platform.getJavaHome(), "../../..");
        String jdkFolderName = jdkFolder.getCanonicalFile().getName();
        jvmRuntime = "<key>JVMRuntime</key>\n    <string>" + jdkFolderName + "</string>";
        jdkPath = new File(dotAppFolder, "Contents/PlugIns/" + jdkFolderName).getAbsolutePath();
      }

      File contentsFolder = new File(dotAppFolder, "Contents");
      contentsFolder.mkdirs();

      // Info.plist will be written later

      // set the jar folder to a different location than windows/linux
      //jarFolder = new File(dotAppFolder, "Contents/Resources/Java");
      jarFolder = new File(contentsFolder, "Java");

      File macosFolder = new File(contentsFolder, "MacOS");
      macosFolder.mkdirs();
      // This is an unsigned copy of the app binary (see build/build.xml)
      Util.copyFile(mode.getContentFile("application/mac-app-stub"),
                    new File(contentsFolder, "MacOS/" + sketch.getName()));

      File pkgInfo = new File(contentsFolder, "PkgInfo");
      PrintWriter writer = PApplet.createWriter(pkgInfo);
      writer.println("APPL????");
      writer.flush();
      writer.close();

      // Use faster(?) native copy here (also to do sym links)
      if (embedJava) {
        Util.copyDirNative(new File(contentsOrig, "PlugIns"),
                           new File(contentsFolder, "PlugIns"));
      }

      File resourcesFolder = new File(contentsFolder, "Resources");
      Util.copyDir(new File(contentsOrig, "Resources/en.lproj"),
                   new File(resourcesFolder, "en.lproj"));
      Util.copyFile(mode.getContentFile("application/sketch.icns"),
                    new File(resourcesFolder, "sketch.icns"));

    } else if (exportPlatform == PConstants.LINUX) {
      if (embedJava) {
        Util.copyDirNative(Platform.getJavaHome(), new File(destFolder, "java"));
      }

    } else if (exportPlatform == PConstants.WINDOWS) {
      if (embedJava) {
        Util.copyDir(Platform.getJavaHome(), new File(destFolder, "java"));
      }
    }

    /// make the jar folder (all platforms)

    if (!jarFolder.exists()) jarFolder.mkdirs();

    /// start copying all jar files

    StringList jarList = new StringList();

    /// create the main .jar file

//    HashMap<String,Object> zipFileContents = new HashMap<String,Object>();

    FileOutputStream zipOutputFile =
      new FileOutputStream(new File(jarFolder, sketch.getName() + ".jar"));
    ZipOutputStream zos = new ZipOutputStream(zipOutputFile);
//    ZipEntry entry;

    // add the manifest file so that the .jar can be double clickable
    addManifest(zos);

    // add the project's .class files to the jar
    // (just grabs everything from the build directory,
    // since there may be some inner classes)
    // TODO this needs to be recursive (for packages)
//    File classFiles[] = tempClassesFolder.listFiles(new FilenameFilter() {
//      public boolean accept(File dir, String name) {
//        return name.endsWith(".class");
//      }
//    });
//    for (File file : classFiles) {
//      entry = new ZipEntry(file.getName());
//      zos.putNextEntry(entry);
//      zos.write(Base.loadBytesRaw(file));
//      zos.closeEntry();
//    }
    addClasses(zos, binFolder);

    // add the data folder to the main jar file
//    addDataFolder(zos);
    // For 2.0a2, make the data folder a separate directory, rather than
    // packaging potentially large files into the JAR. On OS X, we have to hide
    // the folder inside the .app package, while Linux and Windows will have a
    // 'data' folder next to 'lib'.
    if (sketch.hasDataFolder()) {
      if (exportPlatform == PConstants.MACOSX) {
        Util.copyDir(sketch.getDataFolder(),  new File(jarFolder, "data"));
      } else {
        Util.copyDir(sketch.getDataFolder(),  new File(destFolder, "data"));
      }
    }

    // add the contents of the code folder to the jar
    if (sketch.hasCodeFolder()) {
      String includes = Util.contentsToClassPath(sketch.getCodeFolder());
      // Use tokens to get rid of extra blanks, which causes huge exports
      String[] codeList = PApplet.splitTokens(includes, File.pathSeparator);
      for (int i = 0; i < codeList.length; i++) {
        if (codeList[i].toLowerCase().endsWith(".jar") ||
            codeList[i].toLowerCase().endsWith(".zip")) {
          File exportFile = new File(codeList[i]);
          String exportFilename = exportFile.getName();
          Util.copyFile(exportFile, new File(jarFolder, exportFilename));
          jarList.append(exportFilename);
        } else {
//          cp += codeList[i] + File.pathSeparator;
        }
      }
    }

    zos.flush();
    zos.close();

    jarList.append(sketch.getName() + ".jar");

    /// add contents of 'library' folders to the export
    for (Library library : importedLibraries) {
      // add each item from the library folder / export list to the output
      for (File exportFile : library.getApplicationExports(exportPlatform, exportVariant)) {
//        System.out.println("export: " + exportFile);
        String exportName = exportFile.getName();
        if (!exportFile.exists()) {
          System.err.println(exportFile.getName() +
                             " is mentioned in export.txt, but it's " +
                             "a big fat lie and does not exist.");

        } else if (exportFile.isDirectory()) {
          Util.copyDir(exportFile, new File(jarFolder, exportName));

        } else if (exportName.toLowerCase().endsWith(".zip") ||
                   exportName.toLowerCase().endsWith(".jar")) {
          Util.copyFile(exportFile, new File(jarFolder, exportName));
          jarList.append(exportName);

        } else {
          // Starting with 2.0a2 put extra export files (DLLs, plugins folder,
          // anything else for libraries) inside lib or Contents/Resources/Java
          Util.copyFile(exportFile, new File(jarFolder, exportName));
        }
      }
    }

    /// create platform-specific CLASSPATH based on included jars

    String exportClassPath = null;
    if (exportPlatform == PConstants.MACOSX) {
      exportClassPath = "$JAVAROOT/" + jarList.join(":$JAVAROOT/");
    } else if (exportPlatform == PConstants.WINDOWS) {
      exportClassPath = jarList.join(",");
    } else if (exportPlatform == PConstants.LINUX) {
      // why is $APPDIR at the front of this list?
      exportClassPath = "$APPDIR" +
        ":$APPDIR/lib/" + jarList.join(":$APPDIR/lib/");
    }

    /// figure out run options for the VM

    StringList runOptions = new StringList();

    // Set memory options, except for ARM where we're more memory-constrained
    // compared to the machine being used to build/export the sketch
    // https://github.com/processing/processing/pull/4406
    if (Preferences.getBoolean("run.options.memory") &&
        !exportVariant.equals("armv6hf")) {
      runOptions.append("-Xms" + Preferences.get("run.options.memory.initial") + "m");
      runOptions.append("-Xmx" + Preferences.get("run.options.memory.maximum") + "m");
    }
    // https://github.com/processing/processing/issues/2239
    runOptions.append("-Djna.nosys=true");
    // https://github.com/processing/processing/issues/4608
    if (embedJava) {
      // if people don't embed Java, it might be a mess, but what can we do?
      if (exportPlatform == PConstants.MACOSX) {
        runOptions.append("-Djava.ext.dirs=$APP_ROOT/Contents/PlugIns/jdk" +
                          PApplet.javaVersionName +
                          ".jdk/Contents/Home/jre/lib/ext");
      } else if (exportPlatform == PConstants.WINDOWS) {
        runOptions.append("-Djava.ext.dirs=\"%EXEDIR%\\java\\lib\\ext\"");
      } else if (exportPlatform == PConstants.LINUX) {
        runOptions.append("-Djava.ext.dirs=\"$APPDIR/java/lib/ext\"");
      }
    }

    // https://github.com/processing/processing/issues/2559
    if (exportPlatform == PConstants.WINDOWS) {
      runOptions.append("-Djava.library.path=\"%EXEDIR%\\lib\"");
    }

    /// macosx: write out Info.plist (template for classpath, etc)

    if (exportPlatform == PConstants.MACOSX) {
      StringBuilder runOptionsXML = new StringBuilder();
      for (String opt : runOptions) {
        runOptionsXML.append("      <string>");
        runOptionsXML.append(opt);
        runOptionsXML.append("</string>");
        runOptionsXML.append('\n');
      }

      String PLIST_TEMPLATE = "Info.plist.tmpl";
      File plistTemplate = new File(sketch.getFolder(), PLIST_TEMPLATE);
      if (!plistTemplate.exists()) {
        plistTemplate = mode.getContentFile("application/" + PLIST_TEMPLATE);
      }
      File plistFile = new File(dotAppFolder, "Contents/Info.plist");
      PrintWriter pw = PApplet.createWriter(plistFile);

      String lines[] = PApplet.loadStrings(plistTemplate);
      for (int i = 0; i < lines.length; i++) {
        if (lines[i].indexOf("@@") != -1) {
          StringBuilder sb = new StringBuilder(lines[i]);
          int index = 0;
          while ((index = sb.indexOf("@@jvm_runtime@@")) != -1) {
            sb.replace(index, index + "@@jvm_runtime@@".length(),
                       jvmRuntime);
          }
          while ((index = sb.indexOf("@@jvm_options_list@@")) != -1) {
            sb.replace(index, index + "@@jvm_options_list@@".length(),
                       runOptionsXML.toString());
          }
          while ((index = sb.indexOf("@@sketch@@")) != -1) {
            sb.replace(index, index + "@@sketch@@".length(),
                       sketch.getName());
          }
          while ((index = sb.indexOf("@@lsuipresentationmode@@")) != -1) {
            sb.replace(index, index + "@@lsuipresentationmode@@".length(),
                       Preferences.getBoolean("export.application.present") ? "4" : "0");
          }

          lines[i] = sb.toString();
        }
        // explicit newlines to avoid Windows CRLF
        pw.print(lines[i] + "\n");
      }
      pw.flush();
      pw.close();

      // attempt to code sign if the Xcode tools appear to be installed
      if (Platform.isMacOS() && isXcodeInstalled()) {
        if (embedJava) {
          ProcessHelper.ffs("codesign", "--force", "--sign", "-", jdkPath);
        }
        String appPath = dotAppFolder.getAbsolutePath();
        ProcessHelper.ffs("codesign", "--force", "--sign", "-", appPath);
      }

    } else if (exportPlatform == PConstants.WINDOWS) {
      File buildFile = new File(destFolder, "launch4j-build.xml");
      File configFile = new File(destFolder, "launch4j-config.xml");

      XML project = new XML("project");
      XML target = project.addChild("target");
      target.setString("name", "windows");

      XML taskdef = target.addChild("taskdef");
      taskdef.setString("name", "launch4j");
      taskdef.setString("classname", "net.sf.launch4j.ant.Launch4jTask");
      String launchPath = mode.getContentFile("application/launch4j").getAbsolutePath();
      taskdef.setString("classpath", launchPath + "/launch4j.jar:" + launchPath + "/lib/xstream.jar");

      XML launch4j = target.addChild("launch4j");
      // not all launch4j options are available when embedded inside the ant
      // build file (i.e. the icon param doesn't work), so use a config file
      //<launch4j configFile="windows/work/config.xml" />
      launch4j.setString("configFile", configFile.getAbsolutePath());

      XML config = new XML("launch4jConfig");
      config.addChild("headerType").setContent("gui");
      config.addChild("dontWrapJar").setContent("true");
      config.addChild("downloadUrl").setContent("http://java.com/download");

      File exeFile = new File(destFolder, sketch.getName() + ".exe");
      config.addChild("outfile").setContent(exeFile.getAbsolutePath());

      File iconFile = mode.getContentFile("application/sketch.ico");
      config.addChild("icon").setContent(iconFile.getAbsolutePath());

      XML clazzPath = config.addChild("classPath");
      clazzPath.addChild("mainClass").setContent(sketch.getName());
      for (String jarName : jarList) {
        clazzPath.addChild("cp").setContent("lib/" + jarName);
      }
      XML jre = config.addChild("jre");
      if (embedJava) {
        jre.addChild("path").setContent("java");
      }
      // Need u74 for a major JavaFX issue (upside-down display)
      // https://github.com/processing/processing/issues/3795
      jre.addChild("minVersion").setContent("1.8.0_74");
      for (String opt : runOptions) {
        jre.addChild("opt").setContent(opt);
      }

      config.save(configFile);
      project.save(buildFile);
      if (!buildWindowsLauncher(buildFile, "windows")) {
        // don't delete the build file, might be useful for debugging
        return false;
      }
      configFile.delete();
      buildFile.delete();

    } else {
      File shellScript = new File(destFolder, sketch.getName());
      PrintWriter pw = PApplet.createWriter(shellScript);

      // Do the newlines explicitly so that Windows CRLF
      // isn't used when exporting for Unix.
      pw.print("#!/bin/sh\n\n");
      pw.print("APPDIR=$(readlink -f \"$0\")\n");   // allow symlinks
      pw.print("APPDIR=$(dirname \"$APPDIR\")\n");  // more POSIX compliant

      // another fix for bug #234, LD_LIBRARY_PATH ignored on some platforms
      //ps.print("LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$APPDIR\n");

      if (embedJava) {
        // https://github.com/processing/processing/issues/2349
        pw.print("$APPDIR/java/bin/");
      }
      String runOptionsStr = runOptions.join(" ");
      pw.print("java " + runOptionsStr +
               " -Djava.library.path=\"$APPDIR:$APPDIR/lib\"" +
               // these aren't included here since they're added elsewhere
               // (and only included when Java is embedded)
               //" -Djava.ext.dirs=\"$APPDIR/java/lib/ext\"" +
               //" -Djna.nosys=true" +
               " -cp \"" + exportClassPath + "\"" +
               " " + sketch.getName() + " \"$@\"\n");

      pw.flush();
      pw.close();

      String shellPath = shellScript.getAbsolutePath();
      // will work on osx or *nix, but just dies on windows, oh well..
      if (!Platform.isWindows()) {
        Runtime.getRuntime().exec(new String[] { "chmod", "+x", shellPath });
      }
    }

    /// copy the source files to the target
    /// (we like to encourage people to share their code)

    File sourceFolder = new File(destFolder, "source");
    sourceFolder.mkdirs();

    for (SketchCode code : sketch.getCode()) {
      try {
        code.copyTo(new File(sourceFolder, code.getFileName()));
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    // move the .java file from the preproc there too
    String preprocFilename = sketch.getName() + ".java";
    File preprocFile = new File(srcFolder, preprocFilename);
    if (preprocFile.exists()) {
      Util.copyFile(preprocFile, new File(sourceFolder, preprocFilename));
    } else {
      System.err.println("Could not copy source file: " + preprocFile.getAbsolutePath());
    }

    /// goodbye
    return true;
  }

  static Boolean xcodeInstalled;

  static protected boolean isXcodeInstalled() {
    if (xcodeInstalled == null) {
      // http://stackoverflow.com/questions/15371925
      Process p = PApplet.launch("xcode-select", "-p");
      int result = -1;
      try {
        result = p.waitFor();
      } catch (InterruptedException e) { }
      // returns 0 if installed, 2 if not (-1 if exception)
      xcodeInstalled = (result == 0);
    }
    return xcodeInstalled;
  }

  /**
   * Run the launch4j build.xml file through ant to create the exe.
   * Most of this code was lifted from Android mode.
   */
  protected boolean buildWindowsLauncher(File buildFile, String target) {
    Project p = new Project();
    String path = buildFile.getAbsolutePath().replace('\\', '/');
    p.setUserProperty("ant.file", path);

    // deals with a problem where javac error messages weren't coming through
    p.setUserProperty("build.compiler", "extJavac");

    // too chatty
    /*
    // try to spew something useful to the console
    final DefaultLogger consoleLogger = new DefaultLogger();
    consoleLogger.setErrorPrintStream(System.err);
    consoleLogger.setOutputPrintStream(System.out);
    // WARN, INFO, VERBOSE, DEBUG
    consoleLogger.setMessageOutputLevel(Project.MSG_ERR);
    p.addBuildListener(consoleLogger);
    */

    DefaultLogger errorLogger = new DefaultLogger();
    ByteArrayOutputStream errb = new ByteArrayOutputStream();
    PrintStream errp = new PrintStream(errb);
    errorLogger.setErrorPrintStream(errp);
    ByteArrayOutputStream outb = new ByteArrayOutputStream();
    PrintStream outp = new PrintStream(outb);
    errorLogger.setOutputPrintStream(outp);
    errorLogger.setMessageOutputLevel(Project.MSG_INFO);
    p.addBuildListener(errorLogger);

    try {
      p.fireBuildStarted();
      p.init();
      final ProjectHelper helper = ProjectHelper.getProjectHelper();
      p.addReference("ant.projectHelper", helper);
      helper.parse(p, buildFile);
      p.executeTarget(target);
      return true;

    } catch (final BuildException e) {
      // Send a "build finished" event to the build listeners for this project.
      p.fireBuildFinished(e);

      String out = new String(outb.toByteArray());
      String err = new String(errb.toByteArray());
      System.out.println(out);
      System.err.println(err);
    }
    return false;
  }

  protected void addManifest(ZipOutputStream zos) throws IOException {
    ZipEntry entry = new ZipEntry("META-INF/MANIFEST.MF");
    zos.putNextEntry(entry);

    String contents =
      "Manifest-Version: 1.0\n" +
      "Created-By: Processing " + Base.getVersionName() + "\n" +
      "Main-Class: " + sketch.getName() + "\n";  // TODO not package friendly
    zos.write(contents.getBytes());
    zos.closeEntry();
  }

  protected void addClasses(ZipOutputStream zos, File dir) throws IOException {
    String path = dir.getAbsolutePath();
    if (!path.endsWith("/") && !path.endsWith("\\")) {
      path += '/';
    }
//    System.out.println("path is " + path);
    addClasses(zos, dir, path);
  }

  protected void addClasses(ZipOutputStream zos, File dir, String rootPath) throws IOException {
    File files[] = dir.listFiles(new FilenameFilter() {
      public boolean accept(File dir, String name) {
        return (name.charAt(0) != '.');
      }
    });
    for (File sub : files) {
      String relativePath = sub.getAbsolutePath().substring(rootPath.length());
//      System.out.println("relative path is " + relativePath);

      if (sub.isDirectory()) {
        addClasses(zos, sub, rootPath);

      } else if (sub.getName().endsWith(".class")) {
//        System.out.println("  adding item " + relativePath);
        ZipEntry entry = new ZipEntry(relativePath);
        zos.putNextEntry(entry);
        //zos.write(Base.loadBytesRaw(sub));
        PApplet.saveStream(zos, new FileInputStream(sub));
        zos.closeEntry();
      }
    }
  }

  protected void addDataFolder(ZipOutputStream zos) throws IOException {
    if (sketch.hasDataFolder()) {
      String[] dataFiles = Util.listFiles(sketch.getDataFolder(), false);
      int offset = sketch.getFolder().getAbsolutePath().length() + 1;
      for (String path : dataFiles) {
        if (Platform.isWindows()) {
          path = path.replace('\\', '/');
        }
        //File dataFile = new File(dataFiles[i]);
        File dataFile = new File(path);
        if (!dataFile.isDirectory()) {
          // don't export hidden files
          // skipping dot prefix removes all: . .. .DS_Store
          if (dataFile.getName().charAt(0) != '.') {
            ZipEntry entry = new ZipEntry(path.substring(offset));
            zos.putNextEntry(entry);
            //zos.write(Base.loadBytesRaw(dataFile));
            PApplet.saveStream(zos, new FileInputStream(dataFile));
            zos.closeEntry();
          }
        }
      }
    }
  }

  /**
   * Slurps up .class files from a colon (or semicolon on windows)
   * separated list of paths and adds them to a ZipOutputStream.
   */
  protected void packClassPathIntoZipFile(String path,
                                          ZipOutputStream zos,
                                          HashMap<String,Object> zipFileContents)
    throws IOException {
    String[] pieces = PApplet.split(path, File.pathSeparatorChar);

    for (int i = 0; i < pieces.length; i++) {
      if (pieces[i].length() == 0) continue;

      // is it a jar file or directory?
      if (pieces[i].toLowerCase().endsWith(".jar") ||
          pieces[i].toLowerCase().endsWith(".zip")) {
        try {
          ZipFile file = new ZipFile(pieces[i]);
          Enumeration<?> entries = file.entries();
          while (entries.hasMoreElements()) {
            ZipEntry entry = (ZipEntry) entries.nextElement();
            if (entry.isDirectory()) {
              // actually 'continue's for all dir entries

            } else {
              String entryName = entry.getName();
              // ignore contents of the META-INF folders
              if (entryName.indexOf("META-INF") == 0) continue;

              // don't allow duplicate entries
              if (zipFileContents.get(entryName) != null) continue;
              zipFileContents.put(entryName, new Object());

              ZipEntry entree = new ZipEntry(entryName);

              zos.putNextEntry(entree);
              byte buffer[] = new byte[(int) entry.getSize()];
              InputStream is = file.getInputStream(entry);

              int offset = 0;
              int remaining = buffer.length;
              while (remaining > 0) {
                int count = is.read(buffer, offset, remaining);
                offset += count;
                remaining -= count;
              }

              zos.write(buffer);
              zos.flush();
              zos.closeEntry();
            }
          }
          file.close();

        } catch (IOException e) {
          System.err.println("Error in file " + pieces[i]);
          e.printStackTrace();
        }
      } else {  // not a .jar or .zip, prolly a directory
        File dir = new File(pieces[i]);
        // but must be a dir, since it's one of several paths
        // just need to check if it exists
        if (dir.exists()) {
          packClassPathIntoZipFileRecursive(dir, null, zos);
        }
      }
    }
  }

  /**
   * Continue the process of magical exporting. This function
   * can be called recursively to walk through folders looking
   * for more goodies that will be added to the ZipOutputStream.
   */
  static protected void packClassPathIntoZipFileRecursive(File dir,
                                                          String sofar,
                                                          ZipOutputStream zos)
    throws IOException {
    String files[] = dir.list();
    for (int i = 0; i < files.length; i++) {
      // ignore . .. and .DS_Store
      if (files[i].charAt(0) == '.') continue;

      File sub = new File(dir, files[i]);
      String nowfar = (sofar == null) ?
        files[i] : (sofar + "/" + files[i]);

      if (sub.isDirectory()) {
        packClassPathIntoZipFileRecursive(sub, nowfar, zos);

      } else {
        // don't add .jar and .zip files, since they only work
        // inside the root, and they're unpacked
        if (!files[i].toLowerCase().endsWith(".jar") &&
            !files[i].toLowerCase().endsWith(".zip") &&
            files[i].charAt(0) != '.') {
          ZipEntry entry = new ZipEntry(nowfar);
          zos.putNextEntry(entry);
          //zos.write(Base.loadBytesRaw(sub));
          PApplet.saveStream(zos, new FileInputStream(sub));
          zos.closeEntry();
        }
      }
    }
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Textures/TextureCylinder/TextureCylinder.pde
/**
 * Texture Cylinder.
 *
 * Load an image and draw it onto a cylinder and a quad.
 */

int tubeRes = 32;
float[] tubeX = new float[tubeRes];
float[] tubeY = new float[tubeRes];
PImage img;

void setup() {
  size(640, 360, P3D);
  img = loadImage("berlin-1.jpg");
  float angle = 270.0 / tubeRes;
  for (int i = 0; i < tubeRes; i++) {
    tubeX[i] = cos(radians(i * angle));
    tubeY[i] = sin(radians(i * angle));
  }
  noStroke();
}

void draw() {
  background(0);
  translate(width / 2, height / 2);
  rotateX(map(mouseY, 0, height, -PI, PI));
  rotateY(map(mouseX, 0, width, -PI, PI));
  beginShape(QUAD_STRIP);
  texture(img);
  for (int i = 0; i < tubeRes; i++) {
    float x = tubeX[i] * 100;
    float z = tubeY[i] * 100;
    float u = img.width / tubeRes * i;
    vertex(x, -100, z, u, 0);
    vertex(x, 100, z, u, img.height);
  }
  endShape();
  beginShape(QUADS);
  texture(img);
  vertex(0, -100, 0, 0, 0);
  vertex(100, -100, 0, 100, 0);
  vertex(100, 100, 0, 100, 100);
  vertex(0, 100, 0, 0, 100);
  endShape();
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Fractals and L-Systems/Koch/KochFractal.pde
// Koch Curve
// A class to manage the list of line segments in the snowflake pattern

class KochFractal {
  PVector start;       // A PVector for the start
  PVector end;         // A PVector for the end
  ArrayList<KochLine> lines;   // A list to keep track of all the lines
  int count;

  KochFractal() {
    start = new PVector(0,height-20);
    end = new PVector(width,height-20);
    lines = new ArrayList<KochLine>();
    restart();
  }

  void nextLevel() {
    // For every line that is in the arraylist
    // create 4 more lines in a new arraylist
    lines = iterate(lines);
    count++;
  }

  void restart() {
    count = 0;      // Reset count
    lines.clear();  // Empty the array list
    lines.add(new KochLine(start,end));  // Add the initial line (from one end PVector to the other)
  }

  int getCount() {
    return count;
  }

  // This is easy, just draw all the lines
  void render() {
    for(KochLine l : lines) {
      l.display();
    }
  }

  // This is where the **MAGIC** happens
  // Step 1: Create an empty arraylist
  // Step 2: For every line currently in the arraylist
  //   - calculate 4 line segments based on Koch algorithm
  //   - add all 4 line segments into the new arraylist
  // Step 3: Return the new arraylist and it becomes the list of line segments for the structure

  // As we do this over and over again, each line gets broken into 4 lines, which gets broken into 4 lines, and so on. . .
  ArrayList iterate(ArrayList<KochLine> before) {
    ArrayList now = new ArrayList<KochLine>();    // Create emtpy list
    for(KochLine l : before) {
      // Calculate 5 koch PVectors (done for us by the line object)
      PVector a = l.start();
      PVector b = l.kochleft();
      PVector c = l.kochmiddle();
      PVector d = l.kochright();
      PVector e = l.end();
      // Make line segments between all the PVectors and add them
      now.add(new KochLine(a,b));
      now.add(new KochLine(b,c));
      now.add(new KochLine(c,d));
      now.add(new KochLine(d,e));
    }
    return now;
  }

}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/src/processing/mode/java/Commander.java
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
  Part of the Processing project - http://processing.org

  Copyright (c) 2012-15 The Processing Foundation
  Copyright (c) 2008-12 <NAME> and <NAME>

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software Foundation,
  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package processing.mode.java;

import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;

import processing.app.Base;
import processing.app.Platform;
import processing.app.Preferences;
import processing.app.RunnerListener;
import processing.app.Sketch;
import processing.app.SketchException;
import processing.app.Util;
import processing.app.contrib.ModeContribution;
import processing.core.PApplet;
import processing.mode.java.runner.Runner;

/**
 * Class to handle running Processing from the command line.
 *
 * @author fry
 */
public class Commander implements RunnerListener {
  static final String helpArg = "--help";
//  static final String preprocArg = "--preprocess";
  static final String buildArg = "--build";
  static final String runArg = "--run";
  static final String presentArg = "--present";
  static final String sketchArg = "--sketch=";
  static final String forceArg = "--force";
  static final String outputArg = "--output=";
  static final String exportApplicationArg = "--export";
  static final String noJavaArg = "--no-java";
  static final String platformArg = "--platform=";
  static final String bitsArg = "--bits=";
//  static final String preferencesArg = "--preferences=";

  static final int HELP = -1;
  static final int PREPROCESS = 0;
  static final int BUILD = 1;
  static final int RUN = 2;
  static final int PRESENT = 3;
//  static final int EXPORT_APPLET = 4;
  static final int EXPORT = 4;

  Sketch sketch;

  PrintStream systemOut;
  PrintStream systemErr;

  static public void main(String[] args) {
    // Do this early so that error messages go to the console
    Base.setCommandLine();
    // init the platform so that prefs and other native code is ready to go
    Platform.init();
    // make sure a full JDK is installed
    //Base.initRequirements();

    // launch command line handler
    new Commander(args);
  }

  public Commander(String[] args) {
    String sketchPath = null;
    File sketchFolder = null;
    String pdePath = null;  // path to the .pde file
    String outputPath = null;
    File outputFolder = null;
    boolean outputSet = false;  // set an output folder
    boolean force = false;  // replace that no good output folder
//    String preferencesPath = null;
    int platform = PApplet.platform; // default to this platform
//    int platformBits = Base.getNativeBits();
    int task = HELP;
    boolean embedJava = true;

    try {
      if (Platform.isWindows()) {
        // On Windows, it needs to use the default system encoding.
        // https://github.com/processing/processing/issues/1633
        systemOut = new PrintStream(System.out, true);
        systemErr = new PrintStream(System.err, true);
      } else {
        // On OS X, the output goes as MacRoman or something else useless.
        // http://code.google.com/p/processing/issues/detail?id=1418
        // (Not sure about Linux, but this has worked since 2.0)
        systemOut = new PrintStream(System.out, true, "UTF-8");
        systemErr = new PrintStream(System.err, true, "UTF-8");
      }
    } catch (UnsupportedEncodingException e) {
      e.printStackTrace();
      System.exit(1);
    }

    int argOffset = 0;
    for (String arg : args) {
      argOffset++;

      if (arg.length() == 0) {
        // ignore it, just the crappy shell script

      } else if (arg.equals(helpArg)) {
        // mode already set to HELP

//      } else if (arg.equals(preprocArg)) {
//        task = PREPROCESS;

      } else if (arg.equals(buildArg)) {
        task = BUILD;
        break;

      } else if (arg.equals(runArg)) {
        task = RUN;
        break;

      } else if (arg.equals(presentArg)) {
        task = PRESENT;
        break;

      } else if (arg.equals(exportApplicationArg)) {
        task = EXPORT;
        break;

      } else if (arg.equals(noJavaArg)) {
        embedJava = false;

      } else if (arg.startsWith(platformArg)) {
//        complainAndQuit("The --platform option has been removed from Processing 2.1.", false);
        String platformStr = arg.substring(platformArg.length());
        platform = Platform.getIndex(platformStr);
        if (platform == -1) {
          complainAndQuit(platformStr + " should instead be " +
                          "'windows', 'macosx', or 'linux'.", true);
        }

      } else if (arg.startsWith(bitsArg)) {
        complainAndQuit("The --bits option has been removed.", false);
//        String bitsStr = arg.substring(bitsArg.length());
//        if (bitsStr.equals("32")) {
//          platformBits = 32;
//        } else if (bitsStr.equals("64")) {
//          platformBits = 64;
//        } else {
//          complainAndQuit("Bits should be either 32 or 64, not " + bitsStr, true);
//        }

      } else if (arg.startsWith(sketchArg)) {
        sketchPath = arg.substring(sketchArg.length());
        sketchFolder = new File(sketchPath);
        if (!sketchFolder.exists()) {
          complainAndQuit(sketchFolder + " does not exist.", false);
        }
        File pdeFile = new File(sketchFolder, sketchFolder.getName() + ".pde");
        if (!pdeFile.exists()) {
          complainAndQuit("Not a valid sketch folder. " + pdeFile + " does not exist.", true);
        }
        pdePath = pdeFile.getAbsolutePath();

//      } else if (arg.startsWith(preferencesArg)) {
//        preferencesPath = arg.substring(preferencesArg.length());

      } else if (arg.startsWith(outputArg)) {
        outputSet = true;
        outputPath = arg.substring(outputArg.length());

      } else if (arg.equals(forceArg)) {
        force = true;

      } else {
        complainAndQuit("I don't know anything about " + arg + ".", true);
      }
    }
    String[] sketchArgs = PApplet.subset(args, argOffset);

//    if ((outputPath == null) &&
//        (task == PREPROCESS || task == BUILD ||
//         task == RUN || task == PRESENT)) {
//      complainAndQuit("An output path must be specified when using " +
//                      preprocArg + ", " + buildArg + ", " +
//                      runArg + ", or " + presentArg + ".");
//    }
    if (task == HELP) {
      printCommandLine(systemOut);
      System.exit(0);
    }

    if (outputSet) {
      if (outputPath == null) {
        complainAndQuit("An output path must be specified.", true);
      }

      outputFolder = new File(outputPath);
      if (outputFolder.exists()) {
        if (force) {
          Util.removeDir(outputFolder);
        } else {
          complainAndQuit("The output folder already exists. " +
                          "Use --force to remove it.", false);
        }
      }

      if (!outputFolder.mkdirs()) {
        complainAndQuit("Could not create the output folder.", false);
      }
    }

//    // run static initialization that grabs all the prefs
//    // (also pass in a prefs path if that was specified)
//    if (preferencesPath != null) {
//      Preferences.init(preferencesPath);
//    }

    Preferences.init();
    Base.locateSketchbookFolder();

    if (sketchPath == null) {
      complainAndQuit("No sketch path specified.", true);

//    } else if (!pdePath.toLowerCase().endsWith(".pde")) {
//      complainAndQuit("Sketch path must point to the main .pde file.", false);

    } else {

      if (outputSet) {
        if (outputPath.equals(sketchPath)) {
          complainAndQuit("The sketch path and output path cannot be identical.", false);
        }
      }

      boolean success = false;

//      JavaMode javaMode =
//        new JavaMode(null, Base.getContentFile("modes/java"));
      JavaMode javaMode = (JavaMode)
        ModeContribution.load(null, Platform.getContentFile("modes/java"),
                              "processing.mode.java.JavaMode").getMode();
      try {
        sketch = new Sketch(pdePath, javaMode);

        if (!outputSet) {
          outputFolder = sketch.makeTempFolder();
        }

        if (task == BUILD || task == RUN || task == PRESENT) {
          JavaBuild build = new JavaBuild(sketch);
          File srcFolder = new File(outputFolder, "source");
          String className = build.build(srcFolder, outputFolder, true);
//          String className = build.build(sketchFolder, outputFolder, true);
          if (className != null) {
            success = true;
            if (task == RUN || task == PRESENT) {
              Runner runner = new Runner(build, this);
              if (task == PRESENT) {
                runner.present(sketchArgs);
              } else {
                runner.launch(sketchArgs);
              }
              success = !runner.vmReturnedError();
            }
          } else {
            success = false;
          }

        } else if (task == EXPORT) {
          if (outputPath == null) {
            javaMode.handleExportApplication(sketch);
          } else {
            JavaBuild build = new JavaBuild(sketch);
            build.build(true);
            if (build != null) {
              String variant = Platform.getVariant();
              success = build.exportApplication(outputFolder, platform, variant, embedJava);
            }
          }
        }
        if (!success) {  // error already printed
          System.exit(1);
        }
        systemOut.println("Finished.");
        System.exit(0);

      } catch (SketchException re) {
        statusError(re);
        System.exit(1);

      } catch (IOException e) {
        e.printStackTrace();
        System.exit(1);
      }
    }
  }

  public void statusNotice(String message) {
    systemErr.println(message);
  }

  public void statusError(String message) {
    systemErr.println(message);
  }

  public void statusError(Exception exception) {
    if (exception instanceof SketchException) {
      SketchException re = (SketchException) exception;

      int codeIndex = re.getCodeIndex();
      if (codeIndex != -1) {
        // format the runner exception like emacs
        //blah.java:2:10:2:13: Syntax Error: This is a big error message
        // Emacs doesn't like the double line thing coming from Java
        // https://github.com/processing/processing/issues/2158
        String filename = sketch.getCode(codeIndex).getFileName();
        int line = re.getCodeLine() + 1;
        int column = re.getCodeColumn() + 1;
        //if (column == -1) column = 0;
        // TODO if column not specified, should just select the whole line.
        // But what's the correct syntax for that?
        systemErr.println(filename + ":" +
          line + ":" + column + ":" +
          line + ":" + column + ":" + " " + re.getMessage());

      } else {  // no line number, pass the trace along to the user
        exception.printStackTrace();
      }
    } else {
      exception.printStackTrace();
    }
  }

  void complainAndQuit(String lastWords, boolean schoolEmFirst) {
    if (schoolEmFirst) {
      printCommandLine(systemErr);
    }
    systemErr.println(lastWords);
    System.exit(1);
  }

  static void printCommandLine(PrintStream out) {
    out.println();
    out.println("Command line edition for Processing " + Base.getVersionName() + " (Java Mode)");
    out.println();
    out.println("--help               Show this help text. Congratulations.");
    out.println();
    out.println("--sketch=<name>      Specify the sketch folder (required)");
    out.println("--output=<name>      Specify the output folder (optional and");
    out.println("                     cannot be the same as the sketch folder.)");
    out.println();
    out.println("--force              The sketch will not build if the output");
    out.println("                     folder already exists, because the contents");
    out.println("                     will be replaced. This option erases the");
    out.println("                     folder first. Use with extreme caution!");
    out.println();
    out.println("--build              Preprocess and compile a sketch into .class files.");
    out.println("--run                Preprocess, compile, and run a sketch.");
    out.println("--present            Preprocess, compile, and run a sketch in presentation mode.");
    out.println();
    out.println("--export             Export an application.");
    out.println("--no-java            Do not embed Java. Use at your own risk!");
    out.println("--platform           Specify the platform (export to application only).");
    out.println("                     Should be one of 'windows', 'macosx', or 'linux'.");
//    out.println("--bits               Must be specified if libraries are used that are");
//    out.println("                     32- or 64-bit specific such as the OpenGL library.");
//    out.println("                     Otherwise specify 0 or leave it out.");

    out.println();
    out.println("The --build, --run, --present, or --export must be the final parameter");
    out.println("passed to Processing. Arguments passed following one of those four will");
    out.println("be passed through to the sketch itself, and therefore available to the");
    out.println("sketch via the 'args' field. To pass options understood by PApplet.main(),");
    out.println("write a custom main() method so that the preprocessor does not add one.");
    out.println("https://github.com/processing/processing/wiki/Command-Line");

    out.println();
  }

  @Override
  public void startIndeterminate() {
  }

  @Override
  public void stopIndeterminate() {
  }

  @Override
  public void statusHalt() {
  }

  @Override
  public boolean isHalted() {
    return false;
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Create Shapes/PolygonPShapeOOP3/PolygonPShapeOOP3.pde
/**
 * PolygonPShapeOOP.
 *
 * Wrapping a PShape inside a custom class
 * and demonstrating how we can have a multiple objects each
 * using the same PShape.
 */

// A list of objects
ArrayList<Polygon> polygons;

// Three possible shapes
PShape[] shapes = new PShape[3];

void setup() {
  size(640, 360, P2D);

  shapes[0] = createShape(ELLIPSE,0,0,100,100);
  shapes[0].setFill(color(255, 127));
  shapes[0].setStroke(false);
  shapes[1] = createShape(RECT,0,0,100,100);
  shapes[1].setFill(color(255, 127));
  shapes[1].setStroke(false);
  shapes[2] = createShape();
  shapes[2].beginShape();
  shapes[2].fill(0, 127);
  shapes[2].noStroke();
  shapes[2].vertex(0, -50);
  shapes[2].vertex(14, -20);
  shapes[2].vertex(47, -15);
  shapes[2].vertex(23, 7);
  shapes[2].vertex(29, 40);
  shapes[2].vertex(0, 25);
  shapes[2].vertex(-29, 40);
  shapes[2].vertex(-23, 7);
  shapes[2].vertex(-47, -15);
  shapes[2].vertex(-14, -20);
  shapes[2].endShape(CLOSE);

  // Make an ArrayList
  polygons = new ArrayList<Polygon>();

  for (int i = 0; i < 25; i++) {
    int selection = int(random(shapes.length));        // Pick a random index
    Polygon p = new Polygon(shapes[selection]);        // Use corresponding PShape to create Polygon
    polygons.add(p);
  }
}

void draw() {
  background(102);

  // Display and move them all
  for (Polygon poly : polygons) {
    poly.display();
    poly.move();
  }
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/io/examples/Compass_I2C_HMC6352/Compass_I2C_HMC6352.pde
import processing.io.*;
HMC6352 compass;

// see setup.png in the sketch folder for wiring details

void setup() {
  // the module's I2C address can be changed by modifying values in its EEPROM
  // 0x21 is however the default address

  //printArray(I2C.list());
  compass = new HMC6352("i2c-1", 0x21);
}

void draw() {
  background(255);
  float deg = compass.heading();
  println(deg + " degrees");
  line(width/2, height/2, width/2+sin(radians(deg))*width/2, height/2-cos(radians(deg))*height/2);
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Objects/MultipleConstructors/MultipleConstructors.pde
/**
 * Multiple constructors
 *
 * A class can have multiple constructors that assign the fields in different ways.
 * Sometimes it's beneficial to specify every aspect of an object's data by assigning
 * parameters to the fields, but other times it might be appropriate to define only
 * one or a few.
 */

Spot sp1, sp2;

void setup() {
  size(640, 360);
  background(204);
  noLoop();
  // Run the constructor without parameters
  sp1 = new Spot();
  // Run the constructor with three parameters
  sp2 = new Spot(width*0.5, height*0.5, 120);
}

void draw() {
  sp1.display();
  sp2.display();
}

class Spot {
  float x, y, radius;

  // First version of the Spot constructor;
  // the fields are assigned default values
  Spot() {
    radius = 40;
    x = width*0.25;
    y = height*0.5;
  }

  // Second version of the Spot constructor;
  // the fields are assigned with parameters
  Spot(float xpos, float ypos, float r) {
    x = xpos;
    y = ypos;
    radius = r;
  }
  void display() {
    ellipse(x, y, radius*2, radius*2);
  }

}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Lights/Spot/Spot.pde
/**
 * Spot.
 *
 * Move the mouse the change the position and concentation
 * of a blue spot light.
 */

int concentration = 600; // Try values 1 -> 10000

void setup() {
  size(640, 360, P3D);
  noStroke();
  fill(204);
  sphereDetail(60);
}

void draw() {
  background(0);

  // Light the bottom of the sphere
  directionalLight(51, 102, 126, 0, -1, 0);

  // Orange light on the upper-right of the sphere
  spotLight(204, 153, 0, 360, 160, 600, 0, 0, -1, PI/2, 600);

  // Moving spotlight that follows the mouse
  spotLight(102, 153, 204, 360, mouseY, 600, 0, 0, -1, PI/2, 600);

  translate(width/2, height/2, 0);
  sphere(120);
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/src/processing/mode/java/pdex/PDEX.java
package processing.mode.java.pdex;

import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.Document;

import processing.app.SketchCode;
import processing.mode.java.JavaEditor;

public class PDEX {
  static private final boolean SHOW_DEBUG_TREE = false;

  private boolean enabled = true;

  private ErrorChecker errorChecker;

  private InspectMode inspect;
  private ShowUsage usage;
  private Rename rename;
  private DebugTree debugTree;

  private PreprocessingService pps;

  public PDEX(JavaEditor editor, PreprocessingService pps) {
    this.pps = pps;

    this.enabled = !editor.hasJavaTabs();

    errorChecker = new ErrorChecker(editor, pps);

    usage = new ShowUsage(editor, pps);
    inspect = new InspectMode(editor, pps, usage);
    rename = new Rename(editor, pps, usage);

    if (SHOW_DEBUG_TREE) {
      debugTree = new DebugTree(editor, pps);
    }

    for (SketchCode code : editor.getSketch().getCode()) {
      Document document = code.getDocument();
      addDocumentListener(document);
    }

    sketchChanged();
  }

  public void addDocumentListener(Document doc) {
    if (doc != null) doc.addDocumentListener(sketchChangedListener);
  }

  final DocumentListener sketchChangedListener = new DocumentListener() {
    @Override
    public void insertUpdate(DocumentEvent e) {
      sketchChanged();
    }

    @Override
    public void removeUpdate(DocumentEvent e) {
      sketchChanged();
    }

    @Override
    public void changedUpdate(DocumentEvent e) {
      sketchChanged();
    }
  };

  public void sketchChanged() {
    errorChecker.notifySketchChanged();
    pps.notifySketchChanged();
  }

  public void preferencesChanged() {
    errorChecker.preferencesChanged();
    sketchChanged();
  }

  public void hasJavaTabsChanged(boolean hasJavaTabs) {
    enabled = !hasJavaTabs;
    if (!enabled) {
      usage.hide();
    }
  }

  public void dispose() {
    inspect.dispose();
    errorChecker.dispose();
    usage.dispose();
    rename.dispose();
    if (debugTree != null) {
      debugTree.dispose();
    }
  }

  public void documentChanged(Document newDoc) {
    addDocumentListener(newDoc);
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Demos/Performance/LineRendering/LineRendering.pde

public void setup() {
  size(800, 600, P2D);
}

public void draw() {
  background(255);
  stroke(0, 10);
  for (int i = 0; i < 50000; i++) {
    float x0 = random(width);
    float y0 = random(height);
    float z0 = random(-100, 100);
    float x1 = random(width);
    float y1 = random(height);
    float z1 = random(-100, 100);

    // purely 2D lines will trigger the GLU
    // tessellator to add accurate line caps,
    // but performance will be substantially
    // lower.
    line(x0, y0, z0, x1, y1, z1);
  }
  if (frameCount % 10 == 0) println(frameRate);
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/generated/processing/mode/java/preproc/JavaTokenTypes.java
// $ANTLR 2.7.7 (2006-11-01): "java15.g" -> "JavaLexer.java"$

package processing.mode.java.preproc;

public interface JavaTokenTypes {
	int EOF = 1;
	int NULL_TREE_LOOKAHEAD = 3;
	int BLOCK = 4;
	int MODIFIERS = 5;
	int OBJBLOCK = 6;
	int SLIST = 7;
	int CTOR_DEF = 8;
	int METHOD_DEF = 9;
	int VARIABLE_DEF = 10;
	int INSTANCE_INIT = 11;
	int STATIC_INIT = 12;
	int TYPE = 13;
	int CLASS_DEF = 14;
	int INTERFACE_DEF = 15;
	int PACKAGE_DEF = 16;
	int ARRAY_DECLARATOR = 17;
	int EXTENDS_CLAUSE = 18;
	int IMPLEMENTS_CLAUSE = 19;
	int PARAMETERS = 20;
	int PARAMETER_DEF = 21;
	int LABELED_STAT = 22;
	int TYPECAST = 23;
	int INDEX_OP = 24;
	int POST_INC = 25;
	int POST_DEC = 26;
	int METHOD_CALL = 27;
	int EXPR = 28;
	int ARRAY_INIT = 29;
	int IMPORT = 30;
	int UNARY_MINUS = 31;
	int UNARY_PLUS = 32;
	int CASE_GROUP = 33;
	int ELIST = 34;
	int FOR_INIT = 35;
	int FOR_CONDITION = 36;
	int FOR_ITERATOR = 37;
	int EMPTY_STAT = 38;
	int FINAL = 39;
	int ABSTRACT = 40;
	int STRICTFP = 41;
	int SUPER_CTOR_CALL = 42;
	int CTOR_CALL = 43;
	int VARIABLE_PARAMETER_DEF = 44;
	int STATIC_IMPORT = 45;
	int ENUM_DEF = 46;
	int ENUM_CONSTANT_DEF = 47;
	int FOR_EACH_CLAUSE = 48;
	int ANNOTATION_DEF = 49;
	int ANNOTATIONS = 50;
	int ANNOTATION = 51;
	int ANNOTATION_MEMBER_VALUE_PAIR = 52;
	int ANNOTATION_FIELD_DEF = 53;
	int ANNOTATION_ARRAY_INIT = 54;
	int TYPE_ARGUMENTS = 55;
	int TYPE_ARGUMENT = 56;
	int TYPE_PARAMETERS = 57;
	int TYPE_PARAMETER = 58;
	int WILDCARD_TYPE = 59;
	int TYPE_UPPER_BOUNDS = 60;
	int TYPE_LOWER_BOUNDS = 61;
	int LITERAL_package = 62;
	int SEMI = 63;
	int LITERAL_import = 64;
	int LITERAL_static = 65;
	int LBRACK = 66;
	int RBRACK = 67;
	int IDENT = 68;
	int DOT = 69;
	int QUESTION = 70;
	int LITERAL_extends = 71;
	int LITERAL_super = 72;
	int LT = 73;
	int COMMA = 74;
	int GT = 75;
	int SR = 76;
	int BSR = 77;
	int LITERAL_void = 78;
	int LITERAL_boolean = 79;
	int LITERAL_byte = 80;
	int LITERAL_char = 81;
	int LITERAL_short = 82;
	int LITERAL_int = 83;
	int LITERAL_float = 84;
	int LITERAL_long = 85;
	int LITERAL_double = 86;
	int STAR = 87;
	int LITERAL_private = 88;
	int LITERAL_public = 89;
	int LITERAL_protected = 90;
	int LITERAL_transient = 91;
	int LITERAL_native = 92;
	int LITERAL_threadsafe = 93;
	int LITERAL_synchronized = 94;
	int LITERAL_volatile = 95;
	int AT = 96;
	int LPAREN = 97;
	int RPAREN = 98;
	int ASSIGN = 99;
	int LCURLY = 100;
	int RCURLY = 101;
	int LITERAL_class = 102;
	int LITERAL_interface = 103;
	int LITERAL_enum = 104;
	int BAND = 105;
	int LITERAL_default = 106;
	int LITERAL_implements = 107;
	int LITERAL_this = 108;
	int LITERAL_throws = 109;
	int TRIPLE_DOT = 110;
	int COLON = 111;
	int LITERAL_if = 112;
	int LITERAL_else = 113;
	int LITERAL_while = 114;
	int LITERAL_do = 115;
	int LITERAL_break = 116;
	int LITERAL_continue = 117;
	int LITERAL_return = 118;
	int LITERAL_switch = 119;
	int LITERAL_throw = 120;
	int LITERAL_assert = 121;
	int LITERAL_for = 122;
	int LITERAL_case = 123;
	int LITERAL_try = 124;
	int LITERAL_finally = 125;
	int LITERAL_catch = 126;
	int PLUS_ASSIGN = 127;
	int MINUS_ASSIGN = 128;
	int STAR_ASSIGN = 129;
	int DIV_ASSIGN = 130;
	int MOD_ASSIGN = 131;
	int SR_ASSIGN = 132;
	int BSR_ASSIGN = 133;
	int SL_ASSIGN = 134;
	int BAND_ASSIGN = 135;
	int BXOR_ASSIGN = 136;
	int BOR_ASSIGN = 137;
	int LOR = 138;
	int LAND = 139;
	int BOR = 140;
	int BXOR = 141;
	int NOT_EQUAL = 142;
	int EQUAL = 143;
	int LE = 144;
	int GE = 145;
	int LITERAL_instanceof = 146;
	int SL = 147;
	int PLUS = 148;
	int MINUS = 149;
	int DIV = 150;
	int MOD = 151;
	int INC = 152;
	int DEC = 153;
	int BNOT = 154;
	int LNOT = 155;
	int LITERAL_true = 156;
	int LITERAL_false = 157;
	int LITERAL_null = 158;
	int LITERAL_new = 159;
	int NUM_INT = 160;
	int CHAR_LITERAL = 161;
	int STRING_LITERAL = 162;
	int NUM_FLOAT = 163;
	int NUM_LONG = 164;
	int NUM_DOUBLE = 165;
	int WS = 166;
	int SL_COMMENT = 167;
	int ML_COMMENT = 168;
	int ESC = 169;
	int HEX_DIGIT = 170;
	int VOCAB = 171;
	int EXPONENT = 172;
	int FLOAT_SUFFIX = 173;
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Curves/ArcLengthParametrization/BezierCurve.pde
/*
  This class represents a cubic Bézier curve.

  getPointAtParameter() method works the same as bezierPoint().

  Points returned from this method are closer to each other
  at places where the curve bends and farther apart where the
  curve runs straight.

  On the orther hand, getPointAtFraction() and getPointAtLength()
  return points at fixed distances. This is useful in many scenarios:
  you may want to move an object along the curve at some speed
  or you may want to draw dashed Bézier curves.
*/

class BezierCurve {

  private final int SEGMENT_COUNT = 100;

  private PVector v0, v1, v2, v3;

  private float arcLengths[] = new float[SEGMENT_COUNT + 1]; // there are n segments between n+1 points

  private float curveLength;

  BezierCurve(PVector a, PVector b, PVector c, PVector d) {
    v0 = a.get(); // curve begins here
    v1 = b.get();
    v2 = c.get();
    v3 = d.get(); // curve ends here

    // The idea here is to make a handy look up table, which contains
    // parameter values with their arc lengths along the curve. Later,
    // when we want a point at some arc length, we can go through our
    // table, pick the place where the point is going to be located and
    // interpolate the value of parameter from two surrounding parameters
    // in our table.

    // we will keep current length along the curve here
    float arcLength = 0;

    PVector prev = new PVector();
    prev.set(v0);

    // i goes from 0 to SEGMENT_COUNT
    for (int i = 0; i <= SEGMENT_COUNT; i++) {

      // map index from range (0, SEGMENT_COUNT) to parameter in range (0.0, 1.0)
      float t = (float) i / SEGMENT_COUNT;

      // get point on the curve at this parameter value
      PVector point = pointAtParameter(t);

      // get distance from previous point
      float distanceFromPrev = PVector.dist(prev, point);

      // add arc length of last segment to total length
      arcLength += distanceFromPrev;

      // save current arc length to the look up table
      arcLengths[i] = arcLength;

      // keep this point to compute length of next segment
      prev.set(point);
    }

    // Here we have sum of all segment lengths, which should be
    // very close to the actual length of the curve. The more
    // segments we use, the more accurate it becomes.
    curveLength = arcLength;
  }

  // Returns the length of this curve
  float length() {
    return curveLength;
  }

  // Returns a point along the curve at a specified parameter value.
  PVector pointAtParameter(float t) {
    PVector result = new PVector();
    result.x = bezierPoint(v0.x, v1.x, v2.x, v3.x, t);
    result.y = bezierPoint(v0.y, v1.y, v2.y, v3.y, t);
    result.z = bezierPoint(v0.z, v1.z, v2.z, v3.z, t);
    return result;
  }

  // Returns a point at a fraction of curve's length.
  // Example: pointAtFraction(0.25) returns point at one quarter of curve's length.
  PVector pointAtFraction(float r) {
    float wantedLength = curveLength * r;
    return pointAtLength(wantedLength);
  }

  // Returns a point at a specified arc length along the curve.
  PVector pointAtLength(float wantedLength) {
    wantedLength = constrain(wantedLength, 0.0, curveLength);

    // look up the length in our look up table
    int index = java.util.Arrays.binarySearch(arcLengths, wantedLength);

    float mappedIndex;

    if (index < 0) {
      // if the index is negative, exact length is not in the table,
      // but it tells us where it should be in the table
      // see http://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html#binarySearch(float[], float)

      // interpolate two surrounding indexes
      int nextIndex = -(index + 1);
      int prevIndex = nextIndex - 1;
      float prevLength = arcLengths[prevIndex];
      float nextLength = arcLengths[nextIndex];
      mappedIndex = map(wantedLength, prevLength, nextLength, prevIndex, nextIndex);

    } else {
      // wanted length is in the table, we know the index right away
      mappedIndex = index;
    }

    // map index from range (0, SEGMENT_COUNT) to parameter in range (0.0, 1.0)
    float parameter = mappedIndex / SEGMENT_COUNT;

    return pointAtParameter(parameter);
  }

  // Returns an array of equidistant point on the curve
  PVector[] equidistantPoints(int howMany) {

    PVector[] resultPoints = new PVector[howMany];

    // we already know the beginning and the end of the curve
    resultPoints[0] = v0.get();
    resultPoints[howMany - 1] = v3.get();

    int arcLengthIndex = 1;
    for (int i = 1; i < howMany - 1; i++) {

      // compute wanted arc length
      float fraction = (float) i / (howMany - 1);
      float wantedLength = fraction * curveLength;

      // move through the look up table until we find greater length
      while (wantedLength > arcLengths[arcLengthIndex] && arcLengthIndex < arcLengths.length) {
        arcLengthIndex++;
      }

      // interpolate two surrounding indexes
      int nextIndex = arcLengthIndex;
      int prevIndex = arcLengthIndex - 1;
      float prevLength = arcLengths[prevIndex];
      float nextLength = arcLengths[nextIndex];
      float mappedIndex = map(wantedLength, prevLength, nextLength, prevIndex, nextIndex);

      // map index from range (0, SEGMENT_COUNT) to parameter in range (0.0, 1.0)
      float parameter = mappedIndex / SEGMENT_COUNT;

      resultPoints[i] = pointAtParameter(parameter);
    }

    return resultPoints;
  }

  // Returns an array of points on the curve.
  PVector[] points(int howMany) {

    PVector[] resultPoints = new PVector[howMany];

    // we already know the first and the last point of the curve
    resultPoints[0] = v0.get();
    resultPoints[howMany - 1] = v3.get();

    for (int i = 1; i < howMany - 1; i++) {

      // map index to parameter in range (0.0, 1.0)
      float parameter = (float) i / (howMany - 1);

      resultPoints[i] = pointAtParameter(parameter);
    }

    return resultPoints;
  }

}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/dxf/examples/SimpleExport/SimpleExport.pde
/**
 * Simple DXF Export
 * by <NAME>.
 *
 * Press the 'R' key to export a DXF file.
 */

import processing.dxf.*;
boolean record = false;

void setup() {
  size(400, 400, P3D);
  noStroke();
  sphereDetail(12);
}

void draw() {
  if (record == true) {
    beginRaw(DXF, "output.dxf"); // Start recording to the file
  }
  lights();
  background(0);
  translate(width / 3, height / 3, -200);
  rotateZ(map(mouseY, 0, height, 0, PI));
  rotateY(map(mouseX, 0, width, 0, HALF_PI));
  for (int y = -2; y < 2; y++) {
    for (int x = -2; x < 2; x++) {
      for (int z = -2; z < 2; z++) {
        pushMatrix();
        translate(120*x, 120*y, -120*z);
        sphere(30);
        popMatrix();
      }
    }
  }
  if (record == true) {
    endRaw();
    record = false; // Stop recording to the file
  }
}

void keyPressed() {
  if (key == 'R' || key == 'r') { // Press R to save the file
    record = true;
  }
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/svg/README.md
A very simple SVG exporter based on the PDF Export library that ships with Processing. Uses Batik's [SVG Generator](http://xmlgraphics.apache.org/batik/using/svg-generator.html).
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Form/PieChart/PieChart.pde
/**
 * Pie Chart
 *
 * Uses the arc() function to generate a pie chart from the data
 * stored in an array.
 */

int[] angles = { 30, 10, 45, 35, 60, 38, 75, 67 };

void setup() {
  size(640, 360);
  noStroke();
  noLoop();  // Run once and stop
}

void draw() {
  background(100);
  pieChart(300, angles);
}

void pieChart(float diameter, int[] data) {
  float lastAngle = 0;
  for (int i = 0; i < data.length; i++) {
    float gray = map(i, 0, data.length, 0, 255);
    fill(gray);
    arc(width/2, height/2, diameter, diameter, lastAngle, lastAngle+radians(data[i]));
    lastAngle += radians(data[i]);
  }
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Interaction/Reach1/Reach1.pde
/**
 * Reach 1
 * based on code from <NAME>.
 *
 * The arm follows the position of the mouse by
 * calculating the angles with atan2().
 */

float segLength = 80;
float x, y, x2, y2;

void setup() {
  size(640, 360);
  strokeWeight(20.0);
  stroke(255, 100);

  x = width/2;
  y = height/2;
  x2 = x;
  y2 = y;
}

void draw() {
  background(0);

  float dx = mouseX - x;
  float dy = mouseY - y;
  float angle1 = atan2(dy, dx);

  float tx = mouseX - cos(angle1) * segLength;
  float ty = mouseY - sin(angle1) * segLength;
  dx = tx - x2;
  dy = ty - y2;
  float angle2 = atan2(dy, dx);
  x = x2 + cos(angle2) * segLength;
  y = y2 + sin(angle2) * segLength;

  segment(x, y, angle1);
  segment(x2, y2, angle2);
}

void segment(float x, float y, float a) {
  pushMatrix();
  translate(x, y);
  rotate(a);
  line(0, 0, segLength, 0);
  popMatrix();
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/pdf/examples/OneFrame/OneFrame.pde
/**
 * One Frame.
 *
 * Saves one PDF with the contents of the display window.
 * Because this example uses beginRecord, the image is shown
 * on the display window and is saved to the file.
*/

import processing.pdf.*;

size(600, 600);

beginRecord(PDF, "line.pdf");

background(255);
stroke(0, 20);
strokeWeight(20.0);
line(200, 0, 400, height);

endRecord();

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Objects/Objects/Objects.pde
/**
 * Objects
 * by hbarragan.
 *
 * Move the cursor across the image to change the speed and positions
 * of the geometry. The class MRect defines a group of lines.
 */

MRect r1, r2, r3, r4;

void setup()
{
  size(640, 360);
  fill(255, 204);
  noStroke();
  r1 = new MRect(1, 134.0, 0.532, 0.1*height, 10.0, 60.0);
  r2 = new MRect(2, 44.0, 0.166, 0.3*height, 5.0, 50.0);
  r3 = new MRect(2, 58.0, 0.332, 0.4*height, 10.0, 35.0);
  r4 = new MRect(1, 120.0, 0.0498, 0.9*height, 15.0, 60.0);
}

void draw()
{
  background(0);

  r1.display();
  r2.display();
  r3.display();
  r4.display();

  r1.move(mouseX-(width/2), mouseY+(height*0.1), 30);
  r2.move((mouseX+(width*0.05))%width, mouseY+(height*0.025), 20);
  r3.move(mouseX/4, mouseY-(height*0.025), 40);
  r4.move(mouseX-(width/2), (height-mouseY), 50);
}

class MRect
{
  int w; // single bar width
  float xpos; // rect xposition
  float h; // rect height
  float ypos ; // rect yposition
  float d; // single bar distance
  float t; // number of bars

  MRect(int iw, float ixp, float ih, float iyp, float id, float it) {
    w = iw;
    xpos = ixp;
    h = ih;
    ypos = iyp;
    d = id;
    t = it;
  }

  void move (float posX, float posY, float damping) {
    float dif = ypos - posY;
    if (abs(dif) > 1) {
      ypos -= dif/damping;
    }
    dif = xpos - posX;
    if (abs(dif) > 1) {
      xpos -= dif/damping;
    }
  }

  void display() {
    for (int i=0; i<t; i++) {
      rect(xpos+(i*(d+w)), ypos, w, height*h);
    }
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Shape/LoadDisplaySVG/LoadDisplaySVG.pde
/**
 * Load and Display a Shape.
 * Illustration by <NAME>.
 *
 * The loadShape() command is used to read simple SVG (Scalable Vector Graphics)
 * files and OBJ (Object) files into a Processing sketch. This example loads an
 * SVG file of a monster robot face and displays it to the screen.
 */

PShape bot;

void setup() {
  size(640, 360);
  // The file "bot1.svg" must be in the data folder
  // of the current sketch to load successfully
  bot = loadShape("bot1.svg");
}

void draw(){
  background(102);
  shape(bot, 110, 90, 100, 100);  // Draw at coordinate (110, 90) at size 100 x 100
  shape(bot, 280, 40);            // Draw at coordinate (280, 40) at the default size
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Fractals and L-Systems/PenroseSnowflake/PenroseSnowflake.pde
/**
 * Penrose Snowflake L-System
 * by <NAME>.
 *
 * This code was based on <NAME>'s L-System class.
 */

PenroseSnowflakeLSystem ps;

void setup() {
  size(640, 360);
  stroke(255);
  noFill();
  ps = new PenroseSnowflakeLSystem();
  ps.simulate(4);
}

void draw() {
  background(0);
  ps.render();
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Input/Easing/Easing.pde
/**
 * Easing.
 *
 * Move the mouse across the screen and the symbol will follow.
 * Between drawing each frame of the animation, the program
 * calculates the difference between the position of the
 * symbol and the cursor. If the distance is larger than
 * 1 pixel, the symbol moves part of the distance (0.05) from its
 * current position toward the cursor.
 */

float x;
float y;
float easing = 0.05;

void setup() {
  size(640, 360);
  noStroke();
}

void draw() {
  background(51);

  float targetX = mouseX;
  float dx = targetX - x;
  x += dx * easing;

  float targetY = mouseY;
  float dy = targetY - y;
  y += dy * easing;

  ellipse(x, y, 66, 66);
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/io/examples/LedCounter/LedCounter.pde
import processing.io.*;
LED leds[];

// the Raspberry Pi has two build-in LEDs we can control
// led0 (green) and led1 (red)

void setup() {
  String available[] = LED.list();
  print("Available: ");
  println(available);

  // create an object for each LED and store it in an array
  leds = new LED[available.length];
  for (int i=0; i < available.length; i++) {
    leds[i] = new LED(available[i]);
  }

  frameRate(1);
}

void draw() {
  // make the LEDs count in binary
  for (int i=0; i < leds.length; i++) {
    if ((frameCount & (1 << i)) != 0) {
      leds[i].brightness(1.0);
    } else {
      leds[i].brightness(0.0);
    }
  }
  println(frameCount);
}

void keyPressed() {
  // cleanup
  for (int i=0; i < leds.length; i++) {
    leds[i].close();
  }
  exit();
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Color/WaveGradient/WaveGradient.pde
/**
 * Wave Gradient
 * by <NAME>.
 *
 * Generate a gradient along a sin() wave.
 */

float amplitude = 30;
float fillGap = 2.5;

void setup() {
  size(640, 360);
  background(200);

  // To efficiently set all the pixels on screen, make the set()
  // calls on a PImage, then write the result to the screen.
  PImage gradient = createImage(width, height, RGB);
  float frequency = 0;

  for (int i =- 75; i < height+75; i++){
    // Reset angle to 0, so waves stack properly
    float angle = 0;
    // Increasing frequency causes more gaps
    frequency += 0.002;
    for (float j = 0; j < width+75; j++){
      float py = i + sin(radians(angle)) * amplitude;
      angle += frequency;
      color c = color(abs(py-i)*255/amplitude, 255-abs(py-i)*255/amplitude, j*(255.0/(width+50)));
      // Hack to fill gaps. Raise value of fillGap if you increase frequency
      for (int filler = 0; filler < fillGap; filler++){
        gradient.set(int(j-filler), int(py)-filler, c);
        gradient.set(int(j), int(py), c);
        gradient.set(int(j+filler), int(py)+filler, c);
      }
    }
  }
  // Draw the image to the screen
  set(0, 0, gradient);
  // Another alternative for drawing to the screen
  //image(gradient, 0, 0);
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Demos/Graphics/Wiggling/Wiggling.pde
// Press 'w' to start wiggling, space to restore
// original positions.

PShape cube;
float cubeSize = 320;
float circleRad = 100;
int circleRes = 40;
float noiseMag = 1;

boolean wiggling = false;

void setup() {
  size(1024, 768, P3D);

  createCube();
}

void draw() {
  background(0);

  translate(width/2, height/2);
  rotateX(frameCount * 0.01f);
  rotateY(frameCount * 0.01f);

  shape(cube);

  if (wiggling) {
    PVector pos = null;
    for (int i = 0; i < cube.getChildCount(); i++) {
      PShape face = cube.getChild(i);
      for (int j = 0; j < face.getVertexCount(); j++) {
        pos = face.getVertex(j, pos);
        pos.x += random(-noiseMag/2, +noiseMag/2);
        pos.y += random(-noiseMag/2, +noiseMag/2);
        pos.z += random(-noiseMag/2, +noiseMag/2);
        face.setVertex(j, pos.x, pos.y, pos.z);
      }
    }
  }

  if (frameCount % 60 == 0) println(frameRate);
}

public void keyPressed() {
  if (key == 'w') {
    wiggling = !wiggling;
  } else if (key == ' ') {
    restoreCube();
  } else if (key == '1') {
    cube.setStrokeWeight(1);
  } else if (key == '2') {
    cube.setStrokeWeight(5);
  } else if (key == '3') {
    cube.setStrokeWeight(10);
  }
}

void createCube() {
  cube = createShape(GROUP);

  PShape face;

  // Create all faces at front position
  for (int i = 0; i < 6; i++) {
    face = createShape();
    createFaceWithHole(face);
    cube.addChild(face);
  }

  // Rotate all the faces to their positions

  // Front face - already correct
  face = cube.getChild(0);

  // Back face
  face = cube.getChild(1);
  face.rotateY(radians(180));

  // Right face
  face = cube.getChild(2);
  face.rotateY(radians(90));

  // Left face
  face = cube.getChild(3);
  face.rotateY(radians(-90));

  // Top face
  face = cube.getChild(4);
  face.rotateX(radians(90));

  // Bottom face
  face = cube.getChild(5);
  face.rotateX(radians(-90));
}

void createFaceWithHole(PShape face) {
  face.beginShape(POLYGON);
  face.stroke(255, 0, 0);
  face.fill(255);

  // Draw main shape Clockwise
  face.vertex(-cubeSize/2, -cubeSize/2, +cubeSize/2);
  face.vertex(+cubeSize/2, -cubeSize/2, +cubeSize/2);
  face.vertex(+cubeSize/2, +cubeSize/2, +cubeSize/2);
  face.vertex(-cubeSize / 2, +cubeSize / 2, +cubeSize / 2);

  // Draw contour (hole) Counter-Clockwise
  face.beginContour();
  for (int i = 0; i < circleRes; i++) {
    float angle = TWO_PI * i / circleRes;
    float x = circleRad * sin(angle);
    float y = circleRad * cos(angle);
    float z = +cubeSize/2;
    face.vertex(x, y, z);
  }
  face.endContour();

  face.endShape(CLOSE);
}

void restoreCube() {
  // Rotation of faces is preserved, so we just reset them
  // the same way as the "front" face and they will stay
  // rotated correctly
  for (int i = 0; i < 6; i++) {
    PShape face = cube.getChild(i);
    restoreFaceWithHole(face);
  }
}

void restoreFaceWithHole(PShape face) {
  face.setVertex(0, -cubeSize/2, -cubeSize/2, +cubeSize/2);
  face.setVertex(1, +cubeSize/2, -cubeSize/2, +cubeSize/2);
  face.setVertex(2, +cubeSize/2, +cubeSize/2, +cubeSize/2);
  face.setVertex(3, -cubeSize/2, +cubeSize/2, +cubeSize/2);
  for (int i = 0; i < circleRes; i++) {
    float angle = TWO_PI * i / circleRes;
    float x = circleRad * sin(angle);
    float y = circleRad * cos(angle);
    float z = +cubeSize/2;
    face.setVertex(4 + i, x, y, z);
  }
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Color/RadialGradient/RadialGradient.pde
/**
 * Radial Gradient.
 *
 * Draws a series of concentric circles to create a gradient
 * from one color to another.
 */

int dim;

void setup() {
  size(640, 360);
  dim = width/2;
  background(0);
  colorMode(HSB, 360, 100, 100);
  noStroke();
  ellipseMode(RADIUS);
  frameRate(1);
}

void draw() {
  background(0);
  for (int x = 0; x <= width; x+=dim) {
    drawGradient(x, height/2);
  }
}

void drawGradient(float x, float y) {
  int radius = dim/2;
  float h = random(0, 360);
  for (int r = radius; r > 0; --r) {
    fill(h, 90, 90);
    ellipse(x, y, r, r);
    h = (h + 1) % 360;
  }
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Control/EmbeddedIteration/EmbeddedIteration.pde
/**
 * Embedding Iteration.
 *
 * Embedding "for" structures allows repetition in two dimensions.
 *
 */

size(640, 360);
background(0);

int gridSize = 40;

for (int x = gridSize; x <= width - gridSize; x += gridSize) {
  for (int y = gridSize; y <= height - gridSize; y += gridSize) {
    noStroke();
    fill(255);
    rect(x-1, y-1, 3, 3);
    stroke(255, 100);
    line(x, y, width/2, height/2);
  }
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/serial/test/serial_throughput/arduino/serial_thoughput.ino
void setup() {
  Serial.begin(115200);
}

void loop() {
  while (true) {
    Serial.write('.');
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Advanced Data/Regex/Regex.pde
/**
 * Regular Expression example
 * by <NAME>.
 *
 * This example demonstrates how to use matchAll() to create
 * a list of all matches of a given regex.
 *
 * Here we'll load the raw HTML from a URL and search for any
 *  links
 */

// Our source url
String url = "http://processing.org";
// We'll store the results in an array
String[] links;

void setup() {
  size(640, 360);
  // Load the links
  links = loadLinks(url);
}

void draw() {
  background(0);
  // Display the raw links
  fill(255);
  for (int i = 0; i < links.length; i++) {
    text(links[i],10,16+i*16);
  }
}

String[] loadLinks(String s) {
  // Load the raw HTML
  String[] lines = loadStrings(s);
  // Put it in one big string
  String html = join(lines,"\n");

  // A wacky regex for matching a URL
  String regex = "<\\s*a\\s+href\\s*=\\s*\"(.*?)\"";
  // The matches are in a two dimensional array
  // The first dimension is all matches
  // The second dimension is the groups
  String[][] matches = matchAll(html, regex);

  // An array for the results
  String[] results = new String[matches.length];

  // We want group 1 for each result
  for (int i = 0; i < results.length; i++) {
     results[i] = matches[i][1];
  }

  // Return the results
  return results;
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Create Shapes/PolygonPShapeOOP/PolygonPShapeOOP.pde
/**
 * PolygonPShapeOOP.
 *
 * Wrapping a PShape inside a custom class
 */

// A Star object
Star s1, s2;

void setup() {
  size(640, 360, P2D);

  // Make a new Star
  s1 = new Star();
  s2 = new Star();

}

void draw() {
  background(51);

  s1.display();  // Display the first star
  s1.move();  // Move the first star

  s2.display();  // Display the second star
  s2.move();  // Move the second star

}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Vectors/AccelerationWithVectors/AccelerationWithVectors.pde
/**
 * Acceleration with Vectors
 * by <NAME>.
 *
 * Demonstration of the basics of motion with vector.
 * A "Mover" object stores location, velocity, and acceleration as vectors
 * The motion is controlled by affecting the acceleration (in this case towards the mouse)
 *
 * For more examples of simulating motion and physics with vectors, see
 * Simulate/ForcesWithVectors, Simulate/GravitationalAttraction3D
 */

// A Mover object
Mover mover;

void setup() {
  size(640,360);
  mover = new Mover();
}

void draw() {
  background(0);

  // Update the location
  mover.update();
  // Display the Mover
  mover.display();
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/src/processing/mode/java/tweak/ColorSelector.java
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
  Part of the Processing project - http://processing.org
  Copyright (c) 2012-15 The Processing Foundation

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License version 2
  as published by the Free Software Foundation.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software Foundation, Inc.
  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package processing.mode.java.tweak;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;

import javax.swing.Box;
import javax.swing.JComponent;
import javax.swing.JFrame;

public class ColorSelector {
  int hue, saturation, brightness;

  public JFrame frame;
  public ColorControlBox colorBox;
  ColorSelectorBox selectorBox;
  ColorSelectorSlider selectorSlider;
  SelectorTopBar topBar;

  public ColorSelector(ColorControlBox colorBox) {
    this.colorBox = colorBox;
    createFrame();
  }

  public void createFrame() {
    frame = new JFrame();
    frame.setBackground(Color.BLACK);

    Box box = Box.createHorizontalBox();
    box.setBackground(Color.BLACK);

    selectorSlider = new ColorSelectorSlider();

    if (!colorBox.isBW) {
      selectorBox = new ColorSelectorBox();
      box.add(selectorBox);
    }

    box.add(Box.createHorizontalGlue());
    box.add(selectorSlider, BorderLayout.CENTER);
    box.add(Box.createHorizontalGlue());

    frame.getContentPane().add(box, BorderLayout.CENTER);
    frame.pack();
    frame.setResizable(false);
    frame.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
  }

  public void show(int x, int y) {
    frame.setLocation(x, y);
    frame.setVisible(true);
    frame.repaint();
  }

  public void hide() {
    this.colorBox = null;
    frame.setVisible(false);
  }

  public void refreshColor() {
    if (!colorBox.ilegalColor) {
      setColor(colorBox.color);
    }
  }

  public void setColor(Color c) {
    if (selectorBox != null) {
      selectorBox.setToColor(c);
    }
    selectorSlider.setToColor(c);
    repaintSelector();
  }

  public void satBrightChanged() {
    repaintSelector();
  }

  public void hueChanged() {
    if (selectorBox != null) {
      selectorBox.renderBack();
    }
    repaintSelector();
  }

  public void repaintSelector() {
    if (selectorBox != null) {
      selectorBox.repaint();
    }
    selectorSlider.repaint();
  }

  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

  class ColorSelectorBox extends JComponent {
    int lastX, lastY;
    BufferedImage backImg;

    ColorSelectorBox() {
      if (!colorBox.ilegalColor) {
        setToColor(colorBox.color);
      }
      renderBack();

      addMouseListener(new MouseAdapter() {
        public void mousePressed(MouseEvent e) {
          updateMouse(e);
        }
      });
      addMouseMotionListener(new MouseAdapter() {
        public void mouseDragged(MouseEvent e) {
          updateMouse(e);
        }
      });
    }

    public void paintComponent(Graphics g) {
      g.drawImage(backImg, 0, 0, this);

      Graphics2D g2 = (Graphics2D) g;
      // otherwise the oval is hideous
      // TODO make a proper hidpi version of all this
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                          RenderingHints.VALUE_ANTIALIAS_ON);

      g.setColor(lastY < 128 ? Color.BLACK : Color.WHITE);
      AffineTransform tx = g2.getTransform();
      g2.translate(lastX, lastY);
      //g2.drawOval(0, 0, 5, 5);
      g2.drawOval(-3, -3, 6, 6);
      g2.drawLine(-8, 0, -6, 0);
      g2.drawLine(6, 0, 8, 0);
      g2.drawLine(0, -8, 0, -6);
      g2.drawLine(0, 6, 0, 8);
      g2.setTransform(tx);
    }

    public void renderBack() {
      int[] pixels = new int[256 * 256];
      int index = 0;
      for (int j = 0; j < 256; j++) {
        for (int i = 0; i < 256; i++) {
          pixels[index++] =  // color(hue, i, 255-j);
            Color.HSBtoRGB(hue / 255f, (i / 255f), (255-j)/255f);
        }
      }
      backImg = new BufferedImage(256, 256, BufferedImage.TYPE_INT_RGB);
      backImg.getRaster().setDataElements(0, 0, 256, 256, pixels);
    }

    public void setToColor(Color c) {
      // set selector color
      float hsb[] = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null);
      saturation = (int) (hsb[1] * 255);
      brightness = (int) (hsb[2] * 255);
      lastX = saturation;
      lastY = 255 - brightness;
    }

    void updateMouse(MouseEvent event) {
      int mouseX = event.getX();
      int mouseY = event.getY();

      if (mouseX >= 0 && mouseX < 256 &&
          mouseY >= 0 && mouseY < 256) {
        lastX = mouseX;
        lastY = mouseY;
        updateColor();
      }
    }

    void updateColor() {
      saturation = lastX;
      brightness = 255 - lastY;

      satBrightChanged();
      colorBox.selectorChanged(hue, saturation, brightness);
    }

    public Dimension getPreferredSize() {
      return new Dimension(256, 256);
    }

    public Dimension getMinimumSize() {
      return getPreferredSize();
    }

    public Dimension getMaximumSize() {
      return getPreferredSize();
    }
  }

  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

  class ColorSelectorSlider extends JComponent {
    final int WIDE = 30;
    BufferedImage backImg;
    int lastY;

    ColorSelectorSlider() {
//      size(30, 255);
//      noLoop();
//      colorMode(HSB, 255, 255, 255);
//      strokeWeight(1);
//      noFill();
//      loadPixels();
      if (!colorBox.ilegalColor) {
        setToColor(colorBox.color);
      }

      // draw the slider background
      renderBack();

      addMouseListener(new MouseAdapter() {
        public void mousePressed(MouseEvent e) {
          updateMouse(e);
        }
      });
      addMouseMotionListener(new MouseAdapter() {
        public void mouseDragged(MouseEvent e) {
          updateMouse(e);
        }
      });
    }

    public void paintComponent(Graphics g) {
      g.drawImage(backImg, 0, 0, this);

      Graphics2D g2 = (Graphics2D) g;
//      if (colorBox.isBW) {
//        stroke(lastY<128 ? 0 : 255);
//      }
//      else {
//        stroke(0);
//      }
      if (colorBox.isBW && lastY >= 128) {
        g2.setColor(Color.WHITE);
      } else {
        g2.setColor(Color.BLACK);
      }

      AffineTransform tx = g2.getTransform();
      g2.translate(0, lastY);
      // draw left bracket
//      beginShape();
//      vertex(5, -2);
//      vertex(1, -2);
//      vertex(1, 2);
//      vertex(5, 2);
//      endShape();
      g.drawRect(1, -2, 6, 4);

      // draw middle lines
      g.drawLine(13, 0, 17, 0);
      g.drawLine(15, -2, 15, 2);

      // draw right bracket
//      beginShape();
//      vertex(24, -2);
//      vertex(28, -2);
//      vertex(28, 2);
//      vertex(24, 2);
//      endShape();
      g.drawRect(24, -2, 4, 4);
      g2.setTransform(tx);

      /*
      if (colorBox.isBW) {
//        stroke(255);
//        rect(0, 0, 29, 254);
        g.setColor(Color.WHITE);
        g.drawRect(0, 0, WIDE, 255);
      } else {
//        stroke(0);
//        line(0, 0, 0, 255);
//        line(29, 0, 29, 255);
        g.setColor(Color.BLACK);
        g.drawLine(0, 0, 0, 255);
        g.drawLine(29, 0, 29, 255);
      }
      */
    }

    void renderBack() {
      int[] pixels = new int[WIDE * 256];
      int index = 0;

      int argb = 0;
      for (int j = 0; j < 256; j++) {
        if (colorBox.isBW) {
          int gray = 255 - j;
          argb = 0xff000000 | (gray << 16) | (gray << 8) | gray;
        } else {
          // color(255-j, 255, 255);
          argb = Color.HSBtoRGB((255 - j) / 255f, 1, 1);
        }
        for (int i = 0; i < WIDE; i++) {
          pixels[index++] = argb;
        }
      }
      backImg = new BufferedImage(WIDE, 256, BufferedImage.TYPE_INT_RGB);
      backImg.getRaster().setDataElements(0, 0, WIDE, 256, pixels);
    }

    void setToColor(Color c) {
      // set slider position
      if (colorBox.isBW) {
        hue = c.getRed();
      } else {
        float hsb[] = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null);
        hue = (int)(hsb[0]*255);
      }
      lastY = 255 - hue;
    }

    void updateMouse(MouseEvent event) {
      int mouseY = event.getY();
      if (mouseY >= 0 && mouseY < 256) {
        lastY = mouseY;
        updateColor();
      }
    }

    public void updateColor() {
      hue = 255 - lastY;
      hueChanged();
      colorBox.selectorChanged(hue, saturation, brightness);
    }

    public Dimension getPreferredSize() {
      return new Dimension(30, 255);
    }

    public Dimension getMinimumSize() {
      return getPreferredSize();
    }

    public Dimension getMaximumSize() {
      return getPreferredSize();
    }
  }

  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

  public class SelectorTopBar extends JComponent {
    int barWidth;
    int barHeight = 16;

    public SelectorTopBar(int w) {
      barWidth = w;
    }

    @Override
    public void paintComponent(Graphics g) {
      g.setColor(Color.GRAY);
      Dimension size = getSize();
      g.fillRect(0, 0, size.width, size.height);
    }

    public Dimension getPreferredSize() {
      return new Dimension(barWidth, barHeight);
    }

    public Dimension getMinimumSize() {
      return getPreferredSize();
    }

    public Dimension getMaximumSize() {
      return getPreferredSize();
    }
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/src/processing/mode/java/pdex/SourceUtils.java
package processing.mode.java.pdex;

import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.NumberLiteral;
import org.eclipse.jdt.core.dom.SimpleType;

import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import processing.mode.java.pdex.TextTransform.Edit;
import processing.mode.java.preproc.PdePreprocessor;

public class SourceUtils {

  public static final Pattern IMPORT_REGEX =
      Pattern.compile("(?:^|;)\\s*(import\\s+(?:(static)\\s+)?((?:\\w+\\s*\\.)*)\\s*(\\S+)\\s*;)",
                      Pattern.MULTILINE | Pattern.DOTALL);

  public static final Pattern IMPORT_REGEX_NO_KEYWORD =
      Pattern.compile("^\\s*((?:(static)\\s+)?((?:\\w+\\s*\\.)*)\\s*(\\S+))",
                      Pattern.MULTILINE | Pattern.DOTALL);

  public static List<ImportStatement> parseProgramImports(CharSequence source) {
    List<ImportStatement> result = new ArrayList<>();
    Matcher matcher = IMPORT_REGEX.matcher(source);
    while (matcher.find()) {
      ImportStatement is = ImportStatement.parse(matcher.toMatchResult());
      result.add(is);
    }
    return result;
  }

  public static List<Edit> parseProgramImports(CharSequence source,
                                               List<ImportStatement> outImports) {
    List<Edit> result = new ArrayList<>();
    Matcher matcher = IMPORT_REGEX.matcher(source);
    while (matcher.find()) {
      ImportStatement is = ImportStatement.parse(matcher.toMatchResult());
      outImports.add(is);
      int idx = matcher.start(1);
      int len = matcher.end(1) - idx;
      // Remove the import from the main program
      // Substitute with white spaces
      result.add(Edit.move(idx, len, 0));
      result.add(Edit.insert(0, "\n"));
    }
    return result;
  }

  // Positive lookahead and lookbehind are needed to match all type constructors
  // in code like `int(byte(245))` where first bracket matches as last
  // group in "^int(" but also as a first group in "(byte(". Lookahead and
  // lookbehind won't consume the shared character.
  public static final Pattern TYPE_CONSTRUCTOR_REGEX =
      Pattern.compile("(?<=^|\\W)(int|char|float|boolean|byte)(?=\\s*\\()",
                      Pattern.MULTILINE);

  public static List<Edit> replaceTypeConstructors(CharSequence source) {

    List<Edit> result = new ArrayList<>();

    Matcher matcher = TYPE_CONSTRUCTOR_REGEX.matcher(source);
    while (matcher.find()) {
      String match = matcher.group(1);
      int offset = matcher.start(1);
      int length = match.length();
      result.add(Edit.insert(offset, "PApplet."));
      String replace = "parse"
          + Character.toUpperCase(match.charAt(0)) + match.substring(1);
      result.add(Edit.replace(offset, length, replace));
    }

    return result;
  }

  public static final Pattern HEX_LITERAL_REGEX =
      Pattern.compile("(?<=^|\\W)(#[A-Fa-f0-9]{6})(?=\\W|$)");

  public static List<Edit> replaceHexLiterals(CharSequence source) {
    // Find all #[webcolor] and replace with 0xff[webcolor]
    // Should be 6 digits only.
    List<Edit> result = new ArrayList<>();

    Matcher matcher = HEX_LITERAL_REGEX.matcher(source);
    while (matcher.find()) {
      int offset = matcher.start(1);
      result.add(Edit.replace(offset, 1, "0xff"));
    }

    return result;
  }

  public static List<Edit> insertImports(List<ImportStatement> imports) {
    List<Edit> result = new ArrayList<>();
    for (ImportStatement imp : imports) {
      result.add(Edit.insert(0, imp.getFullSourceLine() + "\n"));
    }
    return result;
  }

  public static List<Edit> wrapSketch(PdePreprocessor.Mode mode, String className, int sourceLength) {

    List<Edit> edits = new ArrayList<>();

    StringBuilder b = new StringBuilder();

    // Header
    if (mode != PdePreprocessor.Mode.JAVA) {
      b.append("\npublic class ").append(className).append(" extends PApplet {\n");
      if (mode == PdePreprocessor.Mode.STATIC) {
        b.append("public void setup() {\n");
      }
    }

    edits.add(Edit.insert(0, b.toString()));

    // Reset builder
    b.setLength(0);

    // Footer
    if (mode != PdePreprocessor.Mode.JAVA) {
      if (mode == PdePreprocessor.Mode.STATIC) {
        // no noLoop() here so it does not tell you
        // "can't invoke noLoop() on obj" when you type "obj."
        b.append("\n}");
      }
      b.append("\n}\n");
    }

    edits.add(Edit.insert(sourceLength, b.toString()));

    return edits;
  }

  // Verifies that whole input String is floating point literal. Can't be used for searching.
  // https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-DecimalFloatingPointLiteral
  public static final Pattern FLOATING_POINT_LITERAL_VERIFIER;
  static {
    final String DIGITS = "(?:[0-9]|[0-9][0-9_]*[0-9])";
    final String EXPONENT_PART = "(?:[eE][+-]?" + DIGITS + ")";
    FLOATING_POINT_LITERAL_VERIFIER = Pattern.compile(
        "(?:^" + DIGITS + "\\." + DIGITS + "?" + EXPONENT_PART + "?[fFdD]?$)|" +
            "(?:^\\." + DIGITS + EXPONENT_PART + "?[fFdD]?$)|" +
            "(?:^" + DIGITS + EXPONENT_PART + "[fFdD]?$)|" +
            "(?:^" + DIGITS + EXPONENT_PART + "?[fFdD]$)");
  }

  // Mask to quickly resolve whether there are any access modifiers present
  private static final int ACCESS_MODIFIERS_MASK =
      Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED;

  public static List<Edit> preprocessAST(CompilationUnit cu) {
    final List<Edit> edits = new ArrayList<>();

    // Walk the tree
    cu.accept(new ASTVisitor() {
      @Override
      public boolean visit(SimpleType node) {
        // replace "color" with "int"
        if ("color".equals(node.getName().toString())) {
          edits.add(Edit.replace(node.getStartPosition(), node.getLength(), "int"));
        }
        return super.visit(node);
      }

      @Override
      public boolean visit(NumberLiteral node) {
        // add 'f' to floats
        String s = node.getToken().toLowerCase();
        if (FLOATING_POINT_LITERAL_VERIFIER.matcher(s).matches() && !s.endsWith("f") && !s.endsWith("d")) {
          edits.add(Edit.insert(node.getStartPosition() + node.getLength(), "f"));
        }
        return super.visit(node);
      }

      @Override
      public boolean visit(MethodDeclaration node) {
        // add 'public' to methods with default visibility
        int accessModifiers = node.getModifiers() & ACCESS_MODIFIERS_MASK;
        if (accessModifiers == 0) {
          edits.add(Edit.insert(node.getStartPosition(), "public "));
        }
        return super.visit(node);
      }
    });

    return edits;
  }

  public static final Pattern COLOR_TYPE_REGEX =
      Pattern.compile("(?:^|^\\p{javaJavaIdentifierPart})(color)\\s(?!\\s*\\()",
                      Pattern.MULTILINE | Pattern.UNICODE_CHARACTER_CLASS);

  public static List<Edit> replaceColorRegex(CharSequence source) {
    final List<Edit> edits = new ArrayList<>();

    Matcher matcher = COLOR_TYPE_REGEX.matcher(source);
    while (matcher.find()) {
      int offset = matcher.start(1);
      edits.add(Edit.replace(offset, 5, "int"));
    }

    return edits;
  }

  public static final Pattern NUMBER_LITERAL_REGEX =
      Pattern.compile("[-+]?[0-9]*\\.?[0-9]+(?:[eE][-+]?[0-9]+)?");

  public static List<Edit> fixFloatsRegex(CharSequence source) {
    final List<Edit> edits = new ArrayList<>();

    Matcher matcher = NUMBER_LITERAL_REGEX.matcher(source);
    while (matcher.find()) {
      int offset = matcher.start();
      int end = matcher.end();
      String group = matcher.group().toLowerCase();
      boolean isFloatingPoint = group.contains(".") || group.contains("e");
      boolean hasSuffix = end < source.length() &&
          Character.toLowerCase(source.charAt(end)) != 'f' &&
          Character.toLowerCase(source.charAt(end)) != 'd';
      if (isFloatingPoint && !hasSuffix) {
        edits.add(Edit.insert(offset, "f"));
      }
    }

    return edits;
  }

  static public String scrubCommentsAndStrings(String p) {
    StringBuilder sb = new StringBuilder(p);
    scrubCommentsAndStrings(sb);
    return sb.toString();
  }

  static public void scrubCommentsAndStrings(StringBuilder p) {

    final int length = p.length();

    final int OUT = 0;
    final int IN_BLOCK_COMMENT = 1;
    final int IN_EOL_COMMENT = 2;
    final int IN_STRING_LITERAL = 3;
    final int IN_CHAR_LITERAL = 4;

    int blockStart = -1;

    int prevState = OUT;
    int state = OUT;

    for (int i = 0; i <= length; i++) {
      char ch = (i < length) ? p.charAt(i) : 0;
      char pch = (i == 0) ? 0 : p.charAt(i-1);
      // Get rid of double backslash immediately, otherwise
      // the second backslash incorrectly triggers a new escape sequence
      if (pch == '\\' && ch == '\\') {
        p.setCharAt(i-1, ' ');
        p.setCharAt(i, ' ');
        pch = ' ';
        ch = ' ';
      }
      switch (state) {
        case OUT:
          switch (ch) {
            case '\'': state = IN_CHAR_LITERAL; break;
            case '"': state = IN_STRING_LITERAL; break;
            case '*': if (pch == '/') state = IN_BLOCK_COMMENT; break;
            case '/': if (pch == '/') state = IN_EOL_COMMENT; break;
          }
          break;
        case IN_BLOCK_COMMENT:
          if (pch == '*' && ch == '/' && (i - blockStart) > 0) {
            state = OUT;
          }
          break;
        case IN_EOL_COMMENT:
          if (ch == '\r' || ch == '\n') {
            state = OUT;
          }
          break;
        case IN_STRING_LITERAL:
          if ((pch != '\\' && ch == '"') || ch == '\r' || ch == '\n') {
            state = OUT;
          }
          break;
        case IN_CHAR_LITERAL:
          if ((pch != '\\' && ch == '\'') || ch == '\r' || ch == '\n') {
            state = OUT;
          }
          break;
      }

      // Terminate ongoing block at last char
      if (i == length) {
        state = OUT;
      }

      // Handle state changes
      if (state != prevState) {
        if (state != OUT) {
          // Entering block
          blockStart = i + 1;
        } else {
          // Exiting block
          int blockEnd = i;
          if (prevState == IN_BLOCK_COMMENT && i < length) blockEnd--; // preserve star in '*/'
          for (int j = blockStart; j < blockEnd; j++) {
            char c = p.charAt(j);
            if (c != '\n' && c != '\r') p.setCharAt(j, ' ');
          }
        }
      }

      prevState = state;
    }

  }

  // TODO: move this to a better place when JavaBuild starts using JDT and we
  //       don't need to check errors at two different places [jv 2017-09-19]
  /**
   * Checks a single code fragment (such as a tab) for non-matching braces.
   * Broken out to allow easy use in JavaBuild.
   * @param c Program code scrubbed of comments and string literals.
   * @param start Start index, inclusive.
   * @param end End index, exclusive.
   * @return {@code int[4]} Depth at which the loop stopped, followed by the
   *         line number, column, and string index (within the range) at which
   *         an error was found, if any.
   */
  static public int[] checkForMissingBraces(CharSequence c, int start, int end) {
    int depth = 0;
    int lineNumber = 0;
    int lineStart = start;
    for (int i = start; i < end; i++) {
      char ch = c.charAt(i);
      switch (ch) {
        case '{':
          depth++;
          break;
        case '}':
          depth--;
          break;
        case '\n':
          lineNumber++;
          lineStart = i;
          break;
      }
      if (depth < 0) {
        return new int[] {depth, lineNumber, i - lineStart, i - start};
      }
    }
    return new int[] {depth, lineNumber - 1, end - lineStart - 2, end - start - 2};
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Interaction/Reach2/Reach2.pde
/**
 * Reach 2
 * based on code from <NAME>.
 *
 * The arm follows the position of the mouse by
 * calculating the angles with atan2().
 */

int numSegments = 10;
float[] x = new float[numSegments];
float[] y = new float[numSegments];
float[] angle = new float[numSegments];
float segLength = 26;
float targetX, targetY;

void setup() {
  size(640, 360);
  strokeWeight(20.0);
  stroke(255, 100);
  x[x.length-1] = width/2;     // Set base x-coordinate
  y[x.length-1] = height;  // Set base y-coordinate
}

void draw() {
  background(0);

  reachSegment(0, mouseX, mouseY);
  for(int i=1; i<numSegments; i++) {
    reachSegment(i, targetX, targetY);
  }
  for(int i=x.length-1; i>=1; i--) {
    positionSegment(i, i-1);
  }
  for(int i=0; i<x.length; i++) {
    segment(x[i], y[i], angle[i], (i+1)*2);
  }
}

void positionSegment(int a, int b) {
  x[b] = x[a] + cos(angle[a]) * segLength;
  y[b] = y[a] + sin(angle[a]) * segLength;
}

void reachSegment(int i, float xin, float yin) {
  float dx = xin - x[i];
  float dy = yin - y[i];
  angle[i] = atan2(dy, dx);
  targetX = xin - cos(angle[i]) * segLength;
  targetY = yin - sin(angle[i]) * segLength;
}

void segment(float x, float y, float a, float sw) {
  strokeWeight(sw);
  pushMatrix();
  translate(x, y);
  rotate(a);
  line(0, 0, segLength, 0);
  popMatrix();
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Textures/TextureTriangle/TextureTriangle.pde
/**
 * Texture Triangle.
 *
 * Using a rectangular image to map a texture onto a triangle.
 */

PImage img;

void setup() {
  size(640, 360, P3D);
  img = loadImage("berlin-1.jpg");
  noStroke();
}

void draw() {
  background(0);
  translate(width/2, height/2, 0);
  rotateY(map(mouseX, 0, width, -PI, PI));
  beginShape();
  texture(img);
  vertex(-100, -100, 0, 0, 0);
  vertex(100, -40, 0, 300, 120);
  vertex(0, 100, 0, 200, 400);
  endShape();
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Visualization Code/HandWashing/Logos.pde

// -----------------------------
// LOGOS
// -----------------------------

void displayW21C(float _scale, float _translateX, float _translateY) {
  pushMatrix(); pushStyle();

  translate(_translateX, _translateY);
  scale(_scale);

  image(w21clogo, width/2, height/2);

  popMatrix(); popStyle();
}

// -----------------------------

void displayECUAD(float _scale, float _translateX, float _translateY) {
  pushMatrix(); pushStyle();

  translate(_translateX, _translateY);
  scale(_scale);

  image(eculogo, width/2, height/2);

  popMatrix(); popStyle();
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Demos/Graphics/Trefoil/Trefoil.pde
// Trefoil, by <NAME>
// A parametric surface is textured procedurally
// by drawing on an offscreen PGraphics surface.

PGraphics pg;
PShape trefoil;

void setup() {
  size(1024, 768, P3D);

  textureMode(NORMAL);
  noStroke();

  // Creating offscreen surface for 3D rendering.
  pg = createGraphics(32, 512, P3D);
  pg.beginDraw();
  pg.background(0, 0);
  pg.noStroke();
  pg.fill(255, 0, 0, 200);
  pg.endDraw();

  // Saving trefoil surface into a PShape3D object
  trefoil = createTrefoil(350, 60, 15, pg);
}

void draw() {
  background(0);

  pg.beginDraw();
  pg.ellipse(random(pg.width), random(pg.height), 4, 4);
  pg.endDraw();

  ambient(250, 250, 250);
  pointLight(255, 255, 255, 0, 0, 200);

  pushMatrix();
  translate(width/2, height/2, -200);
  rotateX(frameCount * PI / 500);
  rotateY(frameCount * PI / 500);
  shape(trefoil);
  popMatrix();
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Math/DoubleRandom/DoubleRandom.pde
/**
 * Double Random
 * by <NAME>.
 *
 * Using two random() calls and the point() function
 * to create an irregular sawtooth line.
 */

int totalPts = 300;
float steps = totalPts + 1;

void setup() {
  size(640, 360);
  stroke(255);
  frameRate(1);
}

void draw() {
  background(0);
  float rand = 0;
  for  (int i = 1; i < steps; i++) {
    point( (width/steps) * i, (height/2) + random(-rand, rand) );
    rand += random(-5, 5);
  }
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Image Processing/Convolution/Convolution.pde
/**
 * Convolution
 * by <NAME>.
 *
 * Applies a convolution matrix to a portion of an image. Move mouse to
 * apply filter to different parts of the image. This example is currently
 * not accurate in JavaScript mode.
 */

PImage img;
int w = 120;

// It's possible to convolve the image with many different
// matrices to produce different effects. This is a high-pass
// filter; it accentuates the edges.
float[][] matrix = { { -1, -1, -1 },
                     { -1,  9, -1 },
                     { -1, -1, -1 } };

void setup() {
  size(640, 360);
  img = loadImage("moon-wide.jpg");
}

void draw() {
  // We're only going to process a portion of the image
  // so let's set the whole image as the background first
  image(img, 0, 0);

  // Calculate the small rectangle we will process
  int xstart = constrain(mouseX - w/2, 0, img.width);
  int ystart = constrain(mouseY - w/2, 0, img.height);
  int xend = constrain(mouseX + w/2, 0, img.width);
  int yend = constrain(mouseY + w/2, 0, img.height);
  int matrixsize = 3;
  loadPixels();
  // Begin our loop for every pixel in the smaller image
  for (int x = xstart; x < xend; x++) {
    for (int y = ystart; y < yend; y++ ) {
      color c = convolution(x, y, matrix, matrixsize, img);
      int loc = x + y*img.width;
      pixels[loc] = c;
    }
  }
  updatePixels();
}

color convolution(int x, int y, float[][] matrix, int matrixsize, PImage img)
{
  float rtotal = 0.0;
  float gtotal = 0.0;
  float btotal = 0.0;
  int offset = matrixsize / 2;
  for (int i = 0; i < matrixsize; i++){
    for (int j= 0; j < matrixsize; j++){
      // What pixel are we testing
      int xloc = x+i-offset;
      int yloc = y+j-offset;
      int loc = xloc + img.width*yloc;
      // Make sure we haven't walked off our image, we could do better here
      loc = constrain(loc,0,img.pixels.length-1);
      // Calculate the convolution
      rtotal += (red(img.pixels[loc]) * matrix[i][j]);
      gtotal += (green(img.pixels[loc]) * matrix[i][j]);
      btotal += (blue(img.pixels[loc]) * matrix[i][j]);
    }
  }
  // Make sure RGB is within range
  rtotal = constrain(rtotal, 0, 255);
  gtotal = constrain(gtotal, 0, 255);
  btotal = constrain(btotal, 0, 255);
  // Return the resulting color
  return color(rtotal, gtotal, btotal);
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/src/processing/mode/java/pdex/ErrorMessageSimplifier.java
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
Part of the Processing project - http://processing.org
Copyright (c) 2012-15 The Processing Foundation

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package processing.mode.java.pdex;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.internal.compiler.problem.DefaultProblem;

import processing.app.Language;
import processing.app.Messages;
import processing.core.PApplet;
import processing.data.StringList;

public class ErrorMessageSimplifier {
  /**
   * Mapping between ProblemID constant and the constant name. Holds about 650
   * of them. Also, this is just temporary, will be used to find the common
   * error types, cos you know, identifying String names is easier than
   * identifying 8 digit int constants!
   * TODO: this is temporary
   */
  private static TreeMap<Integer, String> constantsMap;

  private static final boolean DEBUG = false;

  private static final Pattern tokenRegExp = Pattern.compile("\\b token\\b");

  private static void prepareConstantsList() {
    constantsMap = new TreeMap<>();
    Class<DefaultProblem> probClass = DefaultProblem.class;
    Field f[] = probClass.getFields();
    for (Field field : f) {
      if (Modifier.isStatic(field.getModifiers()))
        try {
          if (DEBUG) {
            Messages.log(field.getName() + " :" + field.get(null));
          }
          Object val = field.get(null);
          if (val instanceof Integer) {
            constantsMap.put((Integer) (val), field.getName());
          }
        } catch (Exception e) {
          e.printStackTrace();
          break;
        }
    }
    if (DEBUG) {
      Messages.log("Total items: " + constantsMap.size());
    }
  }

  public static String getIDName(int id) {
    if (constantsMap == null) {
      prepareConstantsList();
    }
    return constantsMap.get(id);
  }

  /**
   * Tones down the jargon in the ecj reported errors.
   */
  public static String getSimplifiedErrorMessage(IProblem iprob, String badCode) {
    if (iprob == null) return null;

    String args[] = iprob.getArguments();

    if (DEBUG) {
      Messages.log("Simplifying message: " + iprob.getMessage() +
                       " ID: " + getIDName(iprob.getID()));
      Messages.log("Arg count: " + args.length);
      for (String arg : args) {
        Messages.log("Arg " + arg);
      }
      Messages.log("Bad code: " + badCode);
    }

    String result = null;

    switch (iprob.getID()) {

      case IProblem.ParsingError:
        if (args.length > 0) {
          result = Language.interpolate("editor.status.error_on", args[0]);
        }
        break;

      case IProblem.ParsingErrorDeleteToken:
        if (args.length > 0) {
          if (args[0].equalsIgnoreCase("Invalid Character")) {
            result = getErrorMessageForCurlyQuote(badCode);
          }
        }
        break;

      case IProblem.ParsingErrorDeleteTokens:
        result = getErrorMessageForCurlyQuote(badCode);
        if (result == null) {
          result = Language.interpolate("editor.status.error_on", args[0]);
        }
        break;

      case IProblem.ParsingErrorInsertToComplete:
        if (args.length > 0) {
          if (args[0].length() == 1) {
            result = getErrorMessageForBracket(args[0].charAt(0));

          } else {
            if (args[0].equals("AssignmentOperator Expression")) {
              result = Language.interpolate("editor.status.missing.add", "=");

            } else if (args[0].equalsIgnoreCase(") Statement")) {
              result = getErrorMessageForBracket(args[0].charAt(0));

            } else {
              result = Language.interpolate("editor.status.error_on", args[0]);
            }
          }
        }
        break;

      case IProblem.ParsingErrorInvalidToken:
        if (args.length > 0) {
          if (args[0].equals("int")) {
            if (args[1].equals("VariableDeclaratorId")) {
              result = Language.text("editor.status.reserved_words");
            } else {
              result = Language.interpolate("editor.status.error_on", args[0]);
            }
          } else if (args[0].equalsIgnoreCase("Invalid Character")) {
            result = getErrorMessageForCurlyQuote(badCode);
          }
          if (result == null) {
            result = Language.interpolate("editor.status.error_on", args[0]);
          }
        }
        break;

      case IProblem.ParsingErrorInsertTokenAfter:
        if (args.length > 0) {
          if (args[1].length() == 1) {
            result = getErrorMessageForBracket(args[1].charAt(0));
          } else {
            // https://github.com/processing/processing/issues/3104
            if (args[1].equalsIgnoreCase("Statement")) {
              result = Language.interpolate("editor.status.error_on", args[0]);
            } else {
              result =
                  Language.interpolate("editor.status.error_on", args[0]) + " " +
                      Language.interpolate("editor.status.missing.add", args[1]);
            }
          }
        }
        break;

      case IProblem.ParsingErrorReplaceTokens:
        result = getErrorMessageForCurlyQuote(badCode);

      case IProblem.UndefinedConstructor:
        if (args.length == 2) {
          String constructorName = args[0];
          // For messages such as "contructor sketch_name.ClassXYZ() is undefined", change
          // constructor name to "ClassXYZ()". See #3434
          if (constructorName.contains(".")) {
            // arg[0] contains sketch name twice: sketch_150705a.sketch_150705a.Thing
            constructorName = constructorName.substring(constructorName.indexOf('.') + 1);
            constructorName = constructorName.substring(constructorName.indexOf('.') + 1);
          }
          String constructorArgs = removePackagePrefixes(args[args.length - 1]);
          result = Language.interpolate("editor.status.undefined_constructor", constructorName, constructorArgs);
        }
        break;

      case IProblem.UndefinedMethod:
        if (args.length > 2) {
          String methodName = args[args.length - 2];
          String methodArgs = removePackagePrefixes(args[args.length - 1]);
          result = Language.interpolate("editor.status.undefined_method", methodName, methodArgs);
        }
        break;

      case IProblem.ParameterMismatch:
        if (args.length > 3) {
          // 2nd arg is method name, 3rd arg is correct param list
          if (args[2].trim().length() == 0) {
            // the case where no params are needed.
            result = Language.interpolate("editor.status.empty_param", args[1]);

          } else {
            result = Language.interpolate("editor.status.wrong_param",
                                          args[1], args[1], removePackagePrefixes(args[2]));
//          String method = q(args[1]);
//          String methodDef = " \"" + args[1] + "(" + getSimpleName(args[2]) + ")\"";
//          result = result.replace("method", method);
//          result += methodDef;
          }
        }
        break;

      case IProblem.UndefinedField:
        if (args.length > 0) {
          result = Language.interpolate("editor.status.undef_global_var", args[0]);
        }
        break;

      case IProblem.UndefinedType:
        if (args.length > 0) {
          result = Language.interpolate("editor.status.undef_class", args[0]);
        }
        break;

      case IProblem.UnresolvedVariable:
        if (args.length > 0) {
          result = Language.interpolate("editor.status.undef_var", args[0]);
        }
        break;

      case IProblem.UndefinedName:
        if (args.length > 0) {
          result = Language.interpolate("editor.status.undef_name", args[0]);
        }
        break;

      case IProblem.UnterminatedString:
        if (badCode.contains("“") || badCode.contains("”")) {
          result = Language.interpolate("editor.status.unterm_string_curly",
              badCode.replaceAll("[^“”]", ""));
        }
        break;

      case IProblem.TypeMismatch:
        if (args.length > 1) {
          result = Language.interpolate("editor.status.type_mismatch", args[0], args[1]);
//        result = result.replace("typeA", q(args[0]));
//        result = result.replace("typeB", q(args[1]));
        }
        break;

      case IProblem.LocalVariableIsNeverUsed:
        if (args.length > 0) {
          result = Language.interpolate("editor.status.unused_variable", args[0]);
        }
        break;

      case IProblem.UninitializedLocalVariable:
        if (args.length > 0) {
          result = Language.interpolate("editor.status.uninitialized_variable", args[0]);
        }
        break;

      case IProblem.AssignmentHasNoEffect:
        if (args.length > 0) {
          result = Language.interpolate("editor.status.no_effect_assignment", args[0]);
        }
        break;

      case IProblem.HidingEnclosingType:
        if (args.length > 0) {
          result = Language.interpolate("editor.status.hiding_enclosing_type", args[0]);
        }
        break;
    }

    if (result == null) {
      String message = iprob.getMessage();
      if (message != null) {
        // Remove all instances of token
        // "Syntax error on token 'blah', delete this token"
        Matcher matcher = tokenRegExp.matcher(message);
        message = matcher.replaceAll("");
        result = message;
      }
    }

    if (DEBUG) {
      Messages.log("Simplified Error Msg: " + result);
    }

    return result;
  }

  /**
   * Converts java.lang.String into String, etc
   */
  static private String removePackagePrefixes(String input) {
    if (!input.contains(".")) {
      return input;
    }
    String[] names = PApplet.split(input, ',');
//    List<String> names = new ArrayList<String>();
//    if (inp.indexOf(',') >= 0) {
//      names.addAll(Arrays.asList(inp.split(",")));
//    } else {
//      names.add(inp);
//    }
    StringList result = new StringList();
    for (String name : names) {
      int dot = name.lastIndexOf('.');
      if (dot >= 0) {
        name = name.substring(dot + 1, name.length());
      }
      result.append(name);
    }
    return result.join(", ");
  }

  static private String getErrorMessageForBracket(char c) {
    switch (c) {
      case ';': return Language.text("editor.status.missing.semicolon");
      case '[': return Language.text("editor.status.missing.left_sq_bracket");
      case ']': return Language.text("editor.status.missing.right_sq_bracket");
      case '(': return Language.text("editor.status.missing.left_paren");
      case ')': return Language.text("editor.status.missing.right_paren");
      case '{': return Language.text("editor.status.missing.left_curly_bracket");
      case '}': return Language.text("editor.status.missing.right_curly_bracket");
    }
    // This seems to be unreachable and wasn't in PDE.properties.
    // I've added it for 3.0a8, but that seems gross. [fry]
    return Language.interpolate("editor.status.missing.default", c);
  }

  /**
   * @param badCode The code which may contain curly quotes
   * @return Friendly error message if there is a curly quote in badCode,
   *         null otherwise.
   */
  static private String getErrorMessageForCurlyQuote(String badCode) {
    if (badCode.contains("‘") || badCode.contains("’") ||
        badCode.contains("“") || badCode.contains("”")) {
      return Language.interpolate("editor.status.bad_curly_quote",
          badCode.replaceAll("[^‘’“”]", ""));
    } else return null;
  }

//  static private final String q(Object quotable) {
//    return "\"" + quotable + "\"";
//  }

//  static private final String qs(Object quotable) {
//    return " " + q(quotable);
//  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Input/Milliseconds/Milliseconds.pde
/**
 * Milliseconds.
 *
 * A millisecond is 1/1000 of a second.
 * Processing keeps track of the number of milliseconds a program has run.
 * By modifying this number with the modulo(%) operator,
 * different patterns in time are created.
 */

float scale;

void setup() {
  size(640, 360);
  noStroke();
  scale = width/20;
}

void draw() {
  for (int i = 0; i < scale; i++) {
    colorMode(RGB, (i+1) * scale * 10);
    fill(millis()%((i+1) * scale * 10));
    rect(i*scale, 0, scale, height);
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/pdf/examples/MultipleFrames/MultipleFrames.pde
/**
 * Multiple Frames.
 *
 * Saves one PDF document of many frames drawn to the screen.
 * Starts the file when the mouse is pressed and end the file
 * when the mouse is released.
 */

import processing.pdf.*;

void setup() {
  size(600, 600);
  frameRate(24);
  background(255);
}

void draw() {
  stroke(0, 20);
  strokeWeight(20.0);
  line(mouseX, 0, width-mouseY, height);
}

void mousePressed() {
  beginRecord(PDF, "Lines.pdf");
  background(255);
}

void mouseReleased() {
  endRecord();
  background(255);
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Demos/Graphics/RotatingArcs/RotatingArcs.pde
/**
 * Geometry
 * by <NAME>.
 *
 * Using sin/cos lookup tables, blends colors, and draws a series of
 * rotating arcs on the screen.
*/

// Trig lookup tables borrowed from Toxi; cryptic but effective.
float sinLUT[];
float cosLUT[];
float SINCOS_PRECISION=1.0;
int SINCOS_LENGTH= int((360.0/SINCOS_PRECISION));

// System data
boolean dosave=false;
int num;
float pt[];
int style[];

void setup() {
  size(1024, 768, P3D);
  background(255);

  // Fill the tables
  sinLUT=new float[SINCOS_LENGTH];
  cosLUT=new float[SINCOS_LENGTH];
  for (int i = 0; i < SINCOS_LENGTH; i++) {
    sinLUT[i]= (float)Math.sin(i*DEG_TO_RAD*SINCOS_PRECISION);
    cosLUT[i]= (float)Math.cos(i*DEG_TO_RAD*SINCOS_PRECISION);
  }

  num = 150;
  pt = new float[6*num]; // rotx, roty, deg, rad, w, speed
  style = new int[2*num]; // color, render style

  // Set up arc shapes
  int index=0;
  float prob;
  for (int i=0; i<num; i++) {
    pt[index++] = random(PI*2); // Random X axis rotation
    pt[index++] = random(PI*2); // Random Y axis rotation

    pt[index++] = random(60,80); // Short to quarter-circle arcs
    if(random(100)>90) pt[index]=(int)random(8,27)*10;

    pt[index++] = int(random(2,50)*5); // Radius. Space them out nicely

    pt[index++] = random(4,32); // Width of band
    if(random(100)>90) pt[index]=random(40,60); // Width of band

    pt[index++] = radians(random(5,30))/5; // Speed of rotation

    // get colors
    prob = random(100);
    if(prob<30) style[i*2]=colorBlended(random(1), 255,0,100, 255,0,0, 210);
    else if(prob<70) style[i*2]=colorBlended(random(1), 0,153,255, 170,225,255, 210);
    else if(prob<90) style[i*2]=colorBlended(random(1), 200,255,0, 150,255,0, 210);
    else style[i*2]=color(255,255,255, 220);

    if(prob<50) style[i*2]=colorBlended(random(1), 200,255,0, 50,120,0, 210);
    else if(prob<90) style[i*2]=colorBlended(random(1), 255,100,0, 255,255,0, 210);
    else style[i*2]=color(255,255,255, 220);

    style[i*2+1]=(int)(random(100))%3;
  }
}

void draw() {

  background(0);

  int index=0;
  translate(width/2, height/2, 0);
  rotateX(PI/6);
  rotateY(PI/6);

  for (int i = 0; i < num; i++) {
    pushMatrix();

    rotateX(pt[index++]);
    rotateY(pt[index++]);

    if(style[i*2+1]==0) {
      stroke(style[i*2]);
      noFill();
      strokeWeight(1);
      arcLine(0,0, pt[index++],pt[index++],pt[index++]);
    }
    else if(style[i*2+1]==1) {
      fill(style[i*2]);
      noStroke();
      arcLineBars(0,0, pt[index++],pt[index++],pt[index++]);
    }
    else {
      fill(style[i*2]);
      noStroke();
      arc(0,0, pt[index++],pt[index++],pt[index++]);
    }

    // increase rotation
    pt[index-5]+=pt[index]/10;
    pt[index-4]+=pt[index++]/20;

    popMatrix();
  }
}

// Get blend of two colors
int colorBlended(float fract,
float r, float g, float b,
float r2, float g2, float b2, float a) {

  r2 = (r2 - r);
  g2 = (g2 - g);
  b2 = (b2 - b);
  return color(r + r2 * fract, g + g2 * fract, b + b2 * fract, a);
}

// Draw arc line
void arcLine(float x,float y,float deg,float rad,float w) {
  int a=(int)(min (deg/SINCOS_PRECISION,SINCOS_LENGTH-1));
  int numlines=(int)(w/2);

  for (int j=0; j<numlines; j++) {
    beginShape();
    for (int i=0; i<a; i++) {
      vertex(cosLUT[i]*rad+x,sinLUT[i]*rad+y);
    }
    endShape();
    rad += 2;
  }
}

// Draw arc line with bars
void arcLineBars(float x,float y,float deg,float rad,float w) {
  int a = int((min (deg/SINCOS_PRECISION,SINCOS_LENGTH-1)));
  a /= 4;

  beginShape(QUADS);
  for (int i=0; i<a; i+=4) {
    vertex(cosLUT[i]*(rad)+x,sinLUT[i]*(rad)+y);
    vertex(cosLUT[i]*(rad+w)+x,sinLUT[i]*(rad+w)+y);
    vertex(cosLUT[i+2]*(rad+w)+x,sinLUT[i+2]*(rad+w)+y);
    vertex(cosLUT[i+2]*(rad)+x,sinLUT[i+2]*(rad)+y);
  }
  endShape();
}

// Draw solid arc
void arc(float x,float y,float deg,float rad,float w) {
  int a = int(min (deg/SINCOS_PRECISION,SINCOS_LENGTH-1));
  beginShape(QUAD_STRIP);
  for (int i = 0; i < a; i++) {
    vertex(cosLUT[i]*(rad)+x,sinLUT[i]*(rad)+y);
    vertex(cosLUT[i]*(rad+w)+x,sinLUT[i]*(rad+w)+y);
  }
  endShape();
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/io/build.xml
<?xml version="1.0"?>
<project name="Processing Hardware I/O Library" default="build">

  <target name="clean" description="Clean the build directories">
    <delete dir="bin" />
    <delete file="library/io.jar" />
  </target>

  <target name="compile" description="Compile sources">
    <condition property="core-built">
      <available file="../../../core/library/core.jar" />
    </condition>
    <fail unless="core-built" message="Please build the core library first and make sure it sits in ../../../core/library/core.jar" />

    <mkdir dir="bin" />
    <javac source="1.8"
	   target="1.8"
	   srcdir="src" destdir="bin"
	   encoding="UTF-8"
	   includeAntRuntime="false"
	   classpath="../../../core/library/core.jar"
	   nowarn="true"
	   compiler="org.eclipse.jdt.core.JDTCompilerAdapter">
      <compilerclasspath path="../../mode/org.eclipse.jdt.core.jar;
                               ../../mode/jdtCompilerAdapter.jar" />
    </javac>
  </target>

  <target name="build" depends="compile" description="Build I/O library">
    <jar basedir="bin" destfile="library/io.jar" />
  </target>

  <target name="dist" depends="build" description="Package standalone library">

    <loadfile srcfile="../../../todo.txt" property="revision">
      <filterchain>
        <headfilter lines="1"/>
        <tokenfilter>
          <stringtokenizer suppressdelims="true"/>

          <containsregex pattern="(\d\d\d\d)" />
        </tokenfilter>
      </filterchain>
    </loadfile>
    <replaceregexp file="library.properties" match="version = .*" replace="version = ${revision}" flags="g" />
    <replaceregexp file="library.properties" match="prettyVersion = .*" replace="prettyVersion = ${revision}" flags="g" />

    <get src="http://download.processing.org/reference.zip"
         dest="reference.zip"
         usetimestamp="true" />
    <mkdir dir="reference" />
    <unzip dest="."
           src="reference.zip"
           overwrite="true">
      <patternset>
        <include name="reference/css/**" />
        <include name="reference/img/**" />
        <include name="reference/javascript/**" />
        <include name="reference/libraries/io/**" />
      </patternset>
    </unzip>
    <delete file="reference.zip" />
    <echo file="reference/index.html" message="<html><head><meta http-equiv='refresh' content='0; url=libraries/io/index.html'></head><body></body></html>" />

    <zip destfile="../io.zip">
      <zipfileset dir="." prefix="io">
        <exclude name="bin/**"/>
      </zipfileset>
    </zip>

    <copy file="library.properties"
          toFile="../io.txt"/>
  </target>
</project>
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Structure/Functions/Functions.pde
/**
 * Functions.
 *
 * The drawTarget() function makes it easy to draw many distinct targets.
 * Each call to drawTarget() specifies the position, size, and number of
 * rings for each target.
 */

void setup() {
  size(640, 360);
  background(51);
  noStroke();
  noLoop();
}

void draw() {
  drawTarget(width*0.25, height*0.4, 200, 4);
  drawTarget(width*0.5, height*0.5, 300, 10);
  drawTarget(width*0.75, height*0.3, 120, 6);
}

void drawTarget(float xloc, float yloc, int size, int num) {
  float grayvalues = 255/num;
  float steps = size/num;
  for (int i = 0; i < num; i++) {
    fill(i*grayvalues);
    ellipse(xloc, yloc, size - i*steps, size - i*steps);
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Fractals and L-Systems/PenroseTile/PenroseTile.pde
/**
 * Penrose Tile L-System
 * by <NAME>.
 *
 * This code was based on <NAME>'s L-System class.
 */

PenroseLSystem ds;

void setup() {
  size(640, 360);
  ds = new PenroseLSystem();
  ds.simulate(4);
}

void draw() {
  background(0);
  ds.render();
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Create Shapes/ParticleSystemPShape/ParticleSystem.pde
// The Particle System

class ParticleSystem {
  // It's just an ArrayList of particle objects
  ArrayList<Particle> particles;

  // The PShape to group all the particle PShapes
  PShape particleShape;

  ParticleSystem(int n) {
    particles = new ArrayList<Particle>();
    // The PShape is a group
    particleShape = createShape(GROUP);

    // Make all the Particles
    for (int i = 0; i < n; i++) {
      Particle p = new Particle();
      particles.add(p);
      // Each particle's PShape gets added to the System PShape
      particleShape.addChild(p.getShape());
    }
  }

  void update() {
    for (Particle p : particles) {
      p.update();
    }
  }

  void setEmitter(float x, float y) {
    for (Particle p : particles) {
      // Each particle gets reborn at the emitter location
      if (p.isDead()) {
        p.rebirth(x, y);
      }
    }
  }

  void display() {
    shape(particleShape);
  }
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Camera/Perspective/Perspective.pde
/**
 * Perspective.
 *
 * Move the mouse left and right to change the field of view (fov).
 * Click to modify the aspect ratio. The perspective() function
 * sets a perspective projection applying foreshortening, making
 * distant objects appear smaller than closer ones. The parameters
 * define a viewing volume with the shape of truncated pyramid.
 * Objects near to the front of the volume appear their actual size,
 * while farther objects appear smaller. This projection simulates
 * the perspective of the world more accurately than orthographic projection.
 * The version of perspective without parameters sets the default
 * perspective and the version with four parameters allows the programmer
 * to set the area precisely.
 */

void setup() {
  size(640, 360, P3D);
  noStroke();
}

void draw() {
  lights();
  background(0);
  float cameraY = height/2.0;
  float fov = mouseX/float(width) * PI/2;
  float cameraZ = cameraY / tan(fov / 2.0);
  float aspect = float(width)/float(height);
  if (mousePressed) {
    aspect = aspect / 2.0;
  }
  perspective(fov, aspect, cameraZ/10.0, cameraZ*10.0);

  translate(width/2+30, height/2, 0);
  rotateX(-PI/6);
  rotateY(PI/3 + mouseY/float(height) * PI);
  box(45);
  translate(0, 0, -50);
  box(30);
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Visualization Code/HandWashing/Reset.pde

// -----------------------------
// RESET
// -----------------------------

void resetData() {

  // Update Day
    println("Resetting Day");
    updateDay(true);

   resetTimer();

  // Remove Items From ArrayList
  if(useGerms == false){
    for (int i = hands.size()-1; i >= 0; i--) {
      hands.remove(i);
    }
  }

}

// -----------------------------
// UPDATE
// -----------------------------

void updateDay(boolean resetArray) {
  println(" -- UPDATING DAILY TABLE -- ");

  if(resetArray) {

    for(int i = 0; i < numHandsThisDay.length; i++) {
      println("Old Daily Count Is " + numHandsThisDay[i]);
      numHandsThisDay[i] = 0;
      println("New Daily Count Is " + numHandsThisDay[i]);
    }
  }
  allHandsThisDay = 0;
  if(useGerms == false){
    for(int i = hands.size()-1; i >= 0; i--){
      hands.remove(i);
    }
  }

}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/io/src/processing/io/LED.java
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
  Copyright (c) The Processing Foundation 2015
  Hardware I/O library developed by <NAME> as part of GSoC 2015

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General
  Public License along with this library; if not, write to the
  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  Boston, MA  02111-1307  USA
*/

package processing.io;

import processing.io.NativeInterface;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;

/**
 *  @webref
 */
public class LED {

  protected String dev;
  protected int maxBrightness;
  protected int prevBrightness;
  protected String prevTrigger;

  /**
   *  Opens a LED device
   *  @param dev device name
   *  @see list
   *  @webref
   */
  public LED(String dev) {
    NativeInterface.loadLibrary();
    this.dev = dev;

    if (NativeInterface.isSimulated()) {
      return;
    }

    // read maximum brightness
    try {
      Path path = Paths.get("/sys/class/leds/" + dev + "/max_brightness");
      String tmp = new String(Files.readAllBytes(path));
      maxBrightness = Integer.parseInt(tmp.trim());
    } catch (Exception e) {
      System.err.println(e.getMessage());
      throw new RuntimeException("Unable to read maximum brightness");
    }

    // read current trigger setting to be able to restore it later
    try {
      Path path = Paths.get("/sys/class/leds/" + dev + "/trigger");
      String tmp = new String(Files.readAllBytes(path));
      int start = tmp.indexOf('[');
      int end = tmp.indexOf(']', start);
      if (start != -1 && end != -1) {
        prevTrigger = tmp.substring(start+1, end);
      }
    } catch (Exception e) {
      System.err.println(e.getMessage());
      throw new RuntimeException("Unable to read trigger setting");
    }

    // read current brightness to be able to restore it later
    try {
      Path path = Paths.get("/sys/class/leds/" + dev + "/brightness");
      String tmp = new String(Files.readAllBytes(path));
      prevBrightness = Integer.parseInt(tmp.trim());
    } catch (Exception e) {
      System.err.println(e.getMessage());
      throw new RuntimeException("Unable to read current brightness");
    }

    // disable trigger
    String fn = "/sys/class/leds/" + dev + "/trigger";
    int ret = NativeInterface.writeFile(fn, "none");
    if (ret < 0) {
      if (ret == -13) {     // EACCES
        System.err.println("You might need to install a custom udev rule to allow regular users to modify /sys/class/leds/*.");
      }
      throw new RuntimeException(NativeInterface.getError(ret));
    }
  }

  /**
   *  Sets the brightness
   *  @param bright 0.0 (off) to 1.0 (maximum)
   *  @webref
   */
  public void brightness(float bright) {
    if (bright < 0.0 || 1.0 < bright) {
      System.err.println("Brightness must be between 0.0 and 1.0.");
      throw new IllegalArgumentException("Illegal argument");
    }

    if (NativeInterface.isSimulated()) {
      return;
    }

    String fn = "/sys/class/leds/" + dev + "/brightness";
    int ret = NativeInterface.writeFile(fn, Integer.toString((int)(bright * maxBrightness)));
    if (ret < 0) {
      throw new RuntimeException(fn + ": " + NativeInterface.getError(ret));
    }
  }

  /**
   *  Restores the previous state
   *  @webref
   */
  public void close() {
    if (NativeInterface.isSimulated()) {
      return;
    }

    // restore previous settings
    String fn = "/sys/class/leds/" + dev + "/brightness";
    int ret = NativeInterface.writeFile(fn, Integer.toString(prevBrightness));
    if (ret < 0) {
      throw new RuntimeException(fn + ": " + NativeInterface.getError(ret));
    }

    fn = "/sys/class/leds/" + dev + "/trigger";
    ret = NativeInterface.writeFile(fn, prevTrigger);
    if (ret < 0) {
      throw new RuntimeException(fn + ": " + NativeInterface.getError(ret));
    }
  }

  /**
   *  Lists all available LED devices
   *  @return String array
   *  @webref
   */
  public static String[] list() {
    if (NativeInterface.isSimulated()) {
      // as on the Raspberry Pi
      return new String[]{ "led0", "led1" };
    }

    ArrayList<String> devs = new ArrayList<>();
    File dir = new File("/sys/class/leds");
    File[] files = dir.listFiles();
    if (files != null) {
      for (File file : files) {
        devs.add(file.getName());
      }
    }
    // listFiles() does not guarantee ordering
    String[] tmp = devs.toArray(new String[devs.size()]);
    Arrays.sort(tmp);
    return tmp;
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/io/examples/Servo_I2C_PCA9685/PCA9685.pde
import processing.io.I2C;

// PCA9685 is a 16-channel servo/PWM driver
// datasheet: https://cdn-shop.adafruit.com/datasheets/PCA9685.pdf
// code contributed by @OlivierLD

public class PCA9685 extends I2C {
  public final static int PCA9685_ADDRESS = 0x40;

  // registers used
  public final static int MODE1 = 0x00;
  public final static int PRESCALE = 0xFE;
  public final static int LED0_ON_L = 0x06;
  public final static int LED0_ON_H = 0x07;
  public final static int LED0_OFF_L = 0x08;
  public final static int LED0_OFF_H = 0x09;

  private int address;
  private int freq = 200;              // 200 Hz default frequency (after power-up)
  private boolean hasFreqSet = false;  // whether a different frequency has been set
  private int minPulses[] = new int[16];
  private int maxPulses[] = new int[16];

  public PCA9685(String dev) {
    this(dev, PCA9685_ADDRESS);
  }
  public PCA9685(String dev, int address) {
    super(dev);
    this.address = address;
    // reset device
    command(MODE1, (byte) 0x00);
  }

  public void attach(int channel) {
    // same as on Arduino
    attach(channel, 544, 2400);
  }

  public void attach(int channel, int minPulse, int maxPulse) {
    if (channel < 0 || 15 < channel) {
      throw new IllegalArgumentException("Channel must be between 0 and 15");
    }
    minPulses[channel] = minPulse;
    maxPulses[channel] = maxPulse;

    // set the PWM frequency to be the same as on Arduino
    if (!hasFreqSet) {
      frequency(50);
    }
  }

  public void write(int channel, float angle) {
    if (channel < 0 || 15 < channel) {
      throw new IllegalArgumentException("Channel must be between 0 and 15");
    }
    if (angle < 0 || 180 < angle) {
      throw new IllegalArgumentException("Angle must be between 0 and 180");
    }
    int us = (int)(minPulses[channel] + (angle/180.0) * (maxPulses[channel]-minPulses[channel]));

    double pulseLength = 1000000; // 1s = 1,000,000 us per pulse
    pulseLength /= freq;          // 40..1000 Hz
    pulseLength /= 4096;          // 12 bits of resolution
    int pulse = us;
    pulse /= pulseLength;
    // println(pulseLength + " us per bit, pulse:" + pulse);
    pwm(channel, 0, pulse);
  }

  public boolean attached(int channel) {
    if (channel < 0 || 15 < channel) {
      return false;
    }
    return (maxPulses[channel] != 0) ? true : false;
  }

  public void detach(int channel) {
    pwm(channel, 0, 0);
    minPulses[channel] = 0;
    maxPulses[channel] = 0;
  }

  /**
   * @param freq 40..1000 Hz
   */
  public void frequency(int freq) {
    this.freq = freq;
    float preScaleVal = 25000000.0f; // 25MHz
    preScaleVal /= 4096.0;           // 4096: 12-bit
    preScaleVal /= freq;
    preScaleVal -= 1.0;
    // println("Setting PWM frequency to " + freq + " Hz");
    // println("Estimated pre-scale: " + preScaleVal);
    double preScale = Math.floor(preScaleVal + 0.5);
    // println("Final pre-scale: " + preScale);
    byte oldmode = (byte) readU8(MODE1);
    byte newmode = (byte) ((oldmode & 0x7F) | 0x10); // sleep
    command(MODE1, newmode);                         // go to sleep
    command(PRESCALE, (byte) (Math.floor(preScale)));
    command(MODE1, oldmode);
    delay(5);
    command(MODE1, (byte) (oldmode | 0x80));
    hasFreqSet = true;
  }

  /**
   * @param channel 0..15
   * @param on      cycle offset to turn output on (0..4095)
   * @param off     cycle offset to turn output off again (0..4095)
   */
  public void pwm(int channel, int on, int off) {
    if (channel < 0 || 15 < channel) {
      throw new IllegalArgumentException("Channel must be between 0 and 15");
    }
    if (on < 0 || 4095 < on) {
      throw new IllegalArgumentException("On must be between 0 and 4095");
    }
    if (off < 0 || 4095 < off) {
      throw new IllegalArgumentException("Off must be between 0 and 4095");
    }
    if (off < on) {
      throw new IllegalArgumentException("Off must be greater than On");
    }
    command(LED0_ON_L + 4 * channel, (byte) (on & 0xFF));
    command(LED0_ON_H + 4 * channel, (byte) (on >> 8));
    command(LED0_OFF_L + 4 * channel, (byte) (off & 0xFF));
    command(LED0_OFF_H + 4 * channel, (byte) (off >> 8));
  }

  private void command(int register, byte value) {
    beginTransmission(address);
    write(register);
    write(value);
    endTransmission();
  }

  private byte readU8(int register) {
    beginTransmission(address);
    write(register);
    byte[] ba = read(1);
    endTransmission();
    return (byte)(ba[0] & 0xFF);
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Shaders/ToonShading/ToonShading.pde
/**
 * Toon Shading.
 *
 * Example showing the use of a custom lighting shader in order
 * to apply a "toon" effect on the scene. Based on the glsl tutorial
 * from lighthouse 3D:
 * http://www.lighthouse3d.com/tutorials/glsl-tutorial/toon-shader-version-ii/
 */

PShader toon;
boolean shaderEnabled = true;

void setup() {
  size(640, 360, P3D);
  noStroke();
  fill(204);
  toon = loadShader("ToonFrag.glsl", "ToonVert.glsl");
}

void draw() {
  if (shaderEnabled == true) {
    shader(toon);
  }

  noStroke();
  background(0);
  float dirY = (mouseY / float(height) - 0.5) * 2;
  float dirX = (mouseX / float(width) - 0.5) * 2;
  directionalLight(204, 204, 204, -dirX, -dirY, -1);
  translate(width/2, height/2);
  sphere(120);
}

void mousePressed() {
  if (shaderEnabled) {
    shaderEnabled = false;
    resetShader();
  }
  else {
    shaderEnabled = true;
  }
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/serial/examples/SerialMultiple/SerialMultiple.pde
/**
 * Many Serial Ports
 *
 * Read data from the multiple Serial Ports
 */

import processing.serial.*;

Serial[] myPorts = new Serial[2];  // Create a list of objects from Serial class
int[] dataIn = new int[2];         // a list to hold data from the serial ports

void setup()  {
  size(400, 300);
  // print a list of the serial ports:
  printArray(Serial.list());
  // On my machine, the first and third ports in the list
  // were the serial ports that my microcontrollers were
  // attached to.
  // Open whatever ports ares the ones you're using.

// get the ports' names:
  String portOne = Serial.list()[0];
  String portTwo = Serial.list()[2];
  // open the ports:
  myPorts[0] = new Serial(this, portOne, 9600);
  myPorts[1] = new Serial(this, portTwo, 9600);
}

void draw() {
  // clear the screen:
  background(0);
  // use the latest byte from port 0 for the first circle
  fill(dataIn[0]);
  ellipse(width/3, height/2, 40, 40);
    // use the latest byte from port 1 for the second circle
   fill(dataIn[1]);
  ellipse(2*width/3, height/2, 40, 40);
}

/**
  * When SerialEvent is generated, it'll also give you
  * the port that generated it.  Check that against a list
  * of the ports you know you opened to find out where
  * the data came from
*/
void serialEvent(Serial thisPort) {
  // variable to hold the number of the port:
  int portNumber = -1;

  // iterate over the list of ports opened, and match the
  // one that generated this event:
  for (int p = 0; p < myPorts.length; p++) {
    if (thisPort == myPorts[p]) {
      portNumber = p;
    }
  }
  // read a byte from the port:
  int inByte = thisPort.read();
  // put it in the list that holds the latest data from each port:
  dataIn[portNumber] = inByte;
  // tell us who sent what:
  println("Got " + inByte + " from serial port " + portNumber);
}

/*
The following Wiring/Arduino code runs on both microcontrollers that
were used to send data to this sketch:

void setup()
{
  // start serial port at 9600 bps:
  Serial.begin(9600);
}

void loop() {
  // read analog input, divide by 4 to make the range 0-255:
  int analogValue = analogRead(0)/4;
  Serial.write(analogValue);
  // pause for 10 milliseconds:
  delay(10);
}

*/
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/net/library.properties
name = Network
version = 1
<file_sep>/Hardware Code - NodeMCU/deep_sleep_volt/deep_sleep_volt.ino
#include <ESP8266WiFi.h>
#include <PubSubClient.h>

int button = D2;
int buttonState = 0;

ADC_MODE(ADC_VCC); //to use getVcc
String batterylevel;

//WIFI  and MQTT Credentials

const char* ssid = "Wi-Fi name";
const char* password = "<PASSWORD>";

const char* mqtt_server = "Server IP";
const int mqtt_port = 1883/Port;
const char* mqtt_username = "MQTT username";
const char* mqtt_password = "<PASSWORD>";

WiFiClient espClient;
PubSubClient client(espClient);

void setup_wifi(){

  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while(WiFi.status() != WL_CONNECTED){
    delay(500);
    Serial.print(".");
  }

  randomSeed(micros());

  Serial.println("");
  Serial.println("WiFi Connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}

void sleepNow(){

  Serial.println("Going into deep sleep until interrupt");
  ESP.deepSleep(0);
}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Create a random client ID
    String clientId = "ESP8266Client-";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
//    if (client.connect(clientId.c_str(), mqtt_username, mqtt_password)) {
    if (client.connect(clientId.c_str())) {
      Serial.println("connected");

    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying (this could potentially be shortened)
      delay(5000);
    }
  }
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(callback);

}

void loop() {
  // put your main code here, to run repeatedly:
 batterylevel = ESP.getVcc();
 char charBuf[50];
 batterylevel.toCharArray(charBuf,50);

 reconnect();
 client.publish("pumpID", "00"); //The number sent here identifies the pump
 Serial.println("Published: 00");
 delay(100);
 client.publish("volt", charBuf); //publishes voltage
 Serial.println(batterylevel);
 Serial.println(charBuf);
 client.loop();

 sleepNow();
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Libraries/mqtt/reference/mqtt/MQTTClient.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<title>MQTTClient (Javadocs: mqtt)</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="date" content="2017-12-27">
<link rel="stylesheet" type="text/css" href="../stylesheet.css" title="Style">
<link rel="stylesheet" type="text/css" href="../jquery/jquery-ui.css" title="Style">

JavaScript is disabled on your browser.

Skip navigation links

Package

Class

Tree

Deprecated

Index

Help

Prev Class

Next Class

Frames

No Frames

All Classes

SEARCH:
<input type="text" id="search" value=" " disabled="disabled">
<input type="reset" id="reset" value=" " disabled="disabled">

JavaScript is disabled on your browser.

Summary:

Nested |

Field |

Constr |

Method

Detail:

Field |

Constr |

Method

Package mqtt

Class MQTTClient

java.lang.Object

mqtt.MQTTClient

public class MQTTClient
extends java.lang.Object

An MQTTClient that can publish and subscribe.

+Example

// This example sketch connects to shiftr.io
// and sends a message on every keystroke.
//
// After starting the sketch you can find the
// client here: https://shiftr.io/try.
//
// Note: If you're running the sketch via the
// Android Mode you need to set the INTERNET
// permission in Android > Sketch Permissions.
//
// by <NAME>
// https://github.com/256dpi/processing-mqtt

import mqtt.*;

MQTTClient client;

void setup() {
  client = new MQTTClient(this);
  client.connect("mqtt://try:try@broker.shiftr.io", "processing");
  client.subscribe("/example");
  // client.unsubscribe("/example");
}

void draw() {}

void keyPressed() {
  client.publish("/hello", "world");
}

void messageReceived(String topic, byte[] payload) {
  println("new message: " + topic + " - " + new String(payload));
}

Field Summary

Fields

Modifier and Type
Field and Description

MqttClient
client

Constructor Summary

Constructors

Constructor and Description

MQTTClient(processing.core.PApplet parent)

The constructor, usually called in the setup() method in your sketch to
 initialize and start the library.

Method Summary

All Methods Instance Methods Concrete Methods

Modifier and Type
Method and Description

void
connect(java.lang.String brokerURI)

Connect to a broker using only a broker URI.

void
connect(java.lang.String brokerURI,
       java.lang.String clientID)

Connect to a broker using an broker URI and client ID.

void
connect(java.lang.String brokerURI,
       java.lang.String clientId,
       boolean cleanSession)

Connect to a broker using an broker URI, client Id and cleanSession flag.

void
connectionLost(java.lang.Throwable throwable)

void
deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken)

void
disconnect()

Disconnect from the broker.

void
dispose()

void
draw()

void
messageArrived(java.lang.String topic,
              MqttMessage mqttMessage)

void
publish(java.lang.String topic)

Publish a message with a topic.

void
publish(java.lang.String topic,
       byte[] payload)

Publish a message with a topic and payload.

void
publish(java.lang.String topic,
       byte[] payload,
       int qos,
       boolean retained)

Publish a message with a topic, payload qos and retain flag.

void
publish(java.lang.String topic,
       java.lang.String payload)

Publish a message with a topic and payload.

void
publish(java.lang.String topic,
       java.lang.String payload,
       int qos,
       boolean retained)

Publish a message with a topic, payload qos and retain flag.

void
setWill(java.lang.String topic,
       byte[] payload,
       int qos,
       boolean retained)

Set a last will message with topic, payload, QoS and the retained flag.

void
setWill(java.lang.String topic,
       java.lang.String payload)

Set a last will message with topic and payload.

void
setWill(java.lang.String topic,
       java.lang.String payload,
       int qos,
       boolean retained)

Set a last will message with topic, payload, QoS and the retained flag.

void
subscribe(java.lang.String topic)

Subscribe a topic.

void
subscribe(java.lang.String topic,
         int qos)

Subscribe a topic with QoS.

void
unsubscribe(java.lang.String topic)

Unsubscrbe a topic.

Methods inherited from class java.lang.Object

equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Field Detail

client

public MqttClient client

Constructor Detail

MQTTClient

public MQTTClient(processing.core.PApplet parent)

The constructor, usually called in the setup() method in your sketch to
 initialize and start the library.

Parameters:

parent -

+Example

// This example sketch connects to shiftr.io
// and sends a message on every keystroke.
//
// After starting the sketch you can find the
// client here: https://shiftr.io/try.
//
// Note: If you're running the sketch via the
// Android Mode you need to set the INTERNET
// permission in Android > Sketch Permissions.
//
// by <NAME>
// https://github.com/256dpi/processing-mqtt

import mqtt.*;

MQTTClient client;

void setup() {
  client = new MQTTClient(this);
  client.connect("mqtt://try:<EMAIL>", "processing");
  client.subscribe("/example");
  // client.unsubscribe("/example");
}

void draw() {}

void keyPressed() {
  client.publish("/hello", "world");
}

void messageReceived(String topic, byte[] payload) {
  println("new message: " + topic + " - " + new String(payload));
}

Method Detail

setWill

public void setWill(java.lang.String topic,
                    java.lang.String payload,
                    int qos,
                    boolean retained)

Set a last will message with topic, payload, QoS and the retained flag.

Parameters:

topic -

payload -

qos -

retained -

setWill

public void setWill(java.lang.String topic,
                    java.lang.String payload)

Set a last will message with topic and payload.

Parameters:

topic -

payload -

setWill

public void setWill(java.lang.String topic,
                    byte[] payload,
                    int qos,
                    boolean retained)

Set a last will message with topic, payload, QoS and the retained flag.

Parameters:

topic -

payload -

qos -

retained -

connect

public void connect(java.lang.String brokerURI)

Connect to a broker using only a broker URI.

Parameters:

brokerURI -

connect

public void connect(java.lang.String brokerURI,
                    java.lang.String clientID)

Connect to a broker using an broker URI and client ID.

Parameters:

brokerURI -

clientID -

connect

public void connect(java.lang.String brokerURI,
                    java.lang.String clientId,
                    boolean cleanSession)

Connect to a broker using an broker URI, client Id and cleanSession flag.

Parameters:

brokerURI -

clientId -

cleanSession -

+Example

// This example sketch connects to shiftr.io
// and sends a message on every keystroke.
//
// After starting the sketch you can find the
// client here: https://shiftr.io/try.
//
// Note: If you're running the sketch via the
// Android Mode you need to set the INTERNET
// permission in Android > Sketch Permissions.
//
// by <NAME>
// https://github.com/256dpi/processing-mqtt

import mqtt.*;

MQTTClient client;

void setup() {
  client = new MQTTClient(this);
  client.connect("mqtt://try:<EMAIL>", "processing");
  client.subscribe("/example");
  // client.unsubscribe("/example");
}

void draw() {}

void keyPressed() {
  client.publish("/hello", "world");
}

void messageReceived(String topic, byte[] payload) {
  println("new message: " + topic + " - " + new String(payload));
}

publish

public void publish(java.lang.String topic)

Publish a message with a topic.

Parameters:

topic -

publish

public void publish(java.lang.String topic,
                    java.lang.String payload)

Publish a message with a topic and payload.

Parameters:

topic -

payload -

+Example

// This example sketch connects to shiftr.io
// and sends a message on every keystroke.
//
// After starting the sketch you can find the
// client here: https://shiftr.io/try.
//
// Note: If you're running the sketch via the
// Android Mode you need to set the INTERNET
// permission in Android > Sketch Permissions.
//
// by <NAME>
// https://github.com/256dpi/processing-mqtt

import mqtt.*;

MQTTClient client;

void setup() {
  client = new MQTTClient(this);
  client.connect("mqtt://try:try@broker.shiftr.io", "processing");
  client.subscribe("/example");
  // client.unsubscribe("/example");
}

void draw() {}

void keyPressed() {
  client.publish("/hello", "world");
}

void messageReceived(String topic, byte[] payload) {
  println("new message: " + topic + " - " + new String(payload));
}

publish

public void publish(java.lang.String topic,
                    java.lang.String payload,
                    int qos,
                    boolean retained)

Publish a message with a topic, payload qos and retain flag.

Parameters:

topic -

payload -

qos -

retained -

publish

public void publish(java.lang.String topic,
                    byte[] payload)

Publish a message with a topic and payload.

Parameters:

topic -

payload -

publish

public void publish(java.lang.String topic,
                    byte[] payload,
                    int qos,
                    boolean retained)

Publish a message with a topic, payload qos and retain flag.

Parameters:

topic -

payload -

qos -

retained -

subscribe

public void subscribe(java.lang.String topic)

Subscribe a topic.

Parameters:

topic -

+Example

// This example sketch connects to shiftr.io
// and sends a message on every keystroke.
//
// After starting the sketch you can find the
// client here: https://shiftr.io/try.
//
// Note: If you're running the sketch via the
// Android Mode you need to set the INTERNET
// permission in Android > Sketch Permissions.
//
// by <NAME>
// https://github.com/256dpi/processing-mqtt

import mqtt.*;

MQTTClient client;

void setup() {
  client = new MQTTClient(this);
  client.connect("mqtt://try:try@broker.shiftr.io", "processing");
  client.subscribe("/example");
  // client.unsubscribe("/example");
}

void draw() {}

void keyPressed() {
  client.publish("/hello", "world");
}

void messageReceived(String topic, byte[] payload) {
  println("new message: " + topic + " - " + new String(payload));
}

subscribe

public void subscribe(java.lang.String topic,
                      int qos)

Subscribe a topic with QoS.

Parameters:

topic -

qos -

unsubscribe

public void unsubscribe(java.lang.String topic)

Unsubscrbe a topic.

Parameters:

topic -

+Example

// This example sketch connects to shiftr.io
// and sends a message on every keystroke.
//
// After starting the sketch you can find the
// client here: https://shiftr.io/try.
//
// Note: If you're running the sketch via the
// Android Mode you need to set the INTERNET
// permission in Android > Sketch Permissions.
//
// by <NAME>
// https://github.com/256dpi/processing-mqtt

import mqtt.*;

MQTTClient client;

void setup() {
  client = new MQTTClient(this);
  client.connect("mqtt://try:<EMAIL>", "processing");
  client.subscribe("/example");
  // client.unsubscribe("/example");
}

void draw() {}

void keyPressed() {
  client.publish("/hello", "world");
}

void messageReceived(String topic, byte[] payload) {
  println("new message: " + topic + " - " + new String(payload));
}

disconnect

public void disconnect()

Disconnect from the broker.

+Example

// This example sketch connects to shiftr.io
// and sends a message on every keystroke.
//
// After starting the sketch you can find the
// client here: https://shiftr.io/try.
//
// Note: If you're running the sketch via the
// Android Mode you need to set the INTERNET
// permission in Android > Sketch Permissions.
//
// by <NAME>
// https://github.com/256dpi/processing-mqtt

import mqtt.*;

MQTTClient client;

void setup() {
  client = new MQTTClient(this);
  client.connect("mqtt://try:<EMAIL>", "processing");
  client.subscribe("/example");
  // client.unsubscribe("/example");
}

void draw() {}

void keyPressed() {
  client.publish("/hello", "world");
}

void messageReceived(String topic, byte[] payload) {
  println("new message: " + topic + " - " + new String(payload));
}

dispose

public void dispose()

draw

public void draw()
          throws java.lang.Exception

Throws:

java.lang.Exception

deliveryComplete

public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken)

messageArrived

public void messageArrived(java.lang.String topic,
                           MqttMessage mqttMessage)

connectionLost

public void connectionLost(java.lang.Throwable throwable)

Skip navigation links

Package

Class

Tree

Deprecated

Index

Help

Prev Class

Next Class

Frames

No Frames

All Classes

JavaScript is disabled on your browser.

Summary:

Nested |

Field |

Constr |

Method

Detail:

Field |

Constr |

Method

Processing Library mqtt by <NAME>. (c) 2015

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Data/TrueFalse/TrueFalse.pde
/**
 * True/False.
 *
 * A Boolean variable has only two possible values: true or false.
 * It is common to use Booleans with control statements to
 * determine the flow of a program. In this example, when the
 * boolean value "x" is true, vertical black lines are drawn and when
 * the boolean value "x" is false, horizontal gray lines are drawn.
 */

boolean b = false;

size(640, 360);
background(0);
stroke(255);

int d = 20;
int middle = width/2;

for (int i = d; i <= width; i += d) {

  if (i < middle) {
    b = true;
  } else {
    b = false;
  }

  if (b == true) {
    // Vertical line
    line(i, d, i, height-d);
  }

  if (b == false) {
    // Horizontal line
    line(middle, i - middle + d, width-d, i - middle + d);
  }
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Image/Transparency/Transparency.pde
/**
 * Transparency.
 *
 * Move the pointer left and right across the image to change
 * its position. This program overlays one image over another
 * by modifying the alpha value of the image with the tint() function.
 */

PImage img;
float offset = 0;
float easing = 0.05;

void setup() {
  size(640, 360);
  img = loadImage("moonwalk.jpg");  // Load an image into the program
}

void draw() {
  image(img, 0, 0);  // Display at full opacity
  float dx = (mouseX-img.width/2) - offset;
  offset += dx * easing;
  tint(255, 127);  // Display at half opacity
  image(img, offset, 0);
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Create Shapes/GroupPShape/GroupPShape.pde
/**
 * GroupPShape
 *
 * How to group multiple PShapes into one PShape
 */

// A PShape that will group PShapes
PShape group;

void setup() {
  size(640, 360, P2D);

  // Create the shape as a group
  group = createShape(GROUP);

  // Make a polygon PShape
  PShape star = createShape();
  star.beginShape();
  star.noFill();
  star.stroke(255);
  star.vertex(0, -50);
  star.vertex(14, -20);
  star.vertex(47, -15);
  star.vertex(23, 7);
  star.vertex(29, 40);
  star.vertex(0, 25);
  star.vertex(-29, 40);
  star.vertex(-23, 7);
  star.vertex(-47, -15);
  star.vertex(-14, -20);
  star.endShape(CLOSE);

  // Make a path PShape
  PShape path = createShape();
  path.beginShape();
  path.noFill();
  path.stroke(255);
  for (float a = -PI; a < 0; a += 0.1) {
    float r = random(60, 70);
    path.vertex(r*cos(a), r*sin(a));
  }
  path.endShape();

  // Make a primitive (Rectangle) PShape
  PShape rectangle = createShape(RECT,-10,-10,20,20);
  rectangle.setFill(false);
  rectangle.setStroke(color(255));

  // Add them all to the group
  group.addChild(star);
  group.addChild(path);
  group.addChild(rectangle);
}

void draw() {
  // We can access them individually via the group PShape
  PShape rectangle = group.getChild(2);
  // Shapes can be rotated
  rectangle.rotate(0.1);

  background(52);
  // Display the group PShape
  translate(mouseX, mouseY);
  shape(group);
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Image Processing/PixelArray/PixelArray.pde
/**
 * Pixel Array.
 *
 * Click and drag the mouse up and down to control the signal and
 * press and hold any key to see the current pixel being read.
 * This program sequentially reads the color of every pixel of an image
 * and displays this color to fill the window.
 */

PImage img;
int direction = 1;
float signal;

void setup() {
  size(640, 360);
  noFill();
  stroke(255);
  frameRate(30);
  img = loadImage("sea.jpg");
}

void draw() {
  if (signal > img.width*img.height-1 || signal < 0) {
    direction = direction * -1;
  }

  if (mousePressed) {
    int mx = constrain(mouseX, 0, img.width-1);
    int my = constrain(mouseY, 0, img.height-1);
    signal = my*img.width + mx;
  } else {
    signal += 0.33*direction;
  }

  int sx = int(signal) % img.width;
  int sy = int(signal) / img.width;

  if (keyPressed) {
    set(0, 0, img);  // fast way to draw an image
    point(sx, sy);
    rect(sx - 5, sy - 5, 10, 10);
  } else {
    color c = img.get(sx, sy);
    background(c);
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/pdf/examples/ManyPages/ManyPages.pde
/**
 * Many Pages.
 *
 * Saves a new page into a PDF file each loop through draw().
 * Pressing the mouse finishes writing the file and exits the program.
 */

import processing.pdf.*;

PGraphicsPDF pdf;

void setup() {
  size(600, 600);
  frameRate(4);
  pdf = (PGraphicsPDF)beginRecord(PDF, "Lines.pdf");
}

void draw() {
  background(255);
  stroke(0, 20);
  strokeWeight(20.0);
  line(mouseX, 0, width-mouseY, height);
  pdf.nextPage();
}

void mousePressed() {
  endRecord();
  exit();
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/lib/languages/PDE_en.properties
# -> PDE.properties<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/serial/test/serial_throughput/serial_throughput.pde
import processing.serial.*;
Serial serial;
int start;
byte[] in = new byte[32768];
long num_ok = 0;
long num_fail = 0;
long num_recv = 0;

void setup() {
  println(serial.list());
  // change this accordingly
  serial = new Serial(this, serial.list()[0], 115200);
  start = millis();
}

void draw() {
  background(255);
  if (0 < serial.available()) {
    int recv = serial.readBytes(in);
    for (int i=0; i < recv; i++) {
      if (in[i] == '.') {
        num_ok++;
      } else {
        num_fail++;
        println("Received "+num_fail+" unexpected bytes");
      }
      num_recv++;
    }
  }
  fill(0);
  text(num_recv/((millis()-start)/1000.0), 0, height/2);
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Demos/Performance/TextRendering/TextRendering.pde

public void setup() {
  size(800, 600, P2D);
  fill(0);
}

public void draw() {
  background(255);
  for (int i = 0; i < 10000; i++) {
    float x = random(width);
    float y = random(height);
    text("HELLO", x, y);
  }
  if (frameCount % 10 == 0) println(frameRate);
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Structure/Loop/Loop.pde
/**
 * Loop.
 *
 * The loop() function causes draw() to execute
 * continuously. If noLoop is called in setup()
 * the draw() is only executed once. In this example
 * click the mouse to execute loop(), which will
 * cause the draw() the execute continuously.
 */

float y = 100;

// The statements in the setup() function
// run once when the program begins
void setup() {
  size(640, 360);  // Size should be the first statement
  stroke(255);     // Set stroke color to white
  noLoop();

  y = height * 0.5;
}

// The statements in draw() are run until the
// program is stopped. Each statement is run in
// sequence and after the last line is read, the first
// line is run again.
void draw() {
  background(0);   // Set the background to black
  line(0, y, width, y);

  y = y - 1;
  if (y < 0) {
    y = height;
  }
}

void mousePressed() {
  loop();
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Input/Mouse1D/Mouse1D.pde
/**
 * Mouse 1D.
 *
 * Move the mouse left and right to shift the balance.
 * The "mouseX" variable is used to control both the
 * size and color of the rectangles.
 */

void setup() {
  size(640, 360);
  noStroke();
  colorMode(RGB, height, height, height);
  rectMode(CENTER);
}

void draw() {
  background(0.0);

  float r1 = map(mouseX, 0, width, 0, height);
  float r2 = height-r1;

  fill(r1);
  rect(width/2 + r1/2, height/2, r1, r1);

  fill(r2);
  rect(width/2 - r2/2, height/2, r2, r2);
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Motion/Brownian/Brownian.pde
/**
 * Brownian motion.
 *
 * Recording random movement as a continuous line.
 */

int num = 2000;
int range = 6;

float[] ax = new float[num];
float[] ay = new float[num];

void setup()
{
  size(640, 360);
  for(int i = 0; i < num; i++) {
    ax[i] = width/2;
    ay[i] = height/2;
  }
  frameRate(30);
}

void draw()
{
  background(51);

  // Shift all elements 1 place to the left
  for(int i = 1; i < num; i++) {
    ax[i-1] = ax[i];
    ay[i-1] = ay[i];
  }

  // Put a new value at the end of the array
  ax[num-1] += random(-range, range);
  ay[num-1] += random(-range, range);

  // Constrain all points to the screen
  ax[num-1] = constrain(ax[num-1], 0, width);
  ay[num-1] = constrain(ay[num-1], 0, height);

  // Draw a line connecting the points
  for(int i=1; i<num; i++) {
    float val = float(i)/num * 204.0 + 51;
    stroke(val);
    line(ax[i-1], ay[i-1], ax[i], ay[i]);
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Arrays/ArrayObjects/Module.pde
class Module {
  int xOffset;
  int yOffset;
  float x, y;
  int unit;
  int xDirection = 1;
  int yDirection = 1;
  float speed;

  // Contructor
  Module(int xOffsetTemp, int yOffsetTemp, int xTemp, int yTemp, float speedTemp, int tempUnit) {
    xOffset = xOffsetTemp;
    yOffset = yOffsetTemp;
    x = xTemp;
    y = yTemp;
    speed = speedTemp;
    unit = tempUnit;
  }

  // Custom method for updating the variables
  void update() {
    x = x + (speed * xDirection);
    if (x >= unit || x <= 0) {
      xDirection *= -1;
      x = x + (1 * xDirection);
      y = y + (1 * yDirection);
    }
    if (y >= unit || y <= 0) {
      yDirection *= -1;
      y = y + (1 * yDirection);
    }
  }

  // Custom method for drawing the object
  void display() {
    fill(255);
    ellipse(xOffset + x, yOffset + y, 6, 6);
  }
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Image Processing/Histogram/Histogram.pde
/**
 * Histogram.
 *
 * Calculates the histogram of an image.
 * A histogram is the frequency distribution
 * of the gray levels with the number of pure black values
 * displayed on the left and number of pure white values on the right.
 *
 * Note that this sketch will behave differently on Android,
 * since most images will no longer be full 24-bit color.
 */

size(640, 360);

// Load an image from the data directory
// Load a different image by modifying the comments
PImage img = loadImage("frontier.jpg");
image(img, 0, 0);
int[] hist = new int[256];

// Calculate the histogram
for (int i = 0; i < img.width; i++) {
  for (int j = 0; j < img.height; j++) {
    int bright = int(brightness(get(i, j)));
    hist[bright]++;
  }
}

// Find the largest value in the histogram
int histMax = max(hist);

stroke(255);
// Draw half of the histogram (skip every second value)
for (int i = 0; i < img.width; i += 2) {
  // Map i (from 0..img.width) to a location in the histogram (0..255)
  int which = int(map(i, 0, img.width, 0, 255));
  // Convert the histogram value to a location between
  // the bottom and the top of the picture
  int y = int(map(hist[which], 0, histMax, img.height, 0));
  line(i, img.height, i, y);
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Control/Conditionals1/Conditionals1.pde
/**
 * Conditionals 1.
 *
 * Conditions are like questions.
 * They allow a program to decide to take one action if
 * the answer to a question is "true" or to do another action
 * if the answer to the question is "false."

 * The questions asked within a program are always logical
 * or relational statements. For example, if the variable 'i' is
 * equal to zero then draw a line.
 */

size(640, 360);
background(0);

for(int i = 10; i < width; i += 10) {
  // If 'i' divides by 20 with no remainder draw
  // the first line, else draw the second line
  if((i % 20) == 0) {
    stroke(255);
    line(i, 80, i, height/2);
  } else {
    stroke(153);
    line(i, 20, i, 180);
  }
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Create Shapes/PolygonPShapeOOP2/PolygonPShapeOOP2.pde
/**
 * PolygonPShapeOOP.
 *
 * Wrapping a PShape inside a custom class
 * and demonstrating how we can have a multiple objects each
 * using the same PShape.
 */

// A list of objects
ArrayList<Polygon> polygons;

void setup() {
  size(640, 360, P2D);

  // Make a PShape
  PShape star = createShape();
  star.beginShape();
  star.noStroke();
  star.fill(0, 127);
  star.vertex(0, -50);
  star.vertex(14, -20);
  star.vertex(47, -15);
  star.vertex(23, 7);
  star.vertex(29, 40);
  star.vertex(0, 25);
  star.vertex(-29, 40);
  star.vertex(-23, 7);
  star.vertex(-47, -15);
  star.vertex(-14, -20);
  star.endShape(CLOSE);

  // Make an ArrayList
  polygons = new ArrayList<Polygon>();

  // Add a bunch of objects to the ArrayList
  // Pass in reference to the PShape
  // We coud make polygons with different PShapes
  for (int i = 0; i < 25; i++) {
    polygons.add(new Polygon(star));
  }
}

void draw() {
  background(255);

  // Display and move them all
  for (Polygon poly : polygons) {
    poly.display();
    poly.move();
  }
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Data/CharactersStrings/CharactersStrings.pde
/**
 * Characters Strings.
 *
 * The character datatype, abbreviated as char, stores letters and
 * symbols in the Unicode format, a coding system developed to support
 * a variety of world languages. Characters are distinguished from other
 * symbols by putting them between single quotes ('P').

 *

 * A string is a sequence of characters. A string is noted by surrounding
 * a group of letters with double quotes ("Processing").
 * Chars and strings are most often used with the keyboard methods,
 * to display text to the screen, and to load images or files.

 *

 * The String datatype must be capitalized because it is a complex datatype.
 * A String is actually a class with its own methods, some of which are
 * featured below.
 */

char letter;
String words = "Begin...";

void setup() {
  size(640, 360);
  // Create the font
  textFont(createFont("SourceCodePro-Regular.ttf", 36));
}

void draw() {
  background(0); // Set background to black

  // Draw the letter to the center of the screen
  textSize(14);
  text("Click on the program, then type to add to the String", 50, 50);
  text("Current key: " + letter, 50, 70);
  text("The String is " + words.length() +  " characters long", 50, 90);

  textSize(36);
  text(words, 50, 120, 540, 300);
}

void keyTyped() {
  // The variable "key" always contains the value
  // of the most recent key pressed.
  if ((key >= 'A' && key <= 'z') || key == ' ') {
    letter = key;
    words = words + key;
    // Write the letter to the console
    println(key);
  }
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/File IO/SaveFile2/SaveFile2.pde
/**
 * SaveFile 2
 *
 * This file a PrintWriter object to write data continuously to a file
 * while the mouse is pressed. When a key is pressed, the file closes
 * itself and the program is stopped.
 */

PrintWriter output;

void setup()
{
  size(200, 200);
  // Create a new file in the sketch directory
  output = createWriter("positions.txt");
  frameRate(12);
}

void draw()
{
  if (mousePressed) {
    point(mouseX, mouseY);
    // Write the coordinate to a file with a
    // "\t" (TAB character) between each entry
    output.println(mouseX + "\t" + mouseY);
  }
}

void keyPressed() { // Press a key to save the data
  output.flush(); // Write the remaining data
  output.close(); // Finish the file
  exit(); // Stop the program
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Create Shapes/ParticleSystemPShape/Particle.pde
// An individual Particle

class Particle {

  // Velocity
  PVector center;
  PVector velocity;
  // Lifespane is tied to alpha
  float lifespan;

  // The particle PShape
  PShape part;
  // The particle size
  float partSize;

  // A single force
  PVector gravity = new PVector(0, 0.1);

  Particle() {
    partSize = random(10, 60);
    // The particle is a textured quad
    part = createShape();
    part.beginShape(QUAD);
    part.noStroke();
    part.texture(sprite);
    part.normal(0, 0, 1);
    part.vertex(-partSize/2, -partSize/2, 0, 0);
    part.vertex(+partSize/2, -partSize/2, sprite.width, 0);
    part.vertex(+partSize/2, +partSize/2, sprite.width, sprite.height);
    part.vertex(-partSize/2, +partSize/2, 0, sprite.height);
    part.endShape();

    // Initialize center vector
    center = new PVector();

    // Set the particle starting location
    rebirth(width/2, height/2);
  }

  PShape getShape() {
    return part;
  }

  void rebirth(float x, float y) {
    float a = random(TWO_PI);
    float speed = random(0.5, 4);
    // A velocity with random angle and magnitude
    velocity = PVector.fromAngle(a);
    velocity.mult(speed);
    // Set lifespan
    lifespan = 255;
    // Set location using translate
    part.resetMatrix();
    part.translate(x, y);

    // Update center vector
    center.set(x, y, 0);
  }

  // Is it off the screen, or its lifespan is over?
  boolean isDead() {
    if (center.x > width  || center.x < 0 ||
        center.y > height || center.y < 0 || lifespan < 0) {
      return true;
    }
    else {
      return false;
    }
  }

  void update() {
    // Decrease life
    lifespan = lifespan - 1;
    // Apply gravity
    velocity.add(gravity);
    part.setTint(color(255, lifespan));
    // Move the particle according to its velocity
    part.translate(velocity.x, velocity.y);
    // and also update the center
    center.add(velocity);
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Control/Conditionals2/Conditionals2.pde
/**
 * Conditionals 2.
 *
 * We extend the language of conditionals from the previous
 * example by adding the keyword "else". This allows conditionals
 * to ask two or more sequential questions, each with a different
 * action.
 */

size(640, 360);
background(0);

for (int i = 2; i < width-2; i += 2) {
  // If 'i' divides by 20 with no remainder
  if ((i % 20) == 0) {
    stroke(255);
    line(i, 80, i, height/2);
    // If 'i' divides by 10 with no remainder
  } else if ((i % 10) == 0) {
    stroke(153);
    line(i, 20, i, 180);
    // If neither of the above two conditions are met
    // then draw this line
  } else {
    stroke(102);
    line(i, height/2, i, height-20);
  }
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/dxf/library.properties
name = DXF Export
version = 1
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/io/examples/Light_I2C_TSL2561/Light_I2C_TSL2561.pde
import processing.io.*;
TSL2561 sensor;

// see setup.png in the sketch folder for wiring details

// this variable will contain the measured brightness
// Lux (lx) is the unit of illuminance
float lux;

void setup() {
  size(700, 100);
  textSize(72);
  //printArray(I2C.list());
  sensor = new TSL2561("i2c-1", 0x39);
}

void draw() {
  background(0);
  stroke(255);
  lux = sensor.lux();
  text(String.format("Light:  %.02f Lux", lux), 10, 75);
}

void dispose() {
  // turn the sensor off
  sensor.stop();
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Shape/ShapeVertices/ShapeVertices.pde
/**
 * Shape Vertices.
 *
 * How to iterate over the vertices of a shape.
 * When loading an obj or SVG, getVertexCount()
 * will typically return 0 since all the vertices
 * are in the child shapes.
 *
 * You should iterate through the children and then
 * iterate through their vertices.
 */

// The shape
PShape uk;

void setup() {
  size(640, 360);
  // Load the shape
  uk = loadShape("uk.svg");
}

void draw() {
  background(51);
  // Center where we will draw all the vertices
  translate(width/2 - uk.width/2, height/2- uk.height/2);

  // Iterate over the children
  int children = uk.getChildCount();
  for (int i = 0; i < children; i++) {
    PShape child = uk.getChild(i);
    int total = child.getVertexCount();

    // Now we can actually get the vertices from each child
    for (int j = 0; j < total; j++) {
      PVector v = child.getVertex(j);
      // Cycling brightness for each vertex
      stroke((frameCount + (i+1)*j) % 255);
      // Just a dot for each one
      point(v.x, v.y);
    }
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/src/processing/mode/java/Compiler.java
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
  Part of the Processing project - http://processing.org

  Copyright (c) 2004-12 <NAME> and <NAME>
  Copyright (c) 2001-04 Massachusetts Institute of Technology

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software Foundation,
  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

package processing.mode.java;

import processing.app.*;
import processing.app.ui.Editor;
import processing.core.*;

import java.io.*;
import java.lang.reflect.Method;
import java.util.HashMap;

//import org.eclipse.jdt.core.compiler.batch.BatchCompiler;
//import org.eclipse.jdt.core.compiler.CompilationProgress;

public class Compiler {

  static HashMap<String, String> importSuggestions;
  static {
    importSuggestions = new HashMap<>();
    importSuggestions.put("Arrays", "java.util.Arrays");
    importSuggestions.put("Collections", "java.util.Collections");
    importSuggestions.put("Date", "java.util.Date");
    importSuggestions.put("Frame", "java.awt.Frame");
    importSuggestions.put("Iterator", "java.util.Iterator");
  }

  /**
   * Compile with ECJ. See http://j.mp/8paifz for documentation.
   *
   * @param sketch Sketch object to be compiled, used for placing exceptions
   * @param buildPath Where the temporary files live and will be built from.
   * @return true if successful.
   * @throws SketchException Only if there's a problem. Only then.
   */
  static public boolean compile(JavaBuild build) throws SketchException {

    // This will be filled in if anyone gets angry
    SketchException exception = null;
    boolean success = false;

    String baseCommand[] = new String[] {
      "-g",
      "-Xemacs",
      //"-noExit",  // not necessary for ecj
      "-source", "1.7",
      "-target", "1.7",
      "-encoding", "utf8",
      "-classpath", build.getClassPath(),
      "-nowarn", // we're not currently interested in warnings (works in ecj)
      "-d", build.getBinFolder().getAbsolutePath() // output the classes in the buildPath
    };
    //PApplet.println(baseCommand);

    String[] sourceFiles = Util.listFiles(build.getSrcFolder(), false, ".java");
    String[] command = PApplet.concat(baseCommand, sourceFiles);
    //PApplet.println(command);

    try {
      // Load errors into a local StringBuilder
      final StringBuilder errorBuffer = new StringBuilder();

      // Create single method dummy writer class to slurp errors from ecj
      Writer internalWriter = new Writer() {
          public void write(char[] buf, int off, int len) {
            errorBuffer.append(buf, off, len);
          }

          public void flush() { }

          public void close() { }
        };
      // Wrap as a PrintWriter since that's what compile() wants
      PrintWriter writer = new PrintWriter(internalWriter);

      //result = com.sun.tools.javac.Main.compile(command, writer);

      PrintWriter outWriter = new PrintWriter(System.out);

      // Version that's not dynamically loaded
      //CompilationProgress progress = null;
      //success = BatchCompiler.compile(command, outWriter, writer, progress);

      // Version that *is* dynamically loaded. First gets the mode class loader
      // so that it can grab the compiler JAR files from it.
      ClassLoader loader = build.mode.getClassLoader();
      try {
        Class<?> batchClass =
          Class.forName("org.eclipse.jdt.core.compiler.batch.BatchCompiler", false, loader);
        Class<?> progressClass =
          Class.forName("org.eclipse.jdt.core.compiler.CompilationProgress", false, loader);
        Class<?>[] compileArgs =
          new Class<?>[] { String[].class, PrintWriter.class, PrintWriter.class, progressClass };
        Method compileMethod = batchClass.getMethod("compile", compileArgs);
        success = (Boolean)
          compileMethod.invoke(null, new Object[] { command, outWriter, writer, null });
      } catch (Exception e) {
        e.printStackTrace();
        throw new SketchException("Unknown error inside the compiler.");
      }

      // Close out the stream for good measure
      writer.flush();
      writer.close();

      BufferedReader reader =
        new BufferedReader(new StringReader(errorBuffer.toString()));
      //System.err.println(errorBuffer.toString());

      String line = null;
      while ((line = reader.readLine()) != null) {
        //System.out.println("got line " + line);  // debug

        // get first line, which contains file name, line number,
        // and at least the first line of the error message
        String errorFormat = "([\\w\\d_]+.java):(\\d+):\\s*(.*):\\s*(.*)\\s*";
        String[] pieces = PApplet.match(line, errorFormat);
        //PApplet.println(pieces);

        // if it's something unexpected, die and print the mess to the console
        if (pieces == null) {
          exception = new SketchException("Cannot parse error text: " + line);
          exception.hideStackTrace();
          // Send out the rest of the error message to the console.
          System.err.println(line);
          while ((line = reader.readLine()) != null) {
            System.err.println(line);
          }
          break;
        }

        // translate the java filename and line number into a un-preprocessed
        // location inside a source file or tab in the environment.
        String dotJavaFilename = pieces[1];
        // Line numbers are 1-indexed from javac
        int dotJavaLineIndex = PApplet.parseInt(pieces[2]) - 1;
        String errorMessage = pieces[4];

        exception = build.placeException(errorMessage,
                                         dotJavaFilename,
                                         dotJavaLineIndex);

        if (exception == null) {
          exception = new SketchException(errorMessage);
        }

        String[] parts = null;

        if (errorMessage.startsWith("The import ") &&
            errorMessage.endsWith("cannot be resolved")) {
          // The import poo cannot be resolved
          //import poo.shoe.blah.*;
          //String what = errorMessage.substring("The import ".length());
          String[] m = PApplet.match(errorMessage, "The import (.*) cannot be resolved");
          //what = what.substring(0, what.indexOf(' '));
          if (m != null) {
//            System.out.println("'" + m[1] + "'");
            if (m[1].equals("processing.xml")) {
              exception.setMessage("processing.xml no longer exists, this code needs to be updated for 2.0.");
              System.err.println("The processing.xml library has been replaced " +
              		               "with a new 'XML' class that's built-in.");
              handleCrustyCode();

            } else {
              exception.setMessage("The package " +
                                   "\u201C" + m[1] + "\u201D" +
                                   " does not exist. " +
                                   "You might be missing a library.");
              System.err.println("Libraries must be " +
                                 "installed in a folder named 'libraries' " +
                                 "inside the sketchbook folder " +
                                 "(see the Preferences window).");
            }
          }

        } else if (errorMessage.endsWith("cannot be resolved to a type")) {
          // xxx cannot be resolved to a type
          //xxx c;

          String what = errorMessage.substring(0, errorMessage.indexOf(' '));

          if (what.equals("BFont") ||
              what.equals("BGraphics") ||
              what.equals("BImage")) {
            exception.setMessage(what + " has been replaced with P" + what.substring(1));
            handleCrustyCode();

          } else {
            exception.setMessage("Cannot find a class or type " +
                                 "named \u201C" + what + "\u201D");

            String suggestion = importSuggestions.get(what);
            if (suggestion != null) {
              System.err.println("You may need to add \"import " + suggestion + ";\" to the top of your sketch.");
              System.err.println("To make sketches more portable, imports that are not part of the Processing API were removed in Processing 2.");
              System.err.println("See the changes page for more information: https://github.com/processing/processing/wiki/Changes");
            }
          }

        } else if (errorMessage.endsWith("cannot be resolved")) {
          // xxx cannot be resolved
          //println(xxx);

          String what = errorMessage.substring(0, errorMessage.indexOf(' '));

          if (what.equals("LINE_LOOP") ||
              what.equals("LINE_STRIP")) {
            exception.setMessage("LINE_LOOP and LINE_STRIP are not available, " +
            		                 "please update your code.");
            handleCrustyCode();

          } else if (what.equals("framerate")) {
            exception.setMessage("framerate should be changed to frameRate.");
            handleCrustyCode();

          } else if (what.equals("screen")) {
            exception.setMessage("Change screen.width and screen.height to " +
            		                 "displayWidth and displayHeight.");
            handleCrustyCode();

          } else if (what.equals("screenWidth") ||
                     what.equals("screenHeight")) {
            exception.setMessage("Change screenWidth and screenHeight to " +
                                 "displayWidth and displayHeight.");
            handleCrustyCode();

          } else {
            exception.setMessage("Cannot find anything " +
                                 "named \u201C" + what + "\u201D");
          }

        } else if (errorMessage.startsWith("Duplicate")) {
          // "Duplicate nested type xxx"
          // "Duplicate local variable xxx"

        } else if (null != (parts = PApplet.match(errorMessage,
                "literal (\\S*) of type (\\S*) is out of range"))) {
          if ("int".equals(parts[2])) {
            exception.setMessage("The type int can't handle numbers that big. Try "
                + parts[1] + "L to upgrade to long.");
          } else {
            // I'd like to give an essay on BigInteger and BigDecimal, but
            // this margin is too narrow to contain it.
            exception.setMessage("Even the type " + parts[2] + " can't handle "
                + parts[1] + ". Research big numbers in Java.");
          }
        } else {
          // The method xxx(String) is undefined for the type Temporary_XXXX_XXXX
          //xxx("blah");
          // The method xxx(String, int) is undefined for the type Temporary_XXXX_XXXX
          //xxx("blah", 34);
          // The method xxx(String, int) is undefined for the type PApplet
          //PApplet.sub("ding");
          String undefined =
            "The method (\\S+\\(.*\\)) is undefined for the type (.*)";
          parts = PApplet.match(errorMessage, undefined);
          if (parts != null) {
            if (parts[1].equals("framerate(int)")) {
              exception.setMessage("framerate() no longer exists, use frameRate() instead.");
              handleCrustyCode();

            } else if (parts[1].equals("push()")) {
              exception.setMessage("push() no longer exists, use pushMatrix() instead.");
              handleCrustyCode();

            } else if (parts[1].equals("pop()")) {
              exception.setMessage("pop() no longer exists, use popMatrix() instead.");
              handleCrustyCode();

            } else {
              String mess = "The function " + parts[1] + " does not exist.";
              exception.setMessage(mess);
            }
            break;
          }
        }
        if (exception != null) {
          // The stack trace just shows that this happened inside the compiler,
          // which is a red herring. Don't ever show it for compiler stuff.
          exception.hideStackTrace();
          break;
        }
      }
    } catch (IOException e) {
      String bigSigh = "Error while compiling. (" + e.getMessage() + ")";
      exception = new SketchException(bigSigh);
      e.printStackTrace();
      success = false;
    }
    // In case there was something else.
    if (exception != null) throw exception;

    return success;
  }

  static protected void handleCrustyCode() {
    System.err.println("This code needs to be updated " +
                       "for this version of Processing, " +
                       "please read the Changes page on the Wiki.");
    Editor.showChanges();
  }

  protected int caretColumn(String caretLine) {
    return caretLine.indexOf("^");
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/io/examples/AnalogDigital_SPI_MCP3001/MCP3001.pde
import processing.io.SPI;

// MCP3001 is a Analog-to-Digital converter using SPI
// datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/21293C.pdf

class MCP3001 extends SPI {

  MCP3001(String dev) {
    super(dev);
    settings(500000, SPI.MSBFIRST, SPI.MODE0);
  }

  // returns a number between 0.0 and 1.0
  float analogRead() {
    // dummy write, actual values don't matter
    byte[] out = { 0, 0 };
    byte[] in = transfer(out);
    // some input bit shifting according to the datasheet p. 16
    int val = ((in[0] & 0x1f) << 5) | ((in[1] & 0xf8) >> 3);
    // val is between 0 and 1023
    return val/1023.0;
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Demos/Graphics/DepthSort/DepthSort.pde
// Depth sorting example by <NAME>
// https://github.com/JakubValtar

void setup() {
  size(640, 720, P3D);
  colorMode(HSB, 100, 100, 100, 100);

  frameRate(60);
}

void draw() {
    //beginRaw(PDF, "output" + frameCount + ".pdf");

  if (!mousePressed) {
    hint(ENABLE_DEPTH_SORT);
  } else {
    hint(DISABLE_DEPTH_SORT);
  }

  noStroke();

  background(0);

  translate(width/2, height/2, -300);
  scale(2);

  int rot = frameCount;

  rotateZ(radians(90));
  rotateX(radians(rot/60.0f * 10));
  rotateY(radians(rot/60.0f * 30));

  blendMode(ADD);

  for (int i = 0; i < 100; i++) {
    fill(map(i % 10, 0, 10, 0, 100), 100, 100, 30);

    beginShape(TRIANGLES);
    vertex(200, 50, -50);
    vertex(100, 100, 50);
    vertex(100, 0, 20);
    endShape();

    rotateY(radians(270.0f/100));
  }

  //endRaw();

  if (frameCount % 30 == 0) println(frameRate);
}  <file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Advanced Data/LoadSaveJSON/Bubble.pde
// A Bubble class

class Bubble {
  float x,y;
  float diameter;
  String name;

  boolean over = false;

  // Create  the Bubble
  Bubble(float x_, float y_, float diameter_, String s) {
    x = x_;
    y = y_;
    diameter = diameter_;
    name = s;
  }

  // CHecking if mouse is over the Bubble
  void rollover(float px, float py) {
    float d = dist(px,py,x,y);
    if (d < diameter/2) {
      over = true;
    } else {
      over = false;
    }
  }

  // Display the Bubble
  void display() {
    stroke(0);
    strokeWeight(2);
    noFill();
    ellipse(x,y,diameter,diameter);
    if (over) {
      fill(0);
      textAlign(CENTER);
      text(name,x,y+diameter/2+20);
    }
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Demos/Graphics/Yellowtail/Yellowtail.pde
/**
 * Yellowtail
 * by <NAME> (www.flong.com).
 *
 * Click, drag, and release to create a kinetic gesture.
 *
 * Yellowtail (1998-2000) is an interactive software system for the gestural
 * creation and performance of real-time abstract animation. Yellowtail repeats
 * a user's strokes end-over-end, enabling simultaneous specification of a
 * line's shape and quality of movement. Each line repeats according to its
 * own period, producing an ever-changing and responsive display of lively,
 * worm-like textures.
 */

import java.awt.Polygon;

Gesture gestureArray[];
final int nGestures = 36;  // Number of gestures
final int minMove = 3;     // Minimum travel for a new point
int currentGestureID;

Polygon tempP;
int tmpXp[];
int tmpYp[];

void setup() {
  size(1024, 768, P2D);
  background(0, 0, 0);
  noStroke();

  currentGestureID = -1;
  gestureArray = new Gesture[nGestures];
  for (int i = 0; i < nGestures; i++) {
    gestureArray[i] = new Gesture(width, height);
  }
  clearGestures();
}

void draw() {
  background(0);

  updateGeometry();
  fill(255, 255, 245);
  for (int i = 0; i < nGestures; i++) {
    renderGesture(gestureArray[i], width, height);
  }
}

void mousePressed() {
  currentGestureID = (currentGestureID+1) % nGestures;
  Gesture G = gestureArray[currentGestureID];
  G.clear();
  G.clearPolys();
  G.addPoint(mouseX, mouseY);
}

void mouseDragged() {
  if (currentGestureID >= 0) {
    Gesture G = gestureArray[currentGestureID];
    if (G.distToLast(mouseX, mouseY) > minMove) {
      G.addPoint(mouseX, mouseY);
      G.smooth();
      G.compile();
    }
  }
}

void keyPressed() {
  if (key == '+' || key == '=') {
    if (currentGestureID >= 0) {
      float th = gestureArray[currentGestureID].thickness;
      gestureArray[currentGestureID].thickness = min(96, th+1);
      gestureArray[currentGestureID].compile();
    }
  } else if (key == '-') {
    if (currentGestureID >= 0) {
      float th = gestureArray[currentGestureID].thickness;
      gestureArray[currentGestureID].thickness = max(2, th-1);
      gestureArray[currentGestureID].compile();
    }
  } else if (key == ' ') {
    clearGestures();
  }
}

void renderGesture(Gesture gesture, int w, int h) {
  if (gesture.exists) {
    if (gesture.nPolys > 0) {
      Polygon polygons[] = gesture.polygons;
      int crosses[] = gesture.crosses;

      int xpts[];
      int ypts[];
      Polygon p;
      int cr;

      beginShape(QUADS);
      int gnp = gesture.nPolys;
      for (int i=0; i<gnp; i++) {

        p = polygons[i];
        xpts = p.xpoints;
        ypts = p.ypoints;

        vertex(xpts[0], ypts[0]);
        vertex(xpts[1], ypts[1]);
        vertex(xpts[2], ypts[2]);
        vertex(xpts[3], ypts[3]);

        if ((cr = crosses[i]) > 0) {
          if ((cr & 3)>0) {
            vertex(xpts[0]+w, ypts[0]);
            vertex(xpts[1]+w, ypts[1]);
            vertex(xpts[2]+w, ypts[2]);
            vertex(xpts[3]+w, ypts[3]);

            vertex(xpts[0]-w, ypts[0]);
            vertex(xpts[1]-w, ypts[1]);
            vertex(xpts[2]-w, ypts[2]);
            vertex(xpts[3]-w, ypts[3]);
          }
          if ((cr & 12)>0) {
            vertex(xpts[0], ypts[0]+h);
            vertex(xpts[1], ypts[1]+h);
            vertex(xpts[2], ypts[2]+h);
            vertex(xpts[3], ypts[3]+h);

            vertex(xpts[0], ypts[0]-h);
            vertex(xpts[1], ypts[1]-h);
            vertex(xpts[2], ypts[2]-h);
            vertex(xpts[3], ypts[3]-h);
          }

          // I have knowingly retained the small flaw of not
          // completely dealing with the corner conditions
          // (the case in which both of the above are true).
        }
      }
      endShape();
    }
  }
}

void updateGeometry() {
  Gesture J;
  for (int g=0; g<nGestures; g++) {
    if ((J=gestureArray[g]).exists) {
      if (g!=currentGestureID) {
        advanceGesture(J);
      } else if (!mousePressed) {
        advanceGesture(J);
      }
    }
  }
}

void advanceGesture(Gesture gesture) {
  // Move a Gesture one step
  if (gesture.exists) { // check
    int nPts = gesture.nPoints;
    int nPts1 = nPts-1;
    Vec3f path[];
    float jx = gesture.jumpDx;
    float jy = gesture.jumpDy;

    if (nPts > 0) {
      path = gesture.path;
      for (int i = nPts1; i > 0; i--) {
        path[i].x = path[i-1].x;
        path[i].y = path[i-1].y;
      }
      path[0].x = path[nPts1].x - jx;
      path[0].y = path[nPts1].y - jy;
      gesture.compile();
    }
  }
}

void clearGestures() {
  for (int i = 0; i < nGestures; i++) {
    gestureArray[i].clear();
  }
}
<file_sep>/Data and System Management/app/main/forms.py
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, SelectMultipleField, widgets, SelectField
from wtforms.fields.html5 import DateTimeField, DateField
from wtforms.validators import DataRequired

class PumpForm(FlaskForm):
    payload = StringField('PumpID - Programmed payload on ESP8266')
    location = StringField('Indicated location')
    pumpsubmit = SubmitField('Add')

class RequestData(FlaskForm):
    topic = SelectField('Standardized Time', choices=[('hour', 'Hourly use'), ('day', 'Daily use'),
                                                      ('week', 'Weekly use'), ('month', 'Monthly use'), ('custom', 'Custom timerange')])
    date1 = DateField('Start Date')
    date2 = DateField('End Date')
    type = SelectField('Type of graph requested', choices=[('bar', 'Bar'), ('line', 'Line')]) # ('stack', 'Stack'),

    pump = SelectMultipleField('Select Pumps', coerce=str)

    requestsubmit = SubmitField('Request')

class RequestExport(FlaskForm):
    date1 = DateField('Start Date')
    date2 = DateField('End Date')

    requestsubmit = SubmitField('Request')
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/src/processing/mode/java/JavaMode.java
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
  Part of the Processing project - http://processing.org

  Copyright (c) 2010-11 <NAME> and <NAME>
  Copyright (c) 2012-15 The Processing Foundation

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License version 2
  as published by the Free Software Foundation.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software Foundation,
  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

package processing.mode.java;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.swing.SwingUtilities;

import processing.app.*;
import processing.app.ui.Editor;
import processing.app.ui.EditorException;
import processing.app.ui.EditorState;
import processing.mode.java.runner.Runner;
import processing.mode.java.tweak.SketchParser;

public class JavaMode extends Mode {

  public Editor createEditor(Base base, String path,
                             EditorState state) throws EditorException {
    return new JavaEditor(base, path, state, this);
  }

  public JavaMode(Base base, File folder) {
    super(base, folder);

//    initLogger();
    loadPreferences();
  }

  public String getTitle() {
    return "Java";
  }

  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

  public File[] getExampleCategoryFolders() {
    return new File[] {
      new File(examplesFolder, "Basics"),
      new File(examplesFolder, "Topics"),
      new File(examplesFolder, "Demos"),
      new File(examplesFolder, "Books")
    };
  }

  public String getDefaultExtension() {
    return "pde";
  }

  public String[] getExtensions() {
    return new String[] { "pde", "java" };
  }

  public String[] getIgnorable() {
    return new String[] {
      "applet",
      "application.macosx",
      "application.windows",
      "application.linux"
    };
  }

  public Library getCoreLibrary() {
    if (coreLibrary == null) {
      File coreFolder = Platform.getContentFile("core");
      coreLibrary = new Library(coreFolder);
//      try {
//        coreLibrary = getLibrary("processing.core");
//        System.out.println("core found at " + coreLibrary.getLibraryPath());
//      } catch (SketchException e) {
//        Base.log("Serious problem while locating processing.core", e);
//      }
    }
    return coreLibrary;
  }

  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

  /** Handles the standard Java "Run" or "Present" */
  public Runner handleLaunch(Sketch sketch, RunnerListener listener,
                             final boolean present) throws SketchException {
    JavaBuild build = new JavaBuild(sketch);
//    String appletClassName = build.build(false);
    String appletClassName = build.build(true);
    if (appletClassName != null) {
      final Runner runtime = new Runner(build, listener);
      new Thread(new Runnable() {
        public void run() {
          // these block until finished
          if (present) {
            runtime.present(null);
          } else {
            runtime.launch(null);
          }
        }
      }).start();
      return runtime;
    }
    return null;
  }

  /** Start a sketch in tweak mode */
  public Runner handleTweak(Sketch sketch,
                            RunnerListener listener) throws SketchException {
//                            final boolean present) throws SketchException {
    final JavaEditor editor = (JavaEditor) listener;

    // first try to build the unmodified code
    JavaBuild build = new JavaBuild(sketch);
//    String appletClassName = build.build(false);
    String appletClassName = build.build(true);
    if (appletClassName == null) {
      // unmodified build failed, so fail
      return null;
    }

    // if compilation passed, modify the code and build again
    // save the original sketch code of the user
    editor.initBaseCode();
    // check for "// tweak" comment in the sketch
    boolean requiresTweak = SketchParser.containsTweakComment(editor.baseCode);
    // parse the saved sketch to get all (or only with "//tweak" comment) numbers
    final SketchParser parser = new SketchParser(editor.baseCode, requiresTweak);

    // add our code to the sketch
    final boolean launchInteractive = editor.automateSketch(sketch, parser);

    build = new JavaBuild(sketch);
    appletClassName = build.build(false);

    if (appletClassName != null) {
      final Runner runtime = new Runner(build, listener);
      new Thread(new Runnable() {
        public void run() {
          // these block until finished
//          if (present) {
//            runtime.present(null);
//          } else {
          runtime.launch(null);
//          }
          // next lines are executed when the sketch quits
          if (launchInteractive) {
            // fix swing deadlock issue: https://github.com/processing/processing/issues/3928
            SwingUtilities.invokeLater(new Runnable() {
              public void run() {
                editor.initEditorCode(parser.allHandles, false);
                editor.stopTweakMode(parser.allHandles);
              }
            });
          }
        }
      }).start();

      if (launchInteractive) {
        // fix swing deadlock issue: https://github.com/processing/processing/issues/3928
        SwingUtilities.invokeLater(new Runnable() {
          public void run() {
            // replace editor code with baseCode
            editor.initEditorCode(parser.allHandles, false);
            editor.updateInterface(parser.allHandles, parser.colorBoxes);
            editor.startTweakMode();
          }
        });
      }
      return runtime;
    }
    return null;
  }

  /*
  // TODO Why is this necessary? Why isn't Sketch.isModified() used?
  static private boolean isSketchModified(Sketch sketch) {
    for (SketchCode sc : sketch.getCode()) {
      if (sc.isModified()) {
        return true;
      }
    }
    return false;
  }
  */

//  public void handleStop() {
//    if (runtime != null) {
//      runtime.close();  // kills the window
//      runtime = null; // will this help?
//    }
//  }

//  public boolean handleExportApplet(Sketch sketch) throws SketchException, IOException {
//    JavaBuild build = new JavaBuild(sketch);
//    return build.exportApplet();
//  }

  public boolean handleExportApplication(Sketch sketch) throws SketchException, IOException {
    JavaBuild build = new JavaBuild(sketch);
    return build.exportApplication();
  }

  /**
   * Any modes that extend JavaMode can override this method to add additional
   * JARs to be included in the classpath for code completion and error checking
   * @return searchPath: file-paths separated by File.pathSeparatorChar
   */
  public String getSearchPath() {
    return getCoreLibrary().getJarPath();
  }

  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

  // Merged from ExperimentalMode

  /*
  void initLogger() {
    final boolean VERBOSE_LOGGING = true;
    final int LOG_SIZE = 512 * 1024; // max log file size (in bytes)

    Logger globalLogger = Logger.getLogger("");
    //Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); // doesn't work on os x
    if (VERBOSE_LOGGING) {
      globalLogger.setLevel(Level.INFO);
    } else {
      globalLogger.setLevel(Level.WARNING);
    }

    // enable logging to file
    try {
      // settings is writable for built-in modes, mode folder is not writable
      File logFolder = Base.getSettingsFile("debug");
      if (!logFolder.exists()) {
        logFolder.mkdir();
      }
      File logFile = new File(logFolder, "DebugMode.%g.log");
      Handler handler = new FileHandler(logFile.getAbsolutePath(), LOG_SIZE, 10, false);
      globalLogger.addHandler(handler);

    } catch (IOException ex) {
      Logger.getLogger(JavaMode.class.getName()).log(Level.SEVERE, null, ex);
    } catch (SecurityException ex) {
      Logger.getLogger(JavaMode.class.getName()).log(Level.SEVERE, null, ex);
    }
  }
  */

  //ImageIcon classIcon, fieldIcon, methodIcon, localVarIcon;

//  protected void loadIcons() {
//    String iconPath = getContentFile("data").getAbsolutePath() + File.separator + "icons";
//    classIcon = new ImageIcon(iconPath + File.separator + "class_obj.png");
//    methodIcon = new ImageIcon(iconPath + File.separator + "methpub_obj.png");
//    fieldIcon = new ImageIcon(iconPath + File.separator + "field_protected_obj.png");
//    localVarIcon = new ImageIcon(iconPath + File.separator + "field_default_obj.png");
//  }

  static public volatile boolean errorCheckEnabled = true;
  static public volatile boolean warningsEnabled = true;
  static public volatile boolean codeCompletionsEnabled = true;
  static public volatile boolean debugOutputEnabled = false;
  static public volatile boolean errorLogsEnabled = false;
  static public volatile boolean autoSaveEnabled = true;
  static public volatile boolean autoSavePromptEnabled = true;
  static public volatile boolean defaultAutoSaveEnabled = true;
  static public volatile boolean ccTriggerEnabled = false;
  static public volatile boolean importSuggestEnabled = true;
  static public volatile boolean inspectModeHotkeyEnabled = true;
  static public int autoSaveInterval = 3; //in minutes

  /**
   * After how many typed characters, code completion is triggered
   */
  volatile public static int codeCompletionTriggerLength = 1;

  static public final String prefErrorCheck = "pdex.errorCheckEnabled";
  static public final String prefWarnings = "pdex.warningsEnabled";
  static public final String prefDebugOP = "pdex.dbgOutput";
  static public final String prefErrorLogs = "pdex.writeErrorLogs";
  static public final String prefAutoSaveInterval = "pdex.autoSaveInterval";
  static public final String prefAutoSave = "pdex.autoSave.autoSaveEnabled";
  static public final String prefAutoSavePrompt = "pdex.autoSave.promptDisplay";
  static public final String prefDefaultAutoSave = "pdex.autoSave.autoSaveByDefault";
  static public final String suggestionsFileName = "suggestions.txt";

  static public final String COMPLETION_PREF = "pdex.completion";
  static public final String COMPLETION_TRIGGER_PREF = "pdex.completion.trigger";
  static public final String SUGGEST_IMPORTS_PREF = "pdex.suggest.imports";
  static public final String INSPECT_MODE_HOTKEY_PREF = "pdex.inspectMode.hotkey";

//  static volatile public boolean enableTweak = false;

  /**
   * Stores the white list/black list of allowed/blacklisted imports. These are defined in
   * suggestions.txt in java mode folder.
   */
  static public final Map<String, Set<String>> suggestionsMap = new HashMap<>();

  public void loadPreferences() {
    Messages.log("Load PDEX prefs");
    ensurePrefsExist();
    errorCheckEnabled = Preferences.getBoolean(prefErrorCheck);
    warningsEnabled = Preferences.getBoolean(prefWarnings);
    codeCompletionsEnabled = Preferences.getBoolean(COMPLETION_PREF);
//    DEBUG = Preferences.getBoolean(prefDebugOP);
    errorLogsEnabled = Preferences.getBoolean(prefErrorLogs);
    autoSaveInterval = Preferences.getInteger(prefAutoSaveInterval);
//    untitledAutoSaveEnabled = Preferences.getBoolean(prefUntitledAutoSave);
    autoSaveEnabled = Preferences.getBoolean(prefAutoSave);
    autoSavePromptEnabled = Preferences.getBoolean(prefAutoSavePrompt);
    defaultAutoSaveEnabled = Preferences.getBoolean(prefDefaultAutoSave);
    ccTriggerEnabled = Preferences.getBoolean(COMPLETION_TRIGGER_PREF);
    importSuggestEnabled = Preferences.getBoolean(SUGGEST_IMPORTS_PREF);
    inspectModeHotkeyEnabled = Preferences.getBoolean(INSPECT_MODE_HOTKEY_PREF);
    loadSuggestionsMap();
  }

  public void savePreferences() {
    Messages.log("Saving PDEX prefs");
    Preferences.setBoolean(prefErrorCheck, errorCheckEnabled);
    Preferences.setBoolean(prefWarnings, warningsEnabled);
    Preferences.setBoolean(COMPLETION_PREF, codeCompletionsEnabled);
//    Preferences.setBoolean(prefDebugOP, DEBUG);
    Preferences.setBoolean(prefErrorLogs, errorLogsEnabled);
    Preferences.setInteger(prefAutoSaveInterval, autoSaveInterval);
//    Preferences.setBoolean(prefUntitledAutoSave,untitledAutoSaveEnabled);
    Preferences.setBoolean(prefAutoSave, autoSaveEnabled);
    Preferences.setBoolean(prefAutoSavePrompt, autoSavePromptEnabled);
    Preferences.setBoolean(prefDefaultAutoSave, defaultAutoSaveEnabled);
    Preferences.setBoolean(COMPLETION_TRIGGER_PREF, ccTriggerEnabled);
    Preferences.setBoolean(SUGGEST_IMPORTS_PREF, importSuggestEnabled);
    Preferences.setBoolean(INSPECT_MODE_HOTKEY_PREF, inspectModeHotkeyEnabled);
  }

  public void loadSuggestionsMap() {
    File suggestionsListFile = new File(getFolder() + File.separator
        + suggestionsFileName);
    if (!suggestionsListFile.exists()) {
      Messages.loge("Suggestions file not found! "
          + suggestionsListFile.getAbsolutePath());
      return;
    }

    try {
      BufferedReader br = new BufferedReader(
                                             new FileReader(suggestionsListFile));
      while (true) {
        String line = br.readLine();
        if (line == null) {
          break;
        }
        line = line.trim();
        if (line.startsWith("#")) {
          continue;
        } else {
          if (line.contains("=")) {
            String key = line.split("=")[0];
            String val = line.split("=")[1];
            if (suggestionsMap.containsKey(key)) {
              suggestionsMap.get(key).add(val);
            } else {
              HashSet<String> set = new HashSet<>();
              set.add(val);
              suggestionsMap.put(key, set);
            }
          }
        }
      }
      br.close();
    } catch (IOException e) {
      Messages.loge("IOException while reading suggestions file:"
          + suggestionsListFile.getAbsolutePath());
    }
  }

  public void ensurePrefsExist() {
    //TODO: Need to do a better job of managing prefs. Think lists.
    if (Preferences.get(prefErrorCheck) == null)
      Preferences.setBoolean(prefErrorCheck, errorCheckEnabled);
    if (Preferences.get(prefWarnings) == null)
      Preferences.setBoolean(prefWarnings, warningsEnabled);
    if (Preferences.get(COMPLETION_PREF) == null)
      Preferences.setBoolean(COMPLETION_PREF, codeCompletionsEnabled);
    if (Preferences.get(prefDebugOP) == null)
//      Preferences.setBoolean(prefDebugOP, DEBUG);
    if (Preferences.get(prefErrorLogs) == null)
      Preferences.setBoolean(prefErrorLogs, errorLogsEnabled);
    if (Preferences.get(prefAutoSaveInterval) == null)
      Preferences.setInteger(prefAutoSaveInterval, autoSaveInterval);
//    if(Preferences.get(prefUntitledAutoSave) == null)
//      Preferences.setBoolean(prefUntitledAutoSave,untitledAutoSaveEnabled);
    if (Preferences.get(prefAutoSave) == null)
      Preferences.setBoolean(prefAutoSave, autoSaveEnabled);
    if (Preferences.get(prefAutoSavePrompt) == null)
      Preferences.setBoolean(prefAutoSavePrompt, autoSavePromptEnabled);
    if (Preferences.get(prefDefaultAutoSave) == null)
      Preferences.setBoolean(prefDefaultAutoSave, defaultAutoSaveEnabled);
    if (Preferences.get(COMPLETION_TRIGGER_PREF) == null)
      Preferences.setBoolean(COMPLETION_TRIGGER_PREF, ccTriggerEnabled);
    if (Preferences.get(SUGGEST_IMPORTS_PREF) == null)
      Preferences.setBoolean(SUGGEST_IMPORTS_PREF, importSuggestEnabled);
    if (Preferences.get(INSPECT_MODE_HOTKEY_PREF) == null)
      Preferences.setBoolean(INSPECT_MODE_HOTKEY_PREF, inspectModeHotkeyEnabled);
  }

  static public void main(String[] args) {
    processing.app.Base.main(args);
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/src/processing/mode/java/pdex/PreprocessingService.java
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
Part of the Processing project - http://processing.org
Copyright (c) 2012-15 The Processing Foundation

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package processing.mode.java.pdex;

import com.google.classpath.ClassPathFactory;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

import javax.swing.text.BadLocationException;

import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.CompilationUnit;

import processing.app.Library;
import processing.app.Messages;
import processing.app.Sketch;
import processing.app.SketchCode;
import processing.app.SketchException;
import processing.app.Util;
import processing.data.IntList;
import processing.data.StringList;
import processing.mode.java.JavaEditor;
import processing.mode.java.JavaMode;
import processing.mode.java.pdex.TextTransform.OffsetMapper;
import processing.mode.java.preproc.PdePreprocessor;
import processing.mode.java.preproc.PdePreprocessor.Mode;

/**
 * The main error checking service
 */
public class PreprocessingService {

  protected final JavaEditor editor;

  protected final ASTParser parser = ASTParser.newParser(AST.JLS8);

  private final ClassPathFactory classPathFactory = new ClassPathFactory();

  private final Thread preprocessingThread;
  private final BlockingQueue<Boolean> requestQueue = new ArrayBlockingQueue<>(1);

  private final Object requestLock = new Object();

  private final AtomicBoolean codeFolderChanged = new AtomicBoolean(true);
  private final AtomicBoolean librariesChanged = new AtomicBoolean(true);

  private volatile boolean running;
  private CompletableFuture<PreprocessedSketch> preprocessingTask = new CompletableFuture<>();

  private CompletableFuture<?> lastCallback =
      new CompletableFuture<Object>() {{
        complete(null); // initialization block
      }};

  private volatile boolean isEnabled = true;

  public PreprocessingService(JavaEditor editor) {
    this.editor = editor;
    isEnabled = !editor.hasJavaTabs();

    // Register listeners for first run
    whenDone(this::fireListeners);

    preprocessingThread = new Thread(this::mainLoop, "ECS");
    preprocessingThread.start();
  }

  private void mainLoop() {
    running = true;
    PreprocessedSketch prevResult = null;
    CompletableFuture<?> runningCallbacks = null;
    Messages.log("PPS: Hi!");
    while (running) {
      try {
        try {
          requestQueue.take(); // blocking until requested
        } catch (InterruptedException e) {
          running = false;
          break;
        }

        Messages.log("PPS: Starting");

        prevResult = preprocessSketch(prevResult);

        // Wait until callbacks finish before firing new wave
        // If new request arrives while waiting, break out and start preprocessing
        while (requestQueue.isEmpty() && runningCallbacks != null) {
          try {
            runningCallbacks.get(10, TimeUnit.MILLISECONDS);
            runningCallbacks = null;
          } catch (TimeoutException e) { }
        }

        synchronized (requestLock) {
          if (requestQueue.isEmpty()) {
            runningCallbacks = lastCallback;
            Messages.log("PPS: Done");
            preprocessingTask.complete(prevResult);
          }
        }
      } catch (Exception e) {
        Messages.loge("problem in preprocessor service loop", e);
      }
    }
    Messages.log("PPS: Bye!");
  }

  public void dispose() {
    cancel();
    running = false;
    preprocessingThread.interrupt();
  }

  public void cancel() {
    requestQueue.clear();
  }

  public void notifySketchChanged() {
    if (!isEnabled) return;
    synchronized (requestLock) {
      if (preprocessingTask.isDone()) {
        preprocessingTask = new CompletableFuture<>();
        // Register callback which executes all listeners
        whenDone(this::fireListeners);
      }
      requestQueue.offer(Boolean.TRUE);
    }
  }

  public void notifyLibrariesChanged() {
    Messages.log("PPS: notified libraries changed");
    librariesChanged.set(true);
    notifySketchChanged();
  }

  public void notifyCodeFolderChanged() {
    Messages.log("PPS: snotified code folder changed");
    codeFolderChanged.set(true);
    notifySketchChanged();
  }

  private CompletableFuture<?> registerCallback(Consumer<PreprocessedSketch> callback) {
    synchronized (requestLock) {
      lastCallback = preprocessingTask
          // Run callback after both preprocessing task and previous callback
          .thenAcceptBothAsync(lastCallback, (ps, a) -> callback.accept(ps))
          // Make sure exception in callback won't cancel whole callback chain
          .handleAsync((res, e) -> {
            if (e != null) Messages.loge("PPS: exception in callback", e);
            return res;
          });
      return lastCallback;
    }
  }

  public void whenDone(Consumer<PreprocessedSketch> callback) {
    if (!isEnabled) return;
    registerCallback(callback);
  }

  public void whenDoneBlocking(Consumer<PreprocessedSketch> callback) {
    if (!isEnabled) return;
    try {
      registerCallback(callback).get(3000, TimeUnit.SECONDS);
    } catch (InterruptedException | ExecutionException | TimeoutException e) {
      // Don't care
    }
  }

  /// LISTENERS ----------------------------------------------------------------

  private Set<Consumer<PreprocessedSketch>> listeners = new CopyOnWriteArraySet<>();

  public void registerListener(Consumer<PreprocessedSketch> listener) {
    if (listener != null) listeners.add(listener);
  }

  public void unregisterListener(Consumer<PreprocessedSketch> listener) {
    listeners.remove(listener);
  }

  private void fireListeners(PreprocessedSketch ps) {
    for (Consumer<PreprocessedSketch> listener : listeners) {
      try {
        listener.accept(ps);
      } catch (Exception e) {
        Messages.loge("error when firing preprocessing listener", e);
      }
    }
  }

  /// --------------------------------------------------------------------------

  private PreprocessedSketch preprocessSketch(PreprocessedSketch prevResult) {

    boolean firstCheck = prevResult == null;

    PreprocessedSketch.Builder result = new PreprocessedSketch.Builder();

    List<ImportStatement> codeFolderImports = result.codeFolderImports;
    List<ImportStatement> programImports = result.programImports;

    JavaMode javaMode = (JavaMode) editor.getMode();
    Sketch sketch = result.sketch = editor.getSketch();
    String className = sketch.getName();

    StringBuilder workBuffer = new StringBuilder();

    // Combine code into one buffer
    IntList tabStartsList = new IntList();
    for (SketchCode sc : sketch.getCode()) {
      if (sc.isExtension("pde")) {
        tabStartsList.append(workBuffer.length());
        if (sc.getDocument() != null) {
          try {
            workBuffer.append(sc.getDocumentText());
          } catch (BadLocationException e) {
            e.printStackTrace();
          }
        } else {
          workBuffer.append(sc.getProgram());
        }
        workBuffer.append('\n');
      }
    }
    result.tabStartOffsets = tabStartsList.array();

    String pdeStage = result.pdeCode = workBuffer.toString();

    boolean reloadCodeFolder = firstCheck || codeFolderChanged.getAndSet(false);
    boolean reloadLibraries = firstCheck || librariesChanged.getAndSet(false);

    // Core and default imports
    if (coreAndDefaultImports == null) {
      PdePreprocessor p = editor.createPreprocessor(null);
      coreAndDefaultImports = buildCoreAndDefaultImports(p);
    }
    result.coreAndDefaultImports.addAll(coreAndDefaultImports);

    // Prepare code folder imports
    if (reloadCodeFolder) {
      codeFolderImports.addAll(buildCodeFolderImports(sketch));
    } else {
      codeFolderImports.addAll(prevResult.codeFolderImports);
    }

    // TODO: convert unicode escapes to chars

    SourceUtils.scrubCommentsAndStrings(workBuffer);

    result.scrubbedPdeCode = workBuffer.toString();

    Mode sketchMode = PdePreprocessor.parseMode(workBuffer);

    // Prepare transforms to convert pde code into parsable code
    TextTransform toParsable = new TextTransform(pdeStage);
    toParsable.addAll(SourceUtils.insertImports(coreAndDefaultImports));
    toParsable.addAll(SourceUtils.insertImports(codeFolderImports));
    toParsable.addAll(SourceUtils.parseProgramImports(workBuffer, programImports));
    toParsable.addAll(SourceUtils.replaceTypeConstructors(workBuffer));
    toParsable.addAll(SourceUtils.replaceHexLiterals(workBuffer));
    toParsable.addAll(SourceUtils.wrapSketch(sketchMode, className, workBuffer.length()));

    { // Refresh sketch classloader and classpath if imports changed
      if (javaRuntimeClassPath == null) {
        javaRuntimeClassPath = buildJavaRuntimeClassPath();
        sketchModeClassPath = buildModeClassPath(javaMode, false);
        searchModeClassPath = buildModeClassPath(javaMode, true);
      }

      if (reloadLibraries) {
        coreLibraryClassPath = buildCoreLibraryClassPath(javaMode);
      }

      boolean rebuildLibraryClassPath = reloadLibraries ||
          checkIfImportsChanged(programImports, prevResult.programImports);

      if (rebuildLibraryClassPath) {
        sketchLibraryClassPath = buildSketchLibraryClassPath(javaMode, programImports);
        searchLibraryClassPath = buildSearchLibraryClassPath(javaMode);
      }

      boolean rebuildClassPath = reloadCodeFolder || rebuildLibraryClassPath ||
          prevResult.classLoader == null || prevResult.classPath == null ||
          prevResult.classPathArray == null || prevResult.searchClassPathArray == null;

      if (reloadCodeFolder) {
        codeFolderClassPath = buildCodeFolderClassPath(sketch);
      }

      if (rebuildClassPath) {
        { // Sketch class path
          List<String> sketchClassPath = new ArrayList<>();
          sketchClassPath.addAll(javaRuntimeClassPath);
          sketchClassPath.addAll(sketchModeClassPath);
          sketchClassPath.addAll(sketchLibraryClassPath);
          sketchClassPath.addAll(coreLibraryClassPath);
          sketchClassPath.addAll(codeFolderClassPath);

          String[] classPathArray = sketchClassPath.stream().toArray(String[]::new);
          URL[] urlArray = Arrays.stream(classPathArray)
              .map(path -> {
                try {
                  return Paths.get(path).toUri().toURL();
                } catch (MalformedURLException e) {
                  Messages.loge("malformed URL when preparing sketch classloader", e);
                  return null;
                }
              })
              .filter(url -> url != null)
              .toArray(URL[]::new);
          result.classLoader = new URLClassLoader(urlArray, null);
          result.classPath = classPathFactory.createFromPaths(classPathArray);
          result.classPathArray = classPathArray;
        }

        { // Search class path
          List<String> searchClassPath = new ArrayList<>();
          searchClassPath.addAll(javaRuntimeClassPath);
          searchClassPath.addAll(searchModeClassPath);
          searchClassPath.addAll(searchLibraryClassPath);
          searchClassPath.addAll(coreLibraryClassPath);
          searchClassPath.addAll(codeFolderClassPath);

          result.searchClassPathArray = searchClassPath.stream().toArray(String[]::new);
        }
      } else {
        result.classLoader = prevResult.classLoader;
        result.classPath = prevResult.classPath;
        result.searchClassPathArray = prevResult.searchClassPathArray;
        result.classPathArray = prevResult.classPathArray;
      }
    }

    // Transform code to parsable state
    String parsableStage = toParsable.apply();
    OffsetMapper parsableMapper = toParsable.getMapper();

    // Create intermediate AST for advanced preprocessing
    CompilationUnit parsableCU =
        makeAST(parser, parsableStage.toCharArray(), COMPILER_OPTIONS);

    // Prepare advanced transforms which operate on AST
    TextTransform toCompilable = new TextTransform(parsableStage);
    toCompilable.addAll(SourceUtils.preprocessAST(parsableCU));

    // Transform code to compilable state
    String compilableStage = toCompilable.apply();
    OffsetMapper compilableMapper = toCompilable.getMapper();
    char[] compilableStageChars = compilableStage.toCharArray();

    // Create compilable AST to get syntax problems
    CompilationUnit compilableCU =
        makeAST(parser, compilableStageChars, COMPILER_OPTIONS);

    // Get syntax problems from compilable AST
    result.hasSyntaxErrors |= Arrays.stream(compilableCU.getProblems())
        .anyMatch(IProblem::isError);

    // Generate bindings after getting problems - avoids
    // 'missing type' errors when there are syntax problems
    CompilationUnit bindingsCU =
        makeASTWithBindings(parser, compilableStageChars, COMPILER_OPTIONS,
                            className, result.classPathArray);

    // Get compilation problems
    List<IProblem> bindingsProblems = Arrays.asList(bindingsCU.getProblems());
    result.hasCompilationErrors = bindingsProblems.stream()
        .anyMatch(IProblem::isError);

    // Update builder
    result.offsetMapper = parsableMapper.thenMapping(compilableMapper);
    result.javaCode = compilableStage;
    result.compilationUnit = bindingsCU;

    // Build it
    return result.build();
  }

  /// IMPORTS -----------------------------------------------------------------

  private List<ImportStatement> coreAndDefaultImports;

  private static List<ImportStatement> buildCoreAndDefaultImports(PdePreprocessor p) {
    List<ImportStatement> result = new ArrayList<>();

    for (String imp : p.getCoreImports()) {
      result.add(ImportStatement.parse(imp));
    }
    for (String imp : p.getDefaultImports()) {
      result.add(ImportStatement.parse(imp));
    }

    return result;
  }

  private static List<ImportStatement> buildCodeFolderImports(Sketch sketch) {
    if (sketch.hasCodeFolder()) {
      File codeFolder = sketch.getCodeFolder();
      String codeFolderClassPath = Util.contentsToClassPath(codeFolder);
      StringList codeFolderPackages = Util.packageListFromClassPath(codeFolderClassPath);
      return StreamSupport.stream(codeFolderPackages.spliterator(), false)
          .map(ImportStatement::wholePackage)
          .collect(Collectors.toList());
    }
    return Collections.emptyList();
  }

  private static boolean checkIfImportsChanged(List<ImportStatement> prevImports,
                                                 List<ImportStatement> imports) {
    if (imports.size() != prevImports.size()) {
      return true;
    } else {
      int count = imports.size();
      for (int i = 0; i < count; i++) {
        if (!imports.get(i).isSameAs(prevImports.get(i))) {
          return true;
        }
      }
    }
    return false;
  }

  /// CLASSPATHS ---------------------------------------------------------------

  private List<String> javaRuntimeClassPath;

  private List<String> sketchModeClassPath;
  private List<String> searchModeClassPath;

  private List<String> coreLibraryClassPath;

  private List<String> codeFolderClassPath;

  private List<String> sketchLibraryClassPath;
  private List<String> searchLibraryClassPath;

  private static List<String> buildCodeFolderClassPath(Sketch sketch) {
    StringBuilder classPath = new StringBuilder();

    // Code folder
    if (sketch.hasCodeFolder()) {
      File codeFolder = sketch.getCodeFolder();
      String codeFolderClassPath = Util.contentsToClassPath(codeFolder);
      classPath.append(codeFolderClassPath);
    }

    return sanitizeClassPath(classPath.toString());
  }

  private static List<String> buildModeClassPath(JavaMode mode, boolean search) {
    StringBuilder classPath = new StringBuilder();

    if (search) {
      String searchClassPath = mode.getSearchPath();
      if (searchClassPath != null) {
        classPath.append(File.pathSeparator).append(searchClassPath);
      }
    } else {
      Library coreLibrary = mode.getCoreLibrary();
      String coreClassPath = coreLibrary != null ?
          coreLibrary.getClassPath() : mode.getSearchPath();
      if (coreClassPath != null) {
        classPath.append(File.pathSeparator).append(coreClassPath);
      }
    }

    return sanitizeClassPath(classPath.toString());
  }

  private static List<String> buildCoreLibraryClassPath(JavaMode mode) {
    StringBuilder classPath = new StringBuilder();

    for (Library lib : mode.coreLibraries) {
      classPath.append(File.pathSeparator).append(lib.getClassPath());
    }

    return sanitizeClassPath(classPath.toString());
  }

  private static List<String> buildSearchLibraryClassPath(JavaMode mode) {
    StringBuilder classPath = new StringBuilder();

    for (Library lib : mode.contribLibraries) {
      classPath.append(File.pathSeparator).append(lib.getClassPath());
    }

    return sanitizeClassPath(classPath.toString());
  }

  static private List<String> buildSketchLibraryClassPath(JavaMode mode,
                                                          List<ImportStatement> programImports) {
    StringBuilder classPath = new StringBuilder();

    programImports.stream()
        .map(ImportStatement::getPackageName)
        .filter(pckg -> !ignorableImport(pckg))
        .map(pckg -> {
          try {
            return mode.getLibrary(pckg);
          } catch (SketchException e) {
            return null;
          }
        })
        .filter(lib -> lib != null)
        .map(Library::getClassPath)
        .forEach(cp -> classPath.append(File.pathSeparator).append(cp));

    return sanitizeClassPath(classPath.toString());
  }

  static private List<String> buildJavaRuntimeClassPath() {
    StringBuilder classPath = new StringBuilder();

    { // Java runtime
      String rtPath = System.getProperty("java.home") +
          File.separator + "lib" + File.separator + "rt.jar";
      if (new File(rtPath).exists()) {
        classPath.append(File.pathSeparator).append(rtPath);
      } else {
        rtPath = System.getProperty("java.home") + File.separator + "jre" +
            File.separator + "lib" + File.separator + "rt.jar";
        if (new File(rtPath).exists()) {
          classPath.append(File.pathSeparator).append(rtPath);
        }
      }
    }

    { // JavaFX runtime
      String jfxrtPath = System.getProperty("java.home") +
          File.separator + "lib" + File.separator + "ext" + File.separator + "jfxrt.jar";
      if (new File(jfxrtPath).exists()) {
        classPath.append(File.pathSeparator).append(jfxrtPath);
      } else {
        jfxrtPath = System.getProperty("java.home") + File.separator + "jre" +
            File.separator + "lib" + File.separator + "ext" + File.separator + "jfxrt.jar";
        if (new File(jfxrtPath).exists()) {
          classPath.append(File.pathSeparator).append(jfxrtPath);
        }
      }
    }

    return sanitizeClassPath(classPath.toString());
  }

  private static List<String> sanitizeClassPath(String classPathString) {
    // Make sure class path does not contain empty string (home dir)
    return Arrays.stream(classPathString.split(File.pathSeparator))
        .filter(p -> p != null && !p.trim().isEmpty())
        .distinct()
        .collect(Collectors.toList());
  }

  /// --------------------------------------------------------------------------

  private static CompilationUnit makeAST(ASTParser parser,
                                           char[] source,
                                           Map<String, String> options) {
    parser.setSource(source);
    parser.setKind(ASTParser.K_COMPILATION_UNIT);
    parser.setCompilerOptions(options);
    parser.setStatementsRecovery(true);

    return (CompilationUnit) parser.createAST(null);
  }

  private static CompilationUnit makeASTWithBindings(ASTParser parser,
                                                       char[] source,
                                                       Map<String, String> options,
                                                       String className,
                                                       String[] classPath) {
    parser.setSource(source);
    parser.setKind(ASTParser.K_COMPILATION_UNIT);
    parser.setCompilerOptions(options);
    parser.setStatementsRecovery(true);
    parser.setUnitName(className);
    parser.setEnvironment(classPath, null, null, false);
    parser.setResolveBindings(true);

    return (CompilationUnit) parser.createAST(null);
  }

  /**
   * Ignore processing packages, java.*.*. etc.
   */
  static private boolean ignorableImport(String packageName) {
    return (packageName.startsWith("java.") ||
            packageName.startsWith("javax."));
  }

  static private final Map<String, String> COMPILER_OPTIONS;
  static {
    Map<String, String> compilerOptions = new HashMap<>();

    JavaCore.setComplianceOptions(JavaCore.VERSION_1_7, compilerOptions);

    // See http://help.eclipse.org/mars/index.jsp?topic=%2Forg.eclipse.jdt.doc.isv%2Fguide%2Fjdt_api_options.htm&anchor=compiler

    final String[] generate = {
        JavaCore.COMPILER_LINE_NUMBER_ATTR,
        JavaCore.COMPILER_SOURCE_FILE_ATTR
    };

    final String[] ignore = {
        JavaCore.COMPILER_PB_UNUSED_IMPORT,
        JavaCore.COMPILER_PB_MISSING_SERIAL_VERSION,
        JavaCore.COMPILER_PB_RAW_TYPE_REFERENCE,
        JavaCore.COMPILER_PB_REDUNDANT_TYPE_ARGUMENTS,
        JavaCore.COMPILER_PB_UNCHECKED_TYPE_OPERATION
    };

    final String[] warn = {
        JavaCore.COMPILER_PB_NO_EFFECT_ASSIGNMENT,
        JavaCore.COMPILER_PB_NULL_REFERENCE,
        JavaCore.COMPILER_PB_POTENTIAL_NULL_REFERENCE,
        JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK,
        JavaCore.COMPILER_PB_POSSIBLE_ACCIDENTAL_BOOLEAN_ASSIGNMENT,
        JavaCore.COMPILER_PB_UNUSED_LABEL,
        JavaCore.COMPILER_PB_UNUSED_LOCAL,
        JavaCore.COMPILER_PB_UNUSED_OBJECT_ALLOCATION,
        JavaCore.COMPILER_PB_UNUSED_PARAMETER,
        JavaCore.COMPILER_PB_UNUSED_PRIVATE_MEMBER
    };

    for (String s : generate) compilerOptions.put(s, JavaCore.GENERATE);
    for (String s : ignore)   compilerOptions.put(s, JavaCore.IGNORE);
    for (String s : warn)     compilerOptions.put(s, JavaCore.WARNING);

    COMPILER_OPTIONS = Collections.unmodifiableMap(compilerOptions);
  }

  public void handleHasJavaTabsChange(boolean hasJavaTabs) {
    isEnabled = !hasJavaTabs;
    if (isEnabled) {
      notifySketchChanged();
    } else {
      preprocessingTask.cancel(false);
    }
  }

}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/serial/test/serial_latency/arduino/serial_latency.ino
void setup() {
  Serial.begin(115200);
}

void loop() {
  while (true) {
    int in = Serial.read();
    if (in != -1) {
      Serial.write(in);
    }
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Motion/CubesWithinCube/Cube.pde

// Custom Cube Class

class Cube {
  // Position, velocity vectors
  PVector position;
  PVector velocity;
  // Also using PVector to hold rotation values for 3 axes
  PVector rotation;

  // Vertices of the cube
  PVector[] vertices = new PVector[24];
  // width, height, depth
  float w, h, d;

  // colors for faces of cube
  color[] quadBG = new color[6];

  Cube(float w, float h, float d) {
    this.w = w;
    this.h = h;
    this.d = d;

    // Colors are hardcoded
    quadBG[0] = color(0);
    quadBG[1] = color(51);
    quadBG[2] = color(102);
    quadBG[3] = color(153);
    quadBG[4] = color(204);
    quadBG[5] = color(255);

    // Start in center
    position = new PVector();
    // Random velocity vector
    velocity = PVector.random3D();
    // Random rotation
    rotation = new PVector(random(40, 100), random(40, 100), random(40, 100));

    // cube composed of 6 quads
    //front
    vertices[0] = new PVector(-w/2, -h/2, d/2);
    vertices[1] = new PVector(w/2, -h/2, d/2);
    vertices[2] = new PVector(w/2, h/2, d/2);
    vertices[3] = new PVector(-w/2, h/2, d/2);
    //left
    vertices[4] = new PVector(-w/2, -h/2, d/2);
    vertices[5] = new PVector(-w/2, -h/2, -d/2);
    vertices[6] = new PVector(-w/2, h/2, -d/2);
    vertices[7] = new PVector(-w/2, h/2, d/2);
    //right
    vertices[8] = new PVector(w/2, -h/2, d/2);
    vertices[9] = new PVector(w/2, -h/2, -d/2);
    vertices[10] = new PVector(w/2, h/2, -d/2);
    vertices[11] = new PVector(w/2, h/2, d/2);
    //back
    vertices[12] = new PVector(-w/2, -h/2, -d/2);
    vertices[13] = new PVector(w/2, -h/2, -d/2);
    vertices[14] = new PVector(w/2, h/2, -d/2);
    vertices[15] = new PVector(-w/2, h/2, -d/2);
    //top
    vertices[16] = new PVector(-w/2, -h/2, d/2);
    vertices[17] = new PVector(-w/2, -h/2, -d/2);
    vertices[18] = new PVector(w/2, -h/2, -d/2);
    vertices[19] = new PVector(w/2, -h/2, d/2);
    //bottom
    vertices[20] = new PVector(-w/2, h/2, d/2);
    vertices[21] = new PVector(-w/2, h/2, -d/2);
    vertices[22] = new PVector(w/2, h/2, -d/2);
    vertices[23] = new PVector(w/2, h/2, d/2);
  }

  // Cube shape itself
  void drawCube() {
    // Draw cube
    for (int i=0; i<6; i++) {
      fill(quadBG[i]);
      beginShape(QUADS);
      for (int j=0; j<4; j++) {
        vertex(vertices[j+4*i].x, vertices[j+4*i].y, vertices[j+4*i].z);
      }
      endShape();
    }
  }

  // Update location
  void update() {
    position.add(velocity);

    // Check wall collisions
    if (position.x > bounds/2 || position.x < -bounds/2) {
      velocity.x*=-1;
    }
    if (position.y > bounds/2 || position.y < -bounds/2) {
      velocity.y*=-1;
    }
    if (position.z > bounds/2 || position.z < -bounds/2) {
      velocity.z*=-1;
    }
  }

  // Display method
  void display() {
    pushMatrix();
    translate(position.x, position.y, position.z);
    rotateX(frameCount*PI/rotation.x);
    rotateY(frameCount*PI/rotation.y);
    rotateZ(frameCount*PI/rotation.z);
    noStroke();
    drawCube(); // Farm out shape to another method
    popMatrix();
  }
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Demos/Graphics/Particles/ParticleSystem.pde
class ParticleSystem {
  ArrayList<Particle> particles;

  PShape particleShape;

  ParticleSystem(int n) {
    particles = new ArrayList<Particle>();
    particleShape = createShape(PShape.GROUP);

    for (int i = 0; i < n; i++) {
      Particle p = new Particle();
      particles.add(p);
      particleShape.addChild(p.getShape());
    }
  }

  void update() {
    for (Particle p : particles) {
      p.update();
    }
  }

  void setEmitter(float x, float y) {
    for (Particle p : particles) {
      if (p.isDead()) {
        p.rebirth(x, y);
      }
    }
  }

  void display() {

    shape(particleShape);
  }
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Math/SineWave/SineWave.pde
/**
 * Sine Wave
 * by <NAME>.
 *
 * Render a simple sine wave.
 */

int xspacing = 16;   // How far apart should each horizontal location be spaced
int w;              // Width of entire wave

float theta = 0.0;  // Start angle at 0
float amplitude = 75.0;  // Height of wave
float period = 500.0;  // How many pixels before the wave repeats
float dx;  // Value for incrementing X, a function of period and xspacing
float[] yvalues;  // Using an array to store height values for the wave

void setup() {
  size(640, 360);
  w = width+16;
  dx = (TWO_PI / period) * xspacing;
  yvalues = new float[w/xspacing];
}

void draw() {
  background(0);
  calcWave();
  renderWave();
}

void calcWave() {
  // Increment theta (try different values for 'angular velocity' here
  theta += 0.02;

  // For every x value, calculate a y value with sine function
  float x = theta;
  for (int i = 0; i < yvalues.length; i++) {
    yvalues[i] = sin(x)*amplitude;
    x+=dx;
  }
}

void renderWave() {
  noStroke();
  fill(255);
  // A simple way to draw the wave with an ellipse at each location
  for (int x = 0; x < yvalues.length; x++) {
    ellipse(x*xspacing, height/2+yvalues[x], 16, 16);
  }
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Simulate/GravitationalAttraction3D/Planet.pde
// Gravitational Attraction (3D)
// <NAME> <http://www.shiffman.net>

// A class for an orbiting Planet

class Planet {

  // Basic physics model (position, velocity, acceleration, mass)
  PVector position;
  PVector velocity;
  PVector acceleration;
  float mass;

  Planet(float m, float x, float y, float z) {
    mass = m;
    position = new PVector(x, y, z);
    velocity = new PVector(1, 0);   // Arbitrary starting velocity
    acceleration = new PVector(0, 0);
  }

  // Newton's 2nd Law (F = M*A) applied
  void applyForce(PVector force) {
    PVector f = PVector.div(force, mass);
    acceleration.add(f);
  }

  // Our motion algorithm (aka Euler Integration)
  void update() {
    velocity.add(acceleration); // Velocity changes according to acceleration
    position.add(velocity);     // position changes according to velocity
    acceleration.mult(0);
  }

  // Draw the Planet
  void display() {
    noStroke();
    fill(255);
    pushMatrix();
    translate(position.x, position.y, position.z);
    sphere(mass*8);
    popMatrix();
  }
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Advanced Data/Threads/Threads.pde
/**
 * Thread function example
 * by <NAME>.
 *
 * This example demonstrates how to use thread() to spawn
 * a process that happens outside of the main animation thread.
 *
 * When thread() is called, the draw() loop will continue while
 * the code inside the function passed to thread() will operate
 * in the background.
 *
 */

// This sketch will load data from all of these URLs in a separate thread
String[] urls = {
  "http://processing.org",
  "http://www.processing.org/exhibition/",
  "http://www.processing.org/reference/",
  "http://www.processing.org/reference/libraries",
  "http://www.processing.org/reference/tools",
  "http://www.processing.org/reference/environment",
  "http://www.processing.org/learning/",
  "http://www.processing.org/learning/basics/",
  "http://www.processing.org/learning/topics/",
  "http://www.processing.org/learning/gettingstarted/",
  "http://www.processing.org/download/",
  "http://www.processing.org/shop/",
  "http://www.processing.org/about/"
};

// This will keep track of whether the thread is finished
boolean finished = false;
// And how far along
float percent = 0;

// A variable to keep all the data loaded
String allData;

void setup() {
  size(640, 360);
  // Spawn the thread!
  thread("loadData");
}

void draw() {
  background(0);

  // If we're not finished draw a "loading bar"
  // This is so that we can see the progress of the thread
  // This would not be necessary in a sketch where you wanted to load data in the background
  // and hide this from the user, allowing the draw() loop to simply continue
  if (!finished) {
    stroke(255);
    noFill();
    rect(width/2-150, height/2, 300, 10);
    fill(255);
    // The size of the rectangle is mapped to the percentage completed
    float w = map(percent, 0, 1, 0, 300);
    rect(width/2-150, height/2, w, 10);
    textSize(16);
    textAlign(CENTER);
    fill(255);
    text("Loading", width/2, height/2+30);
  }
  else {
    // The thread is complete!
    textAlign(CENTER);
    textSize(24);
    fill(255);
    text("Finished loading. Click the mouse to load again.", width/2, height/2);
  }
}

void mousePressed() {
   thread("loadData");
}

void loadData() {
  // The thread is not completed
  finished = false;
  // Reset the data to empty
  allData = "";

  // Look at each URL
  // This example is doing some highly arbitrary things just to make it take longer
  // If you had a lot of data parsing you needed to do, this can all happen in the background
  for (int i = 0; i < urls.length; i++) {
    String[] lines = loadStrings(urls[i]);
    // Demonstrating some arbitrary text splitting, joining, and sorting to make the thread take longer
    String allTxt = join(lines, " ");
    String[] words = splitTokens(allTxt, "\t+\n <>=\\-!@#$%^&*(),.;:/?\"\'");
    for (int j = 0; j < words.length; j++) {
      words[j] = words[j].trim();
      words[j] = words[j].toLowerCase();
    }
    words = sort(words);
    allData += join(words, " ");
    percent = float(i)/urls.length;
  }

  String[] words = split(allData," ");
  words = sort(words);
  allData = join(words, " ");

  // The thread is completed!
  finished = true;
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Create Shapes/WigglePShape/Wiggler.pde
// An object that wraps the PShape

class Wiggler {

  // The PShape to be "wiggled"
  PShape s;
  // Its location
  float x, y;

  // For 2D Perlin noise
  float yoff = 0;

  // We are using an ArrayList to keep a duplicate copy
  // of vertices original locations.
  ArrayList<PVector> original;

  Wiggler() {
    x = width/2;
    y = height/2;

    // The "original" locations of the vertices make up a circle
    original = new ArrayList<PVector>();
    for (float a = 0; a < TWO_PI; a+=0.2) {
      PVector v = PVector.fromAngle(a);
      v.mult(100);
      original.add(v);
    }

    // Now make the PShape with those vertices
    s = createShape();
    s.beginShape();
    s.fill(127);
    s.stroke(0);
    s.strokeWeight(2);
    for (PVector v : original) {
      s.vertex(v.x, v.y);
    }
    s.endShape(CLOSE);
  }

  void wiggle() {
    float xoff = 0;
    // Apply an offset to each vertex
    for (int i = 0; i < s.getVertexCount(); i++) {
      // Calculate a new vertex location based on noise around "original" location
      PVector pos = original.get(i);
      float a = TWO_PI*noise(xoff,yoff);
      PVector r = PVector.fromAngle(a);
      r.mult(4);
      r.add(pos);
      // Set the location of each vertex to the new one
      s.setVertex(i, r.x, r.y);
      // increment perlin noise x value
      xoff+= 0.5;
    }
    // Increment perlin noise y value
    yoff += 0.02;
  }

  void display() {
    pushMatrix();
    translate(x, y);
    shape(s);
    popMatrix();
  }
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Math/OperatorPrecedence/OperatorPrecedence.pde
/**
 * Operator Precedence
 *
 * If you don't explicitly state the order in which
 * an expression is evaluated, they are evaluated based
 * on the operator precedence. For example, in the statement
 * "4+2*8", the 2 will first be multiplied by 8 and then the result will
 * be added to 4. This is because the "*" has a higher precedence
 * than the "+". To avoid ambiguity in reading the program,
 * it is recommended that is statement is written as "4+(2*8)".
 * The order of evaluation can be controlled through placement of
 * parenthesis in the code. A table of operator precedence follows below.
 *
 */

// The highest precedence is at the top of the list and
// the lowest is at the bottom.
// Multiplicative: * / %
// Additive: + -
// Relational: < > <= >=
// Equality: == !=
// Logical AND: &&
// Logical OR: ||
// Assignment: = += -= *= /= %=

size(640, 360);
background(51);
noFill();
stroke(51);

stroke(204);
for(int i=0; i< width-20; i+= 4) {
  // The 30 is added to 70 and then evaluated
  // if it is greater than the current value of "i"
  // For clarity, write as "if (i > (30 + 70)) {"
  if (i > 30 + 70) {
    line(i, 0, i, 50);
  }
}

stroke(255);
// The 2 is multiplied by the 8 and the result is added to the 4
// For clarity, write as "rect(5 + (2 * 8), 0, 90, 20);"
rect(4 + 2 * 8, 52, 290, 48);
rect((4 + 2) * 8, 100, 290, 49);

stroke(153);
for (int i = 0; i < width; i+= 2) {
  // The relational statements are evaluated
  // first, and then the logical AND statements and
  // finally the logical OR. For clarity, write as:
  // "if(((i > 20) && (i < 50)) || ((i > 100) && (i < width-20))) {"
  if (i > 20 && i < 50 || i > 100 && i < width-20) {
    line(i, 151, i, height-1);
  }
}

<file_sep>/Data and System Management/app/templates/config.html
{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}

{% block page_content %}

Resources
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                        ×
                    </button>

                {{ wtf.quick_form(form) }}

Registered Pumps

PumpID

Programmed payload on ESP8266.

Location

Previously indicated location.

            {% for pump in pumps %}

                {{ pump.payload }}
                {{ pump.location }}

                    <button class="btn btn-default">
                        Delete
                    </button>

            {% endfor %}

        <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#Modal">
            Add Pump
        </button>

{% endblock %}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Shaders/DomeProjection/CubeMapUtils.pde
void initCubeMap() {
  sphereDetail(50);
  domeSphere = createShape(SPHERE, height/2.0f);
  domeSphere.rotateX(HALF_PI);
  domeSphere.setStroke(false);

  PGL pgl = beginPGL();

  envMapTextureID = IntBuffer.allocate(1);
  pgl.genTextures(1, envMapTextureID);
  pgl.bindTexture(PGL.TEXTURE_CUBE_MAP, envMapTextureID.get(0));
  pgl.texParameteri(PGL.TEXTURE_CUBE_MAP, PGL.TEXTURE_WRAP_S, PGL.CLAMP_TO_EDGE);
  pgl.texParameteri(PGL.TEXTURE_CUBE_MAP, PGL.TEXTURE_WRAP_T, PGL.CLAMP_TO_EDGE);
  pgl.texParameteri(PGL.TEXTURE_CUBE_MAP, PGL.TEXTURE_WRAP_R, PGL.CLAMP_TO_EDGE);
  pgl.texParameteri(PGL.TEXTURE_CUBE_MAP, PGL.TEXTURE_MIN_FILTER, PGL.NEAREST);
  pgl.texParameteri(PGL.TEXTURE_CUBE_MAP, PGL.TEXTURE_MAG_FILTER, PGL.NEAREST);
  for (int i = PGL.TEXTURE_CUBE_MAP_POSITIVE_X; i < PGL.TEXTURE_CUBE_MAP_POSITIVE_X + 6; i++) {
    pgl.texImage2D(i, 0, PGL.RGBA8, envMapSize, envMapSize, 0, PGL.RGBA, PGL.UNSIGNED_BYTE, null);
  }

  // Init fbo, rbo
  fbo = IntBuffer.allocate(1);
  rbo = IntBuffer.allocate(1);
  pgl.genFramebuffers(1, fbo);
  pgl.bindFramebuffer(PGL.FRAMEBUFFER, fbo.get(0));
  pgl.framebufferTexture2D(PGL.FRAMEBUFFER, PGL.COLOR_ATTACHMENT0, PGL.TEXTURE_CUBE_MAP_POSITIVE_X, envMapTextureID.get(0), 0);

  pgl.genRenderbuffers(1, rbo);
  pgl.bindRenderbuffer(PGL.RENDERBUFFER, rbo.get(0));
  pgl.renderbufferStorage(PGL.RENDERBUFFER, PGL.DEPTH_COMPONENT24, envMapSize, envMapSize);

  // Attach depth buffer to FBO
  pgl.framebufferRenderbuffer(PGL.FRAMEBUFFER, PGL.DEPTH_ATTACHMENT, PGL.RENDERBUFFER, rbo.get(0));

  endPGL();

  // Load cubemap shader.
  cubemapShader = loadShader("cubemapfrag.glsl", "cubemapvert.glsl");
  cubemapShader.set("cubemap", 1);
}

void drawCubeMap() {
  PGL pgl = beginPGL();
  pgl.activeTexture(PGL.TEXTURE1);
  pgl.enable(PGL.TEXTURE_CUBE_MAP);
  pgl.bindTexture(PGL.TEXTURE_CUBE_MAP, envMapTextureID.get(0));
  regenerateEnvMap(pgl);
  endPGL();

  drawDomeMaster();

  pgl.bindTexture(PGL.TEXTURE_CUBE_MAP, 0);
}

void drawDomeMaster() {
  camera();
  ortho();
  resetMatrix();
  shader(cubemapShader);
  shape(domeSphere);
  resetShader();
}

// Called to regenerate the envmap
void regenerateEnvMap(PGL pgl) {
  // bind fbo
  pgl.bindFramebuffer(PGL.FRAMEBUFFER, fbo.get(0));

  // generate 6 views from origin(0, 0, 0)
  pgl.viewport(0, 0, envMapSize, envMapSize);
  perspective(90.0f * DEG_TO_RAD, 1.0f, 1.0f, 1025.0f);
  for (int face = PGL.TEXTURE_CUBE_MAP_POSITIVE_X; face <
                  PGL.TEXTURE_CUBE_MAP_NEGATIVE_Z; face++) {
    resetMatrix();

    if (face == PGL.TEXTURE_CUBE_MAP_POSITIVE_X) {
      camera(0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f);
    } else if (face == PGL.TEXTURE_CUBE_MAP_NEGATIVE_X) {
      camera(0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f);
    } else if (face == PGL.TEXTURE_CUBE_MAP_POSITIVE_Y) {
      camera(0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, -1.0f);
    } else if (face == PGL.TEXTURE_CUBE_MAP_NEGATIVE_Y) {
      camera(0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
    } else if (face == PGL.TEXTURE_CUBE_MAP_POSITIVE_Z) {
      camera(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f);
    }

    scale(-1, 1, -1);
    translate(-width * 0.5f, -height * 0.5f, -500);

    pgl.framebufferTexture2D(PGL.FRAMEBUFFER, PGL.COLOR_ATTACHMENT0, face, envMapTextureID.get(0), 0);

    drawScene(); // Draw objects in the scene
    flush(); // Make sure that the geometry in the scene is pushed to the GPU
    noLights();  // Disabling lights to avoid adding many times
    pgl.framebufferTexture2D(PGL.FRAMEBUFFER, PGL.COLOR_ATTACHMENT0, face, 0, 0);
  }
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/io/src/native/impl.c
/*
  Copyright (c) The Processing Foundation 2015
  Hardware I/O library developed by <NAME> as part of GSoC 2015

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General
  Public License along with this library; if not, write to the
  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  Boston, MA  02111-1307  USA
*/

#include <errno.h>
#include <fcntl.h>
#include <jni.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/spi/spidev.h>
#include <poll.h>
#include <pthread.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/param.h>
#include <time.h>
#include <unistd.h>
#include "iface.h"

static const int servo_pulse_oversleep = 35;  // amount of uS to account for when sleeping

JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_openDevice
  (JNIEnv *env, jclass cls, jstring _fn)
{
	const char *fn = (*env)->GetStringUTFChars(env, _fn, JNI_FALSE);
	int file = open(fn, O_RDWR);
	(*env)->ReleaseStringUTFChars(env, _fn, fn);
	if (file < 0) {
		return -errno;
	} else {
		return file;
	}
}

JNIEXPORT jstring JNICALL Java_processing_io_NativeInterface_getError
  (JNIEnv *env, jclass cls, jint _errno)
{
	char *msg = strerror(abs(_errno));
	if (msg) {
		return (*env)->NewStringUTF(env, msg);
	} else {
		return NULL;
	}
}

JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_closeDevice
  (JNIEnv *env, jclass cls, jint handle)
{
	if (close(handle) < 0) {
		return -errno;
	} else {
		return 0;
	}
}

JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_readFile
  (JNIEnv *env, jclass cls, jstring _fn, jbyteArray _in)
{
	const char *fn = (*env)->GetStringUTFChars(env, _fn, JNI_FALSE);
	int file = open(fn, O_RDONLY);
	(*env)->ReleaseStringUTFChars(env, _fn, fn);
	if (file < 0) {
		return -errno;
	}

	jbyte *in = (*env)->GetByteArrayElements(env, _in, NULL);
	int len = read(file, in, (*env)->GetArrayLength(env, _in));
	if (len < 0) {
		len = -errno;
	}
	(*env)->ReleaseByteArrayElements(env, _in, in, 0);

	close(file);
	return len;
}

JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_writeFile
  (JNIEnv *env, jclass cls, jstring _fn, jbyteArray _out)
{
	const char *fn = (*env)->GetStringUTFChars(env, _fn, JNI_FALSE);
	int file = open(fn, O_WRONLY);
	(*env)->ReleaseStringUTFChars(env, _fn, fn);
	if (file < 0) {
		return -errno;
	}

	jbyte *out = (*env)->GetByteArrayElements(env, _out, JNI_FALSE);
	int len = write(file, out, (*env)->GetArrayLength(env, _out));
	if (len < 0) {
		len = -errno;
	}
	(*env)->ReleaseByteArrayElements(env, _out, out, JNI_ABORT);

	close(file);
	return len;
}

JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_raspbianGpioMemRead
  (JNIEnv *env, jclass cls, jint offset)
{
	// validate offset
	if (4096 <= offset) {
		return -EINVAL;
	}

	int file = open("/dev/gpiomem", O_RDWR|O_SYNC);
	if (file < 0) {
		return -errno;
	}

	uint32_t *mem = mmap(NULL, 4096, PROT_READ, MAP_SHARED, file, 0);
	if (mem == MAP_FAILED) {
		close(file);
		return -errno;
	}

	uint32_t value = mem[offset];

	munmap(mem, 4096);
	close(file);
	return value;
}

JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_raspbianGpioMemWrite
  (JNIEnv *env, jclass cls, jint offset, jint mask, jint value)
{
	// validate offset
	if (4096 <= offset) {
		return -EINVAL;
	}

	int file = open("/dev/gpiomem", O_RDWR|O_SYNC);
	if (file < 0) {
		return -errno;
	}

	uint32_t *mem = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, file, 0);
	if (mem == MAP_FAILED) {
		close(file);
		return -errno;
	}

	mem[offset] = (mem[offset] & ~mask) | (value & mask);

	munmap(mem, 4096);
	close(file);
	return 1;	// number of bytes written
}

#define BCM2835_GPPUD_OFFSET (0x94 >> 2)
#define BCM2835_GPPUDCLK0_OFFSET (0x98 >> 2)
#define BCM2835_GPPUDCLK1_OFFSET (0x9c >> 2)

JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_raspbianGpioMemSetPinBias
  (JNIEnv *env, jclass cls, jint gpio, jint mode)
{
	int ret = 0;	// success

	int file = open("/dev/gpiomem", O_RDWR|O_SYNC);
	if (file < 0) {
		return -errno;
	}

	uint32_t *mem = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, file, 0);
	if (mem == MAP_FAILED) {
		close(file);
		return -errno;
	}

	// validate arguments
	if (gpio < 0 || 53 < gpio) {
		ret = -EINVAL;
		goto out;
	}

	// see BCM2835 datasheet, p. 101
	uint32_t pud;
	if (mode == 0) {
		pud = 0;	// floating
	} else if (mode == 2) {
		pud = 2;	// pull-up
	} else if (mode == 3) {
		pud = 1;	// pull-down
	} else {
		ret = -EINVAL;
		goto out;
	}

	/*
	 * From the BCM2835 datasheet, p. 101:
	 *
	 * The following sequence of events is required:
	 * 1. Write to GPPUD to set the required control signal (i.e. Pull-up or
	 *    Pull-Down or neither to remove the current Pull-up/down)
	 * 2. Wait 150 cycles – this provides the required set-up time for the
	 *    control signal
	 * 3. Write to GPPUDCLK0/1 to clock the control signal into the GPIO pads
	 *    you wish to modify – NOTE only the pads which receive a clock will
	 *    be modified, all others will retain their previous state.
	 * 4. Wait 150 cycles – this provides the required hold time for the
	 *    control signal
	 * 5. Write to GPPUD to remove the control signal
	 * 6. Write to GPPUDCLK0/1 to remove the clock
	 */

	// python-gpiozero uses a delay of 214 ns, so we do the same
	struct timespec wait;
	wait.tv_sec = 0;
	wait.tv_nsec = 214;

	mem[BCM2835_GPPUD_OFFSET] = pud;
	nanosleep(&wait, NULL);
	if (gpio < 32) {
		mem[BCM2835_GPPUDCLK0_OFFSET] = 1 << gpio;
	} else {
		mem[BCM2835_GPPUDCLK1_OFFSET] = 1 << (gpio-32);
	}
	nanosleep(&wait, NULL);
	mem[BCM2835_GPPUD_OFFSET] = 0;
	if (gpio < 32) {
		mem[BCM2835_GPPUDCLK0_OFFSET] = 0;
	} else {
		mem[BCM2835_GPPUDCLK1_OFFSET] = 0;
	}

out:
	munmap(mem, 4096);
	close(file);
	return ret;
}

JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_pollDevice
  (JNIEnv *env, jclass cls, jstring _fn, jint timeout)
{
	const char *fn = (*env)->GetStringUTFChars(env, _fn, JNI_FALSE);
	int file = open(fn, O_RDONLY|O_NONBLOCK);
	(*env)->ReleaseStringUTFChars(env, _fn, fn);
	if (file < 0) {
		return -errno;
	}

	// dummy read
	char tmp;
	while (0 < read(file, &tmp, 1));

	struct pollfd fds[1];
	memset(fds, 0, sizeof(fds));
	fds[0].fd = file;
	fds[0].events = POLLPRI|POLLERR;

	// and wait
	int ret = poll(fds, 1, timeout);
	close(file);

	if (ret < 0) {
		return -errno;
	} else if (ret == 0) {
		// timeout
		return 0;
	} else if (fds[0].revents & POLLPRI) {
		// interrupt
		return 1;
	} else {
		// POLLERR?
		return -ENOMSG;
	}
}

JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_transferI2c
  (JNIEnv *env, jclass cls, jint handle, jint slave, jbyteArray _out, jbyteArray _in)
{
	struct i2c_rdwr_ioctl_data packets;
	struct i2c_msg msgs[2];
	jbyte *out, *in;

	packets.msgs = msgs;
	packets.nmsgs = 0;

	if (_out != NULL) {
		msgs[packets.nmsgs].addr = slave;
		msgs[packets.nmsgs].flags = 0;
		msgs[packets.nmsgs].len = (*env)->GetArrayLength(env, _out);
		out = (*env)->GetByteArrayElements(env, _out, NULL);
		msgs[packets.nmsgs].buf = out;
		packets.nmsgs++;
	}
	if (_in != NULL) {
		msgs[packets.nmsgs].addr = slave;
		msgs[packets.nmsgs].flags = I2C_M_RD;	// I2C_M_RECV_LEN is not supported
		msgs[packets.nmsgs].len = (*env)->GetArrayLength(env, _in);
		in = (*env)->GetByteArrayElements(env, _in, NULL);
		msgs[packets.nmsgs].buf = in;
		packets.nmsgs++;
	}

	// set the timeout to 100ms - this helps slow devices such as the
	// Arduino Uno to keep up
	ioctl(handle, I2C_TIMEOUT, 10);
	int ret = ioctl(handle, I2C_RDWR, &packets);
	if (ret < 0) {
		ret = -errno;
	}

	if (_out != NULL) {
		(*env)->ReleaseByteArrayElements(env, _out, out, JNI_ABORT);
	}
	if (_in != NULL) {
		(*env)->ReleaseByteArrayElements(env, _in, in, 0);
	}

	return ret;
}

typedef struct {
	int fd;
	pthread_t thread;
	int pulse;
	int period;
} SERVO_STATE_T;

static void* servoThread(void *ptr) {
	SERVO_STATE_T *state = (SERVO_STATE_T*)ptr;
	struct timespec on, off;
	on.tv_sec = 0;
	off.tv_sec = 0;

	do {
		write(state->fd, "1", 1);

		on.tv_nsec = state->pulse * 1000;
		nanosleep(&on, NULL);

		write(state->fd, "0", 1);

		off.tv_nsec = (state->period - state->pulse) * 1000;
		nanosleep(&off, NULL);
	} while (1);
}

JNIEXPORT jlong JNICALL Java_processing_io_NativeInterface_servoStartThread
  (JNIEnv *env, jclass cls, jint gpio, jint pulse, jint period)
{
	char path[26 + 19 + 1];
	int fd;
	pthread_t thread;

	// setup struct holding our state
	SERVO_STATE_T *state = malloc(sizeof(SERVO_STATE_T));
	if (!state) {
		return -ENOMEM;
	}
	memset(state, 0, sizeof(*state));
	state->pulse = (pulse - servo_pulse_oversleep > 0) ? pulse - servo_pulse_oversleep : 0;
	// we're obviously also oversleeping in the general period case
	// but other than the pulse, this doesn't seem to be crucial with servos
	state->period = period;

	// open gpio
	sprintf(path, "/sys/class/gpio/gpio%d/value", gpio);
	state->fd = open(path, O_WRONLY);
	if (state->fd < 0) {
		free(state);
		return -errno;
	}

	// start thread
	int ret = pthread_create(&state->thread, NULL, servoThread, state);
	if (ret != 0) {
		free(state);
		return -ret;
	}

	// set scheduling policy and priority
	struct sched_param param;
	param.sched_priority = 75;
	ret = pthread_setschedparam(state->thread, SCHED_FIFO, &param);
	if (ret != 0) {
		fprintf(stderr, "Error setting thread policy: %s\n", strerror(ret));
	}

	return (intptr_t)state;
}

JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_servoUpdateThread
  (JNIEnv *env, jclass cls, jlong handle, jint pulse, jint period)
{
	SERVO_STATE_T *state = (SERVO_STATE_T*)(intptr_t)handle;
	state->pulse = (pulse - servo_pulse_oversleep > 0) ? pulse - servo_pulse_oversleep : 0;
	state->period = period;
	return 0;
}

JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_servoStopThread
  (JNIEnv *env, jclass cls, jlong handle)
{
	SERVO_STATE_T *state = (SERVO_STATE_T*)(intptr_t)handle;

	// signal thread to stop
	pthread_cancel(state->thread);
	pthread_join(state->thread, NULL);

	close(state->fd);
	free(state);
	return 0;
}

JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_setSpiSettings
  (JNIEnv *env, jclass cls, jint handle, jint _maxSpeed, jint dataOrder, jint mode)
{
	uint8_t tmp;
	uint32_t maxSpeed;

	tmp = (uint8_t)mode;
	int ret = ioctl(handle, SPI_IOC_WR_MODE, &tmp);
	if (ret < 0) {
		return ret;
	}

	tmp = (uint8_t)dataOrder;
	ret = ioctl(handle, SPI_IOC_WR_LSB_FIRST, &tmp);
	if (ret < 0) {
		return ret;
	}

	maxSpeed = (uint32_t)_maxSpeed;
	ret = ioctl(handle, SPI_IOC_WR_MAX_SPEED_HZ, &maxSpeed);
	if (ret < 0) {
		return ret;
	}

	return 0;
}

JNIEXPORT jint JNICALL Java_processing_io_NativeInterface_transferSpi
  (JNIEnv *env, jclass cls, jint handle, jbyteArray _out, jbyteArray _in)
{
	jbyte* out = (*env)->GetByteArrayElements(env, _out, NULL);
	jbyte* in = (*env)->GetByteArrayElements(env, _in, NULL);

	struct spi_ioc_transfer xfer = {
		.tx_buf = (unsigned long)out,
		.rx_buf = (unsigned long)in,
		.len = MIN((*env)->GetArrayLength(env, _out), (*env)->GetArrayLength(env, _in)),
	};

	int ret = ioctl(handle, SPI_IOC_MESSAGE(1), &xfer);

	(*env)->ReleaseByteArrayElements(env, _out, out, JNI_ABORT);
	(*env)->ReleaseByteArrayElements(env, _in, in, 0);

	return ret;
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Structure/Recursion/Recursion.pde
/**
 * Recursion.
 *
 * A demonstration of recursion, which means functions call themselves.
 * Notice how the drawCircle() function calls itself at the end of its block.
 * It continues to do this until the variable "level" is equal to 1.
 */

void setup() {
  size(640, 360);
  noStroke();
  noLoop();
}

void draw() {
  drawCircle(width/2, 280, 6);
}

void drawCircle(int x, int radius, int level) {
  float tt = 126 * level/4.0;
  fill(tt);
  ellipse(x, height/2, radius*2, radius*2);
  if(level > 1) {
    level = level - 1;
    drawCircle(x - radius/2, radius/2, level);
    drawCircle(x + radius/2, radius/2, level);
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Advanced Data/ArrayListClass/Ball.pde
// Simple bouncing ball class

class Ball {

  float x;
  float y;
  float speed;
  float gravity;
  float w;
  float life = 255;

  Ball(float tempX, float tempY, float tempW) {
    x = tempX;
    y = tempY;
    w = tempW;
    speed = 0;
    gravity = 0.1;
  }

    void move() {
    // Add gravity to speed
    speed = speed + gravity;
    // Add speed to y location
    y = y + speed;
    // If square reaches the bottom
    // Reverse speed
    if (y > height) {
      // Dampening
      speed = speed * -0.8;
      y = height;
    }
  }

  boolean finished() {
    // Balls fade out
    life--;
    if (life < 0) {
      return true;
    } else {
      return false;
    }
  }

  void display() {
    // Display the circle
    fill(0,life);
    //stroke(0,life);
    ellipse(x,y,w,w);
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/File IO/LoadFile2/LoadFile2.pde
/**
 * LoadFile 2
 *
 * This example loads a data file about cars. Each element is separated
 * with a tab and corresponds to a different aspect of each car. The file stores
 * the miles per gallon, cylinders, displacement, etc., for more than 400 different
 * makes and models. Press a mouse button to advance to the next group of entries.
 */

Record[] records;
String[] lines;
int recordCount;
PFont body;
int num = 9; // Display this many entries on each screen.
int startingEntry = 0;  // Display from this entry number

void setup() {
  size(200, 200);
  fill(255);
  noLoop();

  body = loadFont("TheSans-Plain-12.vlw");
  textFont(body);

  lines = loadStrings("cars2.tsv");
  records = new Record[lines.length];
  for (int i = 0; i < lines.length; i++) {
    String[] pieces = split(lines[i], TAB); // Load data into array
    if (pieces.length == 9) {
      records[recordCount] = new Record(pieces);
      recordCount++;
    }
  }
  if (recordCount != records.length) {
    records = (Record[]) subset(records, 0, recordCount);
  }
}

void draw() {
  background(0);
  for (int i = 0; i < num; i++) {
    int thisEntry = startingEntry + i;
    if (thisEntry < recordCount) {
      text(thisEntry + " > " + records[thisEntry].name, 20, 20 + i*20);
    }
  }
}

void mousePressed() {
  startingEntry += num;
  if (startingEntry > records.length) {
    startingEntry = 0;  // go back to the beginning
  }
  redraw();
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Interaction/Follow3/Follow3.pde
/**
 * Follow 3
 * based on code from <NAME>.
 *
 * A segmented line follows the mouse. The relative angle from
 * each segment to the next is calculated with atan2() and the
 * position of the next is calculated with sin() and cos().
 */

float[] x = new float[20];
float[] y = new float[20];
float segLength = 18;

void setup() {
  size(640, 360);
  strokeWeight(9);
  stroke(255, 100);
}

void draw() {
  background(0);
  dragSegment(0, mouseX, mouseY);
  for(int i=0; i<x.length-1; i++) {
    dragSegment(i+1, x[i], y[i]);
  }
}

void dragSegment(int i, float xin, float yin) {
  float dx = xin - x[i];
  float dy = yin - y[i];
  float angle = atan2(dy, dx);
  x[i] = xin - cos(angle) * segLength;
  y[i] = yin - sin(angle) * segLength;
  segment(x[i], y[i], angle);
}

void segment(float x, float y, float a) {
  pushMatrix();
  translate(x, y);
  rotate(a);
  line(0, 0, segLength, 0);
  popMatrix();
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Shaders/Monjori/Monjori.pde
/**
 * Monjori.
 *
 * GLSL version of the 1k intro Monjori from the demoscene
 * (http://www.pouet.net/prod.php?which=52761)
 * Ported from the webGL version available in ShaderToy:
 * http://www.iquilezles.org/apps/shadertoy/
 * (Look for Monjori under the Plane Deformations Presets)
 */

PShader monjori;

void setup() {
  size(640, 360, P2D);
  noStroke();

  monjori = loadShader("monjori.glsl");
  monjori.set("resolution", float(width), float(height));
}

void draw() {
  monjori.set("time", millis() / 1000.0);

  shader(monjori);
  // This kind of effects are entirely implemented in the
  // fragment shader, they only need a quad covering the
  // entire view area so every pixel is pushed through the
  // shader.
  rect(0, 0, width, height);
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Image/RequestImage/RequestImage.pde
/**
 * Request Image
 * by <NAME> ( From Processing for Flash Developers).
 *
 * Shows how to use the requestImage() function with preloader animation.
 * The requestImage() function loads images on a separate thread so that
 * the sketch does not freeze while they load. It's very useful when you are
 * loading large images.
 *
 * These images are small for a quick download, but try it with your own huge
 * images to get the full effect.
 */

int imgCount = 12;
PImage[] imgs = new PImage[imgCount];
float imgW;

// Keeps track of loaded images (true or false)
boolean[] loadStates = new boolean[imgCount];

// For loading animation
float loaderX, loaderY, theta;

void setup() {
  size(640, 360);
  imgW = width/imgCount;

  // Load images asynchronously
  for (int i = 0; i < imgCount; i++){
    imgs[i] = requestImage("PT_anim"+nf(i, 4)+".gif");
  }
}

void draw(){
  background(0);

  // Start loading animation
  runLoaderAni();

  for (int i = 0; i < imgs.length; i++){
    // Check if individual images are fully loaded
    if ((imgs[i].width != 0) && (imgs[i].width != -1)){
      // As images are loaded set true in boolean array
      loadStates[i] = true;
    }
  }
  // When all images are loaded draw them to the screen
  if (checkLoadStates()){
    drawImages();
  }
}

void drawImages() {
  int y = (height - imgs[0].height) / 2;
  for (int i = 0; i < imgs.length; i++){
    image(imgs[i], width/imgs.length*i, y, imgs[i].height, imgs[i].height);
  }
}

// Loading animation
void runLoaderAni(){
  // Only run when images are loading
  if (!checkLoadStates()){
    ellipse(loaderX, loaderY, 10, 10);
    loaderX += 2;
    loaderY = height/2 + sin(theta) * (height/8);
    theta += PI/22;
    // Reposition ellipse if it goes off the screen
    if (loaderX > width + 5){
      loaderX = -5;
    }
  }
}

// Return true when all images are loaded - no false values left in array
boolean checkLoadStates(){
  for (int i = 0; i < imgs.length; i++){
    if (loadStates[i] == false){
      return false;
    }
  }
  return true;
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Create Shapes/PathPShape/PathPShape.pde
/**
 * PathPShape
 *
 * A simple path using PShape
 */

// A PShape object
PShape path;

void setup() {
  size(640, 360, P2D);

  // Create the shape
  path = createShape();
  path.beginShape();
  // Set fill and stroke
  path.noFill();
  path.stroke(255);
  path.strokeWeight(2);

  float x = 0;
  // Calculate the path as a sine wave
  for (float a = 0; a < TWO_PI; a+=0.1) {
    path.vertex(x,sin(a)*100);
    x+= 5;
  }
  // The path is complete
  path.endShape();

}

void draw() {
  background(51);
  // Draw the path at the mouse location
  translate(mouseX, mouseY);
  shape(path);
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Form/PointsLines/PointsLines.pde
/**
 * Points and Lines.
 *
 * Points and lines can be used to draw basic geometry.
 * Change the value of the variable 'd' to scale the form.
 * The four variables set the positions based on the value of 'd'.
 */

int d = 70;
int p1 = d;
int p2 = p1+d;
int p3 = p2+d;
int p4 = p3+d;

size(640, 360);
noSmooth();
background(0);
translate(140, 0);

// Draw gray box
stroke(153);
line(p3, p3, p2, p3);
line(p2, p3, p2, p2);
line(p2, p2, p3, p2);
line(p3, p2, p3, p3);

// Draw white points
stroke(255);
point(p1, p1);
point(p1, p3);
point(p2, p4);
point(p3, p1);
point(p4, p2);
point(p4, p4);
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Visualization Code/HandWashing/Draw.pde

// -----------------------------
// DRAW
// -----------------------------

void draw() {

  // Background
  background(bgColor);

  // Timer
  checkTime();

  if(useGerms == true){
     checkSplatterTime();
  }

  // Trigger Mode
  if(drawState == 1) {

    // Draw All The Hands
    drawHands();
   if(useGerms == false){
     growHand();
   }
   if(useGerms == true){
     drawSplatter();
     growSplat();
   }
    // Draw Date & Time
    displayCount();
    displayClock();
  }
  // Semi Sleep Mode
  else if(drawState == 2) {

    // Draw All The Hands
    drawHands();

    if(useGerms == true){
     drawSplatter();
   }

    // Draw States

    // Day View y
    if(subDrawState == 1) {
      displayW21C(0.25, width * 0.3, height * 0.75);
    }
    // ECUAD Logo
    else if(subDrawState == 2) {
      displayECUAD(0.25, width * 0.3, height * 0.75);
    }

    // Draw Date & Time
    displayCount();
    displayClock();

  }
  // Full Sleep Mode
  else if(drawState == 3) {

    // Draw States

    // Day View
    if(subDrawState == 1) {
      displayW21C(0.5, width*0.1, height/4);
    }
    // ECUAD Logo
    else if(subDrawState == 2) {
      displayECUAD(0.5, width * 0.1, height/4);
    }

    // Draw Date & Time
    displayCount();
    displayClock();

  }

  if(frameCount % 6000 == 0) {
    int fps = round(frameRate);
    println(" -- W21C Hand Sanitizer Running at " + fps + " FPS -- ");
    println(" -- The Time Is " + time + " And Our Free Memory Is " + Runtime.getRuntime().freeMemory()/1024 + " K -- ");
    System.gc();
    println(" -- We Garbage Collected And Our Free Memory Is Now " + Runtime.getRuntime().freeMemory()/1024 + " K -- ");
    println("\n");
  }

} /* End Of Draw() */
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Math/SineCosine/SineCosine.pde
/**
 * Sine Cosine.
 *
 * Linear movement with sin() and cos().
 * Numbers between 0 and PI*2 (TWO_PI which angles roughly 6.28)
 * are put into these functions and numbers between -1 and 1 are
 * returned. These values are then scaled to produce larger movements.
 */

float x1, x2, y1, y2;
float angle1, angle2;
float scalar = 70;

void setup() {
  size(640, 360);
  noStroke();
  rectMode(CENTER);
}

void draw() {
  background(0);

  float ang1 = radians(angle1);
  float ang2 = radians(angle2);

  x1 = width/2 + (scalar * cos(ang1));
  x2 = width/2 + (scalar * cos(ang2));

  y1 = height/2 + (scalar * sin(ang1));
  y2 = height/2 + (scalar * sin(ang2));

  fill(255);
  rect(width*0.5, height*0.5, 140, 140);

  fill(0, 102, 153);
  ellipse(x1, height*0.5 - 120, scalar, scalar);
  ellipse(x2, height*0.5 + 120, scalar, scalar);

  fill(255, 204, 0);
  ellipse(width*0.5 - 120, y1, scalar, scalar);
  ellipse(width*0.5 + 120, y2, scalar, scalar);

  angle1 += 2;
  angle2 += 3;

}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/File IO/LoadFile2/Record.pde
class Record {
  String name;
  float mpg;
  int cylinders;
  float displacement;
  float horsepower;
  float weight;
  float acceleration;
  int year;
  float origin;

  public Record(String[] pieces) {
    name = pieces[0];
    mpg = float(pieces[1]);
    cylinders = int(pieces[2]);
    displacement = float(pieces[3]);
    horsepower = float(pieces[4]);
    weight = float(pieces[5]);
    acceleration = float(pieces[6]);
    year = int(pieces[7]);
    origin = float(pieces[8]);
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Simulate/MultipleParticleSystems/MultipleParticleSystems.pde
/**
 * Multiple Particle Systems
 * by <NAME>.
 *
 * Click the mouse to generate a burst of particles
 * at mouse position.
 *
 * Each burst is one instance of a particle system
 * with Particles and CrazyParticles (a subclass of Particle)
 * Note use of Inheritance and Polymorphism here.
 */

ArrayList<ParticleSystem> systems;

void setup() {
  size(640, 360);
  systems = new ArrayList<ParticleSystem>();
}

void draw() {
  background(0);
  for (ParticleSystem ps : systems) {
    ps.run();
    ps.addParticle();
  }
  if (systems.isEmpty()) {
    fill(255);
    textAlign(CENTER);
    text("click mouse to add particle systems", width/2, height/2);
  }
}

void mousePressed() {
  systems.add(new ParticleSystem(1, new PVector(mouseX, mouseY)));
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Camera/MoveEye/MoveEye.pde
/**
 * Move Eye.
 * by <NAME>.
 *
 * The camera lifts up (controlled by mouseY) while looking at the same point.
 */

void setup() {
  size(640, 360, P3D);
  fill(204);
}

void draw() {
  lights();
  background(0);

  // Change height of the camera with mouseY
  camera(30.0, mouseY, 220.0, // eyeX, eyeY, eyeZ
         0.0, 0.0, 0.0, // centerX, centerY, centerZ
         0.0, 1.0, 0.0); // upX, upY, upZ

  noStroke();
  box(90);
  stroke(255);
  line(-100, 0, 0, 100, 0, 0);
  line(0, -100, 0, 0, 100, 0);
  line(0, 0, -100, 0, 0, 100);
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Visualization Code/HandWashing/Sanitizer.pde

// -----------------------------
// SANITIZER CLASS
// -----------------------------

class Sanitizer {

  // VARIABLES
  // -----------------------------

  TheHand hand;

  int deviceID;
  String deviceName;
  float pwmRate;

  color myColor;
  String svg;

  int triggersThisHour;
  int triggersThisDay;
  int triggersThisWeek;
  int triggersThisMonth;
  int triggersThisYear;

  int currHour;
  int lastHour;
  int currMinute;
  int lastMinute;
  int currSecond;
  int lastSecond;

  int timeoutPeriod = 2000;
  int triggerTime = 0;
  boolean readyToTrigger = true;

  // CONSTRUCTOR for other SVG files
  // -----------------------------

  Sanitizer(int _id, color _color, String svgFile) {

    deviceID = _id;
    deviceName = "UNIT " + str(deviceID + 1);
    myColor = _color;
    svg = svgFile;

  }

  // TRIGGER
  // -----------------------------

  void dispenserTriggered(int _id) {
    println(" -- TRIGGERING UNIT #" + _id + " -- ");

    // Reset Screen
    drawState = 1;
    subDrawState = 1;

//    // Set XY
    int prevX = newX;
    int prevY = newY;

    float upperXlimit = width * 0.95;
    float lowerXlimit = width * 0.05;
    float upperYlimit = height * 0.85;
    float lowerYlimit = height * 0.15;
    newX = round(random(lowerXlimit, upperXlimit));
    newY = round(random(lowerYlimit, upperYlimit));

   //GERM IMPLEMENTATION
     if( useGerms == true){
       if(hands.size() != 0){
         TheHand currentGerm = hands.get(0);
         splatter.add(new TheSplat(currentGerm.c1, currentGerm.xPos, currentGerm.yPos, currentGerm.prevX, currentGerm.prevY, splatSVG));
         hands.remove(0);
       }

    }
    else{
      hands.add(new TheHand(myColor, newX, newY, prevX, prevY, svg));
    }

    // Update Dataset
    updateData();

    // Reset Timer
    resetTimer();

    // Reset Boolean & Run Timeout Method
    readyToTrigger = false;
    triggerTime = millis();

  }

   // TIMEOUT
  // -----------------------------

  boolean runTimeout() {
    println(" -- RUNNIMG TIMEOUT FOR UNIT #" + deviceID + " -- ");

    if((millis() - triggerTime) >= timeoutPeriod ) {
       readyToTrigger = true;
    }

    return readyToTrigger;
  }

  // SAVE
  // -----------------------------

  void updateData() {
    println(" -- UPDATING DATA -- ");

    try {

      // Update Counters

      allHandsThisDay++;
      count++;
      numHandsThisDay[deviceID]++;

      // println(deviceName + " has been triggered " + numHandsThisHour[deviceID] + " times this hour...");
      println("Device #" + deviceID + " has been triggered " + numHandsThisDay[deviceID] + " times today...");

    }
    catch(Exception e) {
      println("WHOA!!");
      //e.printStackTrace();
    }

  }

} /* End Of Class Sanitizer */

void AssignTheme(){

  int themeIndex = int(random(0,6));
  if(themeIndex == 0){
     for(int i = 0; i < sanitizers.length; i++) {
    // Id, Color
    sanitizers[i] = new Sanitizer(i, paletteAfrica[i], africanAnimals[i]);
     }
  }
  else if(themeIndex == 1){
    for(int i = 0; i < sanitizers.length; i++) {
    // Id, Color
    sanitizers[i] = new Sanitizer(i, paletteCanada[i], canadianAnimals[i]);
    }
  }
  else if(themeIndex == 2){
    for(int i = 0; i < sanitizers.length; i++) {
    // Id, Color
    sanitizers[i] = new Sanitizer(i, paletteOcean[i], oceanCreatures[i]);
    }
  }
  else if(themeIndex == 3){
    for(int i = 0; i < sanitizers.length; i++) {
    // Id, Color
    sanitizers[i] = new Sanitizer(i, paletteDogs[i], dogs[i]);
    }
  }
  else if(themeIndex == 4){
    for(int i = 0; i < sanitizers.length; i++) {
    // Id, Color
    sanitizers[i] = new Sanitizer(i, paletteInsects[i], insects[i]);
    }
  }
  else{
    for(int i = 0; i < sanitizers.length; i++) {
    // Id, Color
    sanitizers[i] = new Sanitizer(i, paletteTransport[i], transport[i]);
    }
  }

}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Geometry/Icosahedra/Icosahedra.pde
/**
 * I Like Icosahedra
 * by <NAME>.
 *
 * This example plots icosahedra. The Icosahdron is a regular
 * polyhedron composed of twenty equalateral triangles.
 */

Icosahedron ico1;
Icosahedron ico2;
Icosahedron ico3;

void setup(){
  size(640, 360, P3D);
  ico1 = new Icosahedron(75);
  ico2 = new Icosahedron(75);
  ico3 = new Icosahedron(75);
}

void draw(){
  background(0);
  lights();
  translate(width/2, height/2);

  pushMatrix();
  translate(-width/3.5, 0);
  rotateX(frameCount*PI/185);
  rotateY(frameCount*PI/-200);
  stroke(170, 0, 0);
  noFill();
  ico1.create();
  popMatrix();

  pushMatrix();
  rotateX(frameCount*PI/200);
  rotateY(frameCount*PI/300);
  stroke(150, 0, 180);
  fill(170, 170, 0);
  ico2.create();
  popMatrix();

  pushMatrix();
  translate(width/3.5, 0);
  rotateX(frameCount*PI/-200);
  rotateY(frameCount*PI/200);
  noStroke();
  fill(0, 0, 185);
  ico3.create();
  popMatrix();
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/io/examples/SimpleI2C/SimpleI2C.pde
import processing.io.*;
I2C i2c;

// MCP4725 is a Digital-to-Analog converter using I2C
// datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/22039d.pdf

// also see DigitalAnalog_I2C_MCP4725 for how to write the
// same sketch in an object-oriented way

void setup() {
  //printArray(I2C.list());
  i2c = new I2C(I2C.list()[0]);
}

void draw() {
  background(map(mouseX, 0, width, 0, 255));
  setAnalog(map(mouseX, 0, width, 0.0, 1.0));
}

// outputs voltages from 0V to the supply voltage
// (works with 3.3V and 5V)
void setAnalog(float fac) {
  fac = constrain(fac, 0.0, 1.0);
  // convert to 12 bit value
  int val = int(4095 * fac);
  i2c.beginTransmission(0x60);
  i2c.write(val >> 8);
  i2c.write(val & 255);
  i2c.endTransmission();
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Simulate/GravitationalAttraction3D/GravitationalAttraction3D.pde
/**
 * Gravitational Attraction (3D)
 * by <NAME>.
 *
 * Simulating gravitational attraction
 * G ---> universal gravitational constant
 * m1 --> mass of object #1
 * m2 --> mass of object #2
 * d ---> distance between objects
 * F = (G*m1*m2)/(d*d)
 *
 * For the basics of working with PVector, see
 * http://processing.org/learning/pvector/
 * as well as examples in Topics/Vectors/
 *
 */

// A bunch of planets
Planet[] planets = new Planet[10];
// One sun (note sun is not attracted to planets (violation of Newton's 3rd Law)
Sun s;

// An angle to rotate around the scene
float angle = 0;

void setup() {
  size(640, 360, P3D);
  // Some random planets
  for (int i = 0; i < planets.length; i++) {
    planets[i] = new Planet(random(0.1, 2), random(-width/2, width/2), random(-height/2, height/2), random(-100, 100));
  }
  // A single sun
  s = new Sun();
}

void draw() {
  background(0);
  // Setup the scene
  sphereDetail(8);
  lights();
  translate(width/2, height/2);
  rotateY(angle);

  // Display the Sun
  s.display();

  // All the Planets
  for (Planet planet : planets) {
    // Sun attracts Planets
    PVector force = s.attract(planet);
    planet.applyForce(force);
    // Update and draw Planets
    planet.update();
    planet.display();
  }

  // Rotate around the scene
  angle += 0.003;
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/io/examples/AnalogDigital_SPI_MCP3001/AnalogDigital_SPI_MCP3001.pde
import processing.io.*;
MCP3001 adc;

// see setup.png in the sketch folder for wiring details

void setup() {
  //printArray(SPI.list());
  adc = new MCP3001(SPI.list()[0]);
}

void draw() {
  // this will return a number between 0 and 1
  float measured = adc.analogRead();

  // multiply with the supply voltage to get an absolute value
  float volts = 3.3 * measured;
  println("Analog Input is " + volts + "V");

  background(measured * 255);
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/net/examples/HTTPClient/HTTPClient.pde
/**
 * HTTP Client.
 *
 * Starts a network client that connects to a server on port 80,
 * sends an HTTP 1.0 GET request, and prints the results.
 *
 * Note that this code is not necessary for simple HTTP GET request:
 * Simply calling loadStrings("http://www.processing.org") would do
 * the same thing as (and more efficiently than) this example.
 * This example is for people who might want to do something more
 * complicated later.
 */

import processing.net.*;

Client c;
String data;

void setup() {
  size(200, 200);
  background(50);
  fill(200);
  c = new Client(this, "www.ucla.edu", 80); // Connect to server on port 80
  c.write("GET / HTTP/1.0\r\n"); // Use the HTTP "GET" command to ask for a Web page
  c.write("\r\n");
}

void draw() {
  if (c.available() > 0) { // If there's incoming data from the client...
    data = c.readString(); // ...then grab it and print it
    println(data);
  }
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/build.xml
<?xml version="1.0"?>
<project name="Java Mode" default="build">

  <property name="generated"
	    value="${basedir}/generated/processing/mode/java/preproc" />
  <mkdir dir="${generated}" />

  <property name="grammars"
	    value="${basedir}/src/processing/mode/java/preproc" />

  <property name="antlr_jar"
	    value="${basedir}/mode/antlr.jar" />

  <property name="mode_jar"
            value="${basedir}/mode/JavaMode.jar" />

  <classloader taskname="antlr">
    <classpath path="${antlr_jar}" />
  </classloader>

  <target name="clean" description="Clean the build directories">
    <delete dir="bin" />
    <delete file="${mode_jar}" />
    <delete>
      <fileset dir="${generated}">
	<include name="*.java" />
	<include name="*.tokens" />
	<include name="*.txt" />
	<include name="*.g" />
	<include name="*.smap" />
	<include name="*.properties" />
      </fileset>
    </delete>
  </target>

  <target name="preproc" description="Compile ANTLR grammar">
    <antlr target="${grammars}/java15.g" outputdirectory="${generated}">
      <classpath path="${antlr_jar}" />
    </antlr>
    <antlr target="${grammars}/pde.g"
	   outputdirectory="${generated}"
	   glib="${grammars}/java15.g">
      <classpath path="${antlr_jar}" />
    </antlr>

    <property name="uucr" value="@SuppressWarnings({ "unused", "unchecked", "cast", "rawtypes"  })${line.separator}" />
    <property name="uc" value="@SuppressWarnings({ "unused", "cast" })${line.separator}" />

    <replaceregexp
        file="generated/processing/mode/java/preproc/JavaLexer.java"
        match="(\n\n)(public class JavaLexer .*)"
        replace="\1${uucr}\2">
    </replaceregexp>

    <replaceregexp
        file="generated/processing/mode/java/preproc/JavaRecognizer.java"
        match="(\*/\n)(public class JavaRecognizer .*)"
        replace="\1${uc}\2">
    </replaceregexp>

    <replaceregexp
        file="generated/processing/mode/java/preproc/PdeLexer.java"
        match="(\n\n)(public class PdeLexer .*)"
        replace="\1${uucr}\2">
    </replaceregexp>

    <replaceregexp
        file="generated/processing/mode/java/preproc/PdeRecognizer.java"
        match="(\n\n)(public class PdeRecognizer .*)"
        replace="\1${uc}\2">
    </replaceregexp>

  </target>

  <target name="compile" depends="preproc" description="Compile sources">
    <condition property="core-built">
      <available file="../core/library/core.jar" />
    </condition>
    <fail unless="core-built" message="Please first build the core library and make sure it is located at ../core/library/core.jar" />

    <condition property="app-built">
      <available file="../app/pde.jar" />
    </condition>
    <fail unless="app-built" message="Please build app first and make sure it is located at ../app/pde.jar" />

    <mkdir dir="bin" />

    <delete file="${mode_jar}" />

    <property environment="env" />

    <javac source="1.8"
	   target="1.8"
	   destdir="bin"
	   excludes="**/tools/format/**"
	   encoding="UTF-8"
	   includeAntRuntime="false"
	   classpath="../core/library/core.jar;

                      ../app/pde.jar;
                      ../app/lib/ant.jar;
                      ../app/lib/ant-launcher.jar;
                      ../app/lib/apple.jar;
                      ../app/lib/jna.jar;
                      ../app/lib/jna-platform.jar;

                      mode/antlr.jar;
                      mode/classpath-explorer-1.0.jar;
                      mode/jsoup-1.7.1.jar;
                      mode/org.netbeans.swing.outline.jar;

                      mode/jdi.jar;
                      mode/jdimodel.jar;

                      mode/com.ibm.icu.jar;

                      mode/org.eclipse.core.contenttype.jar;
                      mode/org.eclipse.core.jobs.jar;
                      mode/org.eclipse.core.resources.jar;
                      mode/org.eclipse.core.runtime.jar;
                      mode/org.eclipse.equinox.common.jar;
                      mode/org.eclipse.equinox.preferences.jar;
                      mode/org.eclipse.jdt.core.jar;
                      mode/org.eclipse.osgi.jar;
                      mode/org.eclipse.text.jar"
	   debug="on"
	   nowarn="true"
	   compiler="org.eclipse.jdt.core.JDTCompilerAdapter">
      <src path="src" />
      <src path="generated" />
      <compilerclasspath path="mode/org.eclipse.jdt.core.jar;
                               mode/jdtCompilerAdapter.jar" />
    </javac>
  </target>

  <target name="build" depends="compile" description="Build PDE">
    <jar basedir="bin" destfile="${mode_jar}" />
  </target>
</project>
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Motion/MovingOnCurves/MovingOnCurves.pde
/**
 * Moving On Curves.
 *
 * In this example, the circles moves along the curve y = x^4.
 * Click the mouse to have it move to a new position.
 */

float beginX = 20.0;  // Initial x-coordinate
float beginY = 10.0;  // Initial y-coordinate
float endX = 570.0;   // Final x-coordinate
float endY = 320.0;   // Final y-coordinate
float distX;          // X-axis distance to move
float distY;          // Y-axis distance to move
float exponent = 4;   // Determines the curve
float x = 0.0;        // Current x-coordinate
float y = 0.0;        // Current y-coordinate
float step = 0.01;    // Size of each step along the path
float pct = 0.0;      // Percentage traveled (0.0 to 1.0)

void setup() {
  size(640, 360);
  noStroke();
  distX = endX - beginX;
  distY = endY - beginY;
}

void draw() {
  fill(0, 2);
  rect(0, 0, width, height);
  pct += step;
  if (pct < 1.0) {
    x = beginX + (pct * distX);
    y = beginY + (pow(pct, exponent) * distY);
  }
  fill(255);
  ellipse(x, y, 20, 20);
}

void mousePressed() {
  pct = 0.0;
  beginX = x;
  beginY = y;
  endX = mouseX;
  endY = mouseY;
  distX = endX - beginX;
  distY = endY - beginY;
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Demos/Graphics/Particles/Particles.pde
// Particles, by <NAME>.

ParticleSystem ps;
PImage sprite;

void setup() {
  size(1024, 768, P2D);
  orientation(LANDSCAPE);
  sprite = loadImage("sprite.png");
  ps = new ParticleSystem(10000);

  // Writing to the depth buffer is disabled to avoid rendering
  // artifacts due to the fact that the particles are semi-transparent
  // but not z-sorted.
  hint(DISABLE_DEPTH_MASK);
}

void draw () {
  background(0);
  ps.update();
  ps.display();

  ps.setEmitter(mouseX,mouseY);

  fill(255);
  textSize(16);
  text("Frame rate: " + int(frameRate), 10, 20);

}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Image Processing/Blending/Blending.pde
/**
 * Blending
 * by <NAME>.
 *
 * Images can be blended using one of the 10 blending modes
 * (currently available only in P2D and P3).
 * Click to go to cycle through the modes.
 */

// NOTE: THIS EXAMPLE IS IN PROGRESS -- REAS

PImage img1, img2;
int selMode = REPLACE;
String name = "REPLACE";
int picAlpha = 255;

void setup() {
  size(640, 360, P3D);
  img1 = loadImage("layer1.jpg");
  img2 = loadImage("layer2.jpg");
  noStroke();
}

void draw() {

  picAlpha = int(map(mouseX, 0, width, 0, 255));

  background(0);

  tint(255, 255);
  image(img1, 0, 0);

  blendMode(selMode);
  tint(255, picAlpha);
  image(img2, 0, 0);

  blendMode(REPLACE);
  fill(255);
  rect(0, 0, 94, 22);
  fill(0);
  text(name, 10, 15);
}

void mousePressed() {

  if (selMode == REPLACE) {
    selMode = BLEND;
    name = "BLEND";
  } else if (selMode == BLEND) {
    selMode = ADD;
    name = "ADD";
  } else if (selMode == ADD) {
    selMode = SUBTRACT;
    name = "SUBTRACT";
  } else if (selMode == SUBTRACT) {
    selMode = LIGHTEST;
    name = "LIGHTEST";
  } else if (selMode == LIGHTEST) {
    selMode = DARKEST;
    name = "DARKEST";
  } else if (selMode == DARKEST) {
    selMode = DIFFERENCE;
    name = "DIFFERENCE";
  } else if (selMode == DIFFERENCE) {
    selMode = EXCLUSION;
    name = "EXCLUSION";
  } else if (selMode == EXCLUSION) {
    selMode = MULTIPLY;
    name = "MULTIPLY";
  } else if (selMode == MULTIPLY) {
    selMode = SCREEN;
    name = "SCREEN";
  } else if (selMode == SCREEN) {
    selMode = REPLACE;
    name = "REPLACE";
  }
}

void mouseDragged() {
  if (height - 50 < mouseY) {
    picAlpha = int(map(mouseX, 0, width, 0, 255));
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Animation/Sequential/Sequential.pde
/**
 * Sequential
 * by <NAME>.
 *
 * Displaying a sequence of images creates the illusion of motion.
 * Twelve images are loaded and each is displayed individually in a loop.
 */

int numFrames = 12;  // The number of frames in the animation
int currentFrame = 0;
PImage[] images = new PImage[numFrames];

void setup() {
  size(640, 360);
  frameRate(24);

  images[0]  = loadImage("PT_anim0000.gif");
  images[1]  = loadImage("PT_anim0001.gif");
  images[2]  = loadImage("PT_anim0002.gif");
  images[3]  = loadImage("PT_anim0003.gif");
  images[4]  = loadImage("PT_anim0004.gif");
  images[5]  = loadImage("PT_anim0005.gif");
  images[6]  = loadImage("PT_anim0006.gif");
  images[7]  = loadImage("PT_anim0007.gif");
  images[8]  = loadImage("PT_anim0008.gif");
  images[9]  = loadImage("PT_anim0009.gif");
  images[10] = loadImage("PT_anim0010.gif");
  images[11] = loadImage("PT_anim0011.gif");

  // If you don't want to load each image separately
  // and you know how many frames you have, you
  // can create the filenames as the program runs.
  // The nf() command does number formatting, which will
  // ensure that the number is (in this case) 4 digits.
  //for (int i = 0; i < numFrames; i++) {
  //  String imageName = "PT_anim" + nf(i, 4) + ".gif";
  //  images[i] = loadImage(imageName);
  //}
}

void draw() {
  background(0);
  currentFrame = (currentFrame+1) % numFrames;  // Use % to cycle through frames
  int offset = 0;
  for (int x = -100; x < width; x += images[0].width) {
    image(images[(currentFrame+offset) % numFrames], x, -20);
    offset+=2;
    image(images[(currentFrame+offset) % numFrames], x, height/2);
    offset+=2;
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Lights/OnOff/OnOff.pde
/**
 * On/Off.
 *
 * Uses the default lights to show a simple box. The lights() function
 * is used to turn on the default lighting. Click the mouse to turn the
 * lights off.
 */

float spin = 0.0;

void setup() {
  size(640, 360, P3D);
  noStroke();
}

void draw() {
  background(51);

  if (!mousePressed) {
    lights();
  }

  spin += 0.01;

  pushMatrix();
  translate(width/2, height/2, 0);
  rotateX(PI/9);
  rotateY(PI/5 + spin);
  box(150);
  popMatrix();
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Geometry/Icosahedra/Shape3D.pde
abstract class Shape3D{
  float x, y, z;
  float w, h, d;

  Shape3D(){
  }

  Shape3D(float x, float y, float z){
    this.x = x;
    this.y = y;
    this.z = z;
  }

  Shape3D(PVector p){
    x = p.x;
    y = p.y;
    z = p.z;
  }

  Shape3D(Dimension3D dim){
    w = dim.w;
    h = dim.h;
    d = dim.d;
  }

  Shape3D(float x, float y, float z, float w, float h, float d){
    this.x = x;
    this.y = y;
    this.z = z;
    this.w = w;
    this.h = h;
    this.d = d;
  }

  Shape3D(float x, float y, float z, Dimension3D dim){
    this.x = x;
    this.y = y;
    this.z = z;
    w = dim.w;
    h = dim.h;
    d = dim.d;
  }

  Shape3D(PVector p, Dimension3D dim){
    x = p.x;
    y = p.y;
    z = p.z;
    w = dim.w;
    h = dim.h;
    d = dim.d;
  }

  void setLoc(PVector p){
    x=p.x;
    y=p.y;
    z=p.z;
  }

  void setLoc(float x, float y, float z){
    this.x=x;
    this.y=y;
    this.z=z;
  }

  // override if you need these
  void rotX(float theta){
  }

  void rotY(float theta){
  }

  void rotZ(float theta){
  }

  // must be implemented in subclasses
  abstract void init();
  abstract void create();
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/src/processing/mode/java/pdex/ShowUsage.java
package processing.mode.java.pdex;

import static processing.mode.java.pdex.ASTUtils.findAllOccurrences;

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import javax.swing.JDialog;
import javax.swing.JMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.WindowConstants;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeModel;

import org.eclipse.jdt.core.dom.IBinding;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.IVariableBinding;
import org.eclipse.jdt.core.dom.SimpleName;

import processing.app.Language;
import processing.app.ui.EditorStatus;
import processing.app.ui.Toolkit;
import processing.app.ui.ZoomTreeCellRenderer;
import processing.mode.java.JavaEditor;
import processing.mode.java.pdex.PreprocessedSketch.SketchInterval;

class ShowUsage {
  final JDialog window;
  final JTree tree;

  final JavaEditor editor;
  final PreprocessingService pps;

  final Consumer<PreprocessedSketch> reloadListener;

  IBinding binding;

  ShowUsage(JavaEditor editor, PreprocessingService pps) {
    this.editor = editor;
    this.pps = pps;

    // Add show usage option
    JMenuItem showUsageItem =
      new JMenuItem(Language.text("editor.popup.show_usage"));
    showUsageItem.addActionListener(e -> handleShowUsage());
    editor.getTextArea().getRightClickPopup().add(showUsageItem);

    reloadListener = this::reloadShowUsage;

    { // Show Usage window
      window = new JDialog(editor);
      window.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
      window.setAutoRequestFocus(false);
      window.addComponentListener(new ComponentAdapter() {
        @Override
        public void componentHidden(ComponentEvent e) {
          binding = null;
          tree.setModel(null);
          pps.unregisterListener(reloadListener);
        }

        @Override
        public void componentShown(ComponentEvent e) {
          pps.registerListener(reloadListener);
        }
      });
      window.setSize(Toolkit.zoom(300, 400));
      window.setFocusableWindowState(false);
      Toolkit.setIcon(window);
      JScrollPane sp2 = new JScrollPane();
      tree = new JTree();
      ZoomTreeCellRenderer renderer =
        new ZoomTreeCellRenderer(editor.getMode());
      tree.setCellRenderer(renderer);
      renderer.setLeafIcon(null);
      renderer.setClosedIcon(null);
      renderer.setOpenIcon(null);
      renderer.setBackgroundSelectionColor(new Color(228, 248, 246));
      renderer.setBorderSelectionColor(new Color(0, 0, 0, 0));
      renderer.setTextSelectionColor(Color.BLACK);
      sp2.setViewportView(tree);
      window.add(sp2);
    }

    tree.addTreeSelectionListener(e -> {
      if (tree.getLastSelectedPathComponent() != null) {
        DefaultMutableTreeNode tnode =
          (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();

        if (tnode.getUserObject() instanceof ShowUsageTreeNode) {
          ShowUsageTreeNode node = (ShowUsageTreeNode) tnode.getUserObject();
          editor.highlight(node.tabIndex, node.startTabOffset, node.stopTabOffset);
        }
      }
    });
  }

  // Thread: EDT
  void handleShowUsage() {
    int startOffset = editor.getSelectionStart();
    int stopOffset = editor.getSelectionStop();
    int tabIndex = editor.getSketch().getCurrentCodeIndex();

    pps.whenDoneBlocking(ps -> handleShowUsage(ps, tabIndex, startOffset, stopOffset));
  }

  // Thread: worker
  void handleShowUsage(PreprocessedSketch ps, int tabIndex,
                       int startTabOffset, int stopTabOffset) {
    // Map offsets
    int startJavaOffset = ps.tabOffsetToJavaOffset(tabIndex, startTabOffset);
    int stopJavaOffset = ps.tabOffsetToJavaOffset(tabIndex, stopTabOffset);

    // Find the node
    SimpleName name = ASTUtils.getSimpleNameAt(ps.compilationUnit, startJavaOffset, stopJavaOffset);
    if (name == null) {
      editor.statusMessage("Cannot find any name under cursor", EditorStatus.NOTICE);
      return;
    }

    // Find binding
    IBinding binding = ASTUtils.resolveBinding(name);
    if (binding == null) {
      editor.statusMessage("Cannot find usages, try to fix errors in your code first",
                           EditorStatus.NOTICE);
      return;
    }

    findUsageAndUpdateTree(ps, binding);
  }

  // Thread: worker
  void findUsageAndUpdateTree(PreprocessedSketch ps, IBinding binding) {

    this.binding = binding;

    // Get label
    String bindingType = "";
    switch (binding.getKind()) {
      case IBinding.METHOD:
        IMethodBinding method = (IMethodBinding) binding;
        if (method.isConstructor()) bindingType = "Constructor";
        else bindingType = "Method";
        break;
      case IBinding.TYPE:
        bindingType = "Type";
        break;
      case IBinding.VARIABLE:
        IVariableBinding variable = (IVariableBinding) binding;
        if (variable.isField()) bindingType = "Field";
        else if (variable.isParameter()) bindingType = "Parameter";
        else if (variable.isEnumConstant()) bindingType = "Enum constant";
        else bindingType = "Local variable";
        break;
    }

    // Find usages, map to tree nodes, add to root node
    String bindingKey = binding.getKey();
    List<SketchInterval> intervals =
        findAllOccurrences(ps.compilationUnit, bindingKey).stream()
            .map(ps::mapJavaToSketch)
            // remove occurrences which fall into generated header
            .filter(ps::inRange)
            // remove empty intervals (happens when occurence was inserted)
            .filter(in -> in.startPdeOffset < in.stopPdeOffset)
            .collect(Collectors.toList());

    int usageCount = intervals.size();

    // Get element name from PDE code if possible, otherwise use one from Java
    String elementName = intervals.stream()
        .findAny()
        .map(si -> ps.pdeCode.substring(si.startPdeOffset, si.stopPdeOffset))
        .orElseGet(binding::getName);

    // Create root node
    DefaultMutableTreeNode rootNode =
        new DefaultMutableTreeNode(bindingType + ": " + elementName);

    intervals.stream()
        // Convert to TreeNodes
        .map(in -> ShowUsageTreeNode.fromSketchInterval(ps, in))
        // Group by tab index
        .collect(Collectors.groupingBy(node -> node.tabIndex))
        // Stream Map Entries of (tab index) <-> (List<ShowUsageTreeNode>)
        .entrySet().stream()
        // Sort by tab index
        .sorted(Comparator.comparing(Map.Entry::getKey))
        .map(entry -> {
          Integer tabIndex = entry.getKey();
          List<ShowUsageTreeNode> nodes = entry.getValue();

          int count = nodes.size();
          String usageLabel = count == 1 ? "usage" : "usages";

          // Create new DefaultMutableTreeNode for this tab
          String tabLabel = "" +
              ps.sketch.getCode(tabIndex).getPrettyName() +
              " " + count + " " + usageLabel + "";
          DefaultMutableTreeNode tabNode = new DefaultMutableTreeNode(tabLabel);

          // Stream nodes belonging to this tab
          nodes.stream()
              // Convert TreeNodes to DefaultMutableTreeNodes
              .map(DefaultMutableTreeNode::new)
              // Add all as children of tab node
              .forEach(tabNode::add);
          return tabNode;
        })
        // Add all tab nodes as children of root node
        .forEach(rootNode::add);

    TreeModel treeModel = new DefaultTreeModel(rootNode);

    // Update tree
    EventQueue.invokeLater(() -> {
      tree.setModel(treeModel);

      // Expand all nodes
      for (int i = 0; i < tree.getRowCount(); i++) {
        tree.expandRow(i);
      }

      tree.setRootVisible(true);

      if (!window.isVisible()) {
        window.setVisible(true);
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsDevice defaultScreen = ge.getDefaultScreenDevice();
        Rectangle rect = defaultScreen.getDefaultConfiguration().getBounds();
        int maxX = (int) rect.getMaxX() - window.getWidth();
        int x = Math.min(editor.getX() + editor.getWidth(), maxX);
        int y = (x == maxX) ? 10 : editor.getY();
        window.setLocation(x, y);
      }
      window.toFront();
      window.setTitle("Usage of \"" + elementName + "\" : " +
                          usageCount + " time(s)");
    });
  }

  // Thread: worker
  void reloadShowUsage(PreprocessedSketch ps) {
    if (binding != null) {
      findUsageAndUpdateTree(ps, binding);
    }
  }

  void hide() {
    window.setVisible(false);
  }

  void dispose() {
    if (window != null) {
      window.dispose();
    }
  }
}

class ShowUsageTreeNode {
  final int tabIndex;
  final int startTabOffset;
  final int stopTabOffset;

  final String text;

  ShowUsageTreeNode(int tabIndex, int startTabOffset, int stopTabOffset, String text) {
    this.tabIndex = tabIndex;
    this.startTabOffset = startTabOffset;
    this.stopTabOffset = stopTabOffset;
    this.text = text;
  }

  static ShowUsageTreeNode fromSketchInterval(PreprocessedSketch ps, SketchInterval in) {
    int lineStartPdeOffset = ps.pdeCode.lastIndexOf('\n', in.startPdeOffset) + 1;
    int lineStopPdeOffset = ps.pdeCode.indexOf('\n', in.stopPdeOffset);
    if (lineStopPdeOffset == -1) lineStopPdeOffset = ps.pdeCode.length();

    int highlightStartOffset = in.startPdeOffset - lineStartPdeOffset;
    int highlightStopOffset = in.stopPdeOffset - lineStartPdeOffset;

    int tabLine = ps.tabOffsetToTabLine(in.tabIndex, in.startTabOffset);

    // TODO: what a mess
    String line = ps.pdeCode.substring(lineStartPdeOffset, lineStopPdeOffset);
    String pre = line.substring(0, highlightStartOffset)
        .replace("&", "&").replace(">", ">").replace("<", "<");
    String highlight = line.substring(highlightStartOffset, highlightStopOffset)
        .replace("&", "&").replace(">", ">").replace("<", "<");
    String post = line.substring(highlightStopOffset)
        .replace("&", "&").replace(">", ">").replace("<", "<");
    line = pre + "" + highlight + "" + post;
    line = line.trim();

    String text = "" +
        (tabLine + 1) + " " + line + "";

    return new ShowUsageTreeNode(in.tabIndex, in.startTabOffset, in.stopTabOffset, text);
  }

  @Override
  public String toString() {
    return text;
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/tools/MovieMaker/src/ch/randelshofer/media/quicktime/QuickTimeWriter.java
/**
 * @(#)QuickTimeWriter.java  1.3.3  2011-01-17
 *
 * Copyright (c) 2010-2011 <NAME>, Immensee, Switzerland.
 * All rights reserved.
 *
 * You may not use, copy or modify this file, except in compliance with the
 * license agreement you entered into with Werner Randelshofer.
 * For details see accompanying license terms.
 */
package ch.randelshofer.media.quicktime;

import ch.randelshofer.io.ImageOutputStreamAdapter;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
import java.awt.image.DataBufferUShort;
import java.awt.image.IndexColorModel;
import java.awt.image.WritableRaster;
import java.io.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.zip.DeflaterOutputStream;
import javax.imageio.*;
import javax.imageio.stream.*;
import javax.sound.sampled.AudioFormat;

/**
 * Supports writing of time-based video and audio data into a QuickTime movie
 * file (.MOV) without the need of native code.
 *

 * {@code QuickTimeWriter} works with tracks and samples. After creating a
 * {@code QuickTimeWriter} one or more video and audio tracks can be added to
 * it. Then samples can be written into the track(s). A sample is a single
 * element in a sequence of time-ordered data. For video data a sample typically
 * consists of a single video frame, for uncompressed stereo audio data a sample
 * contains one PCM impulse per channel. Samples of compressed media data may encompass larger time units.
 *

 * Tracks support edit lists. An edit list specifies when to play which portion
 * of the media data at what speed. An empty edit can be used to insert an empty
 * time span, for example to offset a track from the start of the movie. Edits
 * can also be used to play the same portion of media data multiple times
 * without having it to store it more than once in the track.

 * Moreover edit lists are useful for lossless cutting of media data at non-sync
 * frames. For example, MP3 layer III audio data can not be cut at arbitrary
 * frames, because audio data can be 'borrowed' from previous frames. An edit
 * list can be used to select the desired portion of the audio data, while the
 * track stores the media starting from the nearest sync frame.
 *

 * Samples are stored in a QuickTime file in the same sequence as they are written.
 * In order to get optimal movie playback, the samples from different tracks
 * should be interleaved from time to time. An interleave should occur about twice
 * per second. Furthermore, to overcome any latencies in sound playback, at
 * least one second of sound data needs to be placed at the beginning of the
 * movie. So that the sound and video data is offset from each other in the file
 * by one second.
 *

 * For convenience, this class has built-in encoders for video frames in the following
 * formats: RAW, RLE, JPEG and PNG. Media data in other formats, including all audio
 * data, must be encoded before it can be written with {@code QuickTimeWriter}.
 *

 * Example: Writing 10 seconds of a movie with 640x480 pixel, 30 fps,
 * PNG-encoded video and 16-bit stereo, 44100 Hz, PCM-encoded audio.
 *

 *

 * QuickTimeWriter w = new QuickTimeWriter(new File("mymovie.mov"));
 * w.addAudioTrack(new AudioFormat(AudioFormat.Encoding.PCM_SIGNED), 44100, 2, 16, 2, 44100, true)); // audio in track 0
 * w.addVideoTrack(QuickTimeWriter.VideoFormat.PNG, 30, 640, 480);  // video in track 1
 *
 * // calculate total movie duration in media time units for each track
 * long atmax = w.getMediaTimeScale(0) * 10;
 * long vtmax = w.getMediaTimeScale(1) * 10;
 *
 * // duration of a single sample
 * long asduration = 1;
 * long vsduration = 1;
 *
 * // half a second in media time units (we interleave twice per second)
 * long atstep = w.getMediaTimeScale(0) / 2;
 * long vtstep = w.getMediaTimeScale(1) / 2;
 *
 * // the time when the next interleave occurs in media time units
 * long atnext = w.getMediaTimeScale(0); // offset audio by 1 second
 * long vtnext = 0;
 *
 * // the current time in media time units
 * long atime = 0;
 * long vtime = 0;
 *
 * // create buffers
 * int asamplesize = 2 * 2; // 16-bit stereo * 2 channels
 * byte[] audio=new byte[atstep * asamplesize];
 * BufferedImage img=new BufferedImage(640, 480, BufferedImage.TYPE_INT_RGB);
 *
 * // main loop
 * while (atime < atmax || vtime < vtmax) {
 *      atnext = Math.min(atmax, atnext + atstep); // advance audio to next interleave time
 *      while (atime < atnext) { // catch up with audio time
 *          int duration = (int) Math.min(audio.length / asamplesize, atmax - atime);
 *          ...fill in audio data for time "atime" and duration "duration" here...
 *          w.writeSamples(0, duration, audio, 0, duration * asamplesize, asduration);
 *          atime += duration;
 *      }
 *      vtnext = Math.min(vtmax, vtnext + vtstep); // advance video to next interleave time
 *      while (vtime < vtnext) { // catch up with video time
 *          int duration = (int) Math.min(1, vtmax - vtime);
 *          ...fill in image data for time "vtime" and duration "duration" here...
 *          w.writeFrame(1, img, vsduration);
 *          vtime += duration;
 *      }
 * }
 * w.close();
 *

 *

 * For information about the QuickTime file format see the
 * "QuickTime File Format Specification", Apple Inc. 2010-08-03. (qtff)
 *
 * http://developer.apple.com/library/mac/documentation/QuickTime/QTFF/qtff.pdf
 *
 *
 * @author <NAME>
 * @version 1.3.3 2011-01-17 Improves writing of compressed movie headers.
 *
1.3.2 2011-01-17 Fixes out of bounds exception when writing
 * sub-images with RLE encoder. Fixes writing of compressed movie headers.
 *
1.3.1 2011-01-09 Fixes broken RAW encoder.
 *
1.3 2011-01-07 Improves robustness of API.
 *                    Adds method toWebOptimizedMovie().
 *
1.2.2 2011-01-07 Reduces file seeking with "RLE" encoder.
 *
1.2.1 2011-01-07 Fixed default syncInterval for "RLE" video.
 *
1.2 2011-01-05 Adds support for "RLE" encoded video.
 *
1.1 2011-01-04 Adds "depth" parameter to addVideoTrack method.
 *
1.0 2011-01-02 Adds support for edit lists. Adds support for MP3
 * audio format.
 *
0.1.1 2010-12-05 Updates the link to the QuickTime file format
 * specification.
 *
0.1 2010-09-30 Created.
 */
@SuppressWarnings("resource")
public class QuickTimeWriter {

    /** An {@code Edit} define the portions of the media that are to be used to
     * build up a track for a movie. The edits themselves are stored in an edit
     * list table, which consists of time offset and duration values for each
     * segment.
     *

     * In the absence of an edit list, the presentation of the track starts
     * immediately. An empty edit is used to offset the start time of a track.
     */
    public static class Edit {

        /** A 32-bit integer that specifies the duration of this edit
         * segment in units of the movie's time scale.
         */
        public int trackDuration;
        /** A 32-bit integer containing the start time within the media
         * of this edit segment (in media time scale units). If this field is
         * set to -1, it is an empty edit. The last edit in a track should never
         * be an empty edit. Any differece between the movie's duration and
         * the track's duration is expressed as an implicit empty edit.
         */
        public int mediaTime;
        /** A 32-bit fixed-point number (16.16) that specifies the relative rate
         * at which to play the media corresponding to this edit segment. This
         * rate value cannot be 0 or negative.
         */
        public int mediaRate;

        /**
         * Creates an edit.
         *
         * @param trackDuration Duration of this edit in the movie's time scale.
         * @param mediaTime Start time of this edit in the media's time scale.
         *                  Specify -1 for an empty edit. The last edit in
         *                  a track should never be an empty edit.
         * @param mediaRate The relative rate at which to play this edit.
         */
        public Edit(int trackDuration, int mediaTime, double mediaRate) {
            if (trackDuration < 0) {
                throw new IllegalArgumentException("trackDuration must not be < 0:" + trackDuration);
            }
            if (mediaTime < -1) {
                throw new IllegalArgumentException("mediaTime must not be < -1:" + mediaTime);
            }
            if (mediaRate <= 0) {
                throw new IllegalArgumentException("mediaRate must not be <= 0:" + mediaRate);
            }
            this.trackDuration = trackDuration;
            this.mediaTime = mediaTime;
            this.mediaRate = (int) (mediaRate * (1 << 16));
        }

        /**
         * Creates an edit.
         *

         * Use this constructor only if you want to compute the fixed point
         * media rate by yourself.
         *
         * @param trackDuration Duration of this edit in the movie's time scale.
         * @param mediaTime Start time of this edit in the media's time scale.
         *                  Specify -1 for an empty edit. The last edit in
         *                  a track should never be an empty edit.
         * @param mediaRate The relative rate at which to play this edit given
         *                  as a 16.16 fixed point value.
         */
        public Edit(int trackDuration, int mediaTime, int mediaRate) {
            if (trackDuration < 0) {
                throw new IllegalArgumentException("trackDuration must not be < 0:" + trackDuration);
            }
            if (mediaTime < -1) {
                throw new IllegalArgumentException("mediaTime must not be < -1:" + mediaTime);
            }
            if (mediaRate <= 0) {
                throw new IllegalArgumentException("mediaRate must not be <= 0:" + mediaRate);
            }
            this.trackDuration = trackDuration;
            this.mediaTime = mediaTime;
            this.mediaRate = mediaRate;
        }
    }
    /**
     * Underlying output stream.
     */
    private ImageOutputStream out;
    /** The offset of the QuickTime stream in the underlying ImageOutputStream.
     * Normally this is 0 unless the underlying stream already contained data
     * when it was passed to the constructor.
     */
    private long streamOffset;

    /**
     * Built-in video formats.
     */
    public static enum VideoFormat {

        /** Raw video frames (lossless and uncompressed). */
        RAW("raw ", "None", true),
        /** Photo-JPEG encoded video frames (lossy). */
        JPG("jpeg", "Photo - JPEG", true),
        /** PNG encoded video frames (lossless). */
        PNG("png ", "PNG", true),
        /** Apple Animation (RLE) encoded video frames (lossless). */
        RLE("rle ", "Animation", false),;
        private String compressionType;
        private String compressorName;
        private boolean allSamplesAreSyncSamples;

        VideoFormat(String compressionType, String compressorName, boolean allSamplesAreSyncSamples) {
            this.compressionType = compressionType;
            this.compressorName = compressorName;
            this.allSamplesAreSyncSamples = allSamplesAreSyncSamples;
        }
    }

    /**
     * Supported track types.
     */
    private static enum MediaType {

        VIDEO, AUDIO;
    }
    /**
     * Creation time of the movie output stream.
     */
    private Date creationTime;
    /**
     * The timeScale of the movie.
     * A time value that indicates the time scale for this media—that is,
     * the number of time units that pass per second in its time coordinate
     * system.
     */
    private long movieTimeScale = 600;
    /** The list of tracks in this movie file. */
    private ArrayList<Track> tracks = new ArrayList<Track>();

    private abstract class Track {

        // Common metadata
        /** The media type of the track. */
        final MediaType mediaType;
        /**
         * The timeScale of the track's media.
         * A time value that indicates the time scale for this media—that is,
         * the number of time units that pass per second in its time coordinate
         * system.
         */
        protected long mediaTimeScale = 600;
        /** The compression type of the media. */
        protected String mediaCompressionType;
        /** The compressor name. */
        protected String mediaCompressorName;
        /**
         * List of chunks.
         */
        protected ArrayList<Chunk> chunks = new ArrayList<Chunk>();
        /**
         * List of TimeToSample entries.
         */
        protected ArrayList<TimeToSampleGroup> timeToSamples = new ArrayList<TimeToSampleGroup>();
        /**
         * List of SampleSize entries.
         */
        protected ArrayList<SampleSizeGroup> sampleSizes = new ArrayList<SampleSizeGroup>();
        /**
         * List of sync samples.
         * This list is null as long as all samples in this track are sync samples.
         */
        protected ArrayList<Long> syncSamples = null;
        /** The number of samples in this track. */
        protected long sampleCount = 0;
        /** The duration of the media in this track in media time units. */
        protected long mediaDuration = 0;
        /** The edit list of the track. */
        protected Edit[] editList;

        public Track(MediaType mediaType) {
            this.mediaType = mediaType;
        }

        public void addSample(Sample sample, int sampleDescriptionId, boolean isSyncSample) {
            mediaDuration += sample.duration;
            sampleCount++;
            if (isSyncSample) {
                if (syncSamples != null) {
                    syncSamples.add(sampleCount);
                }
            } else {
                if (syncSamples == null) {
                    syncSamples = new ArrayList<Long>();
                    for (long i = 1; i < sampleCount; i++) {
                        syncSamples.add(i);
                    }
                }
            }
            if (timeToSamples.isEmpty()//
                    || !timeToSamples.get(timeToSamples.size() - 1).maybeAddSample(sample)) {
                timeToSamples.add(new TimeToSampleGroup(sample));
            }
            if (sampleSizes.isEmpty()//
                    || !sampleSizes.get(sampleSizes.size() - 1).maybeAddSample(sample)) {
                sampleSizes.add(new SampleSizeGroup(sample));
            }
            if (chunks.isEmpty()//
                    || !chunks.get(chunks.size() - 1).maybeAddSample(sample, sampleDescriptionId)) {
                chunks.add(new Chunk(sample, sampleDescriptionId));
            }
        }

        public void addChunk(Chunk chunk, boolean isSyncSample) {
            mediaDuration += chunk.firstSample.duration * chunk.sampleCount;
            sampleCount += chunk.sampleCount;
            if (timeToSamples.isEmpty()//
                    || !timeToSamples.get(timeToSamples.size() - 1).maybeAddChunk(chunk)) {
                timeToSamples.add(new TimeToSampleGroup(chunk));
            }
            if (sampleSizes.isEmpty()//
                    || !sampleSizes.get(sampleSizes.size() - 1).maybeAddChunk(chunk)) {
                sampleSizes.add(new SampleSizeGroup(chunk));
            }
            if (chunks.isEmpty()//
                    || !chunks.get(chunks.size() - 1).maybeAddChunk(chunk)) {
                chunks.add(chunk);
            }
        }

//        public boolean isEmpty() {
//            return sampleCount == 0;
//        }

        public long getSampleCount() {
            return sampleCount;
        }

        /** Gets the track duration in the movie time scale.
         *
         * @param movieTimeScale The time scale of the movie.
         */
        public long getTrackDuration(long movieTimeScale) {
            if (editList == null || editList.length == 0) {
                return mediaDuration * movieTimeScale / mediaTimeScale;
            } else {
                long duration = 0;
                for (int i = 0; i < editList.length; ++i) {
                    duration += editList[i].trackDuration;
                }
                return duration;
            }
        }

        private void writeTrackAtoms(int trackIndex, CompositeAtom moovAtom, Date modificationTime) throws IOException {
            DataAtom leaf;
            DataAtomOutputStream d;

            /* Track Atom ======== */
            CompositeAtom trakAtom = new CompositeAtom("trak");
            moovAtom.add(trakAtom);

            /* Track Header Atom -----------
             * The track header atom specifies the characteristics of a single track
             * within a movie. A track header atom contains a size field that
             * specifies the number of bytes and a type field that indicates the
             * format of the data (defined by the atom type 'tkhd').
             *
            typedef struct {
            byte version;
            byte flag0;
            byte flag1;
            byte set TrackHeaderFlags flag2;
            mactimestamp creationTime;
            mactimestamp modificationTime;
            int trackId;
            byte[4] reserved;
            int duration;
            byte[8] reserved;
            short layer;
            short alternateGroup;
            short volume;
            byte[2] reserved;
            int[9] matrix;
            int trackWidth;
            int trackHeight;
            } trackHeaderAtom;     */
            leaf = new DataAtom("tkhd");
            trakAtom.add(leaf);
            d = leaf.getOutputStream();
            d.write(0); // version
            // A 1-byte specification of the version of this track header.

            d.write(0); // flag[0]
            d.write(0); // flag[1]
            d.write(0xf); // flag[2]
            // Three bytes that are reserved for the track header flags. These flags
            // indicate how the track is used in the movie. The following flags are
            // valid (all flags are enabled when set to 1):
            //
            // Track enabled
            //      Indicates that the track is enabled. Flag value is 0x0001.
            // Track in movie
            //      Indicates that the track is used in the movie. Flag value is
            //      0x0002.
            // Track in preview
            //      Indicates that the track is used in the movie’s preview. Flag
            //      value is 0x0004.
            // Track in poster
            //      Indicates that the track is used in the movie’s poster. Flag
            //      value is 0x0008.

            d.writeMacTimestamp(creationTime); // creationTime
            // A 32-bit integer that indicates the calendar date and time (expressed
            // in seconds since midnight, January 1, 1904) when the track header was
            // created. It is strongly recommended that this value should be
            // specified using coordinated universal time (UTC).

            d.writeMacTimestamp(modificationTime); // modificationTime
            // A 32-bit integer that indicates the calendar date and time (expressed
            // in seconds since midnight, January 1, 1904) when the track header was
            // changed. It is strongly recommended that this value should be
            // specified using coordinated universal time (UTC).

            d.writeInt(trackIndex + 1); // trackId
            // A 32-bit integer that uniquely identifies the track. The value 0
            // cannot be used.

            d.writeInt(0); // reserved;
            // A 32-bit integer that is reserved for use by Apple. Set this field to 0.

            d.writeUInt(getTrackDuration(movieTimeScale)); // duration
            // A time value that indicates the duration of this track (in the
            // movie’s time coordinate system). Note that this property is derived
            // from the track’s edits. The value of this field is equal to the sum
            // of the durations of all of the track’s edits. If there is no edit
            // list, then the duration is the sum of the sample durations, converted
            // into the movie timescale.

            d.writeLong(0); // reserved
            // An 8-byte value that is reserved for use by Apple. Set this field to 0.

            d.writeShort(0); // layer;
            // A 16-bit integer that indicates this track’s spatial priority in its
            // movie. The QuickTime Movie Toolbox uses this value to determine how
            // tracks overlay one another. Tracks with lower layer values are
            // displayed in front of tracks with higher layer values.

            d.writeShort(0); // alternate group
            // A 16-bit integer that specifies a collection of movie tracks that
            // contain alternate data for one another. QuickTime chooses one track
            // from the group to be used when the movie is played. The choice may be
            // based on such considerations as playback quality, language, or the
            // capabilities of the computer.

            d.writeFixed8D8(mediaType == MediaType.AUDIO ? 1 : 0); // volume
            // A 16-bit fixed-point value that indicates how loudly this track’s
            // sound is to be played. A value of 1.0 indicates normal volume.

            d.writeShort(0); // reserved
            // A 16-bit integer that is reserved for use by Apple. Set this field to 0.

            d.writeFixed16D16(1); // matrix[0]
            d.writeFixed16D16(0); // matrix[1]
            d.writeFixed2D30(0); // matrix[2]
            d.writeFixed16D16(0); // matrix[3]
            d.writeFixed16D16(1); // matrix[4]
            d.writeFixed2D30(0); // matrix[5]
            d.writeFixed16D16(0); // matrix[6]
            d.writeFixed16D16(0); // matrix[7]
            d.writeFixed2D30(1); // matrix[8]
            // The matrix structure associated with this track.
            // See Figure 2-8 for an illustration of a matrix structure:
            // http://developer.apple.com/documentation/QuickTime/QTFF/QTFFChap2/chapter_3_section_3.html#//apple_ref/doc/uid/TP40000939-CH204-32967

            d.writeFixed16D16(mediaType == MediaType.VIDEO ? ((VideoTrack) this).videoWidth : 0); // width
            // A 32-bit fixed-point number that specifies the width of this track in pixels.

            d.writeFixed16D16(mediaType == MediaType.VIDEO ? ((VideoTrack) this).videoHeight : 0); // height
            // A 32-bit fixed-point number that indicates the height of this track in pixels.

            /* Edit Atom ========= */
            CompositeAtom edtsAtom = new CompositeAtom("edts");
            trakAtom.add(edtsAtom);

            /* Edit List atom ------- */
            /*
            typedef struct {
            byte version;
            byte[3] flags;
            int numberOfEntries;
            editListTable editListTable[numberOfEntries];
            } editListAtom;

            typedef struct {
            int trackDuration;
            int mediaTime;
            fixed16d16 mediaRate;
            } editListTable;
             */
            leaf = new DataAtom("elst");
            edtsAtom.add(leaf);
            d = leaf.getOutputStream();

            d.write(0); // version
            // One byte that specifies the version of this header atom.

            d.write(0); // flag[0]
            d.write(0); // flag[1]
            d.write(0); // flag[2]

            Edit[] elist = editList;
            if (elist == null || elist.length == 0) {
                d.writeUInt(1); // numberOfEntries
                d.writeUInt(getTrackDuration(movieTimeScale)); // trackDuration
                d.writeUInt(0); // mediaTime
                d.writeFixed16D16(1); // mediaRate
            } else {
                d.writeUInt(elist.length); // numberOfEntries
                for (int i = 0; i < elist.length; ++i) {
                    d.writeUInt(elist[i].trackDuration); // trackDuration
                    d.writeUInt(elist[i].mediaTime); // mediaTime
                    d.writeUInt(elist[i].mediaRate); // mediaRate
                }
            }

            /* Media Atom ========= */
            CompositeAtom mdiaAtom = new CompositeAtom("mdia");
            trakAtom.add(mdiaAtom);

            /* Media Header atom -------
            typedef struct {
            byte version;
            byte[3] flags;
            mactimestamp creationTime;
            mactimestamp modificationTime;
            int timeScale;
            int duration;
            short language;
            short quality;
            } mediaHeaderAtom;*/
            leaf = new DataAtom("mdhd");
            mdiaAtom.add(leaf);
            d = leaf.getOutputStream();
            d.write(0); // version
            // One byte that specifies the version of this header atom.

            d.write(0); // flag[0]
            d.write(0); // flag[1]
            d.write(0); // flag[2]
            // Three bytes of space for media header flags. Set this field to 0.

            d.writeMacTimestamp(creationTime); // creationTime
            // A 32-bit integer that specifies (in seconds since midnight, January
            // 1, 1904) when the media atom was created. It is strongly recommended
            // that this value should be specified using coordinated universal time
            // (UTC).

            d.writeMacTimestamp(modificationTime); // modificationTime
            // A 32-bit integer that specifies (in seconds since midnight, January
            // 1, 1904) when the media atom was changed. It is strongly recommended
            // that this value should be specified using coordinated universal time
            // (UTC).

            d.writeUInt(mediaTimeScale); // timeScale
            // A time value that indicates the time scale for this media—that is,
            // the number of time units that pass per second in its time coordinate
            // system.

            d.writeUInt(mediaDuration); // duration
            // The duration of this media in units of its time scale.

            d.writeShort(0); // language;
            // A 16-bit integer that specifies the language code for this media.
            // See “Language Code Values” for valid language codes:
            // http://developer.apple.com/documentation/QuickTime/QTFF/QTFFChap4/chapter_5_section_2.html#//apple_ref/doc/uid/TP40000939-CH206-27005

            d.writeShort(0); // quality
            // A 16-bit integer that specifies the media’s playback quality—that is,
            // its suitability for playback in a given environment.

            /** Media Handler Reference Atom ------- */
            leaf = new DataAtom("hdlr");
            mdiaAtom.add(leaf);
            /*typedef struct {
            byte version;
            byte[3] flags;
            magic componentType;
            magic componentSubtype;
            magic componentManufacturer;
            int componentFlags;
            int componentFlagsMask;
            pstring componentName;
            } handlerReferenceAtom;
             */
            d = leaf.getOutputStream();
            d.write(0); // version
            // A 1-byte specification of the version of this handler information.

            d.write(0); // flag[0]
            d.write(0); // flag[1]
            d.write(0); // flag[2]
            // A 3-byte space for handler information flags. Set this field to 0.

            d.writeType("mhlr"); // componentType
            // A four-character code that identifies the type of the handler. Only
            // two values are valid for this field: 'mhlr' for media handlers and
            // 'dhlr' for data handlers.

            d.writeType(mediaType == MediaType.VIDEO ? "vide" : "soun"); // componentSubtype
            // A four-character code that identifies the type of the media handler
            // or data handler. For media handlers, this field defines the type of
            // data—for example, 'vide' for video data or 'soun' for sound data.
            //
            // For data handlers, this field defines the data reference type—for
            // example, a component subtype value of 'alis' identifies a file alias.

            if (mediaType == MediaType.AUDIO) {
                d.writeType("appl");
            } else {
                d.writeUInt(0);
            }
            // componentManufacturer
            // Reserved. Set to 0.

            d.writeUInt(mediaType == MediaType.AUDIO ? 268435456L : 0); // componentFlags
            // Reserved. Set to 0.

            d.writeUInt(mediaType == MediaType.AUDIO ? 65941 : 0); // componentFlagsMask
            // Reserved. Set to 0.

            d.writePString(mediaType == MediaType.AUDIO ? "Apple Sound Media Handler" : ""); // componentName (empty string)
            // A (counted) string that specifies the name of the component—that is,
            // the media handler used when this media was created. This field may
            // contain a zero-length (empty) string.

            /* Media Information atom ========= */
            writeMediaInformationAtoms(mdiaAtom);
        }

        private void writeMediaInformationAtoms(CompositeAtom mdiaAtom) throws IOException {
            DataAtom leaf;
            DataAtomOutputStream d;
            /* Media Information atom ========= */
            CompositeAtom minfAtom = new CompositeAtom("minf");
            mdiaAtom.add(minfAtom);

            /* Video or Audio media information atom -------- */
            writeMediaInformationHeaderAtom(minfAtom);

            /* Data Handler Reference Atom -------- */
            // The handler reference atom specifies the media handler component that
            // is to be used to interpret the media’s data. The handler reference
            // atom has an atom type value of 'hdlr'.
            leaf = new DataAtom("hdlr");
            minfAtom.add(leaf);
            /*typedef struct {
            byte version;
            byte[3] flags;
            magic componentType;
            magic componentSubtype;
            magic componentManufacturer;
            int componentFlags;
            int componentFlagsMask;
            pstring componentName;
            } handlerReferenceAtom;
             */
            d = leaf.getOutputStream();
            d.write(0); // version
            // A 1-byte specification of the version of this handler information.

            d.write(0); // flag[0]
            d.write(0); // flag[1]
            d.write(0); // flag[2]
            // A 3-byte space for handler information flags. Set this field to 0.

            d.writeType("dhlr"); // componentType
            // A four-character code that identifies the type of the handler. Only
            // two values are valid for this field: 'mhlr' for media handlers and
            // 'dhlr' for data handlers.

            d.writeType("alis"); // componentSubtype
            // A four-character code that identifies the type of the media handler
            // or data handler. For media handlers, this field defines the type of
            // data—for example, 'vide' for video data or 'soun' for sound data.
            // For data handlers, this field defines the data reference type—for
            // example, a component subtype value of 'alis' identifies a file alias.

            if (mediaType == MediaType.AUDIO) {
                d.writeType("appl");
            } else {
                d.writeUInt(0);
            }
            // componentManufacturer
            // Reserved. Set to 0.

            d.writeUInt(mediaType == MediaType.AUDIO ? 268435457L : 0); // componentFlags
            // Reserved. Set to 0.

            d.writeInt(mediaType == MediaType.AUDIO ? 65967 : 0); // componentFlagsMask
            // Reserved. Set to 0.

            d.writePString("Apple Alias Data Handler"); // componentName (empty string)
            // A (counted) string that specifies the name of the component—that is,
            // the media handler used when this media was created. This field may
            // contain a zero-length (empty) string.

            /* Data information atom ===== */
            CompositeAtom dinfAtom = new CompositeAtom("dinf");
            minfAtom.add(dinfAtom);

            /* Data reference atom ----- */
            // Data reference atoms contain tabular data that instructs the data
            // handler component how to access the media’s data.
            leaf = new DataAtom("dref");
            dinfAtom.add(leaf);
            /*typedef struct {
            ubyte version;
            ubyte[3] flags;
            int numberOfEntries;
            dataReferenceEntry dataReference[numberOfEntries];
            } dataReferenceAtom;

            set {
            dataRefSelfReference=1 // I am not shure if this is the correct value for this flag
            } drefEntryFlags;

            typedef struct {
            int size;
            magic type;
            byte version;
            ubyte flag1;
            ubyte flag2;
            ubyte set drefEntryFlags flag3;
            byte[size - 12] data;
            } dataReferenceEntry;
             */
            d = leaf.getOutputStream();
            d.write(0); // version
            // A 1-byte specification of the version of this data reference atom.

            d.write(0); // flag[0]
            d.write(0); // flag[1]
            d.write(0); // flag[2]
            // A 3-byte space for data reference flags. Set this field to 0.

            d.writeInt(1); // numberOfEntries
            // A 32-bit integer containing the count of data references that follow.

            d.writeInt(12); // dataReference.size
            // A 32-bit integer that specifies the number of bytes in the data
            // reference.

            d.writeType("alis"); // dataReference.type
            // A 32-bit integer that specifies the type of the data in the data
            // reference. Table 2-4 lists valid type values:
            // http://developer.apple.com/documentation/QuickTime/QTFF/QTFFChap2/chapter_3_section_4.html#//apple_ref/doc/uid/TP40000939-CH204-38840

            d.write(0); // dataReference.version
            // A 1-byte specification of the version of the data reference.

            d.write(0); // dataReference.flag1
            d.write(0); // dataReference.flag2
            d.write(0x1); // dataReference.flag3
            // A 3-byte space for data reference flags. There is one defined flag.
            //
            // Self reference
            //      This flag indicates that the media’s data is in the same file as
            //      the movie atom. On the Macintosh, and other file systems with
            //      multifork files, set this flag to 1 even if the data resides in
            //      a different fork from the movie atom. This flag’s value is
            //      0x0001.

            /* Sample Table atom ========= */
            writeSampleTableAtoms(minfAtom);
        }

        protected abstract void writeMediaInformationHeaderAtom(CompositeAtom minfAtom) throws IOException;

        protected abstract void writeSampleDescriptionAtom(CompositeAtom stblAtom) throws IOException;

        private void writeSampleTableAtoms(CompositeAtom minfAtom) throws IOException {
            DataAtom leaf;
            DataAtomOutputStream d;

            /* Sample Table atom ========= */
            CompositeAtom stblAtom = new CompositeAtom("stbl");
            minfAtom.add(stblAtom);

            /* Sample Description atom ------- */
            writeSampleDescriptionAtom(stblAtom);

            /* Time to Sample atom ---- */
            // Time-to-sample atoms store duration information for a media’s
            // samples, providing a mapping from a time in a media to the
            // corresponding data sample. The time-to-sample atom has an atom type
            // of 'stts'.
            leaf = new DataAtom("stts");
            stblAtom.add(leaf);
            /*
            typedef struct {
            byte version;
            byte[3] flags;
            int numberOfEntries;
            timeToSampleTable timeToSampleTable[numberOfEntries];
            } timeToSampleAtom;

            typedef struct {
            int sampleCount;
            int sampleDuration;
            } timeToSampleTable;
             */
            d = leaf.getOutputStream();
            d.write(0); // version
            // A 1-byte specification of the version of this time-to-sample atom.

            d.write(0); // flag[0]
            d.write(0); // flag[1]
            d.write(0); // flag[2]
            // A 3-byte space for time-to-sample flags. Set this field to 0.

            d.writeUInt(timeToSamples.size()); // numberOfEntries
            // A 32-bit integer containing the count of entries in the
            // time-to-sample table.

            for (TimeToSampleGroup tts : timeToSamples) {
                d.writeUInt(tts.getSampleCount()); // timeToSampleTable[0].sampleCount
                // A 32-bit integer that specifies the number of consecutive
                // samples that have the same duration.

                d.writeUInt(tts.getSampleDuration()); // timeToSampleTable[0].sampleDuration
                // A 32-bit integer that specifies the duration of each
                // sample.
            }
            /* sample to chunk atom -------- */
            // The sample-to-chunk atom contains a table that maps samples to chunks
            // in the media data stream. By examining the sample-to-chunk atom, you
            // can determine the chunk that contains a specific sample.
            leaf = new DataAtom("stsc");
            stblAtom.add(leaf);
            /*
            typedef struct {
            byte version;
            byte[3] flags;
            int numberOfEntries;
            sampleToChunkTable sampleToChunkTable[numberOfEntries];
            } sampleToChunkAtom;

            typedef struct {
            int firstChunk;
            int samplesPerChunk;
            int sampleDescription;
            } sampleToChunkTable;
             */
            d = leaf.getOutputStream();
            d.write(0); // version
            // A 1-byte specification of the version of this time-to-sample atom.

            d.write(0); // flag[0]
            d.write(0); // flag[1]
            d.write(0); // flag[2]
            // A 3-byte space for time-to-sample flags. Set this field to 0.

            int entryCount = 0;
            long previousSampleCount = -1;
            long previousSampleDescriptionId = -1;
            for (Chunk c : chunks) {
                if (c.sampleCount != previousSampleCount//
                        || c.sampleDescriptionId != previousSampleDescriptionId) {
                    previousSampleCount = c.sampleCount;
                    previousSampleDescriptionId = c.sampleDescriptionId;
                    entryCount++;
                }
            }

            d.writeInt(entryCount); // number of entries
            // A 32-bit integer containing the count of entries in the sample-to-chunk table.

            int firstChunk = 1;
            previousSampleCount = -1;
            previousSampleDescriptionId = -1;
            for (Chunk c : chunks) {
                if (c.sampleCount != previousSampleCount//
                        || c.sampleDescriptionId != previousSampleDescriptionId) {
                    previousSampleCount = c.sampleCount;
                    previousSampleDescriptionId = c.sampleDescriptionId;

                    d.writeUInt(firstChunk); // first chunk
                    // The first chunk number using this table entry.

                    d.writeUInt(c.sampleCount); // samples per chunk
                    // The number of samples in each chunk.

                    d.writeInt(c.sampleDescriptionId); // sample description

                    // The identification number associated with the sample description for
                    // the sample. For details on sample description atoms, see “Sample
                    // Description Atoms.”:
                    // http://developer.apple.com/documentation/QuickTime/QTFF/QTFFChap2/chapter_3_section_5.html#//apple_ref/doc/uid/TP40000939-CH204-25691
                }
                firstChunk++;
            }
            //
        /* sync sample atom -------- */
            if (syncSamples != null) {
                leaf = new DataAtom("stss");
                stblAtom.add(leaf);
                /*
                typedef struct {
                byte version;
                byte[3] flags;
                int numberOfEntries;
                syncSampleTable syncSampleTable[numberOfEntries];
                } syncSampleAtom;

                typedef struct {
                int number;
                } syncSampleTable;
                 */
                d = leaf.getOutputStream();
                d.write(0); // version
                // A 1-byte specification of the version of this time-to-sample atom.

                d.write(0); // flag[0]
                d.write(0); // flag[1]
                d.write(0); // flag[2]
                // A 3-byte space for time-to-sample flags. Set this field to 0.

                d.writeUInt(syncSamples.size());
                // Number of entries
                //A 32-bit integer containing the count of entries in the sync sample table.

                for (Long number : syncSamples) {
                    d.writeUInt(number);
                    // Sync sample table A table of sample numbers; each sample
                    // number corresponds to a key frame.
                }
            }

            /* sample size atom -------- */
            // The sample size atom contains the sample count and a table giving the
            // size of each sample. This allows the media data itself to be
            // unframed. The total number of samples in the media is always
            // indicated in the sample count. If the default size is indicated, then
            // no table follows.
            leaf = new DataAtom("stsz");
            stblAtom.add(leaf);
            /*
            typedef struct {
            byte version;
            byte[3] flags;
            int sampleSize;
            int numberOfEntries;
            sampleSizeTable sampleSizeTable[numberOfEntries];
            } sampleSizeAtom;

            typedef struct {
            int size;
            } sampleSizeTable;
             */
            d = leaf.getOutputStream();
            d.write(0); // version
            // A 1-byte specification of the version of this time-to-sample atom.

            d.write(0); // flag[0]
            d.write(0); // flag[1]
            d.write(0); // flag[2]
            // A 3-byte space for time-to-sample flags. Set this field to 0.

            int sampleUnit = mediaType == MediaType.AUDIO//
                    && ((AudioTrack) this).soundCompressionId != -2 //
                    ? ((AudioTrack) this).soundSampleSize / 8 * ((AudioTrack) this).soundNumberOfChannels//
                    : 1;
            if (sampleSizes.size() == 1) {
                d.writeUInt(sampleSizes.get(0).getSampleLength() / sampleUnit); // sample size
                // A 32-bit integer specifying the sample size. If all the samples are
                // the same size, this field contains that size value. If this field is
                // set to 0, then the samples have different sizes, and those sizes are
                // stored in the sample size table.

                d.writeUInt(sampleSizes.get(0).getSampleCount()); // number of entries
                // A 32-bit integer containing the count of entries in the sample size
                // table.

            } else {
                d.writeUInt(0); // sample size
                // A 32-bit integer specifying the sample size. If all the samples are
                // the same size, this field contains that size value. If this field is
                // set to 0, then the samples have different sizes, and those sizes are
                // stored in the sample size table.

                long count = 0;
                for (SampleSizeGroup s : sampleSizes) {
                    count += s.sampleCount;
                }
                d.writeUInt(count); // number of entries
                // A 32-bit integer containing the count of entries in the sample size
                // table.

                for (SampleSizeGroup s : sampleSizes) {
                    long sampleSize = s.getSampleLength() / sampleUnit;
                    for (int i = 0; i < s.sampleCount; i++) {
                        d.writeUInt(sampleSize); // sample size
                        // The size field contains the size, in bytes, of the sample in
                        // question. The table is indexed by sample number—the first entry
                        // corresponds to the first sample, the second entry is for the
                        // second sample, and so on.
                    }
                }
            }
            //
        /* chunk offset atom -------- */
            // The chunk-offset table gives the index of each chunk into the
            // QuickTime Stream. There are two variants, permitting the use of
            // 32-bit or 64-bit offsets. The latter is useful when managing very
            // large movies. Only one of these variants occurs in any single
            // instance of a sample table atom.
            if (chunks.isEmpty() || chunks.get(chunks.size() - 1).getChunkOffset() <= 0xffffffffL) {
                /* 32-bit chunk offset atom -------- */
                leaf = new DataAtom("stco");
                stblAtom.add(leaf);
                /*
                typedef struct {
                byte version;
                byte[3] flags;
                int numberOfEntries;
                chunkOffsetTable chunkOffsetTable[numberOfEntries];
                } chunkOffsetAtom;

                typedef struct {
                int offset;
                } chunkOffsetTable;
                 */
                d = leaf.getOutputStream();
                d.write(0); // version
                // A 1-byte specification of the version of this time-to-sample atom.

                d.write(0); // flag[0]
                d.write(0); // flag[1]
                d.write(0); // flag[2]
                // A 3-byte space for time-to-sample flags. Set this field to 0.

                d.writeUInt(chunks.size()); // number of entries
                // A 32-bit integer containing the count of entries in the chunk
                // offset table.
                for (Chunk c : chunks) {
                    d.writeUInt(c.getChunkOffset() + mdatOffset); // offset
                    // The offset contains the byte offset from the beginning of the
                    // data stream to the chunk. The table is indexed by chunk
                    // number—the first table entry corresponds to the first chunk,
                    // the second table entry is for the second chunk, and so on.
                }
            } else {
                /* 64-bit chunk offset atom -------- */
                leaf = new DataAtom("co64");
                stblAtom.add(leaf);
                /*
                typedef struct {
                byte version;
                byte[3] flags;
                int numberOfEntries;
                chunkOffsetTable chunkOffset64Table[numberOfEntries];
                } chunkOffset64Atom;

                typedef struct {
                long offset;
                } chunkOffset64Table;
                 */
                d = leaf.getOutputStream();
                d.write(0); // version
                // A 1-byte specification of the version of this time-to-sample atom.

                d.write(0); // flag[0]
                d.write(0); // flag[1]
                d.write(0); // flag[2]
                // A 3-byte space for time-to-sample flags. Set this field to 0.

                d.writeUInt(chunks.size()); // number of entries
                // A 32-bit integer containing the count of entries in the chunk
                // offset table.

                for (Chunk c : chunks) {
                    d.writeLong(c.getChunkOffset()); // offset
                    // The offset contains the byte offset from the beginning of the
                    // data stream to the chunk. The table is indexed by chunk
                    // number—the first table entry corresponds to the first chunk,
                    // the second table entry is for the second chunk, and so on.
                }
            }
        }
    }

    private class VideoTrack extends Track {
        // Video metadata

        /**
         * The video encoding. Must either correspond to {@code sampleType} and
         * {@code compressorName} or must be null.
         * Must be null, if the track is not a video track.
         */
        private VideoFormat videoEncoding;
        /**
         * The video compression quality.
         */
        private float videoQuality = 0.97f;
        /**
         * Width of the video frames. All frames must have the same width.
         * The value -1 is used to mark unspecified width.
         */
        private int videoWidth = -1;
        /**
         * Height of the video frames. All frames must have the same height.
         * The value -1 is used to mark unspecified height.
         */
        private int videoHeight = -1;
        /**
         * Number of bits per ixel. All frames must have the same depth.
         * The value -1 is used to mark unspecified depth.
         */
        private int videoDepth = -1;
        /** The color table used for rendering the video.
         * This variable is only used when the video uses an index color model.
         */
        private IndexColorModel videoColorTable;
        /** The encoder. */
        private AppleRLEEncoder encoder;
        /** The previous frame. This is needed for delta compression. */
        private Object previousData;
        /** Interval between sync samples (keyframes).
         * 0 = automatic.
         * 1 = write all samples as sync samples.
         * n = sync every n-th sample.
         */
        private int syncInterval;

        public VideoTrack() {
            super(MediaType.VIDEO);
        }

        @Override
        protected void writeMediaInformationHeaderAtom(CompositeAtom minfAtom) throws IOException {
            DataAtom leaf;
            DataAtomOutputStream d;

            /* Video media information atom -------- */
            leaf = new DataAtom("vmhd");
            minfAtom.add(leaf);
            /*typedef struct {
            byte version;
            byte flag1;
            byte flag2;
            byte set vmhdFlags flag3;
            short graphicsMode;
            ushort[3] opcolor;
            } videoMediaInformationHeaderAtom;*/
            d = leaf.getOutputStream();
            d.write(0); // version
            // One byte that specifies the version of this header atom.

            d.write(0); // flag[0]
            d.write(0); // flag[1]
            d.write(0x1); // flag[2]
            // Three bytes of space for media header flags.
            // This is a compatibility flag that allows QuickTime to distinguish
            // between movies created with QuickTime 1.0 and newer movies. You
            // should always set this flag to 1, unless you are creating a movie
            // intended for playback using version 1.0 of QuickTime. This flag’s
            // value is 0x0001.

            d.writeShort(0x40); // graphicsMode (0x40 = DitherCopy)
            // A 16-bit integer that specifies the transfer mode. The transfer mode
            // specifies which Boolean operation QuickDraw should perform when
            // drawing or transferring an image from one location to another.
            // See “Graphics Modes” for a list of graphics modes supported by
            // QuickTime:
            // http://developer.apple.com/documentation/QuickTime/QTFF/QTFFChap4/chapter_5_section_5.html#//apple_ref/doc/uid/TP40000939-CH206-18741

            d.writeUShort(0); // opcolor[0]
            d.writeUShort(0); // opcolor[1]
            d.writeUShort(0); // opcolor[2]
            // Three 16-bit values that specify the red, green, and blue colors for
            // the transfer mode operation indicated in the graphics mode field.
        }

        @Override
        protected void writeSampleDescriptionAtom(CompositeAtom stblAtom) throws IOException {
            CompositeAtom leaf;
            DataAtomOutputStream d;

            /* Sample Description atom ------- */
            // The sample description atom stores information that allows you to
            // decode samples in the media. The data stored in the sample
            // description varies, depending on the media type. For example, in the
            // case of video media, the sample descriptions are image description
            // structures. The sample description information for each media type is
            // explained in “Media Data Atom Types”:
            // http://developer.apple.com/documentation/QuickTime/QTFF/QTFFChap3/chapter_4_section_1.html#//apple_ref/doc/uid/TP40000939-CH205-SW1
            leaf = new CompositeAtom("stsd");
            stblAtom.add(leaf);
            /*
            typedef struct {
            byte version;
            byte[3] flags;
            int numberOfEntries;
            sampleDescriptionEntry sampleDescriptionTable[numberOfEntries];
            } sampleDescriptionAtom;

            typedef struct {
            int size;
            magic type;
            byte[6] reserved; // six bytes that must be zero
            short dataReferenceIndex; // A 16-bit integer that contains the index of the data reference to use to retrieve data associated with samples that use this sample description. Data references are stored in data reference atoms.
            byte[size - 16] data;
            } sampleDescriptionEntry;
             */
            d = leaf.getOutputStream();
            d.write(0); // version
            // A 1-byte specification of the version of this sample description atom.

            d.write(0); // flag[0]
            d.write(0); // flag[1]
            d.write(0); // flag[2]
            // A 3-byte space for sample description flags. Set this field to 0.

            d.writeInt(1); // number of Entries
            // A 32-bit integer containing the number of sample descriptions that follow.

            // A 32-bit integer indicating the number of bytes in the sample description.
//            d.writeInt(86); // sampleDescriptionTable[0].size
            d.writeInt(86 + 12);
            // This looks like a bug, it'll be incorrect if the color table
            // is written down below. [fry 131008]
            // 12 bytes for gamma (appears from the file)
            // 18 bytes for colr

            d.writeType(mediaCompressionType); // sampleDescriptionTable[0].type

            // A 32-bit integer indicating the format of the stored data.
            // This depends on the media type, but is usually either the
            // compression format or the media type.

            d.write(new byte[6]); // sampleDescriptionTable[0].reserved
            // Six bytes that must be set to 0.

            d.writeShort(1); // sampleDescriptionTable[0].dataReferenceIndex
            // A 16-bit integer that contains the index of the data
            // reference to use to retrieve data associated with samples
            // that use this sample description. Data references are stored
            // in data reference atoms.

            // Video Sample Description
            // ------------------------
            // The format of the following fields is described here:
            // http://developer.apple.com/documentation/QuickTime/QTFF/QTFFChap3/chapter_4_section_2.html#//apple_ref/doc/uid/TP40000939-CH205-BBCGICBJ

            d.writeShort(0); // sampleDescriptionTable.videoSampleDescription.version
            // A 16-bit integer indicating the version number of the
            // compressed data. This is set to 0, unless a compressor has
            // changed its data format.

            d.writeShort(0); // sampleDescriptionTable.videoSampleDescription.revisionLevel
            // A 16-bit integer that must be set to 0.

            d.writeType("java"); // sampleDescriptionTable.videoSampleDescription.manufacturer
            // A 32-bit integer that specifies the developer of the
            // compressor that generated the compressed data. Often this
            // field contains 'appl' to indicate Apple Computer, Inc.

            d.writeInt(0);  // sampleDescriptionTable.videoSampleDescription.temporalQuality
            // A 32-bit integer containing a value from 0 to 1023 indicating
            // the degree of temporal compression.

            d.writeInt(512); // sampleDescriptionTable.videoSampleDescription.spatialQuality
            // A 32-bit integer containing a value from 0 to 1024 indicating
            // the degree of spatial compression.

            d.writeUShort(videoWidth); // sampleDescriptionTable.videoSampleDescription.width
            // A 16-bit integer that specifies the width of the source image
            // in pixels.

            d.writeUShort(videoHeight); // sampleDescriptionTable.videoSampleDescription.height
            // A 16-bit integer that specifies the height of the source image in pixels.

            d.writeFixed16D16(72.0); // sampleDescriptionTable.videoSampleDescription.horizontalResolution
            // A 32-bit fixed-point number containing the horizontal
            // resolution of the image in pixels per inch.

            d.writeFixed16D16(72.0); // sampleDescriptionTable.videoSampleDescription.verticalResolution
            // A 32-bit fixed-point number containing the vertical
            // resolution of the image in pixels per inch.

            d.writeInt(0); // sampleDescriptionTable.videoSampleDescription.dataSize
            // A 32-bit integer that must be set to 0.

            d.writeShort(1); // sampleDescriptionTable.videoSampleDescription.sampleCount
            // A 16-bit integer that indicates how many bytes of compressed
            // data are stored in each sample. Usually set to 1.

            d.writePString(mediaCompressorName, 32); // sampleDescriptionTable.videoSampleDescription.compressorName
            // A 32-byte Pascal string containing the name of the compressor
            // that created the image, such as "jpeg".

            d.writeShort(videoDepth); // sampleDescriptionTable.videoSampleDescription.depth
            // A 16-bit integer that indicates the pixel depth of the
            // compressed image. Values of 1, 2, 4, 8 ,16, 24, and 32
            // indicate the depth of color images. The value 32 should be
            // used only if the image contains an alpha channel. Values of
            // 34, 36, and 40 indicate 2-, 4-, and 8-bit grayscale,
            // respectively, for grayscale images.

            d.writeShort(videoColorTable == null ? -1 : 0); // sampleDescriptionTable.videoSampleDescription.colorTableID
            // A 16-bit integer that identifies which color table to use.
            // If this field is set to –1, the default color table should be
            // used for the specified depth. For all depths below 16 bits
            // per pixel, this indicates a standard Macintosh color table
            // for the specified depth. Depths of 16, 24, and 32 have no
            // color table.

            if (videoColorTable != null) {
                writeColorTableAtom(leaf);
            }
            // Add gamma atom so things aren't all washed out [fry 131008]
            writeGammaAtom(leaf);
        }

        /**
         * Color table atoms define a list of preferred colors for displaying
         * the movie on devices that support only 256 colors. The list may
         * contain up to 256 colors. These optional atoms have a type value of
         * 'ctab'. The color table atom contains a Macintosh color table data
         * structure.
         *
         * @param stblAtom
         * @throws IOException
         */
        protected void writeGammaAtom(CompositeAtom stblAtom) throws IOException {
            DataAtom leaf;
            DataAtomOutputStream d;
            leaf = new DataAtom("gama");
            stblAtom.add(leaf);

            d = leaf.getOutputStream();

            // Write the gamma value as a 16:16 fixed number
            //d.writeFixed16D16(1.8);
            d.writeFixed16D16(2.2);
        }

        /**
         * Color table atoms define a list of preferred colors for displaying
         * the movie on devices that support only 256 colors. The list may
         * contain up to 256 colors. These optional atoms have a type value of
         * 'ctab'. The color table atom contains a Macintosh color table data
         * structure.
         *
         * @param stblAtom
         * @throws IOException
         */
        protected void writeColorTableAtom(CompositeAtom stblAtom) throws IOException {
            DataAtom leaf;
            DataAtomOutputStream d;
            leaf = new DataAtom("ctab");
            stblAtom.add(leaf);

            d = leaf.getOutputStream();

            d.writeUInt(0); // Color table seed. A 32-bit integer that must be set to 0.
            d.writeUShort(0x8000); // Color table flags. A 16-bit integer that must be set to 0x8000.
            d.writeUShort(videoColorTable.getMapSize() - 1);
            // Color table size. A 16-bit integer that indicates the number of
            // colors in the following color array. This is a zero-relative value;
            // setting this field to 0 means that there is one color in the array.

            for (int i = 0, n = videoColorTable.getMapSize(); i < n; ++i) {
                // An array of colors. Each color is made of four unsigned 16-bit integers.
                // The first integer must be set to 0, the second is the red value,
                // the third is the green value, and the fourth is the blue value.
                d.writeUShort(0);
                d.writeUShort((videoColorTable.getRed(i) << 8) | videoColorTable.getRed(i));
                d.writeUShort((videoColorTable.getGreen(i) << 8) | videoColorTable.getGreen(i));
                d.writeUShort((videoColorTable.getBlue(i) << 8) | videoColorTable.getBlue(i));
            }
        }
    }

    private class AudioTrack extends Track {
        // Audio metadata

        /**
         * Number of sound channels used by the sound sample.
         */
        private int soundNumberOfChannels;
        /**
         * Number of bits per audio sample before compression.
         */
        private int soundSampleSize;
        /** Sound compressionId.
         * The value -1 means fixed bit rate, -2 means varable bit rate.
         */
        private int soundCompressionId;
        /** Sound stsd samples per packet.
         * The number of uncompressed samples generated by a
         * compressed sample (an uncompressed sample is one sample
         * from each channel). This is also the sample duration,
         * expressed in the media’s timescale, where the
         * timescale is equal to the sample rate. For
         * uncompressed formats, this field is always 1.
         */
        private long soundSamplesPerPacket;
        /**
         * For uncompressed audio, the number of bytes in a
         * sample for a single channel. This replaces the older
         * sampleSize field, which is set to 16.
         * This value is calculated by dividing the frame size
         * by the number of channels. The same calculation is
         * performed to calculate the value of this field for
         * compressed audio, but the result of the calculation
         * is not generally meaningful for compressed audio.
         */
        private int soundBytesPerPacket;
        /** The number of bytes in a frame: for uncompressed audio, an
         * uncompressed frame; for compressed audio, a compressed frame. This
         * can be calculated by multiplying the bytes per packet field by the
         * number of channels.
         */
        private int soundBytesPerFrame;
        /**
         * The size of an uncompressed sample in bytes. This is set to 1 for
         * 8-bit audio, 2 for all other cases, even if the sample size is
         * greater than 2 bytes.
         */
        private int soundBytesPerSample;
        /**
         * Sound sample rate. The integer portion must match the media's time scale.
         */
        private double soundSampleRate;
        /** Extensions to the stsd chunk.
         * Must contain atom-based fields:
         * ([long size, long type, some data], repeat)
         */
        private byte[] stsdExtensions = new byte[0];

        public AudioTrack() {
            super(MediaType.AUDIO);
        }

        @Override
        protected void writeMediaInformationHeaderAtom(CompositeAtom minfAtom) throws IOException {
            DataAtom leaf;
            DataAtomOutputStream d;

            /* Sound media information header atom -------- */
            leaf = new DataAtom("smhd");
            minfAtom.add(leaf);
            /*typedef struct {
            ubyte version;
            ubyte[3] flags;
            short balance;
            short reserved;
            } soundMediaInformationHeaderAtom;*/
            d = leaf.getOutputStream();
            d.write(0); // version
            // A 1-byte specification of the version of this sound media information header atom.

            d.write(0); // flag[0]
            d.write(0); // flag[1]
            d.write(0); // flag[2]
            // A 3-byte space for sound media information flags. Set this field to 0.

            d.writeFixed8D8(0); // balance
            // A 16-bit integer that specifies the sound balance of this
            // sound media. Sound balance is the setting that controls
            // the mix of sound between the two speakers of a computer.
            // This field is normally set to 0.
            // Balance values are represented as 16-bit, fixed-point
            // numbers that range from -1.0 to +1.0. The high-order 8
            // bits contain the integer portion of the value; the
            // low-order 8 bits contain the fractional part. Negative
            // values weight the balance toward the left speaker;
            // positive values emphasize the right channel. Setting the
            // balance to 0 corresponds to a neutral setting.

            d.writeUShort(0); // reserved
            // Reserved for use by Apple. Set this field to 0.

        }

        @Override
        protected void writeSampleDescriptionAtom(CompositeAtom stblAtom) throws IOException {
            // TO DO
            DataAtom leaf;
            DataAtomOutputStream d;

            /* Sample Description atom ------- */
            // The sample description atom stores information that allows you to
            // decode samples in the media. The data stored in the sample
            // description varies, depending on the media type. For example, in the
            // case of video media, the sample descriptions are image description
            // structures. The sample description information for each media type is
            // explained in “Media Data Atom Types”:
            // http://developer.apple.com/documentation/QuickTime/QTFF/QTFFChap3/chapter_4_section_1.html#//apple_ref/doc/uid/TP40000939-CH205-SW1
            leaf = new DataAtom("stsd");
            stblAtom.add(leaf);
            /*
            typedef struct {
            byte version;
            byte[3] flags;
            int numberOfEntries;
            soundSampleDescriptionEntry sampleDescriptionTable[numberOfEntries];
            } soundSampleDescriptionAtom;

            typedef struct {
            int size;
            magic type;
            byte[6] reserved;
            short dataReferenceIndex;
            soundSampleDescription data;
            } soundSampleDescriptionEntry;

            typedef struct {
            ushort version;
            ushort revisionLevel;
            uint vendor;
            ushort numberOfChannels;
            ushort sampleSize;
            short compressionId;
            ushort packetSize;
            fixed16d16 sampleRate;
            byte[] extendedData;
            } soundSampleDescription;
             */
            d = leaf.getOutputStream();

            // soundSampleDescriptionAtom:
            // ---------------------------
            d.write(0); // version
            // A 1-byte specification of the version of this sample description atom.

            d.write(0); // flag[0]
            d.write(0); // flag[1]
            d.write(0); // flag[2]
            // A 3-byte space for sample description flags. Set this field to 0.

            d.writeInt(1); // number of Entries
            // A 32-bit integer containing the number of sample descriptions that follow.

            // soundSampleDescriptionEntry:
            // ----------------------------
            // A 32-bit integer indicating the number of bytes in the sample description.
            d.writeUInt(4 + 12 + 20 + 16 + stsdExtensions.length); // sampleDescriptionTable[0].size

            // Common header: 12 bytes
            d.writeType(mediaCompressionType); // sampleDescriptionTable[0].type
            // A 32-bit integer indicating the format of the stored data.
            // This depends on the media type, but is usually either the
            // compression format or the media type.

            d.write(new byte[6]); // sampleDescriptionTable[0].reserved
            // Six bytes that must be set to 0.

            d.writeUShort(1); // sampleDescriptionTable[0].dataReferenceIndex
            // A 16-bit integer that contains the index of the data
            // reference to use to retrieve data associated with samples
            // that use this sample description. Data references are stored
            // in data reference atoms.

            // Sound Sample Description (Version 0) 20 bytes
            // ------------------------

            d.writeUShort(1); // version
            // A 16-bit integer that holds the sample description version (currently 0 or 1).

            d.writeUShort(0); // revisionLevel
            // A 16-bit integer that must be set to 0.

            d.writeUInt(0); // vendor
            // A 32-bit integer that must be set to 0.

            d.writeUShort(soundNumberOfChannels);  // numberOfChannels
            // A 16-bit integer that indicates the number of sound channels used by
            // the sound sample. Set to 1 for monaural sounds, 2 for stereo sounds.
            // Higher numbers of channels are not supported.

            d.writeUShort(soundSampleSize); // sampleSize (bits)
            // A 16-bit integer that specifies the number of bits in each
            // uncompressed sound sample. Allowable values are 8 or 16. Formats
            // using more than 16 bits per sample set this field to 16 and use sound
            // description version 1.

            d.writeUShort(soundCompressionId); // compressionId
            // XXX - This must be set to -1, or the QuickTime player won't accept this file.
            // A 16-bit integer that must be set to 0 for version 0 sound
            // descriptions. This may be set to –2 for some version 1 sound
            // descriptions; see “Redefined Sample Tables” (page 135).

            d.writeUShort(0); // packetSize
            // A 16-bit integer that must be set to 0.

            d.writeFixed16D16(soundSampleRate); // sampleRate
            // A 32-bit unsigned fixed-point number (16.16) that indicates the rate
            // at which the sound samples were obtained. The integer portion of this
            // number should match the media’s time scale. Many older version 0
            // files have values of 22254.5454 or 11127.2727, but most files have
            // integer values, such as 44100. Sample rates greater than 2^16 are not
            // supported.

            // Sound Sample Description Additional fields (only in Version 1) 16 bytes
            // ------------------------
            d.writeUInt(soundSamplesPerPacket); // samplesPerPacket
            // A 32-bit integer.
            // The number of uncompressed samples generated by a
            // compressed sample (an uncompressed sample is one sample
            // from each channel). This is also the sample duration,
            // expressed in the media’s timescale, where the
            // timescale is equal to the sample rate. For
            // uncompressed formats, this field is always 1.
            //
            d.writeUInt(soundBytesPerPacket); // bytesPerPacket
            // A 32-bit integer.
            // For uncompressed audio, the number of bytes in a
            // sample for a single channel. This replaces the older
            // sampleSize field, which is set to 16.
            // This value is calculated by dividing the frame size
            // by the number of channels. The same calculation is
            // performed to calculate the value of this field for
            // compressed audio, but the result of the calculation
            // is not generally meaningful for compressed audio.
            //
            d.writeUInt(soundBytesPerFrame); // bytesPerFrame
            // A 32-bit integer.
            // The number of bytes in a sample: for uncompressed
            // audio, an uncompressed frame; for compressed audio, a
            // compressed frame. This can be calculated by
            // multiplying the bytes per packet field by the number
            // of channels.
            //
            d.writeUInt(soundBytesPerSample); // bytesPerSample
            // A 32-bit integer.
            // The size of an uncompressed sample in bytes. This is
            // set to 1 for 8-bit audio, 2 for all other cases, even
            // if the sample size is greater than 2 bytes.

            // Write stsd Extensions
            // Extensions must be atom-based fields
            // ------------------------------------
            d.write(stsdExtensions);
        }
    }

    /**
     * The states of the movie output stream.
     */
    private static enum States {

        REALIZED, STARTED, FINISHED, CLOSED;
    }
    /**
     * The current state of the movie output stream.
     */
    private States state = States.REALIZED;

    /**
     * QuickTime stores media data in samples.
     * A sample is a single element in a sequence of time-ordered data.
     * Samples are stored in the mdat atom.
     */
    private static class Sample {

        /** Offset of the sample relative to the start of the QuickTime file.
         */
        long offset;
        /** Data length of the sample. */
        long length;
        /**
         * The duration of the sample in media time scale units.
         */
        long duration;

        /**
         * Creates a new sample.
         * @param duration
         * @param offset
         * @param length
         */
        public Sample(long duration, long offset, long length) {
            this.duration = duration;
            this.offset = offset;
            this.length = length;
        }
    }

    /**
     * Groups consecutive samples with same characteristics.
     */
    private abstract static class Group {

        protected Sample firstSample;
        protected Sample lastSample;
        protected long sampleCount;
        private final static long maxSampleCount = Integer.MAX_VALUE;

        protected Group(Sample firstSample) {
            this.firstSample = this.lastSample = firstSample;
            sampleCount = 1;
        }

        protected Group(Sample firstSample, Sample lastSample, long sampleCount) {
            this.firstSample = firstSample;
            this.lastSample = lastSample;
            this.sampleCount = sampleCount;
            if (sampleCount > maxSampleCount) {
                throw new IllegalArgumentException("Capacity exceeded");
            }
        }

        protected Group(Group group) {
            this.firstSample = group.firstSample;
            this.lastSample = group.lastSample;
            sampleCount = group.sampleCount;
        }

        /** Returns true, if the samples was added to the group.
         * If false is returned, the sample must be added to a new group.
         *

         * A sample can only be added to a group, if the capacity of the group
         * is not exceeded.
         */
        protected boolean maybeAddSample(Sample sample) {
            if (sampleCount < maxSampleCount) {
                lastSample = sample;
                sampleCount++;
                return true;
            }
            return false;
        }

        /** Returns true, if the chunk was added to the group.
         * If false is returned, the chunk must be added to a new group.
         *

         * A chunk can only be added to a group, if the capacity of the group
         * is not exceeded.
         */
        protected boolean maybeAddChunk(Chunk chunk) {
            if (sampleCount + chunk.sampleCount <= maxSampleCount) {
                lastSample = chunk.lastSample;
                sampleCount += chunk.sampleCount;
                return true;
            }
            return false;
        }

        public long getSampleCount() {
            return sampleCount;
        }
    }

    /**
     * Groups consecutive smples of the same duration.
     */
    private static class TimeToSampleGroup extends Group {

        public TimeToSampleGroup(Sample firstSample) {
            super(firstSample);
        }

        public TimeToSampleGroup(Group group) {
            super(group);
        }

        /** Returns true, if the sample was added to the group.
         * If false is returned, the sample must be added to a new group.
         *

         * A sample can only be added to a TimeToSampleGroup, if it has the same
         * duration as previously added samples, and if the capacity of the
         * group is not exceeded.
         */
        @Override
        public boolean maybeAddSample(Sample sample) {
            if (firstSample.duration == sample.duration) {
                return super.maybeAddSample(sample);
            }
            return false;
        }

        @Override
        public boolean maybeAddChunk(Chunk chunk) {
            if (firstSample.duration == chunk.firstSample.duration) {
                return super.maybeAddChunk(chunk);
            }
            return false;
        }

        /** Returns the duration that all samples in this group share. */
        public long getSampleDuration() {
            return firstSample.duration;
        }
    }

    /**
     * Groups consecutive samples of the same size.
     */
    private static class SampleSizeGroup extends Group {

        public SampleSizeGroup(Sample firstSample) {
            super(firstSample);
        }

        public SampleSizeGroup(Group group) {
            super(group);
        }

        /** Returns true, if the sample was added to the group.
         * If false is returned, the sample must be added to a new group.
         *

         * A sample can only be added to a SampleSizeGroup, if it has the same
         * size as previously added samples, and if the capacity of the
         * group is not exceeded.
         */
        @Override
        public boolean maybeAddSample(Sample sample) {
            if (firstSample.length == sample.length) {
                return super.maybeAddSample(sample);
            }
            return false;
        }

        @Override
        public boolean maybeAddChunk(Chunk chunk) {
            if (firstSample.length == chunk.firstSample.length) {
                return super.maybeAddChunk(chunk);
            }
            return false;
        }

        /** Returns the length that all samples in this group share. */
        public long getSampleLength() {
            return firstSample.length;
        }
    }

    /**
     * Groups consecutive samples with the same sample description Id and
     * with adjacent offsets in the movie file.
     */
    private static class Chunk extends Group {

        private int sampleDescriptionId;

        /**
         * Creates a new Chunk.
         *
         * @param firstSample The first sample contained in this chunk.
         * @param sampleDescriptionId The description Id of the sample.
         */
        public Chunk(Sample firstSample, int sampleDescriptionId) {
            super(firstSample);
            this.sampleDescriptionId = sampleDescriptionId;
        }

        /**
         * Creates a new Chunk.
         *
         * @param firstSample The first sample contained in this chunk.
         * @param sampleDescriptionId The description Id of the sample.
         */
        public Chunk(Sample firstSample, Sample lastSample, int sampleCount, int sampleDescriptionId) {
            super(firstSample, lastSample, sampleCount);
            this.sampleDescriptionId = sampleDescriptionId;
        }

        /** Returns true, if the sample was added to the chunk.
         * If false is returned, the sample must be added to a new chunk.
         *

         * A sample can only be added to a chunk, if it has the same sample
         * description Id as previously added samples, if the capacity of the
         * chunk is not exceeded and if the sample offset is adjacent to the
         * last sample in this chunk.
         */
        public boolean maybeAddSample(Sample sample, int sampleDescriptionId) {
            if (sampleDescriptionId == this.sampleDescriptionId
                    && lastSample.offset + lastSample.length == sample.offset) {
                return super.maybeAddSample(sample);
            }
            return false;
        }

        @Override
        public boolean maybeAddChunk(Chunk chunk) {
            if (sampleDescriptionId == chunk.sampleDescriptionId //
                    && lastSample.offset + lastSample.length == chunk.firstSample.offset) {
                return super.maybeAddChunk(chunk);
            }
            return false;
        }

        /** Returns the offset of the chunk in the movie file. */
        public long getChunkOffset() {
            return firstSample.offset;
        }
    }
    /**
     * This atom holds the media data.
     */
    private WideDataAtom mdatAtom;
    /**
     * Offset for the mdat atom.
     */
    private long mdatOffset;
    /**
     * This atom holds the moovie header.
     */
    private CompositeAtom moovAtom;

    /**
     * Atom base class.
     */
    private abstract class Atom {

        /**
         * The type of the atom. A String with the length of 4 characters.
         */
        protected String type;
        /**
         * The offset of the atom relative to the start of the
         * ImageOutputStream.
         */
        protected long offset;

        /**
         * Creates a new Atom at the current position of the ImageOutputStream.
         * @param type The type of the atom. A string with a length of 4 characters.
         */
        public Atom(String type) throws IOException {
            this.type = type;
            offset = getRelativeStreamPosition();
        }

        /**
         * Writes the atom to the ImageOutputStream and disposes it.
         */
        public abstract void finish() throws IOException;

        /**
         * Returns the size of the atom including the size of the atom header.
         * @return The size of the atom.
         */
        public abstract long size();
    }

    /**
     * A CompositeAtom contains an ordered list of Atoms.
     */
    private class CompositeAtom extends DataAtom {

        private LinkedList<Atom> children;

        /**
         * Creates a new CompositeAtom at the current position of the
         * ImageOutputStream.
         * @param type The type of the atom.
         */
        public CompositeAtom(String type) throws IOException {
            super(type);
            children = new LinkedList<Atom>();
        }

        public void add(Atom child) throws IOException {
            if (children.size() > 0) {
                children.getLast().finish();
            }
            children.add(child);
        }

        /**
         * Writes the atom and all its children to the ImageOutputStream
         * and disposes of all resources held by the atom.
         * @throws java.io.IOException
         */
        @Override
        public void finish() throws IOException {
            if (!finished) {
                if (size() > 0xffffffffL) {
                    throw new IOException("CompositeAtom \"" + type + "\" is too large: " + size());
                }

                long pointer = getRelativeStreamPosition();
                seekRelative(offset);

                DataAtomOutputStream headerData = new DataAtomOutputStream(new ImageOutputStreamAdapter(out));
                headerData.writeInt((int) size());
                headerData.writeType(type);
                for (Atom child : children) {
                    child.finish();
                }
                seekRelative(pointer);
                finished = true;
            }
        }

        @Override
        public long size() {
            long length = 8 + data.size();
            for (Atom child : children) {
                length += child.size();
            }
            return length;
        }
    }

    /**
     * Data Atom.
     */
    private class DataAtom extends Atom {

        protected DataAtomOutputStream data;
        protected boolean finished;

        /**
         * Creates a new DataAtom at the current position of the
         * ImageOutputStream.
         * @param type The type of the atom.
         */
        public DataAtom(String name) throws IOException {
            super(name);
            out.writeLong(0); // make room for the atom header
            data = new DataAtomOutputStream(new ImageOutputStreamAdapter(out));
        }

        public DataAtomOutputStream getOutputStream() {
            if (finished) {
                throw new IllegalStateException("DataAtom is finished");
            }
            return data;
        }

        /**
         * Returns the offset of this atom to the beginning of the random access file
         * @return
         */
//        public long getOffset() {
//            return offset;
//        }

        @Override
        public void finish() throws IOException {
            if (!finished) {
                long sizeBefore = size();

                if (size() > 0xffffffffL) {
                    throw new IOException("DataAtom \"" + type + "\" is too large: " + size());
                }

                long pointer = getRelativeStreamPosition();
                seekRelative(offset);

                DataAtomOutputStream headerData = new DataAtomOutputStream(new ImageOutputStreamAdapter(out));
                headerData.writeUInt(size());
                headerData.writeType(type);
                seekRelative(pointer);
                finished = true;
                long sizeAfter = size();
                if (sizeBefore != sizeAfter) {
                    System.err.println("size mismatch " + sizeBefore + ".." + sizeAfter);
                }
            }
        }

        @Override
        public long size() {
            return 8 + data.size();
        }
    }

    /**
     * WideDataAtom can grow larger then 4 gigabytes.
     */
    private class WideDataAtom extends Atom {

        private DataAtomOutputStream data;
        private boolean finished;

        /**
         * Creates a new DataAtom at the current position of the
         * ImageOutputStream.
         * @param type The type of the atom.
         */
        public WideDataAtom(String type) throws IOException {
            super(type);
            out.writeLong(0); // make room for the atom header
            out.writeLong(0); // make room for the atom header
            data = new DataAtomOutputStream(new ImageOutputStreamAdapter(out)) {

                @Override
                public void flush() throws IOException {
                    // DO NOT FLUSH UNDERLYING STREAM!
                }
            };
        }

        public DataAtomOutputStream getOutputStream() {
            if (finished) {
                throw new IllegalStateException("Atom is finished");
            }
            return data;
        }

        /**
         * Returns the offset of this atom to the beginning of the random access file
         * @return
         */
        public long getOffset() {
            return offset;
        }

        @Override
        public void finish() throws IOException {
            if (!finished) {
                long pointer = getRelativeStreamPosition();
                seekRelative(offset);

                DataAtomOutputStream headerData = new DataAtomOutputStream(new ImageOutputStreamAdapter(out));
                long finishedSize = size();
                if (finishedSize <= 0xffffffffL) {
                    headerData.writeUInt(8);
                    headerData.writeType("wide");
                    headerData.writeUInt(finishedSize - 8);
                    headerData.writeType(type);
                } else {
                    headerData.writeInt(1); // special value for extended size atoms
                    headerData.writeType(type);
                    headerData.writeLong(finishedSize - 8);
                }

                seekRelative(pointer);
                finished = true;
            }
        }

        @Override
        public long size() {
            return 16 + data.size();
        }
    }

    /**
     * Creates a new QuickTime writer.
     *
     * @param file the output file
     */
    public QuickTimeWriter(File file) throws IOException {
        if (file.exists()) {
            file.delete();
        }
        this.out = new FileImageOutputStream(file);

        this.streamOffset = 0;

    }

    /**
     * Creates a new QuickTime writer.
     *
     * @param out the underlying output stream.
     */
    public QuickTimeWriter(ImageOutputStream out) throws IOException {
        this.out = out;

        this.streamOffset = out.getStreamPosition();

    }

    /**
     * Sets the time scale for this movie, that is, the number of time units
     * that pass per second in its time coordinate system.
     *

     * The default value is 600.
     *
     * @param timeScale
     */
    public void setMovieTimeScale(long timeScale) {
        if (timeScale < 1 || timeScale > (2L << 32)) {
            throw new IllegalArgumentException("timeScale must be between 1 and 2^32:" + timeScale);
        }
        this.movieTimeScale = timeScale;
    }

    /**
     * Returns the time scale of the movie.
     *
     * @return time scale
     * @see #setMovieTimeScale(long)
     */
    public long getMovieTimeScale() {
        return movieTimeScale;
    }

    /**
     * Returns the time scale of the media in a track.
     *
     * @param track Track index.
     * @return time scale
     * @see #setMovieTimeScale(long)
     */
    public long getMediaTimeScale(int track) {
        return tracks.get(track).mediaTimeScale;
    }

    /**
     * Returns the media duration of a track in the media's time scale.
     *
     * @param track Track index.
     * @return media duration
     */
    public long getMediaDuration(int track) {
        return tracks.get(track).mediaDuration;
    }

    /**
     * Returns the track duration in the movie's time scale without taking
     * the edit list into account.
     *

     * The returned value is the media duration of a track in the movies's time
     * scale.
     *
     * @param track Track index.
     * @return unedited track duration
     */
    public long getUneditedTrackDuration(int track) {
        Track t = tracks.get(track);
        return t.mediaDuration * t.mediaTimeScale / movieTimeScale;
    }

    /**
     * Returns the track duration in the movie's time scale.
     *
     * @param track Track index.
     * @return track duration
     */
    public long getTrackDuration(int track) {
        return tracks.get(track).getTrackDuration(movieTimeScale);
    }

    /**
     * Returns the total duration of the movie in the movie's time scale.
     *
     * @return media duration
     */
    public long getMovieDuration() {
        long duration = 0;
        for (Track t : tracks) {
            duration = Math.max(duration, t.getTrackDuration(movieTimeScale));
        }
        return duration;
    }

    /** Sets the color table for videos with indexed color models.
     *
     * @param track The track number.
     * @param icm IndexColorModel. Specify null to use the standard Macintosh
     * color table.
     */
    public void setVideoColorTable(int track, IndexColorModel icm) {
        VideoTrack t = (VideoTrack) tracks.get(track);
        t.videoColorTable = icm;
    }

    /** Gets the preferred color table for displaying the movie on devices that
     * support only 256 colors.
     *
     * @param track The track number.
     * @return The color table or null, if the video uses the standard Macintosh
     * color table.
     */
    public IndexColorModel getVideoColorTable(int track) {
        VideoTrack t = (VideoTrack) tracks.get(track);
        return t.videoColorTable;
    }

    /** Sets the edit list for the specified track.
     *

     * In the absence of an edit list, the presentation of the track starts
     * immediately. An empty edit is used to offset the start time of a track.
     *

     * @throws IllegalArgumentException If the edit list ends with an empty edit.
     */
    public void setEditList(int track, Edit[] editList) {
        if (editList != null && editList.length > 0 && editList[editList.length - 1].mediaTime == -1) {
            throw new IllegalArgumentException("Edit list must not end with empty edit.");
        }
        tracks.get(track).editList = editList;
    }

    /** Adds a video track to the movie.
     *
     * @param encoding The encoding of the video frames.
     * @param timeScale The media time scale. This is typically the frame rate.
     * If the frame rate is not an integer fraction of a second, specify a
     * multiple of the frame rate and specify a correspondingly multiplied
     * duration when writing frames. For example, for a rate of 23.976 fps
     * specify a time scale of 23976 and multiply the duration of a video frame
     * by 1000.
     * @param width The width of a video image. Must be larger than 0.
     * @param height The height of a video image. Must be larger than 0.
     *
     * @throws IllegalArgumentException if the width or the height is smaller
     * than 1.
     */
    public void addVideoTrack(VideoFormat encoding, long timeScale, int width, int height) throws IOException {
        addVideoTrack(encoding.compressionType, encoding.compressorName, timeScale, width, height, 24, encoding.allSamplesAreSyncSamples ? 1 : 30);
    }

    /** Adds a video track to the movie.
     *
     * @param compressionType The QuickTime "image compression format" 4-Character code.
     * A list of supported 4-Character codes is given in qtff, table 3-1, page 96.
     * @param compressorName The QuickTime compressor name. Can be up to 32 characters long.
     * @param timeScale The media time scale between 1 and 2^32.
     * @param width The width of a video frame.
     * @param height The height of a video frame.
     * @param depth Number of bits per pixel.
     * @param syncInterval Interval for sync-samples. 0=automatic. 1=all frames
     * are keyframes. Values larger than 1 specify that for every n-th frame
     * is a keyframe.
     *
     * @throws IllegalArgumentException if {@code width} or {@code height} is
     * smaller than 1, if the length of {@code compressionType} is not equal to 4, if
     * the length of the {@code compressorName} is not between 1 and 32,
     * if the tiimeScale is not between 1 and 2^32.
     */
    public void addVideoTrack(String compressionType, String compressorName, long timeScale, int width, int height, int depth, int syncInterval) throws IOException {
        ensureStarted();
        if (compressionType == null || compressionType.length() != 4) {
            throw new IllegalArgumentException("compressionType must be 4 characters long:" + compressionType);
        }
        if (compressorName == null || compressorName.length() < 1 || compressorName.length() > 32) {
            throw new IllegalArgumentException("compressorName must be between 1 and 32 characters long:" + compressionType);
        }
        if (timeScale < 1 || timeScale > (2L << 32)) {
            throw new IllegalArgumentException("timeScale must be between 1 and 2^32:" + timeScale);
        }
        if (width < 1 || height < 1) {
            throw new IllegalArgumentException("Width and height must be greater than 0, width:" + width + " height:" + height);
        }

        VideoTrack t = new VideoTrack();
        t.mediaCompressionType = compressionType;
        t.mediaCompressorName = compressorName;
        t.mediaTimeScale = timeScale;
        t.videoWidth = width;
        t.videoHeight = height;
        t.videoDepth = depth;
        t.syncInterval = syncInterval;
        for (VideoFormat vf : VideoFormat.values()) {
            if (vf.compressionType.equals(compressionType)) {
                t.videoEncoding = vf;
                break;
            }
        }
        tracks.add(t);
    }

    /** Adds an audio track to the movie, and configures using an
     * {@code AudioFormat} object from the javax.sound API.
     *

     * Use this method for writing audio data from an {@code AudioInputStream}
     * into a QuickTime Movie file.
     *
     * @param format The javax.sound audio format.
     */
    public void addAudioTrack(AudioFormat format) throws IOException {
        ensureStarted();
        String qtAudioFormat;
        double sampleRate = format.getSampleRate();
        long timeScale = (int) Math.floor(sampleRate);
        int sampleSizeInBits = format.getSampleSizeInBits();
        int numberOfChannels = format.getChannels();
        boolean bigEndian = format.isBigEndian();
        int frameDuration = (int) (format.getSampleRate() / format.getFrameRate());
        int frameSize = format.getFrameSize();
        boolean isCompressed = format.getProperty("vbr") != null && ((Boolean) format.getProperty("vbr")).booleanValue();

        if (format.getEncoding().equals(AudioFormat.Encoding.ALAW)) {
            qtAudioFormat = "alaw";
            if (sampleSizeInBits != 8) {
                throw new IllegalArgumentException("Sample size of 8 for ALAW required:" + sampleSizeInBits);
            }
        } else if (format.getEncoding().equals(AudioFormat.Encoding.PCM_SIGNED)) {
            switch (sampleSizeInBits) {
                case 16:
                    qtAudioFormat = (bigEndian) ? "twos" : "sowt";
                    break;
                case 24:
                    qtAudioFormat = "in24";
                    break;
                case 32:
                    qtAudioFormat = "in32";
                    break;
                default:
                    throw new IllegalArgumentException("Sample size of 16, 24 or 32 for PCM_SIGNED required:" + sampleSizeInBits);
            }
        } else if (format.getEncoding().equals(AudioFormat.Encoding.PCM_UNSIGNED)) {
            if (sampleSizeInBits != 8) {
                throw new IllegalArgumentException("Sample size of 8 PCM_UNSIGNED required:" + sampleSizeInBits);
            }
            qtAudioFormat = "raw ";
        } else if (format.getEncoding().equals(AudioFormat.Encoding.ULAW)) {
            if (sampleSizeInBits != 8) {
                throw new IllegalArgumentException("Sample size of 8 for ULAW required:" + sampleSizeInBits);
            }
            qtAudioFormat = "ulaw";
        } else if (format.getEncoding().toString().equals("MP3")) {
            qtAudioFormat = ".mp3";
        } else {
            qtAudioFormat = format.getEncoding().toString();
            if (qtAudioFormat.length() != 4) {
                throw new IllegalArgumentException("Unsupported encoding:" + format.getEncoding());
            }
        }

        addAudioTrack(qtAudioFormat, timeScale, sampleRate,
                numberOfChannels, sampleSizeInBits,
                isCompressed, frameDuration, frameSize);
    }

    /** Adds an audio track to the movie.
     *
     * @param compressionType The QuickTime 4-character code.
     * A list of supported 4-Character codes is given in qtff, table 3-7, page 113.
     * @param timeScale The media time scale between 1 and 2^32.
     * @param sampleRate The sample rate. The integer portion must match the
     * {@code timeScale}.
     * @param numberOfChannels The number of channels: 1 for mono, 2 for stereo.
     * @param sampleSizeInBits The number of bits in a sample: 8 or 16.
     * @param isCompressed Whether the sound is compressed.
     * @param frameDuration The frame duration, expressed in the media’s
     *                   timescale, where the timescale is equal to the sample
     *                   rate. For uncompressed formats, this field is always 1.
     * @param frameSize  For uncompressed audio, the number of bytes in a
     *                   sample for a single channel (sampleSize divided by 8).
     *                   For compressed audio, the number of bytes in a frame.
     *
     * @throws IllegalArgumentException if the audioFormat is not 4 characters long,
     * if the time scale is not between 1 and 2^32, if the integer portion of the
     * sampleRate is not equal to the timeScale, if numberOfChannels is not 1 or 2.
     */
    public void addAudioTrack(String compressionType, //
            long timeScale, double sampleRate, //
            int numberOfChannels, int sampleSizeInBits, //
            boolean isCompressed, //
            int frameDuration, int frameSize) throws IOException {
        ensureStarted();
        if (compressionType == null || compressionType.length() != 4) {
            throw new IllegalArgumentException("audioFormat must be 4 characters long:" + compressionType);
        }
        if (timeScale < 1 || timeScale > (2L << 32)) {
            throw new IllegalArgumentException("timeScale must be between 1 and 2^32:" + timeScale);
        }
        if (timeScale != (int) Math.floor(sampleRate)) {
            throw new IllegalArgumentException("timeScale: " + timeScale + " must match integer portion of sampleRate: " + sampleRate);
        }
        if (numberOfChannels != 1 && numberOfChannels != 2) {
            throw new IllegalArgumentException("numberOfChannels must be 1 or 2: " + numberOfChannels);
        }
        if (sampleSizeInBits != 8 && sampleSizeInBits != 16) {
            throw new IllegalArgumentException("sampleSize must be 8 or 16: " + numberOfChannels);
        }

        AudioTrack t = new AudioTrack();
        t.mediaCompressionType = compressionType;
        t.mediaTimeScale = timeScale;
        t.soundSampleRate = sampleRate;
        t.soundCompressionId = isCompressed ? -2 : -1;
        t.soundNumberOfChannels = numberOfChannels;
        t.soundSampleSize = sampleSizeInBits;
        t.soundSamplesPerPacket = frameDuration;
        if (isCompressed) {
            t.soundBytesPerPacket = frameSize;
            t.soundBytesPerFrame = frameSize * numberOfChannels;
        } else {
            t.soundBytesPerPacket = frameSize / numberOfChannels;
            t.soundBytesPerFrame = frameSize;
        }
        t.soundBytesPerSample = sampleSizeInBits / 8;
        tracks.add(t);
    }

    /**
     * Sets the compression quality of a  track.
     *

     * A value of 0 stands for "high compression is important" a value of
     * 1 for "high image quality is important".
     *

     * Changing this value affects the encoding of video frames which are
     * subsequently written into the track. Frames which have already been written
     * are not changed.
     *

     * This value has no effect on videos encoded with lossless encoders
     * such as the PNG format.
     *

     * The default value is 0.97.
     *
     * @param newValue
     */
    public void setCompressionQuality(int track, float newValue) {
        ((VideoTrack) tracks.get(track)).videoQuality = newValue;
    }

    /**
     * Returns the compression quality of a track.
     *
     * @return compression quality
     */
    public float getCompressionQuality(int track) {
        return ((VideoTrack) tracks.get(track)).videoQuality;
    }

    /** Sets the sync interval for the specified video track. */
    public void setSyncInterval(int track, int i) {
        ((VideoTrack) tracks.get(track)).syncInterval = i;
    }

    /** Gets the sync interval from the specified video track. */
    public int getSyncInterval(int track) {
        return ((VideoTrack) tracks.get(track)).syncInterval;
    }

    /**
     * Sets the state of the QuickTimeOutpuStream to started.
     *

     * If the state is changed by this method, the prolog is
     * written.
     */
    private void ensureStarted() throws IOException {
        ensureOpen();
        if (state == States.FINISHED) {
            throw new IOException("Can not write into finished movie.");
        }
        if (state != States.STARTED) {
            creationTime = new Date();
            writeProlog();
            mdatAtom = new WideDataAtom("mdat");
            state = States.STARTED;
        }
    }

    /**
     * Encodes an image as a video frame and writes it into a video track.
     *

     * Only the video encodings listed below are supported by this method.
     * For other encodings, you have to encode the image by yourself and then
     * call one of the {@code writeSample} methods.
     *

     *
RAW

     *
JPG

     *
PNG

     *

     *
     * @param track The track index.
     * @param image The image of the video frame.
     * @param duration The duration of the video frame in media time scale units.
     *
     * @throws IndexOutofBoundsException if the track index is out of bounds.
     * @throws if the duration is less than 1, or if the dimension of the frame
     * does not match the dimension of the video.
     * @throws UnsupportedOperationException if the QuickTimeWriter does not have
     * a built-in encoder for this video format.
     * @throws IOException if writing the sample data failed.
     */
    public void writeFrame(int track, BufferedImage image, long duration) throws IOException {
        if (duration <= 0) {
            throw new IllegalArgumentException("Duration must be greater 0.");
        }
        VideoTrack t = (VideoTrack) tracks.get(track); // throws index out of bounds exception if illegal track index
        if (t.mediaType != MediaType.VIDEO) {
            throw new IllegalArgumentException("Track " + track + " is not a video track");
        }
        if (t.videoEncoding == null) {
            throw new UnsupportedOperationException("Encoding not supported.");
        }

        ensureStarted();

        // The dimension of the image must match the dimension of the video track
        if (t.videoWidth != image.getWidth() || t.videoHeight != image.getHeight()) {
            throw new IllegalArgumentException("Dimensions of frame[" + tracks.get(track).getSampleCount()
                    + "] (width=" + image.getWidth() + ", height=" + image.getHeight()
                    + ") differs from video dimension (width="
                    + t.videoWidth + ", height=" + t.videoHeight + ") in track " + track + ".");
        }
        long offset = getRelativeStreamPosition();
        boolean isSync;
        switch (t.videoEncoding) {
            case RAW: {
                isSync = true;
                switch (t.videoDepth) {
                    case 8: {
                        if (image.getType() != BufferedImage.TYPE_BYTE_INDEXED) {
                            throw new IllegalArgumentException("BufferedImage type " + image.getType() + " does not match track type " + BufferedImage.TYPE_BYTE_INDEXED + ".");
                        }

                        // Handle sub-image
                        WritableRaster raster = image.getRaster();
                        int sw = raster.getSampleModel().getWidth();
//                        int sh = raster.getSampleModel().getHeight();
                        Rectangle r = raster.getBounds();
                        r.x -= raster.getSampleModelTranslateX();
                        r.y -= raster.getSampleModelTranslateY();
                        DataBufferByte buf = (DataBufferByte) raster.getDataBuffer();
                        byte[] bytes = buf.getData();

                        // Write the samples
                        for (int xy = r.x + r.y * sw, ymax = r.x + (r.y + r.height) * sw; xy < ymax; xy += sw) {
                            mdatAtom.getOutputStream().write(bytes, xy, r.width);
                        }
                        break;
                    }
                    case 24: {
                        WritableRaster raster = image.getRaster();
                        int[] rgb = new int[t.videoWidth * 3]; // holds a scanline of raw image data with 3 channels of 32 bit data
                        byte[] bytes = new byte[t.videoWidth * 3]; // holds a scanline of raw image data with 3 channels of 8 bit data
                        for (int y = 0; y < t.videoHeight; y++) {
                            // Note: Method getPixels is very slow as it does sample conversions for us
                            rgb = raster.getPixels(0, y, t.videoWidth, 1, rgb);
                            for (int k = 0, n = t.videoWidth * 3; k < n; k++) {
                                bytes[k] = (byte) rgb[k];
                            }
                            mdatAtom.getOutputStream().write(bytes);
                        }
                        break;
                    }
                    default:
                        throw new UnsupportedOperationException("Encoding not supported.");

                }
                break;
            }
            case JPG: {
                isSync = true;
                ImageWriter iw = ImageIO.getImageWritersByMIMEType("image/jpeg").next();
                ImageWriteParam iwParam = iw.getDefaultWriteParam();
                iwParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
                iwParam.setCompressionQuality(t.videoQuality);
                MemoryCacheImageOutputStream imgOut = new MemoryCacheImageOutputStream(mdatAtom.getOutputStream());
                iw.setOutput(imgOut);
                IIOImage img = new IIOImage(image, null, null);
                iw.write(null, img, iwParam);
                iw.dispose();
                break;
            }
            case PNG: {
                isSync = true;
                ImageWriter iw = ImageIO.getImageWritersByMIMEType("image/png").next();
                ImageWriteParam iwParam = iw.getDefaultWriteParam();
                // FIXME - Detect number of bits per pixel, ensure that correct value is written into video media header atom.
                // FIXME - Maybe we should quietly enforce 24 bits per pixel
                MemoryCacheImageOutputStream imgOut = new MemoryCacheImageOutputStream(mdatAtom.getOutputStream());
                iw.setOutput(imgOut);
                IIOImage img = new IIOImage(image, null, null);
                iw.write(null, img, iwParam);
                iw.dispose();
                break;
            }
            case RLE: {
                isSync = t.previousData == null || t.syncInterval != 0 && t.sampleCount % t.syncInterval == 0;

                // Handle sub-image
                WritableRaster raster = image.getRaster();
                int sw = raster.getSampleModel().getWidth();
//                int sh = raster.getSampleModel().getHeight();
                Rectangle r = raster.getBounds();
                r.x -= raster.getSampleModelTranslateX();
                r.y -= raster.getSampleModelTranslateY();
                if (t.encoder == null) {
                    t.encoder = new AppleRLEEncoder();
                }
                AppleRLEEncoder enc = t.encoder;
                switch (t.videoDepth) {
                    case 16: {
                        DataBufferUShort buf = (DataBufferUShort) raster.getDataBuffer();
                        short[] data = buf.getData();
                        if (isSync) {
                            enc.writeKey16(mdatAtom.getOutputStream(), data, r.width, r.height, r.x + r.y * sw, sw);
                        } else {
                            // FIXME - We blindly assume that the sub-image of the previous image is the same as the current one
                            enc.writeDelta16(mdatAtom.getOutputStream(), data, (short[]) t.previousData, r.width, r.height, r.x + r.y * sw, sw);
                        }
                        if (t.previousData == null) {
                            t.previousData = new short[data.length];
                        }
                        System.arraycopy(data, 0, t.previousData, 0, data.length);
                        break;
                    }
                    case 24: {
                        DataBufferInt buf = (DataBufferInt) raster.getDataBuffer();
                        int[] data = buf.getData();
                        if (isSync) {
                            enc.writeKey24(mdatAtom.getOutputStream(), data, r.width, r.height, r.x + r.y * sw, sw);
                        } else {
                            // FIXME - We blindly assume that the sub-image of the previous image is the same as the current one
                            enc.writeDelta24(mdatAtom.getOutputStream(), data, (int[]) t.previousData, r.width, r.height, r.x + r.y * sw, sw);
                        }
                        if (t.previousData == null) {
                            t.previousData = new int[data.length];
                        }
                        System.arraycopy(data, 0, t.previousData, 0, data.length);
                        break;
                    }
                    case 32: {
                        DataBufferInt buf = (DataBufferInt) raster.getDataBuffer();
                        int[] data = buf.getData();
                        if (isSync) {
                            enc.writeKey32(mdatAtom.getOutputStream(), data, image.getWidth(), image.getHeight(), 0, image.getWidth());
                        } else {
                            // FIXME - We blindly assume that the sub-image of the previous image is the same as the current one
                            enc.writeDelta32(mdatAtom.getOutputStream(), data, (int[]) t.previousData, image.getWidth(), image.getHeight(), 0, image.getWidth());
                        }
                        if (t.previousData == null) {
                            t.previousData = new int[data.length];
                        }
                        System.arraycopy(data, 0, t.previousData, 0, data.length);
                        break;
                    }
                    default:
                        throw new UnsupportedOperationException("Encoding not supported.");

                }
                break;
            }
            default: {
                throw new UnsupportedOperationException("Encoding not supported.");
            }
        }
        long length = getRelativeStreamPosition() - offset;
        t.addSample(new Sample(duration, offset, length), 1, isSync);
    }

    /**
     * Writes an already encoded sync sample from a file into a track.
     *

     * This method does not inspect the contents of the samples. The contents
     * has to match the format and dimensions of the media in this track.
     *
     * @param track The track index.
     * @param file The file which holds the encoded data sample.
     * @param duration The duration of the sample in media time scale units.
     *
     * @throws IndexOutofBoundsException if the track index is out of bounds.
     * @throws IllegalArgumentException if the track does not support video,
     * if the duration is less than 1, or if the dimension of the frame does not
     * match the dimension of the video.
     * @throws IOException if writing the sample data failed.
     */
    public void writeSample(int track, File file, long duration) throws IOException {
        writeSample(track, file, duration, true);
    }

    /**
     * Writes an already encoded sample from a file into a track.
     *

     * This method does not inspect the contents of the samples. The contents
     * has to match the format and dimensions of the media in this track.
     *
     * @param track The track index.
     * @param file The file which holds the encoded data sample.
     * @param duration The duration of the sample in media time scale units.
     * @param isSync whether the sample is a sync sample (key frame).
     *
     * @throws IndexOutofBoundsException if the track index is out of bounds.
     * @throws IllegalArgumentException if the track does not support video,
     * if the duration is less than 1, or if the dimension of the frame does not
     * match the dimension of the video.
     * @throws IOException if writing the sample data failed.
     */
    public void writeSample(int track, File file, long duration, boolean isSync) throws IOException {
        ensureStarted();
        FileInputStream in = null;
        try {
            in = new FileInputStream(file);
            writeSample(track, in, duration, isSync);
        } finally {
            if (in != null) {
                in.close();
            }
        }
    }

    /**
     * Writes an already encoded sync sample from an input stream into a track.
     *

     * This method does not inspect the contents of the samples. The contents
     * has to match the format and dimensions of the media in this track.
     *
     * @param track The track index.
     * @param in The input stream which holds the encoded sample data.
     * @param duration The duration of the video frame in media time scale units.
     *
     * @throws IllegalArgumentException if the duration is less than 1.
     * @throws IOException if writing the image failed.
     */
    public void writeSample(int track, InputStream in, long duration) throws IOException {
        writeSample(track, in, duration, true);
    }

    /**
     * Writes an already encoded sample from an input stream into a track.
     *

     * This method does not inspect the contents of the samples. The contents
     * has to match the format and dimensions of the media in this track.
     *
     * @param track The track index.
     * @param in The input stream which holds the encoded sample data.
     * @param duration The duration of the video frame in media time scale units.
     * @param isSync Whether the sample is a sync sample (keyframe).
     *
     * @throws IllegalArgumentException if the duration is less than 1.
     * @throws IOException if writing the image failed.
     */
    public void writeSample(int track, InputStream in, long duration, boolean isSync) throws IOException {
        ensureStarted();
        if (duration <= 0) {
            throw new IllegalArgumentException("duration must be greater 0");
        }
        Track t = tracks.get(track); // throws index out of bounds exception if illegal track index
        ensureOpen();
        ensureStarted();
        long offset = getRelativeStreamPosition();
        OutputStream mdatOut = mdatAtom.getOutputStream();
        byte[] buf = new byte[4096];
        int len;
        while ((len = in.read(buf)) != -1) {
            mdatOut.write(buf, 0, len);
        }
        long length = getRelativeStreamPosition() - offset;
        t.addSample(new Sample(duration, offset, length), 1, isSync);
    }

    /**
     * Writes an already encoded sync sample from a byte array into a track.
     *

     * This method does not inspect the contents of the samples. The contents
     * has to match the format and dimensions of the media in this track.
     *
     * @param track The track index.
     * @param data The encoded sample data.
     * @param duration The duration of the sample in media time scale units.
     *
     * @throws IllegalArgumentException if the duration is less than 1.
     * @throws IOException if writing the image failed.
     */
    public void writeSample(int track, byte[] data, long duration) throws IOException {
        ensureStarted();
        writeSample(track, data, 0, data.length, duration, true);
    }

    /**
     * Writes an already encoded sample from a byte array into a track.
     *

     * This method does not inspect the contents of the samples. The contents
     * has to match the format and dimensions of the media in this track.
     *
     * @param track The track index.
     * @param data The encoded sample data.
     * @param duration The duration of the sample in media time scale units.
     * @param isSync Whether the sample is a sync sample.
     *
     * @throws IllegalArgumentException if the duration is less than 1.
     * @throws IOException if writing the image failed.
     */
    public void writeSample(int track, byte[] data, long duration, boolean isSync) throws IOException {
        ensureStarted();
        writeSample(track, data, 0, data.length, duration, isSync);
    }

    /**
     * Writes an already encoded sync sample from a byte array into a track.
     *

     * This method does not inspect the contents of the samples. The contents
     * has to match the format and dimensions of the media in this track.
     *
     * @param track The track index.
     * @param data The encoded sample data.
     * @param off The start offset in the data.
     * @param len The number of bytes to write.
     * @param duration The duration of the sample in media time scale units.
     *
     * @throws IllegalArgumentException if the duration is less than 1.
     * @throws IOException if writing the image failed.
     */
    public void writeSample(int track, byte[] data, int off, int len, long duration) throws IOException {
        ensureStarted();
        writeSample(track, data, off, len, duration, true);
    }

    /**
     * Writes an already encoded sample from a byte array into a track.
     *

     * This method does not inspect the contents of the samples. The contents
     * has to match the format and dimensions of the media in this track.
     *
     * @param track The track index.
     * @param data The encoded sample data.
     * @param off The start offset in the data.
     * @param len The number of bytes to write.
     * @param duration The duration of the sample in media time scale units.
     * @param isSync Whether the sample is a sync sample (keyframe).
     *
     * @throws IllegalArgumentException if the duration is less than 1.
     * @throws IOException if writing the image failed.
     */
    public void writeSample(int track, byte[] data, int off, int len, long duration, boolean isSync) throws IOException {
        ensureStarted();
        if (duration <= 0) {
            throw new IllegalArgumentException("duration must be greater 0");
        }
        Track t = tracks.get(track); // throws index out of bounds exception if illegal track index
        ensureOpen();
        ensureStarted();
        long offset = getRelativeStreamPosition();
        OutputStream mdatOut = mdatAtom.getOutputStream();
        mdatOut.write(data, off, len);
        t.addSample(new Sample(duration, offset, len), 1, isSync);
    }

    /**
     * Writes multiple sync samples from a byte array into a track.
     *

     * This method does not inspect the contents of the samples. The contents
     * has to match the format and dimensions of the media in this track.
     *
     * @param track The track index.
     * @param sampleCount The number of samples.
     * @param data The encoded sample data. The length of data must be dividable
     * by sampleCount.
     * @param sampleDuration The duration of a sample. All samples must
     * have the same duration.
     *
     * @throws IllegalArgumentException if {@code sampleDuration} is less than 1
     * or if the length of {@code data} is not dividable by {@code sampleCount}.
     * @throws IOException if writing the chunk failed.
     */
    public void writeSamples(int track, int sampleCount, byte[] data, int sampleDuration) throws IOException {
        writeSamples(track, sampleCount, data, 0, data.length, sampleDuration, true);
    }

    /**
     * Writes multiple sync samples from a byte array into a track.
     *

     * This method does not inspect the contents of the samples. The contents
     * has to match the format and dimensions of the media in this track.
     *
     * @param track The track index.
     * @param sampleCount The number of samples.
     * @param data The encoded sample data.
     * @param off The start offset in the data.
     * @param len The number of bytes to write. Must be dividable by sampleCount.
     * @param sampleDuration The duration of a sample. All samples must
     * have the same duration.
     *
     * @throws IllegalArgumentException if the duration is less than 1.
     * @throws IOException if writing the image failed.
     */
    public void writeSamples(int track, int sampleCount, byte[] data, int off, int len, int sampleDuration) throws IOException {
        writeSamples(track, sampleCount, data, off, len, sampleDuration, true);
    }

    /**
     * Writes multiple samples from a byte array into a track.
     *

     * This method does not inspect the contents of the data. The
     * contents has to match the format and dimensions of the media in this
     * track.
     *
     * @param track The track index.
     * @param sampleCount The number of samples.
     * @param data The encoded sample data.
     * @param off The start offset in the data.
     * @param len The number of bytes to write. Must be dividable by sampleCount.
     * @param sampleDuration The duration of a sample. All samples must
     * have the same duration.
     * @param isSync Whether the samples are sync samples. All samples must
     * either be sync samples or non-sync samples.
     *
     * @throws IllegalArgumentException if the duration is less than 1.
     * @throws IOException if writing the image failed.
     */
    public void writeSamples(int track, int sampleCount, byte[] data, int off, int len, int sampleDuration, boolean isSync) throws IOException {
        ensureStarted();
        if (sampleDuration <= 0) {
            throw new IllegalArgumentException("sampleDuration must be greater 0, sampleDuration=" + sampleDuration);
        }
        if (sampleCount <= 0) {
            throw new IllegalArgumentException("sampleCount must be greater 0, sampleCount=" + sampleCount);
        }
        if (len % sampleCount != 0) {
            throw new IllegalArgumentException("len must be divisable by sampleCount len=" + len + " sampleCount=" + sampleCount);
        }
        Track t = tracks.get(track); // throws index out of bounds exception if illegal track index
        ensureOpen();
        ensureStarted();
        long offset = getRelativeStreamPosition();
        OutputStream mdatOut = mdatAtom.getOutputStream();
        mdatOut.write(data, off, len);

        int sampleLength = len / sampleCount;
        Sample first = new Sample(sampleDuration, offset, sampleLength);
        Sample last = new Sample(sampleDuration, offset + sampleLength * (sampleCount - 1), sampleLength);
        t.addChunk(new Chunk(first, last, sampleCount, 1), isSync);
    }

    /**
     * Closes the movie file as well as the stream being filtered.
     *
     * @exception IOException if an I/O error has occurred
     */
    public void close() throws IOException {
        try {
            if (state == States.STARTED) {
                finish();
            }
        } finally {
            if (state != States.CLOSED) {
                out.close();
                state = States.CLOSED;
            }
        }
    }

    /**
     * Finishes writing the contents of the QuickTime output stream without closing
     * the underlying stream. Use this method when applying multiple filters
     * in succession to the same output stream.
     *
     * @exception IllegalStateException if the dimension of the video track
     * has not been specified or determined yet.
     * @exception IOException if an I/O exception has occurred
     */
    public void finish() throws IOException {
        ensureOpen();
        if (state != States.FINISHED) {
            for (int i = 0, n = tracks.size(); i < n; i++) {
            }
            mdatAtom.finish();
            writeEpilog();
            state = States.FINISHED;
            /*
            for (int i = 0, n = tracks.size(); i < n; i++) {
            if (tracks.get(i) instanceof VideoTrack) {
            VideoTrack t = (VideoTrack) tracks.get(i);
            t.videoWidth = t.videoHeight = -1;
            }
            }*/
        }
    }

    /**
     * Check to make sure that this stream has not been closed
     */
    private void ensureOpen() throws IOException {
        if (state == States.CLOSED) {
            throw new IOException("Stream closed");
        }
    }

    /** Gets the position relative to the beginning of the QuickTime stream.
     *

     * Usually this value is equal to the stream position of the underlying
     * ImageOutputStream, but can be larger if the underlying stream already
     * contained data.
     *
     * @return The relative stream position.
     * @throws IOException
     */
    private long getRelativeStreamPosition() throws IOException {
        return out.getStreamPosition() - streamOffset;
    }

    /** Seeks relative to the beginning of the QuickTime stream.
     *

     * Usually this equal to seeking in the underlying ImageOutputStream, but
     * can be different if the underlying stream already contained data.
     *
     */
    private void seekRelative(long newPosition) throws IOException {
        out.seek(newPosition + streamOffset);
    }

    /** Writes the stream prolog. */
    private void writeProlog() throws IOException {
        /* File type atom
         *
        typedef struct {
        magic brand;
        bcd4 versionYear;
        bcd2 versionMonth;
        bcd2 versionMinor;
        magic[4] compatibleBrands;
        } ftypAtom;
         */
        DataAtom ftypAtom = new DataAtom("ftyp");
        DataAtomOutputStream d = ftypAtom.getOutputStream();
        d.writeType("qt  "); // brand
        d.writeBCD4(2005); // versionYear
        d.writeBCD2(3); // versionMonth
        d.writeBCD2(0); // versionMinor
        d.writeType("qt  "); // compatibleBrands
        d.writeInt(0); // compatibleBrands (0 is used to denote no value)
        d.writeInt(0); // compatibleBrands (0 is used to denote no value)
        d.writeInt(0); // compatibleBrands (0 is used to denote no value)
        ftypAtom.finish();
    }

    private void writeEpilog() throws IOException {
        Date modificationTime = new Date();
        long duration = getMovieDuration();

        DataAtom leaf;

        /* Movie Atom ========= */
        moovAtom = new CompositeAtom("moov");

        /* Movie Header Atom -------------
         * The data contained in this atom defines characteristics of the entire
         * QuickTime movie, such as time scale and duration. It has an atom type
         * value of 'mvhd'.
         *
         * typedef struct {
        byte version;
        byte[3] flags;
        mactimestamp creationTime;
        mactimestamp modificationTime;
        int timeScale;
        int duration;
        int preferredRate;
        short preferredVolume;
        byte[10] reserved;
        int[9] matrix;
        int previewTime;
        int previewDuration;
        int posterTime;
        int selectionTime;
        int selectionDuration;
        int currentTime;
        int nextTrackId;
        } movieHeaderAtom;
         */
        leaf = new DataAtom("mvhd");
        moovAtom.add(leaf);
        DataAtomOutputStream d = leaf.getOutputStream();
        d.writeByte(0); // version
        // A 1-byte specification of the version of this movie header atom.

        d.writeByte(0); // flags[0]
        d.writeByte(0); // flags[1]
        d.writeByte(0); // flags[2]
        // Three bytes of space for future movie header flags.

        d.writeMacTimestamp(creationTime); // creationTime
        // A 32-bit integer that specifies the calendar date and time (in
        // seconds since midnight, January 1, 1904) when the movie atom was
        // created. It is strongly recommended that this value should be
        // specified using coordinated universal time (UTC).

        d.writeMacTimestamp(modificationTime); // modificationTime
        // A 32-bit integer that specifies the calendar date and time (in
        // seconds since midnight, January 1, 1904) when the movie atom was
        // changed. BooleanIt is strongly recommended that this value should be
        // specified using coordinated universal time (UTC).

        d.writeUInt(movieTimeScale); // timeScale
        // A time value that indicates the time scale for this movie—that is,
        // the number of time units that pass per second in its time coordinate
        // system. A time coordinate system that measures time in sixtieths of a
        // second, for example, has a time scale of 60.

        d.writeUInt(duration); // duration
        // A time value that indicates the duration of the movie in time scale
        // units. Note that this property is derived from the movie’s tracks.
        // The value of this field corresponds to the duration of the longest
        // track in the movie.

        d.writeFixed16D16(1d); // preferredRate
        // A 32-bit fixed-point number that specifies the rate at which to play
        // this movie. A value of 1.0 indicates normal rate.

        d.writeShort(256); // preferredVolume
        // A 16-bit fixed-point number that specifies how loud to play this
        // movie’s sound. A value of 1.0 indicates full volume.

        d.write(new byte[10]); // reserved;
        // Ten bytes reserved for use by Apple. Set to 0.

        d.writeFixed16D16(1f); // matrix[0]
        d.writeFixed16D16(0f); // matrix[1]
        d.writeFixed2D30(0f); // matrix[2]
        d.writeFixed16D16(0f); // matrix[3]
        d.writeFixed16D16(1f); // matrix[4]
        d.writeFixed2D30(0); // matrix[5]
        d.writeFixed16D16(0); // matrix[6]
        d.writeFixed16D16(0); // matrix[7]
        d.writeFixed2D30(1f); // matrix[8]
        // The matrix structure associated with this movie. A matrix shows how
        // to map points from one coordinate space into another. See “Matrices”
        // for a discussion of how display matrices are used in QuickTime:
        // http://developer.apple.com/documentation/QuickTime/QTFF/QTFFChap4/chapter_5_section_4.html#//apple_ref/doc/uid/TP40000939-CH206-18737

        d.writeInt(0); // previewTime
        // The time value in the movie at which the preview begins.

        d.writeInt(0); // previewDuration
        // The duration of the movie preview in movie time scale units.

        d.writeInt(0); // posterTime
        // The time value of the time of the movie poster.

        d.writeInt(0); // selectionTime
        // The time value for the start time of the current selection.

        d.writeInt(0); // selectionDuration
        // The duration of the current selection in movie time scale units.

        d.writeInt(0); // currentTime;
        // The time value for current time position within the movie.

        d.writeUInt(tracks.size() + 1); // nextTrackId
        // A 32-bit integer that indicates a value to use for the track ID
        // number of the next track added to this movie. Note that 0 is not a
        // valid track ID value.

        for (int i = 0, n = tracks.size(); i < n; i++) {
            Track t = tracks.get(i);
            /* Track Atom ======== */
            t.writeTrackAtoms(i, moovAtom, modificationTime);
        }
        //
        moovAtom.finish();
    }

    /** Writes a version of the movie which is optimized for the web into the
     * specified output file.
     *

     * This method finishes the movie and then copies its content into
     * the specified file. The web-optimized file starts with the movie header.
     *
     * @param outputFile The output file
     * @param compressHeader Whether the movie header shall be compressed.
     */
    public void toWebOptimizedMovie(File outputFile, boolean compressHeader) throws IOException {
        finish();
        long originalMdatOffset = mdatAtom.getOffset();
        CompositeAtom originalMoovAtom = moovAtom;
        mdatOffset = 0;

        ImageOutputStream originalOut = out;
        try {
            out = null;

            if (compressHeader) {
                ByteArrayOutputStream buf = new ByteArrayOutputStream();
                int maxIteration = 5;
                long compressionHeadersSize = 40+8;
                long headerSize = 0;
                long freeSize = 0;
                while (true) {
                    mdatOffset = compressionHeadersSize + headerSize + freeSize;
                    buf.reset();
                    DeflaterOutputStream deflater = new DeflaterOutputStream(buf);
                    out = new MemoryCacheImageOutputStream(deflater);
                    writeEpilog();
                    out.close();
                    deflater.close();

                    if (buf.size() > headerSize + freeSize && --maxIteration > 0) {
                        if (headerSize!=0) {
                        freeSize = Math.max(freeSize,buf.size()-headerSize - freeSize);
                        }
                        headerSize = buf.size();
                    } else {
                        freeSize = headerSize + freeSize - buf.size();
                        headerSize = buf.size();
                        break;
                    }
                }

                if (maxIteration < 0 || buf.size() == 0) {
                    compressHeader = false;
                    System.err.println("WARNING QuickTimeWriter failed to compress header.");
                } else {
                    out = new FileImageOutputStream(outputFile);
                    writeProlog();

                    // 40 bytes compression headers
                    DataAtomOutputStream daos = new DataAtomOutputStream(new ImageOutputStreamAdapter(out));
                    daos.writeUInt(headerSize + 40);
                    daos.writeType("moov");

                    daos.writeUInt(headerSize + 32);
                    daos.writeType("cmov");

                    daos.writeUInt(12);
                    daos.writeType("dcom");
                    daos.writeType("zlib");

                    daos.writeUInt(headerSize + 12);
                    daos.writeType("cmvd");
                    daos.writeUInt(originalMoovAtom.size());

                    daos.write(buf.toByteArray());

                    // 8 bytes "free" atom + free data
                    daos.writeUInt(freeSize + 8);
                    daos.writeType("free");
                    for (int i = 0; i < freeSize; i++) {
                        daos.write(0);
                    }
                }

            }
            if (!compressHeader) {
                out = new FileImageOutputStream(outputFile);
                mdatOffset = moovAtom.size();
                writeProlog();
                writeEpilog();
            }

            byte[] buf = new byte[4096];
            originalOut.seek((originalMdatOffset));
            for (long count = 0, n = mdatAtom.size(); count < n;) {
                int read = originalOut.read(buf, 0, (int) Math.min(buf.length, n - count));
                out.write(buf, 0, read);
                count += read;
            }
            out.close();
        } finally {
            mdatOffset = 0;
            moovAtom = originalMoovAtom;
            out = originalOut;
        }
    }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/io/examples/DigitalAnalog_I2C_MCP4725/DigitalAnalog_I2C_MCP4725.pde
import processing.io.*;
MCP4725 dac;

void setup() {
  //printArray(I2C.list());
  dac = new MCP4725(I2C.list()[0], 0x60);
}

void draw() {
  background(map(mouseX, 0, width, 0, 255));
  dac.setAnalog(map(mouseX, 0, width, 0.0, 1.0));
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/src/processing/mode/java/pdex/ErrorChecker.java
package processing.mode.java.pdex;

import java.awt.EventQueue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import org.eclipse.jdt.core.compiler.IProblem;

import com.google.classpath.ClassPath;
import com.google.classpath.ClassPathFactory;
import com.google.classpath.RegExpResourceFilter;

import processing.app.Language;
import processing.app.Problem;
import processing.mode.java.JavaEditor;
import processing.mode.java.JavaMode;
import processing.mode.java.pdex.PreprocessedSketch.SketchInterval;

class ErrorChecker {
  // Delay delivering error check result after last sketch change #2677
  private final static long DELAY_BEFORE_UPDATE = 650;

  private ScheduledExecutorService scheduler;
  private volatile ScheduledFuture<?> scheduledUiUpdate = null;
  private volatile long nextUiUpdate = 0;
  private volatile boolean enabled = true;

  private final Consumer<PreprocessedSketch> errorHandlerListener = this::handleSketchProblems;

  private JavaEditor editor;
  private PreprocessingService pps;

  public ErrorChecker(JavaEditor editor, PreprocessingService pps) {
    this.editor = editor;
    this.pps = pps;
    scheduler = Executors.newSingleThreadScheduledExecutor();
    this.enabled = JavaMode.errorCheckEnabled;
    if (enabled) {
      pps.registerListener(errorHandlerListener);
    }
  }

  public void notifySketchChanged() {
    nextUiUpdate = System.currentTimeMillis() + DELAY_BEFORE_UPDATE;
  }

  public void preferencesChanged() {
    if (enabled != JavaMode.errorCheckEnabled) {
      enabled = JavaMode.errorCheckEnabled;
      if (enabled) {
        pps.registerListener(errorHandlerListener);
      } else {
        pps.unregisterListener(errorHandlerListener);
        editor.setProblemList(Collections.emptyList());
        nextUiUpdate = 0;
      }
    }
  }

  public void dispose() {
    if (scheduler != null) {
      scheduler.shutdownNow();
    }
  }

  private void handleSketchProblems(PreprocessedSketch ps) {
    Map<String, String[]> suggCache =
        JavaMode.importSuggestEnabled ? new HashMap<>() : Collections.emptyMap();

    final List<Problem> problems = new ArrayList<>();

    IProblem[] iproblems = ps.compilationUnit.getProblems();

    { // Check for curly quotes
      List<JavaProblem> curlyQuoteProblems = checkForCurlyQuotes(ps);
      problems.addAll(curlyQuoteProblems);
    }

    if (problems.isEmpty()) { // Check for missing braces
      List<JavaProblem> missingBraceProblems = checkForMissingBraces(ps);
      problems.addAll(missingBraceProblems);
    }

    if (problems.isEmpty()) {
      AtomicReference<ClassPath> searchClassPath = new AtomicReference<>(null);
      List<Problem> cuProblems = Arrays.stream(iproblems)
          // Filter Warnings if they are not enabled
          .filter(iproblem -> !(iproblem.isWarning() && !JavaMode.warningsEnabled))
          // Hide a useless error which is produced when a line ends with
          // an identifier without a semicolon. "Missing a semicolon" is
          // also produced and is preferred over this one.
          // (Syntax error, insert ":: IdentifierOrNew" to complete Expression)
          // See: https://bugs.eclipse.org/bugs/show_bug.cgi?id=405780
          .filter(iproblem -> !iproblem.getMessage()
              .contains("Syntax error, insert \":: IdentifierOrNew\""))
          // Transform into our Problems
          .map(iproblem -> {
            JavaProblem p = convertIProblem(iproblem, ps);

            // Handle import suggestions
            if (p != null && JavaMode.importSuggestEnabled && isUndefinedTypeProblem(iproblem)) {
              ClassPath cp = searchClassPath.updateAndGet(prev -> prev != null ?
                  prev : new ClassPathFactory().createFromPaths(ps.searchClassPathArray));
              String[] s = suggCache.computeIfAbsent(iproblem.getArguments()[0],
                                                     name -> getImportSuggestions(cp, name));
              p.setImportSuggestions(s);
            }

            return p;
          })
          .filter(Objects::nonNull)
          .collect(Collectors.toList());

      problems.addAll(cuProblems);
    }

    if (scheduledUiUpdate != null) {
      scheduledUiUpdate.cancel(true);
    }
    // Update UI after a delay. See #2677
    long delay = nextUiUpdate - System.currentTimeMillis();
    Runnable uiUpdater = () -> {
      if (nextUiUpdate > 0 && System.currentTimeMillis() >= nextUiUpdate) {
        EventQueue.invokeLater(() -> editor.setProblemList(problems));
      }
    };
    scheduledUiUpdate = scheduler.schedule(uiUpdater, delay,
                                           TimeUnit.MILLISECONDS);
  }

  static private JavaProblem convertIProblem(IProblem iproblem, PreprocessedSketch ps) {
    SketchInterval in = ps.mapJavaToSketch(iproblem);
    if (in == SketchInterval.BEFORE_START) return null;
    String badCode = ps.getPdeCode(in);
    int line = ps.tabOffsetToTabLine(in.tabIndex, in.startTabOffset);
    JavaProblem p = JavaProblem.fromIProblem(iproblem, in.tabIndex, line, badCode);
    p.setPDEOffsets(in.startTabOffset, in.stopTabOffset);
    return p;
  }

  static private boolean isUndefinedTypeProblem(IProblem iproblem) {
    int id = iproblem.getID();
    return id == IProblem.UndefinedType ||
        id == IProblem.UndefinedName ||
        id == IProblem.UnresolvedVariable;
  }

  static private boolean isMissingBraceProblem(IProblem iproblem) {
    switch (iproblem.getID()) {
      case IProblem.ParsingErrorInsertToComplete: {
        char brace = iproblem.getArguments()[0].charAt(0);
        return brace == '{' || brace == '}';
      }
      case IProblem.ParsingErrorInsertTokenAfter: {
        char brace = iproblem.getArguments()[1].charAt(0);
        return brace == '{' || brace == '}';
      }
      default:
        return false;
    }
  }

  private static final Pattern CURLY_QUOTE_REGEX =
      Pattern.compile("([“”‘’])", Pattern.UNICODE_CHARACTER_CLASS);

  static private List<JavaProblem> checkForCurlyQuotes(PreprocessedSketch ps) {
    List<JavaProblem> problems = new ArrayList<>(0);

    // Go through the scrubbed code and look for curly quotes (they should not be any)
    Matcher matcher = CURLY_QUOTE_REGEX.matcher(ps.scrubbedPdeCode);
    while (matcher.find()) {
      int pdeOffset = matcher.start();
      String q = matcher.group();

      int tabIndex = ps.pdeOffsetToTabIndex(pdeOffset);
      int tabOffset = ps.pdeOffsetToTabOffset(tabIndex, pdeOffset);
      int tabLine = ps.tabOffsetToTabLine(tabIndex, tabOffset);

      String message = Language.interpolate("editor.status.bad_curly_quote", q);
      JavaProblem problem = new JavaProblem(message, JavaProblem.ERROR, tabIndex, tabLine);
      problem.setPDEOffsets(tabOffset, tabOffset+1);

      problems.add(problem);
    }

    // Go through iproblems and look for problems involving curly quotes
    List<JavaProblem> problems2 = new ArrayList<>(0);
    IProblem[] iproblems = ps.compilationUnit.getProblems();

    for (IProblem iproblem : iproblems) {
      switch (iproblem.getID()) {
        case IProblem.ParsingErrorDeleteToken:
        case IProblem.ParsingErrorDeleteTokens:
        case IProblem.ParsingErrorInvalidToken:
        case IProblem.ParsingErrorReplaceTokens:
        case IProblem.UnterminatedString:
          SketchInterval in = ps.mapJavaToSketch(iproblem);
          if (in == SketchInterval.BEFORE_START) continue;
          String badCode = ps.getPdeCode(in);
          matcher.reset(badCode);
          while (matcher.find()) {
            int offset = matcher.start();
            String q = matcher.group();
            int tabStart = in.startTabOffset + offset;
            int tabStop = tabStart + 1;
            // Prevent duplicate problems
            if (problems.stream().noneMatch(p -> p.getStartOffset() == tabStart)) {
              int line = ps.tabOffsetToTabLine(in.tabIndex, tabStart);
              String message;
              if (iproblem.getID() == IProblem.UnterminatedString) {
                message = Language.interpolate("editor.status.unterm_string_curly", q);
              } else {
                message = Language.interpolate("editor.status.bad_curly_quote", q);
              }
              JavaProblem p = new JavaProblem(message, JavaProblem.ERROR, in.tabIndex, line);
              p.setPDEOffsets(tabStart, tabStop);
              problems2.add(p);
            }
          }
      }
    }

    problems.addAll(problems2);

    return problems;
  }

  static private List<JavaProblem> checkForMissingBraces(PreprocessedSketch ps) {
    List<JavaProblem> problems = new ArrayList<>(0);
    for (int tabIndex = 0; tabIndex < ps.tabStartOffsets.length; tabIndex++) {
      int tabStartOffset = ps.tabStartOffsets[tabIndex];
      int tabEndOffset = (tabIndex < ps.tabStartOffsets.length - 1) ?
          ps.tabStartOffsets[tabIndex + 1] : ps.scrubbedPdeCode.length();
      int[] braceResult = SourceUtils.checkForMissingBraces(ps.scrubbedPdeCode, tabStartOffset, tabEndOffset);
      if (braceResult[0] != 0) {
        JavaProblem problem =
            new JavaProblem(braceResult[0] < 0
                                ? Language.interpolate("editor.status.missing.left_curly_bracket")
                                : Language.interpolate("editor.status.missing.right_curly_bracket"),
                            JavaProblem.ERROR, tabIndex, braceResult[1]);
        problem.setPDEOffsets(braceResult[3], braceResult[3] + 1);
        problems.add(problem);
      }
    }

    if (problems.isEmpty()) {
      return problems;
    }

    int problemTabIndex = problems.get(0).getTabIndex();

    IProblem missingBraceProblem = Arrays.stream(ps.compilationUnit.getProblems())
        .filter(ErrorChecker::isMissingBraceProblem)
        // Ignore if it is at the end of file
        .filter(p -> p.getSourceEnd() + 1 < ps.javaCode.length())
        // Ignore if the tab number does not match our detected tab number
        .filter(p -> problemTabIndex == ps.mapJavaToSketch(p).tabIndex)
        .findFirst()
        .orElse(null);

    // Prefer ECJ problem, shows location more accurately
    if (missingBraceProblem != null) {
      JavaProblem p = convertIProblem(missingBraceProblem, ps);
      if (p != null) {
        problems.clear();
        problems.add(p);
      }
    }

    return problems;
  }

  static public String[] getImportSuggestions(ClassPath cp, String className) {
    className = className.replace("[", "\\[").replace("]", "\\]");
    RegExpResourceFilter regf = new RegExpResourceFilter(
        Pattern.compile(".*"),
        Pattern.compile("(.*\\$)?" + className + "\\.class",
                        Pattern.CASE_INSENSITIVE));

    String[] resources = cp.findResources("", regf);
    return Arrays.stream(resources)
        // remove ".class" suffix
        .map(res -> res.substring(0, res.length() - 6))
        // replace path separators with dots
        .map(res -> res.replace('/', '.'))
        // replace inner class separators with dots
        .map(res -> res.replace('$', '.'))
        // sort, prioritize clases from java. package
        .sorted((o1, o2) -> {
          // put java.* first, should be prioritized more
          boolean o1StartsWithJava = o1.startsWith("java");
          boolean o2StartsWithJava = o2.startsWith("java");
          if (o1StartsWithJava != o2StartsWithJava) {
            if (o1StartsWithJava) return -1;
            return 1;
          }
          return o1.compareTo(o2);
        })
        .toArray(String[]::new);
  }
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Demos/Graphics/Patch/Patch.pde
// Bezier patch By <NAME>:
// http://www.openprocessing.org/sketch/57709
// Normal calculation added by <NAME>
// Direct port of sample code by <NAME>.
// Original code: http://paulbourke.net/geometry/bezier/

int ni=4, nj=5, RESI=ni*10, RESJ=nj*10;
PVector outp[][], inp[][];
PVector normp[][];
boolean autoNormals = false;

void setup() {
  size(1024, 768, P3D);
  build();
}

void draw() {
  background(255);
  translate(width/2,height/2);
  lights();
  scale(0.9);
  rotateY(map(mouseX,0,width,-PI,PI));
  rotateX(map(mouseY,0,height,-PI,PI));

  noStroke();
  fill(255);
  for(int i=0; i<RESI-1; i++) {
    beginShape(QUAD_STRIP);
    for(int j=0; j<RESJ; j++) {
      if (!autoNormals) {
        normal(normp[i][j].x, normp[i][j].y, normp[i][j].z);
      }
      vertex(outp[i][j].x,outp[i][j].y,outp[i][j].z);
      vertex(outp[i+1][j].x,outp[i+1][j].y,outp[i+1][j].z);
    }
    endShape();
  }
}

void keyPressed() {
  if(key==' ') build();
  saveFrame("bezPatch.png");
}

void build() {
  int i, j, ki, kj;
  double mui, muj, bi, bj, dbi, dbj;

  outp=new PVector[RESI][RESJ];
  normp=new PVector[RESI][RESJ];
  inp=new PVector[ni+1][nj+1];
  PVector uitang = new PVector();
  PVector ujtang = new PVector();

  for (i=0;i<=ni;i++) {
    for (j=0;j<=nj;j++) {
      inp[i][j]=new PVector(i,j,random(-3,3));
    }
  }

  for (i=0;i<RESI;i++) {
    mui = i / (double)(RESI-1);
    for (j=0;j<RESJ;j++) {
      muj = j / (double)(RESJ-1);
      outp[i][j]=new PVector();
      uitang.set(0, 0, 0);
      ujtang.set(0, 0, 0);
      for (ki=0;ki<=ni;ki++) {
        bi = BezierBlend(ki, mui, ni);
        dbi = DBezierBlend(ki, mui, ni);
        for (kj=0;kj<=nj;kj++) {
          bj = BezierBlend(kj, muj, nj);
          dbj = DBezierBlend(kj, muj, nj);
          outp[i][j].x += (inp[ki][kj].x * bi * bj);
          outp[i][j].y += (inp[ki][kj].y * bi * bj);
          outp[i][j].z += (inp[ki][kj].z * bi * bj);

          uitang.x += (inp[ki][kj].x * dbi * bj);
          uitang.y += (inp[ki][kj].y * dbi * bj);
          uitang.z += (inp[ki][kj].z * dbi * bj);

          ujtang.x += (inp[ki][kj].x * bi * dbj);
          ujtang.y += (inp[ki][kj].y * bi * dbj);
          ujtang.z += (inp[ki][kj].z * bi * dbj);
        }
      }
      outp[i][j].add(new PVector(-ni/2,-nj/2,0));
      outp[i][j].mult(100);

      uitang.normalize();
      ujtang.normalize();
      normp[i][j] = uitang.cross(ujtang);
    }
  }
}

double BezierBlend(int k, double mu, int n) {
  int nn, kn, nkn;
  double blend=1;

  nn = n;
  kn = k;
  nkn = n - k;

  while (nn >= 1) {
    blend *= nn;
    nn--;
    if (kn > 1) {
      blend /= (double)kn;
      kn--;
    }
    if (nkn > 1) {
      blend /= (double)nkn;
      nkn--;
    }
  }
  if (k > 0)
    blend *= Math.pow(mu, (double)k);
  if (n-k > 0)
    blend *= Math.pow(1-mu, (double)(n-k));

  return(blend);
}

double DBezierBlend(int k, double mu, int n) {
  int nn, kn, nkn;
  double dblendf = 1;

  nn = n;
  kn = k;
  nkn = n - k;

  while (nn >= 1) {
    dblendf *= nn;
    nn--;
    if (kn > 1) {
      dblendf /= (double)kn;
      kn--;
    }
    if (nkn > 1) {
      dblendf /= (double)nkn;
      nkn--;
    }
  }

  double fk = 1;
  double dk = 0;
  double fnk = 1;
  double dnk = 0;
  if (k > 0) {
    fk = Math.pow(mu, (double)k);
    dk = k*Math.pow(mu, (double)k-1);
  }
  if (n-k > 0) {
    fnk = Math.pow(1-mu, (double)(n-k));
    dnk = (k-n)*Math.pow(1-mu, (double)(n-k-1));
  }
  dblendf *= (dk * fnk + fk * dnk);

  return(dblendf);
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/tools/MovieMaker/src/processing/app/tools/MovieMaker.java
package processing.app.tools;
/*
 * Nearly all of this code is
 * Copyright (c) 2010-2011 <NAME>, Immensee, Switzerland.
 * All rights reserved.
 * (However, he should not be held responsible for the current mess of a hack
 * that it has become.)
 *
 * You may not use, copy or modify this file, except in compliance with the
 * license agreement you entered into with <NAME>.
 * For details see accompanying license terms.
 */

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import java.util.*;
import java.util.prefs.Preferences;

import javax.imageio.ImageIO;
import javax.sound.sampled.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.filechooser.FileSystemView;

import processing.app.Base;
import processing.app.Language;

import ch.randelshofer.gui.datatransfer.FileTextFieldTransferHandler;
import ch.randelshofer.media.mp3.MP3AudioInputStream;
import ch.randelshofer.media.quicktime.QuickTimeWriter;

/**
 * Hacked from <NAME>'s QuickTimeWriter demo. The original version
 * can be found here.
 *

 * A more up-to-date version of the project is
 * here.
 * Problem is, it's too big, so we don't want to merge it into our code.
 *

 * Broken out as a separate project because the license (CC) probably isn't
 * compatible with the rest of Processing and we don't want any confusion.
 *

 * Added JAI ImageIO to support lots of other image file formats [131008].
 * Also copied the Processing TGA implementation.
 *

 * Added support for the gamma ('gama') atom [131008].
 *

 * A few more notes on the implementation:
 *

 *
 The dialog box is super ugly. It's a hacked up version of the previous
 *      interface, but I'm too scared to pull that GUI layout code apart.
 *
 The 'None' compressor seems to have bugs, so just disabled it instead.
 *
 The 'pass through' option seems to be broken, so it's been removed.
 *      In its place is an option to use the same width/height as the originals.
 *
 When this new 'pass through' is set, there's some nastiness with how
 *      the 'final' width/height variables are passed to the movie maker.
 *      This is an easy fix but needs a couple minutes.
 *

 * <NAME> 2011-09-06, updated 2013-10-09
 */
public class MovieMaker extends JFrame implements Tool {
  private Preferences prefs;

  public String getMenuTitle() {
    return Language.text("movie_maker");
  }

  public void run() {
    setVisible(true);
  }

  public void init(Base base) {
    initComponents(base.getActiveEditor() == null);

    ((JComponent) getContentPane()).setBorder(new EmptyBorder(12, 18, 18, 18));
    imageFolderField.setTransferHandler(new FileTextFieldTransferHandler(JFileChooser.DIRECTORIES_ONLY));
    soundFileField.setTransferHandler(new FileTextFieldTransferHandler());

    JComponent[] smallComponents = {
      compressionBox,
      compressionLabel,
      fpsField,
      fpsLabel,
      widthField,
      widthLabel,
      heightField,
      heightLabel,
      originalSizeCheckBox,
    };
    for (JComponent c : smallComponents) {
      c.putClientProperty("JComponent.sizeVariant", "small");
    }

    // Get Preferences
    prefs = Preferences.userNodeForPackage(MovieMaker.class);
    imageFolderField.setText(prefs.get("movie.imageFolder", ""));
    soundFileField.setText(prefs.get("movie.soundFile", ""));
    widthField.setText("" + prefs.getInt("movie.width", 640));
    heightField.setText("" + prefs.getInt("movie.height", 480));
    boolean original = prefs.getBoolean("movie.originalSize", false);
    originalSizeCheckBox.setSelected(original);
    widthField.setEnabled(!original);
    heightField.setEnabled(!original);
    String fps = "" + prefs.getDouble("movie.fps", 30);
    if (fps.endsWith(".0")) {
      fps = fps.substring(0, fps.length() - 2);
    }
    fpsField.setText(fps);
    compressionBox.setSelectedIndex(Math.max(0, Math.min(compressionBox.getItemCount() - 1, prefs.getInt("movie.compression", 0))));

    originalSizeCheckBox.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        boolean enabled = !originalSizeCheckBox.isSelected();
        widthField.setEnabled(enabled);
        heightField.setEnabled(enabled);
      }
    });

//    String streaming = prefs.get("movie.streaming", "fastStartCompressed");
//    for (Enumeration<AbstractButton> i = streamingGroup.getElements(); i.hasMoreElements();) {
//      AbstractButton btn = i.nextElement();
//      if (btn.getActionCommand().equals(streaming)) {
//        btn.setSelected(true);
//        break;
//      }
//    }

    // scoot everybody around
    pack();
    // center the frame on screen
    setLocationRelativeTo(null);
  }

  /**
   * Registers key events for a Ctrl-W and ESC with an ActionListener
   * that will take care of disposing the window.
   */
  static public void registerWindowCloseKeys(JRootPane root,
                                             ActionListener disposer) {
    KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
    root.registerKeyboardAction(disposer, stroke,
                                JComponent.WHEN_IN_FOCUSED_WINDOW);

    int modifiers = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
    stroke = KeyStroke.getKeyStroke('W', modifiers);
    root.registerKeyboardAction(disposer, stroke,
                                JComponent.WHEN_IN_FOCUSED_WINDOW);
  }

  private void initComponents(final boolean standalone) {
    imageFolderHelpLabel = new JLabel();
    imageFolderField = new JTextField();
    chooseImageFolderButton = new JButton();
    soundFileHelpLabel = new JLabel();
    soundFileField = new JTextField();
    chooseSoundFileButton = new JButton();
    createMovieButton = new JButton();
    widthLabel = new JLabel();
    widthField = new JTextField();
    heightLabel = new JLabel();
    heightField = new JTextField();
    compressionLabel = new JLabel();
    compressionBox = new JComboBox<String>();
    fpsLabel = new JLabel();
    fpsField = new JTextField();
    originalSizeCheckBox = new JCheckBox();

    setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
    addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        setVisible(false);
      }
    });
    registerWindowCloseKeys(getRootPane(), new ActionListener() {
      public void actionPerformed(ActionEvent actionEvent) {
        if (standalone) {
          System.exit(0);
        } else {
          setVisible(false);
        }
      }
    });
    setTitle(Language.text("movie_maker.title"));

    aboutLabel = new JLabel(Language.text("movie_maker.blurb"));
    imageFolderHelpLabel.setText(Language.text("movie_maker.image_folder_help_label"));
    chooseImageFolderButton.setText(Language.text("movie_maker.choose_button"));
    //chooseImageFolderButton.addActionListener(formListener);
    chooseImageFolderButton.addActionListener(new ActionListener() {

      @Override
      public void actionPerformed(ActionEvent e) {
        Chooser.selectFolder(MovieMaker.this,
                             Language.text("movie_maker.select_image_folder"),
                             new File(imageFolderField.getText()),
                             new Chooser.Callback() {
          void select(File file) {
            if (file != null) {
              imageFolderField.setText(file.getAbsolutePath());
            }
          }
        });
      }
    });

    soundFileHelpLabel.setText(Language.text("movie_maker.sound_file_help_label"));
    chooseSoundFileButton.setText(Language.text("movie_maker.choose_button"));
    //chooseSoundFileButton.addActionListener(formListener);
    chooseSoundFileButton.addActionListener(new ActionListener() {

      @Override
      public void actionPerformed(ActionEvent e) {
        Chooser.selectInput(MovieMaker.this,
                            Language.text("movie_maker.select_sound_file"),
                            new File(soundFileField.getText()),
                            new Chooser.Callback() {

          void select(File file) {
            if (file != null) {
              soundFileField.setText(file.getAbsolutePath());
            }
          }
        });
      }
    });

    createMovieButton.setText(Language.text("movie_maker.create_movie_button"));
//    createMovieButton.addActionListener(formListener);
    createMovieButton.addActionListener(new ActionListener() {

      @Override
      public void actionPerformed(ActionEvent e) {
        String lastPath = prefs.get("movie.outputFile", null);
        File lastFile = lastPath == null ? null : new File(lastPath);
        Chooser.selectOutput(MovieMaker.this,
                             Language.text("movie_maker.save_dialog_prompt"),
                             lastFile,
                             new Chooser.Callback() {
          @Override
          void select(File file) {
            if (file != null) {
              String path = file.getAbsolutePath();
              if (!path.toLowerCase().endsWith(".mov")) {
                path += ".mov";
              }
              prefs.put("movie.outputFile", path);
              createMovie(new File(path));
//              final File target = new File(path);
//              //new Thread(new Runnable() {
//              EventQueue.invokeLater(new Runnable() {
//
//                @Override
//                public void run() {
//                  createMovie(target);
//                }
//
//              });
            }
          }
        });
      }
    });

    Font font = new Font("Dialog", Font.PLAIN, 11);

    widthLabel.setFont(font);
    widthLabel.setText(Language.text("movie_maker.width"));
    widthField.setColumns(4);
    widthField.setFont(font);
    widthField.setText("320");

    heightLabel.setFont(font);
    heightLabel.setText(Language.text("movie_maker.height"));
    heightField.setColumns(4);
    heightField.setFont(font);
    heightField.setText("240");

    compressionLabel.setFont(font);
    compressionLabel.setText(Language.text("movie_maker.compression"));
    compressionBox.setFont(font);
    //compressionBox.setModel(new DefaultComboBoxModel(new String[] { "None", "Animation", "JPEG", "PNG" }));
    compressionBox.setModel(new DefaultComboBoxModel<String>(
      new String[] {
        Language.text("movie_maker.compression.animation"),
        Language.text("movie_maker.compression.jpeg"),
        Language.text("movie_maker.compression.png")
      }
    ));

    fpsLabel.setFont(font);
    fpsLabel.setText(Language.text("movie_maker.framerate"));
    fpsField.setColumns(4);
    fpsField.setFont(font);
    fpsField.setText("30");

    originalSizeCheckBox.setFont(font);
    originalSizeCheckBox.setText(Language.text("movie_maker.orig_size_button"));
    originalSizeCheckBox.setToolTipText(Language.text("movie_maker.orig_size_tooltip"));

//        streamingLabel.setText("Prepare for Internet Streaming");
//
//        streamingGroup.add(noPreparationRadio);
//        noPreparationRadio.setFont(font);
//        noPreparationRadio.setSelected(true);
//        noPreparationRadio.setText("No preparation");
//        noPreparationRadio.setActionCommand("none");
//        noPreparationRadio.addActionListener(formListener);
//
//        streamingGroup.add(fastStartRadio);
//        fastStartRadio.setFont(font);
//        fastStartRadio.setText("Fast Start");
//        fastStartRadio.setActionCommand("fastStart");
//        fastStartRadio.addActionListener(formListener);
//
//        streamingGroup.add(fastStartCompressedRadio);
//        fastStartCompressedRadio.setFont(font);
//        fastStartCompressedRadio.setText("Fast Start - Compressed Header");
//        fastStartCompressedRadio.setActionCommand("fastStartCompressed");
//        fastStartCompressedRadio.addActionListener(formListener);

    GroupLayout layout = new GroupLayout(getContentPane());
    getContentPane().setLayout(layout);
    layout.setHorizontalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
      .addGroup(layout.createSequentialGroup()
        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
          .addGroup(layout.createSequentialGroup()
            .addGap(61, 61, 61)
            .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
              .addComponent(widthLabel)
              .addComponent(fpsLabel))
              .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
              .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup()
                  .addComponent(fpsField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                  .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
                  .addComponent(compressionLabel)
                  .addGap(1, 1, 1)
                  .addComponent(compressionBox, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                  .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
                  .addComponent(originalSizeCheckBox))
                  .addGroup(layout.createSequentialGroup()
                    .addComponent(widthField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                    .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
                    .addComponent(heightLabel)
                    .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
                    .addComponent(heightField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)))
                    .addGap(41, 41, 41))
                    .addGroup(layout.createSequentialGroup()
                      .addContainerGap()
                      .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                        .addComponent(aboutLabel, GroupLayout.DEFAULT_SIZE, 484, Short.MAX_VALUE)
                        .addComponent(imageFolderHelpLabel)
                        .addComponent(soundFileHelpLabel)
                        .addGroup(layout.createSequentialGroup()
                          .addComponent(soundFileField, GroupLayout.DEFAULT_SIZE, 372, Short.MAX_VALUE)
                          .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
                          .addComponent(chooseSoundFileButton))
                          .addComponent(createMovieButton, GroupLayout.Alignment.TRAILING)
                          .addGroup(GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                            .addComponent(imageFolderField, GroupLayout.DEFAULT_SIZE, 372, Short.MAX_VALUE)
                            .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
                            .addComponent(chooseImageFolderButton))))
                            .addGroup(layout.createSequentialGroup()
                              .addContainerGap())))
    );
    layout.setVerticalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
              .addContainerGap()
              .addComponent(aboutLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
              .addGap(18, 18, 18)
              .addComponent(imageFolderHelpLabel)
              .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
              .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
                .addComponent(imageFolderField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                .addComponent(chooseImageFolderButton))
                .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
                  .addComponent(widthLabel)
                  .addComponent(widthField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                  .addComponent(heightLabel)
                  .addComponent(heightField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                  .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
                  .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
                    .addComponent(compressionBox, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                    .addComponent(fpsLabel)
                    .addComponent(fpsField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                    .addComponent(compressionLabel)
                    .addComponent(originalSizeCheckBox))
                    .addGap(18, 18, 18)
                    .addComponent(soundFileHelpLabel)
                    .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
                    .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
                      .addComponent(soundFileField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                      .addComponent(chooseSoundFileButton))
                      .addGap(18, 18, 18)
                      .addComponent(createMovieButton)
                      .addContainerGap())
    );

    pack();
  }

  // Code for dispatching events from components to event handlers.

//  private class FormListener implements java.awt.event.ActionListener {
//    FormListener() {}
//    public void actionPerformed(java.awt.event.ActionEvent evt) {
//      if (evt.getSource() == chooseImageFolderButton) {
//        MovieMaker.this.chooseImageFolder(evt);
//      }
//      else if (evt.getSource() == chooseSoundFileButton) {
//        MovieMaker.this.chooseSoundFile(evt);
//      }
//      else if (evt.getSource() == createMovieButton) {
//        MovieMaker.this.createMovie(evt);
//      }
////      else if (evt.getSource() == fastStartCompressedRadio) {
////        MovieMaker.this.streamingRadioPerformed(evt);
////      }
////      else if (evt.getSource() == fastStartRadio) {
////        MovieMaker.this.streamingRadioPerformed(evt);
////      }
////      else if (evt.getSource() == noPreparationRadio) {
////        MovieMaker.this.streamingRadioPerformed(evt);
////      }
//    }
//  }

//  private void chooseImageFolder(ActionEvent evt) {
//    if (imageFolderChooser == null) {
//      imageFolderChooser = new JFileChooser();
//      imageFolderChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
//      if (imageFolderField.getText().length() > 0) {
//        imageFolderChooser.setSelectedFile(new File(imageFolderField.getText()));
//      } else if (soundFileField.getText().length() > 0) {
//        imageFolderChooser.setCurrentDirectory(new File(soundFileField.getText()).getParentFile());
//      }
//    }
//    if (JFileChooser.APPROVE_OPTION == imageFolderChooser.showOpenDialog(this)) {
//      imageFolderField.setText(imageFolderChooser.getSelectedFile().getPath());
//    }
//  }
//
//  private void chooseSoundFile(ActionEvent evt) {
//    if (soundFileChooser == null) {
//      soundFileChooser = new JFileChooser();
//      if (soundFileField.getText().length() > 0) {
//        soundFileChooser.setSelectedFile(new File(soundFileField.getText()));
//      } else if (imageFolderField.getText().length() > 0) {
//        soundFileChooser.setCurrentDirectory(new File(imageFolderField.getText()));
//      }
//    }
//    if (JFileChooser.APPROVE_OPTION == soundFileChooser.showOpenDialog(this)) {
//      soundFileField.setText(soundFileChooser.getSelectedFile().getPath());
//    }
//  }

  // this is super naughty, and shouldn't be out here. it's a hack to get the
  // ImageIcon width/height setting to work. there are better ways to do this
  // given a bit of time. you know, time? the infinite but non-renewable resource?
  int width, height;

  private void createMovie(final File movieFile) {
    createMovieButton.setEnabled(false);

    // ---------------------------------
    // Check input
    // ---------------------------------
    final File soundFile = soundFileField.getText().trim().length() == 0 ? null : new File(soundFileField.getText().trim());
    final File imageFolder = imageFolderField.getText().trim().length() == 0 ? null : new File(imageFolderField.getText().trim());
    //final String streaming = prefs.get("movie.streaming", "fastStartCompressed");
    final String streaming = "fastStartCompressed";
    if (soundFile == null && imageFolder == null) {
      JOptionPane.showMessageDialog(this, Language.text("movie_maker.error.need_input"));
      return;
    }

    final double fps;
    try {
      width = Integer.parseInt(widthField.getText());
      height = Integer.parseInt(heightField.getText());
      fps = Double.parseDouble(fpsField.getText());
    } catch (Throwable t) {
      JOptionPane.showMessageDialog(this, Language.text("movie_maker.error.badnumbers"));
      return;
    }
    if (width < 1 || height < 1 || fps < 1) {
      JOptionPane.showMessageDialog(this, Language.text("movie_maker.error.badnumbers"));
      return;
    }

    final QuickTimeWriter.VideoFormat videoFormat;
    switch (compressionBox.getSelectedIndex()) {
//    case 0:
//      videoFormat = QuickTimeWriter.VideoFormat.RAW;
//      break;
    case 0://1:
      videoFormat = QuickTimeWriter.VideoFormat.RLE;
      break;
    case 1://2:
      videoFormat = QuickTimeWriter.VideoFormat.JPG;
      break;
    case 2://3:
    default:
      videoFormat = QuickTimeWriter.VideoFormat.PNG;
      break;
    }

    // ---------------------------------
    // Update Preferences
    // ---------------------------------
    prefs.put("movie.imageFolder", imageFolderField.getText());
    prefs.put("movie.soundFile", soundFileField.getText());
    prefs.putInt("movie.width", width);
    prefs.putInt("movie.height", height);
    prefs.putDouble("movie.fps", fps);
    prefs.putInt("movie.compression", compressionBox.getSelectedIndex());
    prefs.putBoolean("movie.originalSize", originalSizeCheckBox.isSelected());

    final boolean originalSize = originalSizeCheckBox.isSelected();

    // ---------------------------------
    // Create the QuickTime movie
    // ---------------------------------
    new SwingWorker<Throwable, Object>() {

      @Override
      protected Throwable doInBackground() {
        try {
          // Read image files
          File[] imgFiles = null;
          if (imageFolder != null) {
            imgFiles = imageFolder.listFiles(new FileFilter() {
              FileSystemView fsv = FileSystemView.getFileSystemView();

              public boolean accept(File f) {
                return f.isFile() && !fsv.isHiddenFile(f) &&
                  !f.getName().equals("Thumbs.db");
              }
            });
            if (imgFiles == null || imgFiles.length == 0) {
              return new RuntimeException(Language.text("movie_maker.error.no_images_found"));
            }
            Arrays.sort(imgFiles);
          }

          // Get the width and height if we're preserving size.
          if (originalSize) {
            Dimension d = findSize(imgFiles);
            if (d == null) {
              // No images at all? No video then.
              throw new RuntimeException(Language.text("movie_maker.error.no_images_found"));
            }
            width = d.width;
            height = d.height;
          }

          // Delete movie file if it already exists.
          if (movieFile.exists()) {
            movieFile.delete();
          }

          if (imageFolder != null && soundFile != null) {
            writeVideoAndAudio(movieFile, imgFiles, soundFile, width, height, fps, videoFormat, /*passThrough,*/ streaming);
          } else if (imageFolder != null) {
            writeVideoOnlyVFR(movieFile, imgFiles, width, height, fps, videoFormat, /*passThrough,*/ streaming);
          } else {
            writeAudioOnly(movieFile, soundFile, streaming);
          }
          return null;

        } catch (Throwable t) {
          return t;
        }
      }

      Dimension findSize(File[] imgFiles) {
        for (int i = 0; i < imgFiles.length; i++) {
          BufferedImage temp = readImage(imgFiles[i]);
          if (temp != null) {
            return new Dimension(temp.getWidth(), temp.getHeight());
          } else {
            // Nullify bad Files so we don't get errors twice.
            imgFiles[i] = null;
          }
        }
        return null;
      }

      @Override
      protected void done() {
        Throwable t;
        try {
          t = get();
        } catch (Exception ex) {
          t = ex;
        }
        if (t != null) {
          t.printStackTrace();
          JOptionPane.showMessageDialog(MovieMaker.this,
                                      Language.text("movie_maker.error.movie_failed") + "\n" +
                                      (t.getMessage() == null ? t.toString() : t.getMessage()),
                                      Language.text("movie_maker.error.sorry"),
                                      JOptionPane.ERROR_MESSAGE);
        }
        createMovieButton.setEnabled(true);
      }
    }.execute();

  }//GEN-LAST:event_createMovie

  /**
   * Read an image from a file. ImageIcon doesn't don't do well with some
   * file types, so we use ImageIO. ImageIO doesn't handle TGA files
   * created by Processing, so this calls our own loadImageTGA().
   *
 Prints errors itself.
   * @return null on error; image only if okay.
   */
  private BufferedImage readImage(File file) {
    try {
      Thread current = Thread.currentThread();
      ClassLoader origLoader = Thread.currentThread().getContextClassLoader();
      current.setContextClassLoader(getClass().getClassLoader());

      BufferedImage image;
      try {
        image = ImageIO.read(file);
      } catch (IOException e) {
        System.err.println(Language.interpolate("movie_maker.error.cannot_read",
              file.getAbsolutePath()));
        return null;
      }

      current.setContextClassLoader(origLoader);

      /*
      String[] loadImageFormats = ImageIO.getReaderFormatNames();
      if (loadImageFormats != null) {
        for (String format : loadImageFormats) {
          System.out.println(format);
        }
      }
      */

      if (image == null) {
        String path = file.getAbsolutePath();
        String pathLower = path.toLowerCase();
        // Might be an incompatible TGA or TIFF created by Processing
        if (pathLower.endsWith(".tga")) {
          try {
            return loadImageTGA(file);
          } catch (IOException e) {
            cannotRead(file);
            return null;
          }

        } else if (pathLower.endsWith(".tif") || pathLower.endsWith(".tiff")) {
          cannotRead(file);
          System.err.println(Language.text("movie_maker.error.avoid_tiff"));
          return null;

        } else {
          cannotRead(file);
          return null;
        }

      } else {
        if (image.getWidth() <= 0 || image.getHeight() <= 0) {
          System.err.println(Language.interpolate("movie_maker.error.cannot_read_maybe_bad", file.getAbsolutePath()));
          return null;
        }
      }
      return image;

    // Catch-all is sometimes needed.
    } catch (RuntimeException e) {
      cannotRead(file);
      return null;
    }
  }

  static private void cannotRead(File file) {
    String path = file.getAbsolutePath();
    String msg = Language.interpolate("movie_maker.error.cannot_read", path);
    System.err.println(msg);
  }

  /** variable frame rate. */
  private void writeVideoOnlyVFR(File movieFile, File[] imgFiles, int width, int height, double fps, QuickTimeWriter.VideoFormat videoFormat, /*boolean passThrough,*/ String streaming) throws IOException {
    File tmpFile = streaming.equals("none") ? movieFile : new File(movieFile.getPath() + ".tmp");
    ProgressMonitor p = new ProgressMonitor(MovieMaker.this,
                                            Language.interpolate("movie_maker.progress.creating_file_name", movieFile.getName()),
                                            Language.text("movie_maker.progress.creating_output_file"),
                                            0, imgFiles.length);
    Graphics2D g = null;
    BufferedImage img = null;
    BufferedImage prevImg = null;
    int[] data = null;
    int[] prevData = null;
    QuickTimeWriter qtOut = null;
    try {
      int timeScale = (int) (fps * 100.0);
      int duration = 100;

      qtOut = new QuickTimeWriter(videoFormat == QuickTimeWriter.VideoFormat.RAW ? movieFile : tmpFile);
      qtOut.addVideoTrack(videoFormat, timeScale, width, height);
      qtOut.setSyncInterval(0, 30);

      //if (!passThrough) {
      if (true) {
        img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        data = ((DataBufferInt) img.getRaster().getDataBuffer()).getData();
        prevImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        prevData = ((DataBufferInt) prevImg.getRaster().getDataBuffer()).getData();
        g = img.createGraphics();
        g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
      }
      int prevImgDuration = 0;
      for (int i = 0; i < imgFiles.length && !p.isCanceled(); i++) {
        File f = imgFiles[i];
        if (f == null) continue;

        p.setNote(Language.interpolate("movie_maker.progress.processing", f.getName()));
        p.setProgress(i);

        //if (passThrough) {
        if (false) {
          qtOut.writeSample(0, f, duration);
        } else {
          //BufferedImage fImg = ImageIO.read(f);
          BufferedImage fImg = readImage(f);
          if (fImg == null) continue;

          g.drawImage(fImg, 0, 0, width, height, null);
          if (i != 0 && Arrays.equals(data, prevData)) {
            prevImgDuration += duration;
          } else {
            if (prevImgDuration != 0) {
              qtOut.writeFrame(0, prevImg, prevImgDuration);
            }
            prevImgDuration = duration;
            System.arraycopy(data, 0, prevData, 0, data.length);
          }
        }
      }
      if (prevImgDuration != 0) {
        qtOut.writeFrame(0, prevImg, prevImgDuration);
      }
      if (streaming.equals("fastStart")) {
        qtOut.toWebOptimizedMovie(movieFile, false);
        tmpFile.delete();
      } else if (streaming.equals("fastStartCompressed")) {
        qtOut.toWebOptimizedMovie(movieFile, true);
        tmpFile.delete();
      }
      qtOut.close();
      qtOut = null;
    } finally {
      p.close();
      if (g != null) {
        g.dispose();
      }
      if (img != null) {
        img.flush();
      }
      if (qtOut != null) {
        qtOut.close();
      }
    }
  }

  private void writeAudioOnly(File movieFile, File audioFile, String streaming) throws IOException {
    File tmpFile = streaming.equals("none") ? movieFile : new File(movieFile.getPath() + ".tmp");

    int length = (int) Math.min(Integer.MAX_VALUE, audioFile.length()); // file length is used for a rough progress estimate. This will only work for uncompressed audio.
    ProgressMonitor p = new ProgressMonitor(MovieMaker.this,
      Language.interpolate("movie_maker.progress.creating_file_name", movieFile.getName()),
      Language.text("movie_maker.progress.initializing"), 0, length);
    AudioInputStream audioIn = null;
    QuickTimeWriter qtOut = null;

    try {
      qtOut = new QuickTimeWriter(tmpFile);
      if (audioFile.getName().toLowerCase().endsWith(".mp3")) {
        audioIn = new MP3AudioInputStream(audioFile);
      } else {
        audioIn = AudioSystem.getAudioInputStream(audioFile);
      }
      AudioFormat audioFormat = audioIn.getFormat();
      //System.out.println("QuickTimeMovieMakerMain " + audioFormat);
      qtOut.addAudioTrack(audioFormat);
      boolean isVBR = audioFormat.getProperty("vbr") != null && ((Boolean) audioFormat.getProperty("vbr")).booleanValue();
      int asSize = audioFormat.getFrameSize();
      int nbOfFramesInBuffer = isVBR ? 1 : Math.max(1, 1024 / asSize);
      int asDuration = (int) (audioFormat.getSampleRate() / audioFormat.getFrameRate());
      //System.out.println("  frameDuration=" + asDuration);
      long count = 0;
      byte[] audioBuffer = new byte[asSize * nbOfFramesInBuffer];
      for (int bytesRead = audioIn.read(audioBuffer);
          bytesRead != -1;
          bytesRead = audioIn.read(audioBuffer)) {
        if (bytesRead != 0) {
          int framesRead = bytesRead / asSize;
          qtOut.writeSamples(0, framesRead, audioBuffer, 0, bytesRead, asDuration);
          count += bytesRead;
          p.setProgress((int) count);
        }
        if (isVBR) {
          audioFormat = audioIn.getFormat();
          if (audioFormat == null) {
            break;
          }
          asSize = audioFormat.getFrameSize();
          asDuration = (int) (audioFormat.getSampleRate() / audioFormat.getFrameRate());
          if (audioBuffer.length < asSize) {
            audioBuffer = new byte[asSize];
          }
        }
      }
      audioIn.close();
      audioIn = null;
      if (streaming.equals("fastStart")) {
        qtOut.toWebOptimizedMovie(movieFile, false);
        tmpFile.delete();
      } else if (streaming.equals("fastStartCompressed")) {
        qtOut.toWebOptimizedMovie(movieFile, true);
        tmpFile.delete();
      }
      qtOut.close();
      qtOut = null;
    } catch (UnsupportedAudioFileException e) {
      IOException ioe = new IOException(e.getMessage());
      ioe.initCause(e);
      throw ioe;
    } finally {
      p.close();
      if (audioIn != null) {
        audioIn.close();
      }
      if (qtOut != null) {
        qtOut.close();
      }
    }
  }

  private void writeVideoAndAudio(File movieFile, File[] imgFiles, File audioFile,
      int width, int height, double fps, QuickTimeWriter.VideoFormat videoFormat,
      /*boolean passThrough,*/ String streaming) throws IOException {

    File tmpFile = streaming.equals("none") ? movieFile : new File(movieFile.getPath() + ".tmp");
    ProgressMonitor p = new ProgressMonitor(MovieMaker.this,
        Language.interpolate("movie_maker.progress.creating_file_name", movieFile.getName()),
        Language.text("movie_maker.progress.creating_output_file"),
        0, imgFiles.length);
    AudioInputStream audioIn = null;
    QuickTimeWriter qtOut = null;
    BufferedImage imgBuffer = null;
    Graphics2D g = null;

    try {
      // Determine audio format
      if (audioFile.getName().toLowerCase().endsWith(".mp3")) {
        audioIn = new MP3AudioInputStream(audioFile);
      } else {
        audioIn = AudioSystem.getAudioInputStream(audioFile);
      }
      AudioFormat audioFormat = audioIn.getFormat();
      boolean isVBR = audioFormat.getProperty("vbr") != null && ((Boolean) audioFormat.getProperty("vbr")).booleanValue();

      // Determine duration of a single sample
      int asDuration = (int) (audioFormat.getSampleRate() / audioFormat.getFrameRate());
      int vsDuration = 100;
      // Create writer
      qtOut = new QuickTimeWriter(videoFormat == QuickTimeWriter.VideoFormat.RAW ? movieFile : tmpFile);
      qtOut.addAudioTrack(audioFormat); // audio in track 0
      qtOut.addVideoTrack(videoFormat, (int) (fps * vsDuration), width, height);  // video in track 1

      // Create audio buffer
      int asSize;
      byte[] audioBuffer;
      if (isVBR) {
        // => variable bit rate: create audio buffer for a single frame
        asSize = audioFormat.getFrameSize();
        audioBuffer = new byte[asSize];
      } else {
        // => fixed bit rate: create audio buffer for half a second
        asSize = audioFormat.getChannels() * audioFormat.getSampleSizeInBits() / 8;
        audioBuffer = new byte[(int) (qtOut.getMediaTimeScale(0) / 2 * asSize)];
      }

      // Create video buffer
      //if (!passThrough) {
      if (true) {
        imgBuffer = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        g = imgBuffer.createGraphics();
        g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
      } // Main loop
      int movieTime = 0;
      int imgIndex = 0;
      boolean isAudioDone = false;
      while ((imgIndex < imgFiles.length || !isAudioDone) && !p.isCanceled()) {
        // Advance movie time by half a second (we interleave twice per second)
        movieTime += qtOut.getMovieTimeScale() / 2;

        // Advance audio to movie time + 1 second (audio must be ahead of video by 1 second)
        while (!isAudioDone && qtOut.getTrackDuration(0) < movieTime + qtOut.getMovieTimeScale()) {
          int len = audioIn.read(audioBuffer);
          if (len == -1) {
            isAudioDone = true;
          } else {
            qtOut.writeSamples(0, len / asSize, audioBuffer, 0, len, asDuration);
          }
          if (isVBR) {
            // => variable bit rate: format can change at any time
            audioFormat = audioIn.getFormat();
            if (audioFormat == null) {
              break;
            }
            asSize = audioFormat.getFrameSize();
            asDuration = (int) (audioFormat.getSampleRate() / audioFormat.getFrameRate());
            if (audioBuffer.length < asSize) {
              audioBuffer = new byte[asSize];
            }
          }
        }

        // Advance video to movie time
        for (; imgIndex < imgFiles.length && qtOut.getTrackDuration(1) < movieTime; ++imgIndex) {
          // catch up with video time
          p.setProgress(imgIndex);
          File f = imgFiles[imgIndex];
          if (f == null) continue;

          p.setNote(Language.interpolate("movie_maker.progress.processing", f.getName()));
          //if (passThrough) {
          if (false) {
            qtOut.writeSample(1, f, vsDuration);
          } else {
            //BufferedImage fImg = ImageIO.read(imgFiles[imgIndex]);
            BufferedImage fImg = readImage(f);
            if (fImg == null) continue;

            g.drawImage(fImg, 0, 0, width, height, null);
            fImg.flush();
            qtOut.writeFrame(1, imgBuffer, vsDuration);
          }
        }
      }
      if (streaming.equals("fastStart")) {
        qtOut.toWebOptimizedMovie(movieFile, false);
        tmpFile.delete();
      } else if (streaming.equals("fastStartCompressed")) {
        qtOut.toWebOptimizedMovie(movieFile, true);
        tmpFile.delete();
      }
      qtOut.close();
      qtOut = null;
    } catch (UnsupportedAudioFileException e) {
      IOException ioe = new IOException(e.getMessage());
      ioe.initCause(e);
      throw ioe;
    } finally {
      p.close();
      if (qtOut != null) {
        qtOut.close();
      }
      if (audioIn != null) {
        audioIn.close();
      }
      if (g != null) {
        g.dispose();
      }
      if (imgBuffer != null) {
        imgBuffer.flush();
      }
    }
  }

  /**
   * Targa image loader for RLE-compressed TGA files.
   * Code taken from PApplet, any changes here should lead to updates there.
   */
  static private BufferedImage loadImageTGA(File file) throws IOException {
    InputStream is = new FileInputStream(file);

    try {
      byte header[] = new byte[18];
      int offset = 0;
      do {
        int count = is.read(header, offset, header.length - offset);
        if (count == -1) return null;
        offset += count;
      } while (offset < 18);

    /*
      header[2] image type code
      2  (0x02) - Uncompressed, RGB images.
      3  (0x03) - Uncompressed, black and white images.
      10 (0x0A) - Run-length encoded RGB images.
      11 (0x0B) - Compressed, black and white images. (grayscale?)

      header[16] is the bit depth (8, 24, 32)

      header[17] image descriptor (packed bits)
      0x20 is 32 = origin upper-left
      0x28 is 32 + 8 = origin upper-left + 32 bits

        7  6  5  4  3  2  1  0
      128 64 32 16  8  4  2  1
    */

      int format = 0;
      final int RGB = 1;
      final int ARGB = 2;
      final int ALPHA = 4;

      if (((header[2] == 3) || (header[2] == 11)) &&  // B&W, plus RLE or not
          (header[16] == 8) &&  // 8 bits
          ((header[17] == 0x8) || (header[17] == 0x28))) {  // origin, 32 bit
        format = ALPHA;

      } else if (((header[2] == 2) || (header[2] == 10)) &&  // RGB, RLE or not
          (header[16] == 24) &&  // 24 bits
          ((header[17] == 0x20) || (header[17] == 0))) {  // origin
        format = RGB;

      } else if (((header[2] == 2) || (header[2] == 10)) &&
          (header[16] == 32) &&
          ((header[17] == 0x8) || (header[17] == 0x28))) {  // origin, 32
        format = ARGB;
      }

      if (format == 0) {
        throw new IOException(Language.interpolate("movie_maker.error.unknown_tga_format", file.getName()));
      }

      int w = ((header[13] & 0xff) << 8) + (header[12] & 0xff);
      int h = ((header[15] & 0xff) << 8) + (header[14] & 0xff);
      //PImage outgoing = createImage(w, h, format);
      int[] pixels = new int[w * h];

      // where "reversed" means upper-left corner (normal for most of
      // the modernized world, but "reversed" for the tga spec)
      //boolean reversed = (header[17] & 0x20) != 0;
      // https://github.com/processing/processing/issues/1682
      boolean reversed = (header[17] & 0x20) == 0;

      if ((header[2] == 2) || (header[2] == 3)) {  // not RLE encoded
        if (reversed) {
          int index = (h-1) * w;
          switch (format) {
          case ALPHA:
            for (int y = h-1; y >= 0; y--) {
              for (int x = 0; x < w; x++) {
                pixels[index + x] = is.read();
              }
              index -= w;
            }
            break;
          case RGB:
            for (int y = h-1; y >= 0; y--) {
              for (int x = 0; x < w; x++) {
                pixels[index + x] =
                    is.read() | (is.read() << 8) | (is.read() << 16) |
                    0xff000000;
              }
              index -= w;
            }
            break;
          case ARGB:
            for (int y = h-1; y >= 0; y--) {
              for (int x = 0; x < w; x++) {
                pixels[index + x] =
                    is.read() | (is.read() << 8) | (is.read() << 16) |
                    (is.read() << 24);
              }
              index -= w;
            }
          }
        } else {  // not reversed
          int count = w * h;
          switch (format) {
          case ALPHA:
            for (int i = 0; i < count; i++) {
              pixels[i] = is.read();
            }
            break;
          case RGB:
            for (int i = 0; i < count; i++) {
              pixels[i] =
                  is.read() | (is.read() << 8) | (is.read() << 16) |
                  0xff000000;
            }
            break;
          case ARGB:
            for (int i = 0; i < count; i++) {
              pixels[i] =
                  is.read() | (is.read() << 8) | (is.read() << 16) |
                  (is.read() << 24);
            }
            break;
          }
        }

      } else {  // header[2] is 10 or 11
        int index = 0;

        while (index < pixels.length) {
          int num = is.read();
          boolean isRLE = (num & 0x80) != 0;
          if (isRLE) {
            num -= 127;  // (num & 0x7F) + 1
            int pixel = 0;
            switch (format) {
            case ALPHA:
              pixel = is.read();
              break;
            case RGB:
              pixel = 0xFF000000 |
                is.read() | (is.read() << 8) | (is.read() << 16);
              break;
            case ARGB:
              pixel = is.read() |
                (is.read() << 8) | (is.read() << 16) | (is.read() << 24);
              break;
            }
            for (int i = 0; i < num; i++) {
              pixels[index++] = pixel;
              if (index == pixels.length) break;
            }
          } else {  // write up to 127 bytes as uncompressed
            num += 1;
            switch (format) {
            case ALPHA:
              for (int i = 0; i < num; i++) {
                pixels[index++] = is.read();
              }
              break;
            case RGB:
              for (int i = 0; i < num; i++) {
                pixels[index++] = 0xFF000000 |
                  is.read() | (is.read() << 8) | (is.read() << 16);
              }
              break;
            case ARGB:
              for (int i = 0; i < num; i++) {
                pixels[index++] = is.read() |
                  (is.read() << 8) | (is.read() << 16) | (is.read() << 24);
              }
              break;
            }
          }
        }

        if (!reversed) {
          int[] temp = new int[w];
          for (int y = 0; y < h/2; y++) {
            int z = (h-1) - y;
            System.arraycopy(pixels, y*w, temp, 0, w);
            System.arraycopy(pixels, z*w, pixels, y*w, w);
            System.arraycopy(temp, 0, pixels, z*w, w);
          }
        }
      }
      //is.close();
      int type = (format == RGB) ?
        BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
      BufferedImage image = new BufferedImage(w, h, type);
      WritableRaster wr = image.getRaster();
      wr.setDataElements(0, 0, w, h, pixels);
      return image;

    } finally {
      is.close();
    }
  }

  /**
   * @param args the command line arguments
   */
  public static void main(String args[]) {
    java.awt.EventQueue.invokeLater(new Runnable() {
      public void run() {
        MovieMaker m = new MovieMaker();
        m.init(null);
//        m.init();
        m.setVisible(true);
//        m.pack();
      }
    });
  }

  private JLabel aboutLabel;
  private JButton chooseImageFolderButton;
  private JButton chooseSoundFileButton;
  private JComboBox<String> compressionBox;
  private JLabel compressionLabel;
//  private JRadioButton fastStartCompressedRadio;
//  private JRadioButton fastStartRadio;
  private JTextField fpsField;
  private JLabel fpsLabel;
  private JTextField heightField;
  private JLabel heightLabel;
  private JTextField imageFolderField;
  private JLabel imageFolderHelpLabel;
//  private JRadioButton noPreparationRadio;
  private JCheckBox originalSizeCheckBox;
  private JTextField soundFileField;
  private JLabel soundFileHelpLabel;
//  private ButtonGroup streamingGroup;
//  private JLabel streamingLabel;
  private JTextField widthField;
  private JLabel widthLabel;
//  private JLabel copyrightLabel;
  private JButton createMovieButton;
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/io/examples/SimpleInput/SimpleInput.pde
import processing.io.*;

// GPIO numbers refer to different phyiscal pins on various boards
// On the Raspberry Pi GPIO 4 is physical pin 7 on the header
// see setup.png in the sketch folder for wiring details

void setup() {
  // INPUT_PULLUP enables the built-in pull-up resistor for this pin
  // left alone, the pin will read as HIGH
  // connected to ground (via e.g. a button or switch) it will read LOW
  GPIO.pinMode(4, GPIO.INPUT_PULLUP);
}

void draw() {
  if (GPIO.digitalRead(4) == GPIO.LOW) {
    // button is pressed
    fill(255);
  } else {
    // button is not pressed
    fill(204);
  }
  stroke(255);
  ellipse(width/2, height/2, width*0.75, height*0.75);
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/src/processing/mode/java/pdex/JavaProblem.java
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
Part of the Processing project - http://processing.org
Copyright (c) 2012-15 The Processing Foundation

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package processing.mode.java.pdex;

import org.eclipse.jdt.core.compiler.IProblem;

import processing.app.Problem;

/**
 * Wrapper class for IProblem that stores the tabIndex and line number
 * according to its tab, including the original IProblem object
 */
public class JavaProblem implements Problem {
  /**
   * The tab number to which the error belongs to
   */
  private int tabIndex;
  /**
   * Line number(pde code) of the error
   */
  private int lineNumber;

  private int startOffset;

  private int stopOffset;

  /**
   * Error Message. Processed form of IProblem.getMessage()
   */
  private String message;

  /**
   * The type of error - WARNING or ERROR.
   */
  private int type;

  /**
   * If the error is a 'cannot find type' contains the list of suggested imports
   */
  private String[] importSuggestions;

  public static final int ERROR = 1, WARNING = 2;

  public JavaProblem(String message, int type, int tabIndex, int lineNumber) {
    this.message = message;
    this.type = type;
    this.tabIndex = tabIndex;
    this.lineNumber = lineNumber;
  }

  /**
   *
   * @param iProblem - The IProblem which is being wrapped
   * @param tabIndex - The tab number to which the error belongs to
   * @param lineNumber - Line number(pde code) of the error
   * @param badCode - The code iProblem refers to.
   */
  public static JavaProblem fromIProblem(IProblem iProblem,
      int tabIndex, int lineNumber, String badCode) {
    int type = 0;
    if(iProblem.isError()) {
      type = ERROR;
    } else if (iProblem.isWarning()) {
      type = WARNING;
    }
    String message = ErrorMessageSimplifier.getSimplifiedErrorMessage(iProblem, badCode);
    return new JavaProblem(message, type, tabIndex, lineNumber);
  }

  public void setPDEOffsets(int startOffset, int stopOffset){
    this.startOffset = startOffset;
    this.stopOffset = stopOffset;
  }

  @Override
  public int getStartOffset() {
    return startOffset;
  }

  @Override
  public int getStopOffset() {
    return stopOffset;
  }

  @Override
  public boolean isError() {
    return type == ERROR;
  }

  @Override
  public boolean isWarning() {
    return type == WARNING;
  }

  @Override
  public String getMessage() {
    return message;
  }

  @Override
  public int getTabIndex() {
    return tabIndex;
  }

  @Override
  public int getLineNumber() {
    return lineNumber;
  }

  public String[] getImportSuggestions() {
    return importSuggestions;
  }

  public void setImportSuggestions(String[] a) {
    importSuggestions = a;
  }

  @Override
  public String toString() {
    return "TAB " + tabIndex + ",LN " + lineNumber + "LN START OFF: "
        + startOffset + ",LN STOP OFF: " + stopOffset + ",PROB: "
        + message;
  }

}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Demos/Tests/MultipleWindows/MultipleWindows.pde
// Based on code by GeneKao (https://github.com/GeneKao)

ChildApplet child;
boolean mousePressedOnParent = false;
Arcball arcball, arcball2;

void settings() {
  size(320, 240, P3D);
  smooth();
}

void setup() {
  surface.setTitle("Main sketch");
  arcball = new Arcball(this, 300);
  child = new ChildApplet();
}

void draw() {
  background(250);
  arcball.run();
  if (mousePressed) {
    fill(0);
    text("Mouse pressed on parent.", 10, 10);
    fill(0, 240, 0);
    ellipse(mouseX, mouseY, 60, 60);
    mousePressedOnParent = true;
  } else {
    fill(20);
    ellipse(width/2, height/2, 60, 60);
    mousePressedOnParent = false;
  }
  box(100);
  if (child.mousePressed) {
    text("Mouse pressed on child.", 10, 30);
  }
}

void mousePressed() {
  arcball.mousePressed();
}

void mouseDragged() {
  arcball.mouseDragged();
}

class ChildApplet extends PApplet {
  //JFrame frame;

  public ChildApplet() {
    super();
    PApplet.runSketch(new String[]{this.getClass().getName()}, this);
  }

  public void settings() {
    size(400, 400, P3D);
    smooth();
  }
  public void setup() {
    surface.setTitle("Child sketch");
    arcball2 = new Arcball(this, 300);
  }

  public void draw() {
    background(0);
    arcball2.run();
    if (mousePressed) {
      fill(240, 0, 0);
      ellipse(mouseX, mouseY, 20, 20);
      fill(255);
      text("Mouse pressed on child.", 10, 30);
    } else {
      fill(255);
      ellipse(width/2, height/2, 20, 20);
    }

    box(100, 200, 100);
    if (mousePressedOnParent) {
      fill(255);
      text("Mouse pressed on parent", 20, 20);
    }
  }

  public void mousePressed() {
    arcball2.mousePressed();
  }

  public void mouseDragged() {
    arcball2.mouseDragged();
  }
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Image/Alphamask/Alphamask.pde
/**
 * Alpha Mask.
 *
 * Loads a "mask" for an image to specify the transparency
 * in different parts of the image. The two images are blended
 * together using the mask() method of PImage.
 */

PImage img;
PImage imgMask;

void setup() {
  size(640, 360);
  img = loadImage("moonwalk.jpg");
  imgMask = loadImage("mask.jpg");
  img.mask(imgMask);
  imageMode(CENTER);
}

void draw() {
  background(0, 102, 153);
  image(img, width/2, height/2);
  image(img, mouseX, mouseY);
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/src/processing/mode/java/pdex/ASTUtils.java
package processing.mode.java.pdex;

import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.IBinding;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.NodeFinder;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.Type;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;

import processing.app.Messages;

public class ASTUtils {

  public static ASTNode getASTNodeAt(ASTNode root, int startJavaOffset, int stopJavaOffset) {
    Messages.log("* getASTNodeAt");

    int length = stopJavaOffset - startJavaOffset;

    NodeFinder f = new NodeFinder(root, startJavaOffset, length);
    ASTNode node = f.getCoveredNode();
    if (node == null) {
      node = f.getCoveringNode();
    }
    if (node == null) {
      Messages.log("no node found");
    } else {
      Messages.log("found " + node.getClass().getSimpleName());
    }
    return node;
  }

  public static SimpleName getSimpleNameAt(ASTNode root, int startJavaOffset, int stopJavaOffset) {
    Messages.log("* getSimpleNameAt");

    // Find node at offset
    ASTNode node = getASTNodeAt(root, startJavaOffset, stopJavaOffset);

    SimpleName result = null;

    if (node == null) {
      result = null;
    } else if (node.getNodeType() == ASTNode.SIMPLE_NAME) {
      result = (SimpleName) node;
    } else {
      // Return SimpleName with highest coverage
      List<SimpleName> simpleNames = getSimpleNameChildren(node);
      if (!simpleNames.isEmpty()) {
        // Compute coverage <selection x node>
        int[] coverages = simpleNames.stream()
            .mapToInt(name -> {
              int start = name.getStartPosition();
              int stop = start + name.getLength();
              return Math.min(stop, stopJavaOffset) -
                  Math.max(startJavaOffset, start);
            })
            .toArray();
        // Select node with highest coverage
        int maxIndex = IntStream.range(0, simpleNames.size())
            .filter(i -> coverages[i] >= 0)
            .reduce((i, j) -> coverages[i] > coverages[j] ? i : j)
            .orElse(-1);
        if (maxIndex == -1) return null;
        result = simpleNames.get(maxIndex);
      }
    }

    if (result == null) {
      Messages.log("no simple name found");
    } else {
      Messages.log("found " + node.toString());
    }
    return result;
  }

  public static List<SimpleName> getSimpleNameChildren(ASTNode node) {
    List<SimpleName> simpleNames = new ArrayList<>();
    node.accept(new ASTVisitor() {
      @Override
      public boolean visit(SimpleName simpleName) {
        simpleNames.add(simpleName);
        return super.visit(simpleName);
      }
    });
    return simpleNames;
  }

  public static IBinding resolveBinding(SimpleName node) {
    IBinding binding = node.resolveBinding();
    if (binding == null) return null;

    // Fix constructor call/declaration being resolved as type
    if (binding.getKind() == IBinding.TYPE) {
      ASTNode context = node;

      // Go up until we find non Name or Type node
      // stop if context is type argument (parent is also Name/Type, but unrelated)
      while (isNameOrType(context) &&
          !context.getLocationInParent().getId().equals("typeArguments")) {
        context = context.getParent();
      }

      switch (context.getNodeType()) {
        case ASTNode.METHOD_DECLARATION:
          MethodDeclaration decl = (MethodDeclaration) context;
          if (decl.isConstructor()) {
            binding = decl.resolveBinding();
          }
          break;
        case ASTNode.CLASS_INSTANCE_CREATION:
          ClassInstanceCreation cic = (ClassInstanceCreation) context;
          binding = cic.resolveConstructorBinding();
          break;
      }
    }

    if (binding == null) return null;

    // Normalize parametrized and raw bindings into generic bindings
    switch (binding.getKind()) {
      case IBinding.TYPE:
        ITypeBinding type = (ITypeBinding) binding;
        if (type.isParameterizedType() || type.isRawType()) {
          binding = type.getErasure();
        }
        break;
      case IBinding.METHOD:
        IMethodBinding method = (IMethodBinding) binding;
        ITypeBinding declaringClass = method.getDeclaringClass();
        if (declaringClass.isParameterizedType() ||
            declaringClass.isRawType()) {
          IMethodBinding[] methods = declaringClass.getErasure().getDeclaredMethods();
          IMethodBinding generic = Arrays.stream(methods)
              .filter(method::overrides)
              .findAny().orElse(null);
          if (generic != null) method = generic;
        }
        if (method.isParameterizedMethod() || method.isRawMethod()) {
          method = method.getMethodDeclaration();
        }
        binding = method;
        break;
    }

    return binding;
  }

  public static boolean isNameOrType(ASTNode node) {
    return node instanceof Name || node instanceof Type;
  }

  protected static List<SimpleName> findAllOccurrences(ASTNode root, String bindingKey) {
    List<SimpleName> occurences = new ArrayList<>();
    root.getRoot().accept(new ASTVisitor() {
      @Override
      public boolean visit(SimpleName name) {
        IBinding binding = resolveBinding(name);
        if (binding != null && bindingKey.equals(binding.getKey())) {
          occurences.add(name);
        }
        return super.visit(name);
      }
    });

    return occurences;
  }

}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/src/processing/mode/java/pdex/CompletionGenerator.java
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
Part of the Processing project - http://processing.org
Copyright (c) 2012-15 The Processing Foundation

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package processing.mode.java.pdex;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.regex.Pattern;
import java.util.stream.Stream;

import javax.swing.DefaultListModel;

import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.ArrayAccess;
import org.eclipse.jdt.core.dom.ArrayType;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.ExpressionStatement;
import org.eclipse.jdt.core.dom.FieldAccess;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.ParameterizedType;
import org.eclipse.jdt.core.dom.PrimitiveType;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SimpleType;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclarationExpression;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.core.dom.VariableDeclarationStatement;

import processing.app.Messages;
import processing.mode.java.JavaMode;

import com.google.classpath.ClassPath;
import com.google.classpath.RegExpResourceFilter;

@SuppressWarnings({ "unchecked" })
public class CompletionGenerator {

  public CompletionGenerator() {
    //addCompletionPopupListner();
    //loadJavaDoc();
  }

  public static CompletionCandidate[] checkForTypes(ASTNode node) {

    List<VariableDeclarationFragment> vdfs = null;
    switch (node.getNodeType()) {
    case ASTNode.TYPE_DECLARATION:
      return new CompletionCandidate[]{new CompletionCandidate((TypeDeclaration) node)};

    case ASTNode.METHOD_DECLARATION:
      MethodDeclaration md = (MethodDeclaration) node;
      log(getNodeAsString(md));
      List<ASTNode> params = (List<ASTNode>) md
          .getStructuralProperty(MethodDeclaration.PARAMETERS_PROPERTY);
      CompletionCandidate[] cand = new CompletionCandidate[params.size() + 1];
      cand[0] = new CompletionCandidate(md);
      for (int i = 0; i < params.size(); i++) {
//        cand[i + 1] = new CompletionCandidate(params.get(i).toString(), "", "",
//                                              CompletionCandidate.LOCAL_VAR);
        cand[i + 1] = new CompletionCandidate((SingleVariableDeclaration) params.get(i));
      }
      return cand;

    case ASTNode.SINGLE_VARIABLE_DECLARATION:
      return new CompletionCandidate[]{new CompletionCandidate((SingleVariableDeclaration) node)};

    case ASTNode.FIELD_DECLARATION:
      vdfs = ((FieldDeclaration) node).fragments();
      break;
    case ASTNode.VARIABLE_DECLARATION_STATEMENT:
      vdfs = ((VariableDeclarationStatement) node).fragments();
      break;
    case ASTNode.VARIABLE_DECLARATION_EXPRESSION:
      vdfs = ((VariableDeclarationExpression) node).fragments();
      break;
    default:
      break;
    }

    if (vdfs != null) {
      CompletionCandidate ret[] = new CompletionCandidate[vdfs.size()];
      int i = 0;
      for (VariableDeclarationFragment vdf : vdfs) {
//        ret[i++] = new CompletionCandidate(getNodeAsString2(vdf), "", "",
//                                           CompletionCandidate.LOCAL_VAR);
        ret[i++] = new CompletionCandidate(vdf);
      }
      return ret;
    }

    return null;
  }

  /**
   * Find the parent of the expression in a().b, this would give me the return
   * type of a(), so that we can find all children of a() begininng with b
   *
   * @param nearestNode
   * @param expression
   * @return
   */
  public static ASTNode resolveExpression(ASTNode nearestNode,
                                          ASTNode expression, boolean noCompare) {
    log("Resolving " + getNodeAsString(expression) + " noComp "
        + noCompare);
    if (expression instanceof SimpleName) {
      return findDeclaration2(((SimpleName) expression), nearestNode);
    } else if (expression instanceof MethodInvocation) {
      log("3. Method Invo "
          + ((MethodInvocation) expression).getName());
      return findDeclaration2(((MethodInvocation) expression).getName(),
                              nearestNode);
    } else if (expression instanceof FieldAccess) {
      log("2. Field access "
          + getNodeAsString(((FieldAccess) expression).getExpression()) + "|||"
          + getNodeAsString(((FieldAccess) expression).getName()));
      if (noCompare) {
        /*
         * ASTNode ret = findDeclaration2(((FieldAccess) expression).getName(),
         * nearestNode); log("Found as ->"+getNodeAsString(ret));
         * return ret;
         */
        return findDeclaration2(((FieldAccess) expression).getName(),
                                nearestNode);
      } else {

        /*
         * Note how for the next recursion, noCompare is reversed. Let's say
         * I've typed getABC().quark.nin where nin is incomplete(ninja being the
         * field), when execution first enters here, it calls resolveExpr again
         * for "getABC().quark" where we know that quark field must be complete,
         * so we toggle noCompare. And kaboom.
         */
        return resolveExpression(nearestNode,
                                 ((FieldAccess) expression).getExpression(),
                                 true);
      }
      //return findDeclaration2(((FieldAccess) expression).getExpression(), nearestNode);
    } else if (expression instanceof QualifiedName) {
      log("1. Resolving "
          + ((QualifiedName) expression).getQualifier() + " ||| "
          + ((QualifiedName) expression).getName());
      if (noCompare) { // no compare, as in "abc.hello." need to resolve hello here
        return findDeclaration2(((QualifiedName) expression).getName(),
                                nearestNode);
      } else {
        //User typed "abc.hello.by" (bye being complete), so need to resolve "abc.hello." only
        return findDeclaration2(((QualifiedName) expression).getQualifier(),
                          nearestNode);
      }
    }

    return null;
  }

  /**
   * Finds the type of the expression in foo.bar().a().b, this would give me the
   * type of b if it exists in return type of a(). If noCompare is true,
   * it'll return type of a()
   * @param nearestNode
   * @param astNode
   * @return
   */
  public static ClassMember resolveExpression3rdParty(PreprocessedSketch ps, ASTNode nearestNode,
                                                      ASTNode astNode, boolean noCompare) {
    log("Resolve 3rdParty expr-- " + getNodeAsString(astNode)
        + " nearest node " + getNodeAsString(nearestNode));
    if(astNode == null) return null;
    ClassMember scopeParent;
    SimpleType stp;
    if(astNode instanceof SimpleName){
      ASTNode decl = findDeclaration2(((SimpleName)astNode),nearestNode);
      if(decl != null){
        // see if locally defined
        log(getNodeAsString(astNode)+" found decl -> " + getNodeAsString(decl));

        {
          if (decl.getNodeType() == ASTNode.TYPE_DECLARATION) {
            TypeDeclaration td = (TypeDeclaration) decl;
            return new ClassMember(ps, td);
          }
        }

        { // Handle "array." x "array[1]."
          Type type = extracTypeInfo2(decl);
          if (type != null && type.isArrayType() &&
              astNode.getParent().getNodeType() != ASTNode.ARRAY_ACCESS) {
            // No array access, we want members of the array itself
            Type elementType = ((ArrayType) type).getElementType();

            // Get name of the element class
            String name = "";
            if (elementType.isSimpleType()) {
              Class<?> c = findClassIfExists(ps, elementType.toString());
              if (c != null) name = c.getName();
            } else if (elementType.isPrimitiveType()) {
              name = ((PrimitiveType) elementType).getPrimitiveTypeCode().toString();
            }

            // Convert element class to array class
            Class<?> arrayClass = getArrayClass(name, ps.classLoader);

            return arrayClass == null ? null : new ClassMember(arrayClass);
          }
        }

        return new ClassMember(ps, extracTypeInfo(decl));
      }
      else {
        // or in a predefined class?
        Class<?> tehClass = findClassIfExists(ps, astNode.toString());
        if (tehClass != null) {
          return new ClassMember(tehClass);
        }
      }
      astNode = astNode.getParent();
    }
    switch (astNode.getNodeType()) {
    //TODO: Notice the redundancy in the 3 cases, you can simplify things even more.
    case ASTNode.FIELD_ACCESS:
      FieldAccess fa = (FieldAccess) astNode;
      if (fa.getExpression() == null) {

        // TODO: Check for existence of 'new' keyword. Could be a ClassInstanceCreation

        // Local code or belongs to super class
        log("FA,Not implemented.");
        return null;
      } else {
        if (fa.getExpression() instanceof SimpleName) {
          stp = extracTypeInfo(findDeclaration2((SimpleName) fa.getExpression(),
                                                nearestNode));
          if(stp == null){
            /*The type wasn't found in local code, so it might be something like
             * log(), or maybe belonging to super class, etc.
             */
            Class<?> tehClass = findClassIfExists(ps, fa.getExpression().toString());
            if (tehClass != null) {
              // Method Expression is a simple name and wasn't located locally, but found in a class
              // so look for method in this class.
              return definedIn3rdPartyClass(ps, new ClassMember(tehClass), fa
                  .getName().toString());
            }
            log("FA resolve 3rd par, Can't resolve " + fa.getExpression());

            return null;
          }
          log("FA, SN Type " + getNodeAsString(stp));
          scopeParent = definedIn3rdPartyClass(ps, stp.getName().toString(), "THIS");

        } else {
          scopeParent = resolveExpression3rdParty(ps, nearestNode,
                                                  fa.getExpression(), noCompare);
        }
        log("FA, ScopeParent " + scopeParent);
        return definedIn3rdPartyClass(ps, scopeParent, fa.getName().toString());
      }
    case ASTNode.METHOD_INVOCATION:
      MethodInvocation mi = (MethodInvocation) astNode;
      ASTNode temp = findDeclaration2(mi.getName(), nearestNode);
      if(temp instanceof MethodDeclaration){
        // method is locally defined
        log(mi.getName() + " was found locally," + getNodeAsString(extracTypeInfo(temp)));

        { // Handle "array." x "array[1]."
          Type type = extracTypeInfo2(temp);
          if (type != null && type.isArrayType() &&
              astNode.getParent().getNodeType() != ASTNode.ARRAY_ACCESS) {
            // No array access, we want members of the array itself
            Type elementType = ((ArrayType) type).getElementType();

            // Get name of the element class
            String name = "";
            if (elementType.isSimpleType()) {
              Class<?> c = findClassIfExists(ps, elementType.toString());
              if (c != null) name = c.getName();
            } else if (elementType.isPrimitiveType()) {
              name = ((PrimitiveType) elementType).getPrimitiveTypeCode().toString();
            }

            // Convert element class to array class
            Class<?> arrayClass = getArrayClass(name, ps.classLoader);

            return arrayClass == null ? null : new ClassMember(arrayClass);
          }
        }

        return new ClassMember(ps, extracTypeInfo(temp));
      }
      if (mi.getExpression() == null) {
//        if()
        //Local code or belongs to super class
        log("MI,Not implemented.");
        return null;
      } else {
        if (mi.getExpression() instanceof SimpleName) {
          ASTNode decl = findDeclaration2((SimpleName) mi.getExpression(),
                                          nearestNode);
          if (decl != null) {
            if (decl.getNodeType() == ASTNode.TYPE_DECLARATION) {
              TypeDeclaration td = (TypeDeclaration) decl;
              return new ClassMember(ps, td);
            }

            stp = extracTypeInfo(decl);
            if(stp == null){
            /*The type wasn't found in local code, so it might be something like
             * System.console()., or maybe belonging to super class, etc.
             */
              Class<?> tehClass = findClassIfExists(ps, mi.getExpression().toString());
              if (tehClass != null) {
                // Method Expression is a simple name and wasn't located locally, but found in a class
                // so look for method in this class.
                return definedIn3rdPartyClass(ps, new ClassMember(tehClass), mi
                    .getName().toString());
              }
              log("MI resolve 3rd par, Can't resolve " + mi.getExpression());
              return null;
            }
            log("MI, SN Type " + getNodeAsString(stp));
            ASTNode typeDec = findDeclaration2(stp.getName(),nearestNode);
            if(typeDec == null){
              log(stp.getName() + " couldn't be found locally..");
              Class<?> tehClass = findClassIfExists(ps, stp.getName().toString());
              if (tehClass != null) {
                // Method Expression is a simple name and wasn't located locally, but found in a class
                // so look for method in this class.
                return definedIn3rdPartyClass(ps, new ClassMember(tehClass), mi
                    .getName().toString());
              }
              //return new ClassMember(findClassIfExists(stp.getName().toString()));
            }
            //scopeParent = definedIn3rdPartyClass(stp.getName().toString(), "THIS");
            return definedIn3rdPartyClass(ps, new ClassMember(ps, typeDec), mi
                .getName().toString());
          }
        } else {
          log("MI EXP.."+getNodeAsString(mi.getExpression()));
//          return null;
          scopeParent = resolveExpression3rdParty(ps, nearestNode,
                                                  mi.getExpression(), noCompare);
          log("MI, ScopeParent " + scopeParent);
          return definedIn3rdPartyClass(ps, scopeParent, mi.getName().toString());
        }

      }
      break;
    case ASTNode.QUALIFIED_NAME:
      QualifiedName qn = (QualifiedName) astNode;
      ASTNode temp2 = findDeclaration2(qn.getName(), nearestNode);
      if(temp2 instanceof FieldDeclaration){
        // field is locally defined
        log(qn.getName() + " was found locally," + getNodeAsString(extracTypeInfo(temp2)));
        return new ClassMember(ps, extracTypeInfo(temp2));
      }
      if (qn.getQualifier() == null) {
        log("QN,Not implemented.");
        return null;
      } else  {

        if (qn.getQualifier() instanceof SimpleName) {
          stp = extracTypeInfo(findDeclaration2(qn.getQualifier(), nearestNode));
          if(stp == null){
            /*The type wasn't found in local code, so it might be something like
             * log(), or maybe belonging to super class, etc.
             */
            Class<?> tehClass = findClassIfExists(ps, qn.getQualifier().toString());
            if (tehClass != null) {
              // note how similar thing is called on line 690. Check check.
              return definedIn3rdPartyClass(ps, new ClassMember(tehClass), qn
                  .getName().toString());
            }
            log("QN resolve 3rd par, Can't resolve " + qn.getQualifier());
            return null;
          }
          log("QN, SN Local Type " + getNodeAsString(stp));
          //scopeParent = definedIn3rdPartyClass(stp.getName().toString(), "THIS");
          ASTNode typeDec = findDeclaration2(stp.getName(),nearestNode);
          if(typeDec == null){
            log(stp.getName() + " couldn't be found locally..");

            Class<?> tehClass = findClassIfExists(ps, stp.getName().toString());
            if (tehClass != null) {
              // note how similar thing is called on line 690. Check check.
              return definedIn3rdPartyClass(ps, new ClassMember(tehClass), qn
                  .getName().toString());
            }
            log("QN resolve 3rd par, Can't resolve " + qn.getQualifier());
            return null;
          }
          return definedIn3rdPartyClass(ps, new ClassMember(ps, typeDec), qn
                                        .getName().toString());
        } else {
          scopeParent = resolveExpression3rdParty(ps, nearestNode,
                                                  qn.getQualifier(), noCompare);
          log("QN, ScopeParent " + scopeParent);
          return definedIn3rdPartyClass(ps, scopeParent, qn.getName().toString());
        }

      }
    case ASTNode.ARRAY_ACCESS:
      ArrayAccess arac = (ArrayAccess)astNode;
      return resolveExpression3rdParty(ps, nearestNode, arac.getArray(), noCompare);
    default:
      log("Unaccounted type " + getNodeAsString(astNode));
      break;
    }

    return null;
  }

  public static Class<?> getArrayClass(String elementClass, ClassLoader classLoader) {
    String name;
    if (elementClass.startsWith("[")) {
      // just add a leading "["
      name = "[" + elementClass;
    } else if (elementClass.equals("boolean")) {
      name = "[Z";
    } else if (elementClass.equals("byte")) {
      name = "[B";
    } else if (elementClass.equals("char")) {
      name = "[C";
    } else if (elementClass.equals("double")) {
      name = "[D";
    } else if (elementClass.equals("float")) {
      name = "[F";
    } else if (elementClass.equals("int")) {
      name = "[I";
    } else if (elementClass.equals("long")) {
      name = "[J";
    } else if (elementClass.equals("short")) {
      name = "[S";
    } else {
      // must be an object non-array class
      name = "[L" + elementClass + ";";
    }
    return loadClass(name, classLoader);
  }

  /**
   * For a().abc.a123 this would return a123
   *
   * @param expression
   * @return
   */
  public static ASTNode getChildExpression(ASTNode expression) {
//    ASTNode anode = null;
    if (expression instanceof SimpleName) {
      return expression;
    } else if (expression instanceof FieldAccess) {
      return ((FieldAccess) expression).getName();
    } else if (expression instanceof QualifiedName) {
      return ((QualifiedName) expression).getName();
    }else if (expression instanceof MethodInvocation) {
      return ((MethodInvocation) expression).getName();
    }else if(expression instanceof ArrayAccess){
      return ((ArrayAccess)expression).getArray();
    }
    log(" getChildExpression returning NULL for "
        + getNodeAsString(expression));
    return null;
  }

  public static ASTNode getParentExpression(ASTNode expression) {
//  ASTNode anode = null;
    if (expression instanceof SimpleName) {
      return expression;
    } else if (expression instanceof FieldAccess) {
      return ((FieldAccess) expression).getExpression();
    } else if (expression instanceof QualifiedName) {
      return ((QualifiedName) expression).getQualifier();
    } else if (expression instanceof MethodInvocation) {
      return ((MethodInvocation) expression).getExpression();
    } else if (expression instanceof ArrayAccess) {
      return ((ArrayAccess) expression).getArray();
    }
    log("getParentExpression returning NULL for "
        + getNodeAsString(expression));
    return null;
  }

  /**
   * Loads classes from .jar files in sketch classpath
   *
   * @param typeName
   * @param child
   * @param noCompare
   * @return
   */
  public static ArrayList<CompletionCandidate> getMembersForType(PreprocessedSketch ps,
                                                                 String typeName,
                                                                 String child,
                                                                 boolean noCompare,
                                                                 boolean staticOnly) {
    ArrayList<CompletionCandidate> candidates = new ArrayList<>();
    log("In GMFT(), Looking for match " + child
        + " in class " + typeName + " noCompare " + noCompare + " staticOnly "
        + staticOnly);
    Class<?> probableClass = findClassIfExists(ps, typeName);
    if(probableClass == null){
      log("In GMFT(), class not found.");
      return candidates;
    }
   return getMembersForType(ps, new ClassMember(probableClass), child, noCompare, staticOnly);

  }

  public static ArrayList<CompletionCandidate> getMembersForType(PreprocessedSketch ps,
                                                                 ClassMember tehClass,
                                                                 String childToLookFor,
                                                                 boolean noCompare,
                                                                 boolean staticOnly) {
    String child = childToLookFor.toLowerCase();
    ArrayList<CompletionCandidate> candidates = new ArrayList<>();
    log("getMemFoType-> Looking for match " + child
        + " inside " + tehClass + " noCompare " + noCompare + " staticOnly "
        + staticOnly);
    if(tehClass == null){
      return candidates;
    }
    // tehClass will either be a TypeDecl defined locally
    if(tehClass.getDeclaringNode() instanceof TypeDeclaration){
      TypeDeclaration td = (TypeDeclaration) tehClass.getDeclaringNode();
      {
        FieldDeclaration[] fields = td.getFields();
        for (FieldDeclaration field : fields) {
          if (staticOnly && !isStatic(field.modifiers())) {
            continue;
          }
          List<VariableDeclarationFragment> vdfs = field.fragments();
          for (VariableDeclarationFragment vdf : vdfs) {
            if (noCompare) {
              candidates.add(new CompletionCandidate(vdf));
            } else if (vdf.getName().toString().toLowerCase().startsWith(child))
              candidates.add(new CompletionCandidate(vdf));
          }
        }
      }
      {
        MethodDeclaration[] methods = td.getMethods();
        for (MethodDeclaration method : methods) {
          if (staticOnly && !isStatic(method.modifiers())) {
            continue;
          }
          if (noCompare) {
            candidates.add(new CompletionCandidate(method));
          } else if (method.getName().toString().toLowerCase()
              .startsWith(child))
            candidates.add(new CompletionCandidate(method));
        }
      }

      ArrayList<CompletionCandidate> superClassCandidates;
      if(td.getSuperclassType() != null){
        log(getNodeAsString(td.getSuperclassType()) + " <-Looking into superclass of " + tehClass);
        superClassCandidates = getMembersForType(ps, new ClassMember(ps, td
                                                     .getSuperclassType()),
                                                 childToLookFor, noCompare, staticOnly);
      }
      else
      {
        superClassCandidates = getMembersForType(ps, new ClassMember(Object.class),
                                                 childToLookFor, noCompare, staticOnly);
      }
      for (CompletionCandidate cc : superClassCandidates) {
        candidates.add(cc);
      }
      return candidates;
    }

    // Or tehClass will be a predefined class

    Class<?> probableClass;
    if (tehClass.getClass_() != null) {
      probableClass = tehClass.getClass_();
    } else {
      probableClass = findClassIfExists(ps, tehClass.getTypeAsString());
      if (probableClass == null) {
        log("Couldn't find class " + tehClass.getTypeAsString());
        return candidates;
      }
      log("Loaded " + probableClass.toString());
    }
    for (Method method : probableClass.getMethods()) {
      if (!Modifier.isStatic(method.getModifiers()) && staticOnly) {
        continue;
      }

      StringBuilder label = new StringBuilder(method.getName() + "(");
      for (int i = 0; i < method.getParameterTypes().length; i++) {
        label.append(method.getParameterTypes()[i].getSimpleName());
        if (i < method.getParameterTypes().length - 1)
          label.append(",");
      }
      label.append(")");
      if (noCompare) {
        candidates.add(new CompletionCandidate(method));
      } else if (label.toString().toLowerCase().startsWith(child)) {
        candidates.add(new CompletionCandidate(method));
      }
    }
    for (Field field : probableClass.getFields()) {
      if (!Modifier.isStatic(field.getModifiers()) && staticOnly) {
        continue;
      }
      if (noCompare) {
        candidates.add(new CompletionCandidate(field));
      } else if (field.getName().toLowerCase().startsWith(child)) {
        candidates.add(new CompletionCandidate(field));
      }
    }
    if (probableClass.isArray() && !staticOnly) {
      // add array members manually, they can't be fetched through code

      String className = probableClass.getSimpleName();

      if (noCompare || "clone()".startsWith(child)) {
        String methodLabel = "clone() : " + className +
            " - " + className + "";
        candidates.add(new CompletionCandidate("clone()", methodLabel, "clone()",
                                               CompletionCandidate.PREDEF_METHOD));
      }

      if ("length".startsWith(child)) {
        String fieldLabel = "length : int - " +
            className + "";
        candidates.add(new CompletionCandidate("length", fieldLabel, "length",
                                               CompletionCandidate.PREDEF_FIELD));
      }
    }
    return candidates;
  }

  private static boolean isStatic(List<org.eclipse.jdt.core.dom.Modifier> modifiers) {
    for (org.eclipse.jdt.core.dom.Modifier m : modifiers) {
      if (m.isStatic()) return true;
    }
    return false;
  }

  /**
   * Searches for the particular class in the default list of imports as well as
   * the Sketch classpath
   * @param className
   * @return
   */
  protected static Class<?> findClassIfExists(PreprocessedSketch ps, String className){
    if (className == null){
      return null;
    }

    if (className.indexOf('.') >= 0) {
      // Figure out what is package and what is class
      String[] parts = className.split("\\.");
      String newClassName = parts[0];
      int i = 1;
      while (i < parts.length &&
          ps.classPath.isPackage(newClassName)) {
        newClassName = newClassName + "/" + parts[i++];
      }
      while (i < parts.length) {
        newClassName = newClassName + "$" + parts[i++];
      }
      className = newClassName.replace('/', '.');
    }

    // First, see if the classname is a fully qualified name and loads straightaway
    Class<?> tehClass = loadClass(className, ps.classLoader);

    if (tehClass != null) {
      //log(tehClass.getName() + " located straightaway");
      return tehClass;
    }

    // This name is qualified and it already had its chance
    if (className.indexOf('.') >= 0) {
      return null;
    }

    log("Looking in the classloader for " + className);
    // Using ClassPath and RegExResourceFilter to find a matching class
    // and then loading the thing might be simpler and faster

    // These can be preprocessed during error check for performance
    // (collect, split into starred and not starred)
    List<ImportStatement> programImports = ps.programImports;
    List<ImportStatement> codeFolderImports = ps.codeFolderImports;
    List<ImportStatement> coreAndDefaultImports = ps.coreAndDefaultImports;

    ImportStatement javaLang = ImportStatement.wholePackage("java.lang");

    Stream<List<ImportStatement>> importListStream =
        Stream.of(Collections.singletonList(javaLang), coreAndDefaultImports,
                  programImports, codeFolderImports);

    final String finalClassName = className;

    // These streams can be made unordered parallel if it helps performance
    return importListStream
        .map(list -> list.stream()
            .map(is -> {
              if (is.getClassName().equals(finalClassName)) {
                return is.getFullClassName();
              } else if (is.isStarredImport()) {
                return is.getPackageName() + "." + finalClassName;
              }
              return null;
            })
            .filter(name -> name != null)
            .map(name -> loadClass(name, ps.classLoader))
            .filter(cls -> cls != null)
            .findAny())
        .filter(Optional::isPresent)
        .map(Optional::get)
        .findAny()
        .orElse(null);
  }

  protected static Class<?> loadClass(String className, ClassLoader classLoader){
    Class<?> tehClass = null;
    if (className != null) {
      try {
        tehClass = Class.forName(className, false, classLoader);
      } catch (ClassNotFoundException e) {
        //log("Doesn't exist in package: ");
      }
    }
    return tehClass;
  }

  public static ClassMember definedIn3rdPartyClass(PreprocessedSketch ps, String className,String memberName){
    Class<?> probableClass = findClassIfExists(ps, className);
    if (probableClass == null) {
      log("Couldn't load " + className);
      return null;
    }
    if (memberName.equals("THIS")) {
      return new ClassMember(probableClass);
    } else {
      return definedIn3rdPartyClass(ps, new ClassMember(probableClass), memberName);
    }
  }

  public static ClassMember definedIn3rdPartyClass(PreprocessedSketch ps, ClassMember tehClass,String memberName){
    if(tehClass == null)
      return null;
    log("definedIn3rdPartyClass-> Looking for " + memberName
        + " in " + tehClass);
    String memberNameL = memberName.toLowerCase();
    if (tehClass.getDeclaringNode() instanceof TypeDeclaration) {

      TypeDeclaration td = (TypeDeclaration) tehClass.getDeclaringNode();
      for (int i = 0; i < td.getFields().length; i++) {
        List<VariableDeclarationFragment> vdfs =
          td.getFields()[i].fragments();
        for (VariableDeclarationFragment vdf : vdfs) {
          if (vdf.getName().toString().toLowerCase()
              .startsWith(memberNameL))
            return new ClassMember(ps, vdf);
        }

      }
      for (int i = 0; i < td.getMethods().length; i++) {
       if (td.getMethods()[i].getName().toString().toLowerCase()
            .startsWith(memberNameL))
         return new ClassMember(ps, td.getMethods()[i]);
      }
      if (td.getSuperclassType() != null) {
        log(getNodeAsString(td.getSuperclassType()) + " <-Looking into superclass of " + tehClass);
        return definedIn3rdPartyClass(ps, new ClassMember(ps, td
                                                     .getSuperclassType()),memberName);
      } else {
        return definedIn3rdPartyClass(ps, new ClassMember(Object.class),memberName);
      }
    }

    Class<?> probableClass;
    if (tehClass.getClass_() != null) {
      probableClass = tehClass.getClass_();
    } else {
      probableClass = findClassIfExists(ps, tehClass.getTypeAsString());
      log("Loaded " + probableClass.toString());
    }
    for (Method method : probableClass.getMethods()) {
      if (method.getName().equalsIgnoreCase(memberName)) {
        return new ClassMember(method);
      }
    }
    for (Field field : probableClass.getFields()) {
      if (field.getName().equalsIgnoreCase(memberName)) {
        return new ClassMember(field);
      }
    }
    return null;
  }

  protected static ASTNode findClosestParentNode(int lineNumber, ASTNode node) {
    // Base.loge("Props of " + node.getClass().getName());
    for (StructuralPropertyDescriptor prop : (Iterable<StructuralPropertyDescriptor>) node
        .structuralPropertiesForType()) {
      if (prop.isChildProperty() || prop.isSimpleProperty()) {
        if (node.getStructuralProperty(prop) != null) {
//          System.out
//              .println(node.getStructuralProperty(prop) + " -> " + (prop));
          if (node.getStructuralProperty(prop) instanceof ASTNode) {
            ASTNode cnode = (ASTNode) node.getStructuralProperty(prop);
//            log("Looking at " + getNodeAsString(cnode)+ " for line num " + lineNumber);
            int cLineNum = ((CompilationUnit) cnode.getRoot())
                .getLineNumber(cnode.getStartPosition() + cnode.getLength());
            if (getLineNumber(cnode) <= lineNumber && lineNumber <= cLineNum) {
              return findClosestParentNode(lineNumber, cnode);
            }
          }
        }
      } else if (prop.isChildListProperty()) {
        List<ASTNode> nodelist = (List<ASTNode>) node
            .getStructuralProperty(prop);
        for (ASTNode cnode : nodelist) {
          int cLineNum = ((CompilationUnit) cnode.getRoot())
              .getLineNumber(cnode.getStartPosition() + cnode.getLength());
//          log("Looking at " + getNodeAsString(cnode)+ " for line num " + lineNumber);
          if (getLineNumber(cnode) <= lineNumber && lineNumber <= cLineNum) {
            return findClosestParentNode(lineNumber, cnode);
          }
        }
      }
    }
    return node;
  }

  protected static ASTNode findClosestNode(int lineNumber, ASTNode node) {
    log("findClosestNode to line " + lineNumber);
    ASTNode parent = findClosestParentNode(lineNumber, node);
    log("findClosestParentNode returned " + getNodeAsString(parent));
    if (parent == null)
      return null;
    if (getLineNumber(parent) == lineNumber){
      log(parent + "|PNode " + getLineNumber(parent) + ", lfor " + lineNumber );
      return parent;
    }
    List<ASTNode> nodes;
    if (parent instanceof TypeDeclaration) {
      nodes = ((TypeDeclaration) parent).bodyDeclarations();
    } else if (parent instanceof Block) {
      nodes = ((Block) parent).statements();
    } else {
      log("findClosestNode() found " + getNodeAsString(parent));
      return null;
    }

    if (nodes.size() > 0) {
      ASTNode retNode = parent;
      for (ASTNode cNode : nodes) {
        log(cNode + "|cNode " + getLineNumber(cNode) + ", lfor " + lineNumber);
        if (getLineNumber(cNode) <= lineNumber)
          retNode = cNode;
      }

      return retNode;
    }
    return parent;
  }

  /**
   * Fetches line number of the node in its CompilationUnit.
   * @param node
   * @return
   */
  public static int getLineNumber(ASTNode node) {
    return ((CompilationUnit) node.getRoot()).getLineNumber(node
        .getStartPosition());
  }

  /*
  protected SketchOutline sketchOutline;

  public void showSketchOutline() {
    if (editor.hasJavaTabs()) return;

    sketchOutline = new SketchOutline(editor, codeTree);
    sketchOutline.show();
  }

  public void showTabOutline() {
    new TabOutline(editor).show();
  }
  */

  /**
   * Give this thing a {@link Name} instance - a {@link SimpleName} from the
   * ASTNode for ex, and it tries its level best to locate its declaration in
   * the AST. It really does.
   *
   * @param findMe
   * @return
   */
  protected static ASTNode findDeclaration(Name findMe) {

    // WARNING: You're entering the Rube Goldberg territory of Experimental Mode.
    // To debug this code, thou must take the Recursive Leap of Faith.

    // log("entering --findDeclaration1 -- " + findMe.toString());
    ASTNode declaringClass;
    ASTNode parent = findMe.getParent();
    ASTNode ret;
    ArrayList<Integer> constrains = new ArrayList<>();
    if (parent.getNodeType() == ASTNode.METHOD_INVOCATION) {
      Expression exp = (Expression) parent.getStructuralProperty(MethodInvocation.EXPRESSION_PROPERTY);
      //TODO: Note the imbalance of constrains.add(ASTNode.METHOD_DECLARATION);
      // Possibly a bug here. Investigate later.
      if (((MethodInvocation) parent).getName().toString()
          .equals(findMe.toString())) {
        constrains.add(ASTNode.METHOD_DECLARATION);

        if (exp != null) {
          constrains.add(ASTNode.TYPE_DECLARATION);
//          log("MI EXP: " + exp.toString() + " of type "
//              + exp.getClass().getName() + " parent: " + exp.getParent());
          if (exp instanceof MethodInvocation) {
            SimpleType stp = extracTypeInfo(findDeclaration(((MethodInvocation) exp)
                .getName()));
            if (stp == null)
              return null;
            declaringClass = findDeclaration(stp.getName());
            return definedIn(declaringClass, ((MethodInvocation) parent)
                .getName().toString(), constrains);
          } else if (exp instanceof FieldAccess) {
            SimpleType stp = extracTypeInfo(findDeclaration(((FieldAccess) exp)
                .getName()));
            if (stp == null)
              return null;
            declaringClass = findDeclaration((stp.getName()));
            return definedIn(declaringClass, ((MethodInvocation) parent)
                .getName().toString(), constrains);
          }
          if (exp instanceof SimpleName) {
            SimpleType stp = extracTypeInfo(findDeclaration(((SimpleName) exp)));
            if (stp == null)
              return null;
            declaringClass = findDeclaration(stp.getName());
//            log("MI.SN " + getNodeAsString(declaringClass));
            constrains.add(ASTNode.METHOD_DECLARATION);
            return definedIn(declaringClass, ((MethodInvocation) parent)
                .getName().toString(), constrains);
          }

        }
      } else {
        parent = parent.getParent(); // Move one up the ast. V V IMP!!
      }
    } else if (parent.getNodeType() == ASTNode.FIELD_ACCESS) {
      FieldAccess fa = (FieldAccess) parent;
      Expression exp = fa.getExpression();
      if (fa.getName().toString().equals(findMe.toString())) {
        constrains.add(ASTNode.FIELD_DECLARATION);

        if (exp != null) {
          constrains.add(ASTNode.TYPE_DECLARATION);
//          log("FA EXP: " + exp.toString() + " of type "
//              + exp.getClass().getName() + " parent: " + exp.getParent());
          if (exp instanceof MethodInvocation) {
            SimpleType stp = extracTypeInfo(findDeclaration(((MethodInvocation) exp)
                .getName()));
            if (stp == null)
              return null;
            declaringClass = findDeclaration(stp.getName());
            return definedIn(declaringClass, fa.getName().toString(),
                             constrains);
          } else if (exp instanceof FieldAccess) {
            SimpleType stp = extracTypeInfo(findDeclaration(((FieldAccess) exp)
                .getName()));
            if (stp == null)
              return null;
            declaringClass = findDeclaration((stp.getName()));
            constrains.add(ASTNode.TYPE_DECLARATION);
            return definedIn(declaringClass, fa.getName().toString(),
                             constrains);
          }
          if (exp instanceof SimpleName) {
            SimpleType stp = extracTypeInfo(findDeclaration(((SimpleName) exp)));
            if (stp == null)
              return null;
            declaringClass = findDeclaration(stp.getName());
//            log("FA.SN " + getNodeAsString(declaringClass));
            constrains.add(ASTNode.METHOD_DECLARATION);
            return definedIn(declaringClass, fa.getName().toString(),
                             constrains);
          }
        }

      } else {
        parent = parent.getParent(); // Move one up the ast. V V IMP!!
      }
    } else if (parent.getNodeType() == ASTNode.QUALIFIED_NAME) {

      QualifiedName qn = (QualifiedName) parent;
      if (!findMe.toString().equals(qn.getQualifier().toString())) {

        SimpleType stp = extracTypeInfo(findDeclaration((qn.getQualifier())));
//        log(qn.getQualifier() + "->" + qn.getName());
        if (stp == null) {
          return null;
        }

        declaringClass = findDeclaration(stp.getName());

//        log("QN decl class: " + getNodeAsString(declaringClass));
        constrains.clear();
        constrains.add(ASTNode.TYPE_DECLARATION);
        constrains.add(ASTNode.FIELD_DECLARATION);
        return definedIn(declaringClass, qn.getName().toString(), constrains);
      }
      else{
        if(findMe instanceof QualifiedName){
          QualifiedName qnn = (QualifiedName) findMe;
//          log("findMe is a QN, "
//              + (qnn.getQualifier().toString() + " other " + qnn.getName()
//                  .toString()));

          SimpleType stp = extracTypeInfo(findDeclaration((qnn.getQualifier())));
          if (stp == null) {
            return null;
          }
          declaringClass = findDeclaration(stp.getName());
          constrains.clear();
          constrains.add(ASTNode.TYPE_DECLARATION);
          constrains.add(ASTNode.FIELD_DECLARATION);
          return definedIn(declaringClass, qnn.getName().toString(),
                           constrains);
        }
      }
    } else if (parent.getNodeType() == ASTNode.SIMPLE_TYPE) {
      constrains.add(ASTNode.TYPE_DECLARATION);
      if (parent.getParent().getNodeType() == ASTNode.CLASS_INSTANCE_CREATION) {
        constrains.add(ASTNode.CLASS_INSTANCE_CREATION);
      }
    } else if (parent.getNodeType() == ASTNode.TYPE_DECLARATION) {
      // The condition where we look up the name of a class decl
      TypeDeclaration td = (TypeDeclaration) parent;
      if (findMe.equals(td.getName())) {
        return parent;
      }

    } else if (parent instanceof Expression) {
//      constrains.add(ASTNode.TYPE_DECLARATION);
//      constrains.add(ASTNode.METHOD_DECLARATION);
//      constrains.add(ASTNode.FIELD_DECLARATION);
    }
//    else if(findMe instanceof QualifiedName){
//      QualifiedName qn = (QualifiedName) findMe;
//      System.out
//          .println("findMe is a QN, "
//              + (qn.getQualifier().toString() + " other " + qn.getName()
//                  .toString()));
//    }
    while (parent != null) {
//      log("findDeclaration1 -> " + getNodeAsString(parent));
      for (Object oprop : parent.structuralPropertiesForType()) {
        StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) oprop;
        if (prop.isChildProperty() || prop.isSimpleProperty()) {
          if (parent.getStructuralProperty(prop) instanceof ASTNode) {
//            log(prop + " C/S Prop of -> "
//                + getNodeAsString(parent));
            ret = definedIn((ASTNode) parent.getStructuralProperty(prop),
                            findMe.toString(), constrains);
            if (ret != null)
              return ret;
          }
        } else if (prop.isChildListProperty()) {
//          log((prop) + " ChildList props of "
//              + getNodeAsString(parent));
          List<ASTNode> nodelist = (List<ASTNode>) parent
              .getStructuralProperty(prop);
          for (ASTNode retNode : nodelist) {
            ret = definedIn(retNode, findMe.toString(), constrains);
            if (ret != null)
              return ret;
          }
        }
      }
      parent = parent.getParent();
    }
    return null;
  }

  /**
   * A variation of findDeclaration() but accepts an alternate parent ASTNode
   * @param findMe
   * @param alternateParent
   * @return
   */
  protected static ASTNode findDeclaration2(Name findMe, ASTNode alternateParent) {
    ASTNode declaringClass;
    ASTNode parent = findMe.getParent();
    ASTNode ret;
    ArrayList<Integer> constrains = new ArrayList<>();
    if (parent.getNodeType() == ASTNode.METHOD_INVOCATION) {
      Expression exp = (Expression) parent.getStructuralProperty(MethodInvocation.EXPRESSION_PROPERTY);
      //TODO: Note the imbalance of constrains.add(ASTNode.METHOD_DECLARATION);
      // Possibly a bug here. Investigate later.
      if (((MethodInvocation) parent).getName().toString()
          .equals(findMe.toString())) {
        constrains.add(ASTNode.METHOD_DECLARATION);

        if (exp != null) {
          constrains.add(ASTNode.TYPE_DECLARATION);
//          log("MI EXP: " + exp.toString() + " of type "
//              + exp.getClass().getName() + " parent: " + exp.getParent());
          if (exp instanceof MethodInvocation) {
            SimpleType stp = extracTypeInfo(findDeclaration2(((MethodInvocation) exp)
                                                                 .getName(),
                                                             alternateParent));
            if (stp == null)
              return null;
            declaringClass = findDeclaration2(stp.getName(), alternateParent);
            return definedIn(declaringClass, ((MethodInvocation) parent)
                .getName().toString(), constrains);
          } else if (exp instanceof FieldAccess) {
            SimpleType stp = extracTypeInfo(findDeclaration2(((FieldAccess) exp)
                                                                 .getName(),
                                                             alternateParent));
            if (stp == null)
              return null;
            declaringClass = findDeclaration2((stp.getName()), alternateParent);
            return definedIn(declaringClass, ((MethodInvocation) parent)
                .getName().toString(), constrains);
          }
          if (exp instanceof SimpleName) {
            SimpleType stp = extracTypeInfo(findDeclaration2(((SimpleName) exp),
                                                             alternateParent));
            if (stp == null)
              return null;
            declaringClass = findDeclaration2(stp.getName(), alternateParent);
//            log("MI.SN " + getNodeAsString(declaringClass));
            constrains.add(ASTNode.METHOD_DECLARATION);
            return definedIn(declaringClass, ((MethodInvocation) parent)
                .getName().toString(), constrains);
          }

        }
      } else {
        parent = parent.getParent(); // Move one up the ast. V V IMP!!
        alternateParent = alternateParent.getParent();
      }
    } else if (parent.getNodeType() == ASTNode.FIELD_ACCESS) {
      FieldAccess fa = (FieldAccess) parent;
      Expression exp = fa.getExpression();
      if (fa.getName().toString().equals(findMe.toString())) {
        constrains.add(ASTNode.FIELD_DECLARATION);

        if (exp != null) {
          constrains.add(ASTNode.TYPE_DECLARATION);
//          log("FA EXP: " + exp.toString() + " of type "
//              + exp.getClass().getName() + " parent: " + exp.getParent());
          if (exp instanceof MethodInvocation) {
            SimpleType stp = extracTypeInfo(findDeclaration2(((MethodInvocation) exp)
                                                                 .getName(),
                                                             alternateParent));
            if (stp == null)
              return null;
            declaringClass = findDeclaration2(stp.getName(), alternateParent);
            return definedIn(declaringClass, fa.getName().toString(),
                             constrains);
          } else if (exp instanceof FieldAccess) {
            SimpleType stp = extracTypeInfo(findDeclaration2(((FieldAccess) exp)
                                                                 .getName(),
                                                             alternateParent));
            if (stp == null)
              return null;
            declaringClass = findDeclaration2((stp.getName()), alternateParent);
            constrains.add(ASTNode.TYPE_DECLARATION);
            return definedIn(declaringClass, fa.getName().toString(),
                             constrains);
          }
          if (exp instanceof SimpleName) {
            SimpleType stp = extracTypeInfo(findDeclaration2(((SimpleName) exp),
                                                             alternateParent));
            if (stp == null)
              return null;
            declaringClass = findDeclaration2(stp.getName(), alternateParent);
//            log("FA.SN " + getNodeAsString(declaringClass));
            constrains.add(ASTNode.METHOD_DECLARATION);
            return definedIn(declaringClass, fa.getName().toString(),
                             constrains);
          }
        }

      } else {
        parent = parent.getParent(); // Move one up the ast. V V IMP!!
        alternateParent = alternateParent.getParent();
      }
    } else if (parent.getNodeType() == ASTNode.QUALIFIED_NAME) {

      QualifiedName qn = (QualifiedName) parent;
      if (!findMe.toString().equals(qn.getQualifier().toString())) {

        SimpleType stp = extracTypeInfo(findDeclaration2((qn.getQualifier()),
                                                         alternateParent));
        if(stp == null)
          return null;
        declaringClass = findDeclaration2(stp.getName(), alternateParent);
//        log(qn.getQualifier() + "->" + qn.getName());
//        log("QN decl class: " + getNodeAsString(declaringClass));
        constrains.clear();
        constrains.add(ASTNode.TYPE_DECLARATION);
        constrains.add(ASTNode.FIELD_DECLARATION);
        return definedIn(declaringClass, qn.getName().toString(), constrains);
      }
      else{
        if(findMe instanceof QualifiedName){
          QualifiedName qnn = (QualifiedName) findMe;
//          log("findMe is a QN, "
//              + (qnn.getQualifier().toString() + " other " + qnn.getName()
//                  .toString()));

          SimpleType stp = extracTypeInfo(findDeclaration2((qnn.getQualifier()), alternateParent));

          if (stp == null) {
            return null;
          }

//          log(qnn.getQualifier() + "->" + qnn.getName());
          declaringClass = findDeclaration2(stp.getName(), alternateParent);

//          log("QN decl class: "
//              + getNodeAsString(declaringClass));
          constrains.clear();
          constrains.add(ASTNode.TYPE_DECLARATION);
          constrains.add(ASTNode.FIELD_DECLARATION);
          return definedIn(declaringClass, qnn.getName().toString(), constrains);
        }
      }
    } else if (parent.getNodeType() == ASTNode.SIMPLE_TYPE) {
      constrains.add(ASTNode.TYPE_DECLARATION);
      if (parent.getParent().getNodeType() == ASTNode.CLASS_INSTANCE_CREATION)
        constrains.add(ASTNode.CLASS_INSTANCE_CREATION);
    } else if (parent instanceof Expression) {
//      constrains.add(ASTNode.TYPE_DECLARATION);
//      constrains.add(ASTNode.METHOD_DECLARATION);
//      constrains.add(ASTNode.FIELD_DECLARATION);
    } // TODO: in findDec, we also have a case where parent of type TD is handled.
      // Figure out if needed here as well.
//    log("Alternate parent: " + getNodeAsString(alternateParent));
    while (alternateParent != null) {
//      log("findDeclaration2 -> "
//          + getNodeAsString(alternateParent));
      for (Object oprop : alternateParent.structuralPropertiesForType()) {
        StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) oprop;
        if (prop.isChildProperty() || prop.isSimpleProperty()) {
          if (alternateParent.getStructuralProperty(prop) instanceof ASTNode) {
//            log(prop + " C/S Prop of -> "
//                + getNodeAsString(alternateParent));
            ret = definedIn((ASTNode) alternateParent
                                .getStructuralProperty(prop),
                            findMe.toString(), constrains);
            if (ret != null)
              return ret;
          }
        } else if (prop.isChildListProperty()) {
//          log((prop) + " ChildList props of "
//              + getNodeAsString(alternateParent));
          List<ASTNode> nodelist = (List<ASTNode>) alternateParent
              .getStructuralProperty(prop);
          for (ASTNode retNode : nodelist) {
            ret = definedIn(retNode, findMe.toString(), constrains);
            if (ret != null)
              return ret;
          }
        }
      }
      alternateParent = alternateParent.getParent();
    }
    return null;
  }

  protected static boolean ignorableSuggestionImport(PreprocessedSketch ps, String impName) {

    String impNameLc = impName.toLowerCase();

    List<ImportStatement> programImports = ps.programImports;
    List<ImportStatement> codeFolderImports = ps.codeFolderImports;

    boolean isImported = Stream
        .concat(programImports.stream(), codeFolderImports.stream())
        .anyMatch(impS -> {
          String packageNameLc = impS.getPackageName().toLowerCase();
          return impNameLc.startsWith(packageNameLc);
        });

    if (isImported) return false;

    final String include = "include";
    final String exclude = "exclude";

    if (impName.startsWith("processing")) {
      if (JavaMode.suggestionsMap.containsKey(include) && JavaMode.suggestionsMap.get(include).contains(impName)) {
        return false;
      } else if (JavaMode.suggestionsMap.containsKey(exclude) && JavaMode.suggestionsMap.get(exclude).contains(impName)) {
        return true;
      }
    } else if (impName.startsWith("java")) {
      if (JavaMode.suggestionsMap.containsKey(include) && JavaMode.suggestionsMap.get(include).contains(impName)) {
        return false;
      }
    }

    return true;
  }

  /**
   * A wrapper for java.lang.reflect types.
   * Will have to see if the usage turns out to be internal only here or not
   * and then accordingly decide where to place this class.
   * @author quarkninja
   *
   */
  public static class ClassMember {
    private Field field;

    private Method method;

    private Constructor<?> cons;

    private Class<?> thisclass;

    private String stringVal;

    private String classType;

    private ASTNode astNode;

    private ASTNode declaringNode;

    public ClassMember(Class<?> m) {
      thisclass = m;
      stringVal = "Predefined Class " + m.getName();
      classType = m.getName();
    }

    public ClassMember(Method m) {
      method = m;
      stringVal = "Method " + m.getReturnType().getName() + " | " + m.getName()
          + " defined in " + m.getDeclaringClass().getName();
      classType = m.getReturnType().getName();
    }

    public ClassMember(Field m) {
      field = m;
      stringVal = "Field " + m.getType().getName() + " | " + m.getName()
          + " defined in " + m.getDeclaringClass().getName();
      classType = m.getType().getName();
    }

    public ClassMember(Constructor<?> m) {
      cons = m;
      stringVal = "Cons " + " " + m.getName() + " defined in "
          + m.getDeclaringClass().getName();
    }

    public ClassMember(PreprocessedSketch ps, ASTNode node){
      astNode = node;
      stringVal = getNodeAsString(node);
      if(node instanceof TypeDeclaration){
        declaringNode = node;
      }
      if(node instanceof SimpleType){
        classType = ((SimpleType)node).getName().toString();
      }
      SimpleType stp = (node instanceof SimpleType) ? (SimpleType) node
          : extracTypeInfo(node);
      if(stp != null){
        ASTNode decl =findDeclaration(stp.getName());
        // Czech out teh mutation
        if(decl == null){
          // a predefined type
          classType = stp.getName().toString();
          thisclass = findClassIfExists(ps, classType);
        }
        else{
          // a local type
          declaringNode = decl;
        }
      }
    }

    public Class<?> getClass_() {
      return thisclass;
    }

    public ASTNode getDeclaringNode(){
      return declaringNode;
    }

    public Field getField() {
      return field;
    }

    public Method getMethod() {
      return method;
    }

    public Constructor<?> getCons() {
      return cons;
    }

    public ASTNode getASTNode(){
      return astNode;
    }

    public String toString() {
      return stringVal;
    }

    public String getTypeAsString(){
      return classType;
    }
  }

  /**
   * Find the SimpleType from FD, SVD, VDS, etc
   *
   * @param node
   * @return
   */
  public static SimpleType extracTypeInfo(ASTNode node) {
    if (node == null) {
      return null;
    }
    Type t = extracTypeInfo2(node);
    if (t instanceof PrimitiveType) {
      return null;
    } else if (t instanceof ArrayType) {
      ArrayType at = (ArrayType) t;
      log("ele type "
              + at.getElementType() + ", "
              + at.getElementType().getClass().getName());
      if (at.getElementType() instanceof PrimitiveType) {
        return null;
      } else if (at.getElementType() instanceof SimpleType) {
        return (SimpleType) at.getElementType();
      } else
        return null;
    } else if (t instanceof ParameterizedType) {
      ParameterizedType pmt = (ParameterizedType) t;
      log(pmt.getType() + ", " + pmt.getType().getClass());
      if (pmt.getType() instanceof SimpleType) {
        return (SimpleType) pmt.getType();
      } else
        return null;
    }
    return (SimpleType) t;
  }

  static public Type extracTypeInfo2(ASTNode node) {
    Messages.log("* extracTypeInfo2");
    if (node == null)
      return null;
    switch (node.getNodeType()) {
    case ASTNode.METHOD_DECLARATION:
      return ((MethodDeclaration) node).getReturnType2();
    case ASTNode.FIELD_DECLARATION:
      return ((FieldDeclaration) node).getType();
    case ASTNode.VARIABLE_DECLARATION_EXPRESSION:
      return  ((VariableDeclarationExpression) node).getType();
    case ASTNode.VARIABLE_DECLARATION_STATEMENT:
      return  ((VariableDeclarationStatement) node).getType();
    case ASTNode.SINGLE_VARIABLE_DECLARATION:
      return  ((SingleVariableDeclaration) node).getType();
    case ASTNode.VARIABLE_DECLARATION_FRAGMENT:
      return extracTypeInfo2(node.getParent());
    }
    log("Unknown type info request " + getNodeAsString(node));
    return null;
  }

  static protected ASTNode definedIn(ASTNode node, String name,
                                   ArrayList<Integer> constrains) {
    if (node == null)
      return null;
    if (constrains != null) {
//      log("Looking at " + getNodeAsString(node) + " for " + name
//          + " in definedIn");
      if (!constrains.contains(node.getNodeType()) && constrains.size() > 0) {
//        System.err.print("definedIn -1 " + " But constrain was ");
//        for (Integer integer : constrains) {
//          System.out.print(ASTNode.nodeClassForType(integer) + ",");
//        }
//        log();
        return null;
      }
    }

    List<VariableDeclarationFragment> vdfList = null;
    switch (node.getNodeType()) {

    case ASTNode.TYPE_DECLARATION:
      //Base.loge(getNodeAsString(node));
      TypeDeclaration td = (TypeDeclaration) node;
      if (td.getName().toString().equals(name)) {
        if (constrains.contains(ASTNode.CLASS_INSTANCE_CREATION)) {
          // look for constructor;
          MethodDeclaration[] methods = td.getMethods();
          for (MethodDeclaration md : methods) {
            if (md.getName().toString().equalsIgnoreCase(name)) {
              log("Found a constructor.");
              return md;
            }
          }
        } else {
          // it's just the TD we're lookin for
          return node;
        }
      } else {
        if (constrains.contains(ASTNode.FIELD_DECLARATION)) {
          // look for fields
          FieldDeclaration[] fields = td.getFields();
          for (FieldDeclaration fd : fields) {
            List<VariableDeclarationFragment> fragments = fd.fragments();
            for (VariableDeclarationFragment vdf : fragments) {
              if (vdf.getName().toString().equalsIgnoreCase(name))
                return fd;
            }
          }
        } else if (constrains.contains(ASTNode.METHOD_DECLARATION)) {
          // look for methods
          MethodDeclaration[] methods = td.getMethods();
          for (MethodDeclaration md : methods) {
            if (md.getName().toString().equalsIgnoreCase(name)) {
              return md;
            }
          }
        }
      }
      break;
    case ASTNode.METHOD_DECLARATION:
      //Base.loge(getNodeAsString(node));
      if (((MethodDeclaration) node).getName().toString().equalsIgnoreCase(name))
        return node;
      break;
    case ASTNode.SINGLE_VARIABLE_DECLARATION:
      //Base.loge(getNodeAsString(node));
      if (((SingleVariableDeclaration) node).getName().toString().equalsIgnoreCase(name))
        return node;
      break;
    case ASTNode.FIELD_DECLARATION:
      //Base.loge("FD" + node);
      vdfList = ((FieldDeclaration) node).fragments();
      break;
    case ASTNode.VARIABLE_DECLARATION_EXPRESSION:
      //Base.loge("VDE" + node);
      vdfList = ((VariableDeclarationExpression) node).fragments();
      break;
    case ASTNode.VARIABLE_DECLARATION_STATEMENT:
      //Base.loge("VDS" + node);
      vdfList = ((VariableDeclarationStatement) node).fragments();
      break;

    default:

    }
    if (vdfList != null) {
      for (VariableDeclarationFragment vdf : vdfList) {
        if (vdf.getName().toString().equalsIgnoreCase(name))
          return node;
      }
    }
    return null;
  }

  static protected String getNodeAsString(ASTNode node) {
    if (node == null)
      return "NULL";
    String className = node.getClass().getName();
    int index = className.lastIndexOf(".");
    if (index > 0)
      className = className.substring(index + 1);

    // if(node instanceof BodyDeclaration)
    // return className;

    String value = className;

    if (node instanceof TypeDeclaration)
      value = ((TypeDeclaration) node).getName().toString() + " | " + className;
    else if (node instanceof MethodDeclaration)
      value = ((MethodDeclaration) node).getName().toString() + " | "
          + className;
    else if (node instanceof MethodInvocation)
      value = ((MethodInvocation) node).getName().toString() + " | "
          + className;
    else if (node instanceof FieldDeclaration)
      value = node.toString() + " FldDecl | ";
    else if (node instanceof SingleVariableDeclaration)
      value = ((SingleVariableDeclaration) node).getName() + " - "
          + ((SingleVariableDeclaration) node).getType() + " | SVD ";
    else if (node instanceof ExpressionStatement)
      value = node.toString() + className;
    else if (node instanceof SimpleName)
      value = ((SimpleName) node).getFullyQualifiedName() + " | " + className;
    else if (node instanceof QualifiedName)
      value = node.toString() + " | " + className;
    else if(node instanceof FieldAccess)
      value = node.toString() + " | ";
    else if (className.startsWith("Variable"))
      value = node.toString() + " | " + className;
    else if (className.endsWith("Type"))
      value = node.toString() + " | " + className;
    value += " [" + node.getStartPosition() + ","
        + (node.getStartPosition() + node.getLength()) + "]";
    value += " Line: "
        + ((CompilationUnit) node.getRoot()).getLineNumber(node
            .getStartPosition());
    return value;
  }

//  public void jdocWindowVisible(boolean visible) {
//   // frmJavaDoc.setVisible(visible);
//  }

//  public static String readFile2(String path) {
//    BufferedReader reader = null;
//    try {
//      reader = new BufferedReader(
//                                  new InputStreamReader(
//                                                        new FileInputStream(
//                                                                            new File(
//                                                                                path))));
//    } catch (FileNotFoundException e) {
//      e.printStackTrace();
//    }
//    try {
//      StringBuilder ret = new StringBuilder();
//      // ret.append("package " + className + ";\n");
//      String line;
//      while ((line = reader.readLine()) != null) {
//        ret.append(line);
//        ret.append("\n");
//      }
//      return ret.toString();
//    } catch (IOException e) {
//      e.printStackTrace();
//    } finally {
//      try {
//        reader.close();
//      } catch (IOException e) {
//        e.printStackTrace();
//      }
//    }
//    return null;
//  }

  static private void log(Object object) {
    Messages.log(object == null ? "null" : object.toString());
  }

  /// Predictions --------------------------------------------------------------

  protected static List<CompletionCandidate> trimCandidates(String newWord, List<CompletionCandidate> candidates) {
    ArrayList<CompletionCandidate> newCandidate = new ArrayList<>();
    newWord = newWord.toLowerCase();
    for (CompletionCandidate comp : candidates) {
      //if (comp.getNoHtmlLabel().toLowerCase().startsWith(newWord)) {
      if (comp.startsWith(newWord)) {
        newCandidate.add(comp);
      }
    }
    return newCandidate;
  }

  protected List<CompletionCandidate> candidates;
  protected String lastPredictedPhrase = " ";

  /**
   * The main function that calculates possible code completion candidates
   *
   * @param pdePhrase
   * @param line
   * @param lineStartNonWSOffset
   */
  public List<CompletionCandidate> preparePredictions(final PreprocessedSketch ps,
                                                      final String pdePhrase,
                                                      final int lineNumber) {
    Messages.log("* preparePredictions");

    ASTNode astRootNode = (ASTNode) ps.compilationUnit.types().get(0);

    // If the parsed code contains pde enhancements, take 'em out.
    // TODO: test this
    TextTransform transform = new TextTransform(pdePhrase);
    transform.addAll(SourceUtils.replaceTypeConstructors(pdePhrase));
    transform.addAll(SourceUtils.replaceHexLiterals(pdePhrase));
    transform.addAll(SourceUtils.replaceColorRegex(pdePhrase));
    transform.addAll(SourceUtils.fixFloatsRegex(pdePhrase));
    String phrase = transform.apply();

    //After typing 'arg.' all members of arg type are to be listed. This one is a flag for it
    boolean noCompare = phrase.endsWith(".");

    if (noCompare) {
      phrase = phrase.substring(0, phrase.length() - 1);
    }

    boolean incremental = !noCompare &&
        phrase.length() > lastPredictedPhrase.length() &&
        phrase.startsWith(lastPredictedPhrase);

    if (incremental) {
      log(pdePhrase + " starts with " + lastPredictedPhrase);
      log("Don't recalc");

      if (phrase.contains(".")) {
        int x = phrase.lastIndexOf('.');
        candidates = trimCandidates(phrase.substring(x + 1), candidates);
      } else {
        candidates = trimCandidates(phrase, candidates);
      }
      lastPredictedPhrase = phrase;
      return candidates;
    }

    // Ensure that we're not inside a comment. TODO: Binary search

    /*for (Comment comm : getCodeComments()) {
      int commLineNo = PdeToJavaLineNumber(compilationUnit
          .getLineNumber(comm.getStartPosition()));
      if(commLineNo == lineNumber){
        log("Found a comment line " + comm);
        log("Comment LSO "
            + javaCodeOffsetToLineStartOffset(compilationUnit
          .getLineNumber(comm.getStartPosition()),
                                              comm.getStartPosition()));
        break;
      }
    }*/

    // Now parse the expression into an ASTNode object
    ASTNode nearestNode;
    ASTParser parser = ASTParser.newParser(AST.JLS8);
    parser.setKind(ASTParser.K_EXPRESSION);
    parser.setSource(phrase.toCharArray());
    ASTNode testnode = parser.createAST(null);
    //Base.loge("PREDICTION PARSER PROBLEMS: " + parser);
    // Find closest ASTNode of the document to this word
    Messages.loge("Typed: " + phrase + "|" + " temp Node type: " + testnode.getClass().getSimpleName());
    if(testnode instanceof MethodInvocation){
      MethodInvocation mi = (MethodInvocation)testnode;
      log(mi.getName() + "," + mi.getExpression() + "," + mi.typeArguments().size());
    }

    // find nearest ASTNode
    nearestNode = findClosestNode(lineNumber, astRootNode);
    if (nearestNode == null) {
      // Make sure nearestNode is not NULL if couldn't find a closest node
      nearestNode = astRootNode;
    }
    Messages.loge(lineNumber + " Nearest ASTNode to PRED "
                      + getNodeAsString(nearestNode));

    candidates = new ArrayList<>();
    lastPredictedPhrase = phrase;
    // Determine the expression typed

    if (testnode instanceof SimpleName && !noCompare) {
      Messages.loge("One word expression " + getNodeAsString(testnode));
      //==> Simple one word exprssion - so is just an identifier

      // Bottom up traversal of the AST to look for possible definitions at
      // higher levels.
      //nearestNode = nearestNode.getParent();
      while (nearestNode != null) {
        // If the current class has a super class, look inside it for
        // definitions.
        if (nearestNode instanceof TypeDeclaration) {
          TypeDeclaration td = (TypeDeclaration) nearestNode;
          if (td.getStructuralProperty(TypeDeclaration.SUPERCLASS_TYPE_PROPERTY) != null) {
            SimpleType st = (SimpleType) td.getStructuralProperty(TypeDeclaration.SUPERCLASS_TYPE_PROPERTY);
            log("Superclass " + st.getName());
            ArrayList<CompletionCandidate> tempCandidates =
                getMembersForType(ps, st.getName().toString(), phrase, false, false);
            for (CompletionCandidate can : tempCandidates) {
              candidates.add(can);
            }
            //findDeclaration(st.getName())
          }
        }
        List<StructuralPropertyDescriptor> sprops =
            nearestNode.structuralPropertiesForType();
        for (StructuralPropertyDescriptor sprop : sprops) {
          ASTNode cnode;
          if (!sprop.isChildListProperty()) {
            if (nearestNode.getStructuralProperty(sprop) instanceof ASTNode) {
              cnode = (ASTNode) nearestNode.getStructuralProperty(sprop);
              CompletionCandidate[] types = checkForTypes(cnode);
              if (types != null) {
                for (CompletionCandidate type : types) {
                  if (type.getElementName().toLowerCase().startsWith(phrase.toLowerCase()))
                    candidates.add(type);
                }
              }
            }
          } else {
            // Childlist prop
            List<ASTNode> nodelist =
                (List<ASTNode>) nearestNode.getStructuralProperty(sprop);
            for (ASTNode clnode : nodelist) {
              CompletionCandidate[] types = checkForTypes(clnode);
              if (types != null) {
                for (CompletionCandidate type : types) {
                  if (type.getElementName().toLowerCase().startsWith(phrase.toLowerCase()))
                    candidates.add(type);
                }
              }
            }
          }
        }
        nearestNode = nearestNode.getParent();
      }
      // We're seeing a simple name that's not defined locally or in
      // the parent class. So most probably a pre-defined type.
      log("Empty can. " + phrase);
      ClassPath classPath = ps.classPath;
      if (classPath != null) {
        RegExpResourceFilter regExpResourceFilter =
            new RegExpResourceFilter(Pattern.compile(".*"),
                                     Pattern.compile(phrase + "[a-zA-Z_0-9]*.class",
                                                     Pattern.CASE_INSENSITIVE));
        String[] resources = classPath.findResources("", regExpResourceFilter);

        for (String matchedClass2 : resources) {
          matchedClass2 = matchedClass2.replace('/', '.'); //package name
          String matchedClass = matchedClass2.substring(0, matchedClass2.length() - 6);
          int d = matchedClass.lastIndexOf('.');
          if (!ignorableSuggestionImport(ps, matchedClass)) {
            matchedClass = matchedClass.substring(d + 1); //class name
            // display package name in grey
            String html = "" + matchedClass + " : " +
                matchedClass2.substring(0, d) + "";
            candidates.add(new CompletionCandidate(matchedClass, html,
                                                   matchedClass,
                                                   CompletionCandidate.PREDEF_CLASS));
          }
        }
      }
    } else {
      // ==> Complex expression of type blah.blah2().doIt,etc
      // Have to resolve it by carefully traversing AST of testNode
      Messages.loge("Complex expression " + getNodeAsString(testnode));
      log("candidates empty");
      ASTNode childExpr = getChildExpression(testnode);
      log("Parent expression : " + getParentExpression(testnode));
      log("Child expression : " + childExpr);
      if (!noCompare) {
        log("Original testnode " + getNodeAsString(testnode));
        testnode = getParentExpression(testnode);
        log("Corrected testnode " + getNodeAsString(testnode));
      }
      ClassMember expr =
          resolveExpression3rdParty(ps, nearestNode, testnode, noCompare);
      if (expr == null) {
        log("Expr is null");
      } else {
        boolean isArray = expr.thisclass != null && expr.thisclass.isArray();
        boolean isSimpleType = (expr.astNode != null) &&
            expr.astNode.getNodeType() == ASTNode.SIMPLE_TYPE;
        boolean isMethod = expr.method != null;
        boolean staticOnly = !isMethod && !isArray && !isSimpleType;
        log("Expr is " + expr.toString());
        String lookFor = (noCompare || (childExpr == null)) ?
            "" : childExpr.toString();
        candidates = getMembersForType(ps, expr, lookFor, noCompare, staticOnly);
      }
    }
    return candidates;
  }

  protected static DefaultListModel<CompletionCandidate> filterPredictions(List<CompletionCandidate> candidates) {
    Messages.log("* filterPredictions");
    DefaultListModel<CompletionCandidate> defListModel = new DefaultListModel<>();
    if (candidates.isEmpty())
      return defListModel;
    // check if first & last CompCandidate are the same methods, only then show all overloaded methods
    if (candidates.get(0).getElementName()
        .equals(candidates.get(candidates.size() - 1).getElementName())) {
      log("All CC are methods only: " + candidates.get(0).getElementName());
      for (int i = 0; i < candidates.size(); i++) {
        CompletionCandidate cc = candidates.get(i).withRegeneratedCompString();
        candidates.set(i, cc);
        defListModel.addElement(cc);
      }
    }
    else {
      boolean ignoredSome = false;
      for (int i = 0; i < candidates.size(); i++) {
        if(i > 0 && (candidates.get(i).getElementName()
            .equals(candidates.get(i - 1).getElementName()))){
          if (candidates.get(i).getType() == CompletionCandidate.LOCAL_METHOD
              || candidates.get(i).getType() == CompletionCandidate.PREDEF_METHOD) {
            CompletionCandidate cc = candidates.get(i - 1);
            String label = cc.getLabel();
            int x = label.lastIndexOf(')');
            String newLabel;
            if (candidates.get(i).getType() == CompletionCandidate.PREDEF_METHOD) {
              newLabel = (cc.getLabel().contains("") ? "" : "")
                  + cc.getElementName() + "(...)" + label.substring(x + 1);
            } else {
              newLabel = cc.getElementName() + "(...)" + label.substring(x + 1);
            }
            String newCompString = cc.getElementName() + "(";
            candidates.set(i - 1, cc.withLabelAndCompString(newLabel, newCompString));
            ignoredSome = true;
            continue;
          }
        }
        defListModel.addElement(candidates.get(i));
      }
      if (ignoredSome) {
        log("Some suggestions hidden");
      }
    }
    return defListModel;
  }

  /// JavaDocs -----------------------------------------------------------------

  //TODO: Work on this later.
/*
  protected TreeMap<String, String> jdocMap;

  protected void loadJavaDoc() {
    jdocMap = new TreeMap<>();

    // presently loading only p5 reference for PApplet
    // TODO: use something like ExecutorService here [jv]
    new Thread(new Runnable() {
      @Override
      public void run() {
        try {
          loadJavaDoc(jdocMap, editor.getMode().getReferenceFolder());
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    }).start();
  }

  static void loadJavaDoc(TreeMap<String, String> jdocMap,
                          File referenceFolder) throws IOException {
    Document doc;

    FileFilter fileFilter = new FileFilter() {
      @Override
      public boolean accept(File file) {
        if(!file.getName().endsWith("_.html"))
          return false;
        int k = 0;
        for (int i = 0; i < file.getName().length(); i++) {
          if(file.getName().charAt(i)== '_')
            k++;
          if(k > 1)
            return false;
        }
        return true;
      }
    };

    for (File docFile : referenceFolder.listFiles(fileFilter)) {
      doc = Jsoup.parse(docFile, null);
      Elements elm = doc.getElementsByClass("ref-item");
      String msg = "";
      String methodName = docFile.getName().substring(0, docFile.getName().indexOf('_'));
      //System.out.println(methodName);
      for (org.jsoup.nodes.Element ele : elm) {
        msg = "

"
            + ele.html() + "

";
        //mat.replaceAll("");
        msg = msg.replaceAll("img src=\"", "img src=\""
            + referenceFolder.toURI().toURL().toString() + "/");
        //System.out.println(ele.text());
      }
      jdocMap.put(methodName, msg);
    }
    //System.out.println("JDoc loaded " + jdocMap.size());
  }

  public void updateJavaDoc(final CompletionCandidate candidate) {
    String methodmatch = candidate.toString();
    if (methodmatch.indexOf('(') != -1) {
      methodmatch = methodmatch.substring(0, methodmatch.indexOf('('));
    }

    //log("jdoc match " + methodmatch);
    String temp = " ";
    for (final String key : jdocMap.keySet()) {
      if (key.startsWith(methodmatch) && key.length() > 3) {
        log("Matched jdoc " + key);
        if (candidate.getWrappedObject() != null) {
          String definingClass = "";
          if (candidate.getWrappedObject() instanceof Field)
            definingClass = ((Field) candidate.getWrappedObject())
                .getDeclaringClass().getName();
          else if (candidate.getWrappedObject() instanceof Method)
            definingClass = ((Method) candidate.getWrappedObject())
                .getDeclaringClass().getName();
          if (definingClass.equals("processing.core.PApplet")) {
            temp = (jdocMap.get(key));
            break;
          }
        }
      }
    }

    final String jdocString = temp;
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        javadocPane.setText(jdocString);
        scrollPane.getVerticalScrollBar().setValue(0);
        //frmJavaDoc.setVisible(!jdocString.equals(" "));
        editor.toFront();
        editor.ta.requestFocus();
      }
    });
  }
*/

}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/GUI/Handles/Handles.pde
/**
 * Handles.
 *
 * Click and drag the white boxes to change their position.
 */

Handle[] handles;

void setup() {
  size(640, 360);
  int num = height/15;
  handles = new Handle[num];
  int hsize = 10;
  for (int i = 0; i < handles.length; i++) {
    handles[i] = new Handle(width/2, 10+i*15, 50-hsize/2, 10, handles);
  }
}

void draw() {
  background(153);

  for (int i = 0; i < handles.length; i++) {
    handles[i].update();
    handles[i].display();
  }

  fill(0);
  rect(0, 0, width/2, height);
}

void mouseReleased()  {
  for (int i = 0; i < handles.length; i++) {
    handles[i].releaseEvent();
  }
}

class Handle {

  int x, y;
  int boxx, boxy;
  int stretch;
  int size;
  boolean over;
  boolean press;
  boolean locked = false;
  boolean otherslocked = false;
  Handle[] others;

  Handle(int ix, int iy, int il, int is, Handle[] o) {
    x = ix;
    y = iy;
    stretch = il;
    size = is;
    boxx = x+stretch - size/2;
    boxy = y - size/2;
    others = o;
  }

  void update() {
    boxx = x+stretch;
    boxy = y - size/2;

    for (int i=0; i<others.length; i++) {
      if (others[i].locked == true) {
        otherslocked = true;
        break;
      } else {
        otherslocked = false;
      }
    }

    if (otherslocked == false) {
      overEvent();
      pressEvent();
    }

    if (press) {
      stretch = lock(mouseX-width/2-size/2, 0, width/2-size-1);
    }
  }

  void overEvent() {
    if (overRect(boxx, boxy, size, size)) {
      over = true;
    } else {
      over = false;
    }
  }

  void pressEvent() {
    if (over && mousePressed || locked) {
      press = true;
      locked = true;
    } else {
      press = false;
    }
  }

  void releaseEvent() {
    locked = false;
  }

  void display() {
    line(x, y, x+stretch, y);
    fill(255);
    stroke(0);
    rect(boxx, boxy, size, size);
    if (over || press) {
      line(boxx, boxy, boxx+size, boxy+size);
      line(boxx, boxy+size, boxx+size, boxy);
    }

  }
}

boolean overRect(int x, int y, int width, int height) {
  if (mouseX >= x && mouseX <= x+width &&
      mouseY >= y && mouseY <= y+height) {
    return true;
  } else {
    return false;
  }
}

int lock(int val, int minv, int maxv) {
  return  min(max(val, minv), maxv);
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Shaders/EdgeFilter/EdgeFilter.pde
/**
 * Edge Filter
 *
 * Apply a custom shader to the filter() function to affect the geometry drawn to the screen.
 *
 * Press the mouse to turn the filter on and off.
 */

 PShader edges;
boolean applyFilter = true;

void setup() {
  size(640, 360, P3D);
  edges = loadShader("edges.glsl");
  noStroke();
}

void draw() {
  background(0);
  lights();

  translate(width/2, height/2);
  pushMatrix();
  rotateX(frameCount * 0.01);
  rotateY(frameCount * 0.01);
  box(120);
  popMatrix();

  if (applyFilter == true) {
    filter(edges);
  }

  // The sphere doesn't have the edge detection applied
  // on it because it is drawn after filter() is called.
  rotateY(frameCount * 0.02);
  translate(150, 0);
  sphere(40);
}

void mousePressed() {
  applyFilter = !applyFilter;
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Simulate/SoftBody/SoftBody.pde
/**
 * Soft Body
 * by <NAME>.
 *
 * Softbody dynamics simulation using curveVertex() and curveTightness().
 */

// center point
float centerX = 0, centerY = 0;

float radius = 45, rotAngle = -90;
float accelX, accelY;
float springing = .0009, damping = .98;

//corner nodes
int nodes = 5;
float nodeStartX[] = new float[nodes];
float nodeStartY[] = new float[nodes];
float[]nodeX = new float[nodes];
float[]nodeY = new float[nodes];
float[]angle = new float[nodes];
float[]frequency = new float[nodes];

// soft-body dynamics
float organicConstant = 1;

void setup() {
  size(640, 360);
  //center shape in window
  centerX = width/2;
  centerY = height/2;
  // iniitalize frequencies for corner nodes
  for (int i=0; i<nodes; i++){
    frequency[i] = random(5, 12);
  }
  noStroke();
  frameRate(30);
}

void draw() {
  //fade background
  fill(0, 100);
  rect(0,0,width, height);
  drawShape();
  moveShape();
}

void drawShape() {
  //  calculate node  starting positions
  for (int i=0; i<nodes; i++){
    nodeStartX[i] = centerX+cos(radians(rotAngle))*radius;
    nodeStartY[i] = centerY+sin(radians(rotAngle))*radius;
    rotAngle += 360.0/nodes;
  }

  // draw polygon
  curveTightness(organicConstant);
  fill(255);
  beginShape();
  for (int i=0; i<nodes; i++){
    curveVertex(nodeX[i], nodeY[i]);
  }
  for (int i=0; i<nodes-1; i++){
    curveVertex(nodeX[i], nodeY[i]);
  }
  endShape(CLOSE);
}

void moveShape() {
  //move center point
  float deltaX = mouseX-centerX;
  float deltaY = mouseY-centerY;

  // create springing effect
  deltaX *= springing;
  deltaY *= springing;
  accelX += deltaX;
  accelY += deltaY;

  // move predator's center
  centerX += accelX;
  centerY += accelY;

  // slow down springing
  accelX *= damping;
  accelY *= damping;

  // change curve tightness
  organicConstant = 1-((abs(accelX)+abs(accelY))*.1);

  //move nodes
  for (int i=0; i<nodes; i++){
    nodeX[i] = nodeStartX[i]+sin(radians(angle[i]))*(accelX*2);
    nodeY[i] = nodeStartY[i]+sin(radians(angle[i]))*(accelY*2);
    angle[i]+=frequency[i];
  }
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/GUI/Rollover/Rollover.pde
/**
 * Rollover.
 *
 * Roll over the colored squares in the center of the image
 * to change the color of the outside rectangle.
 */

int rectX, rectY;      // Position of square button
int circleX, circleY;  // Position of circle button
int rectSize = 90;     // Diameter of rect
int circleSize = 93;   // Diameter of circle

color rectColor;
color circleColor;
color baseColor;

boolean rectOver = false;
boolean circleOver = false;

void setup() {
  size(640, 360);
  rectColor = color(0);
  circleColor = color(255);
  baseColor = color(102);
  circleX = width/2+circleSize/2+10;
  circleY = height/2;
  rectX = width/2-rectSize-10;
  rectY = height/2-rectSize/2;
  ellipseMode(CENTER);
}

void draw() {
  update(mouseX, mouseY);

  noStroke();
  if (rectOver) {
    background(rectColor);
  } else if (circleOver) {
    background(circleColor);
  } else {
    background(baseColor);
  }

  stroke(255);
  fill(rectColor);
  rect(rectX, rectY, rectSize, rectSize);
  stroke(0);
  fill(circleColor);
  ellipse(circleX, circleY, circleSize, circleSize);
}

void update(int x, int y) {
  if( overCircle(circleX, circleY, circleSize) ) {
    circleOver = true;
    rectOver = false;
  } else if ( overRect(rectX, rectY, rectSize, rectSize) ) {
    rectOver = true;
    circleOver = false;
  } else {
    circleOver = rectOver = false;
  }
}

boolean overRect(int x, int y, int width, int height) {
  if (mouseX >= x && mouseX <= x+width &&
      mouseY >= y && mouseY <= y+height) {
    return true;
  } else {
    return false;
  }
}

boolean overCircle(int x, int y, int diameter) {
  float disX = x - mouseX;
  float disY = y - mouseY;
  if(sqrt(sq(disX) + sq(disY)) < diameter/2 ) {
    return true;
  } else {
    return false;
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/GUI/Button/Button.pde
/**
 * Button.
 *
 * Click on one of the colored squares in the
 * center of the image to change the color of
 * the background.
 */

int rectX, rectY;      // Position of square button
int circleX, circleY;  // Position of circle button
int rectSize = 90;     // Diameter of rect
int circleSize = 93;   // Diameter of circle
color rectColor, circleColor, baseColor;
color rectHighlight, circleHighlight;
color currentColor;
boolean rectOver = false;
boolean circleOver = false;

void setup() {
  size(640, 360);
  rectColor = color(0);
  rectHighlight = color(51);
  circleColor = color(255);
  circleHighlight = color(204);
  baseColor = color(102);
  currentColor = baseColor;
  circleX = width/2+circleSize/2+10;
  circleY = height/2;
  rectX = width/2-rectSize-10;
  rectY = height/2-rectSize/2;
  ellipseMode(CENTER);
}

void draw() {
  update(mouseX, mouseY);
  background(currentColor);

  if (rectOver) {
    fill(rectHighlight);
  } else {
    fill(rectColor);
  }
  stroke(255);
  rect(rectX, rectY, rectSize, rectSize);

  if (circleOver) {
    fill(circleHighlight);
  } else {
    fill(circleColor);
  }
  stroke(0);
  ellipse(circleX, circleY, circleSize, circleSize);
}

void update(int x, int y) {
  if ( overCircle(circleX, circleY, circleSize) ) {
    circleOver = true;
    rectOver = false;
  } else if ( overRect(rectX, rectY, rectSize, rectSize) ) {
    rectOver = true;
    circleOver = false;
  } else {
    circleOver = rectOver = false;
  }
}

void mousePressed() {
  if (circleOver) {
    currentColor = circleColor;
  }
  if (rectOver) {
    currentColor = rectColor;
  }
}

boolean overRect(int x, int y, int width, int height)  {
  if (mouseX >= x && mouseX <= x+width &&
      mouseY >= y && mouseY <= y+height) {
    return true;
  } else {
    return false;
  }
}

boolean overCircle(int x, int y, int diameter) {
  float disX = x - mouseX;
  float disY = y - mouseY;
  if (sqrt(sq(disX) + sq(disY)) < diameter/2 ) {
    return true;
  } else {
    return false;
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Advanced Data/HashMapClass/HashMapClass.pde
/**
 * HashMap example
 * by <NAME>.
 *
 * This example demonstrates how to use a HashMap to store
 * a collection of objects referenced by a key. This is much like an array,
 * only instead of accessing elements with a numeric index, we use a String.
 * If you are familiar with associative arrays from other languages,
 * this is the same idea.
 *
 * A simpler example is CountingStrings which uses IntDict instead of
 * HashMap.  The Processing classes IntDict, FloatDict, and StringDict
 * offer a simpler way of pairing Strings with numbers or other Strings.
 * Here we use a HashMap because we want to pair a String with a custom
 * object, in this case a "Word" object that stores two numbers.
 *
 * In this example, words that appear in one book (Dracula) only are colored white
 * while words the other (Frankenstein) are colored black.
 */

HashMap<String, Word> words;  // HashMap object

void setup() {
  size(640, 360);

  // Create the HashMap
  words = new HashMap<String, Word>();

  // Load two files
  loadFile("dracula.txt");
  loadFile("frankenstein.txt");

  // Create the font
  textFont(createFont("SourceCodePro-Regular.ttf", 24));
}

void draw() {
  background(126);

  // Show words
  for (Word w : words.values()) {
    if (w.qualify()) {
        w.display();
        w.move();
    }
  }
}

// Load a file
void loadFile(String filename) {
  String[] lines = loadStrings(filename);
  String allText = join(lines, " ").toLowerCase();
  String[] tokens = splitTokens(allText, " ,.?!:;[]-\"'");

  for (String s : tokens) {
    // Is the word in the HashMap
    if (words.containsKey(s)) {
      // Get the word object and increase the count
      // We access objects from a HashMap via its key, the String
      Word w = words.get(s);
      // Which book am I loading?
      if (filename.contains("dracula")) {
        w.incrementDracula();
      }
      else if (filename.contains("frankenstein")) {
        w.incrementFranken();
      }
    }
    else {
      // Otherwise make a new word
      Word w = new Word(s);
      // And add to the HashMap put() takes two arguments, "key" and "value"
      // The key for us is the String and the value is the Word object
      words.put(s, w);
      if (filename.contains("dracula")) {
        w.incrementDracula();
      } else if (filename.contains("frankenstein")) {
        w.incrementFranken();
      }
    }
  }
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/io/examples/Environment_I2C_BME280/BME280.pde
import processing.io.I2C;

// BME280 is an integrated environmental sensor
// It can measure temperature, pressure and humidity
// datasheet: https://cdn-shop.adafruit.com/datasheets/BST-BME280_DS001-10.pdf
// code contributed by @OlivierLD

public class BME280 extends I2C {

  public final static int BME280_I2CADDR = 0x77; // this is the default I2C address
  public final static int DEFAULT_ADDR = BME280_I2CADDR;

  // Operating Modes
  public final static int BME280_OSAMPLE_1  = 1;
  public final static int BME280_OSAMPLE_2  = 2;
  public final static int BME280_OSAMPLE_4  = 3;
  public final static int BME280_OSAMPLE_8  = 4;
  public final static int BME280_OSAMPLE_16 = 5;

  // BME280 Registers
  public final static int BME280_REGISTER_DIG_T1 = 0x88; // Trimming parameter registers
  public final static int BME280_REGISTER_DIG_T2 = 0x8A;
  public final static int BME280_REGISTER_DIG_T3 = 0x8C;

  public final static int BME280_REGISTER_DIG_P1 = 0x8E;
  public final static int BME280_REGISTER_DIG_P2 = 0x90;
  public final static int BME280_REGISTER_DIG_P3 = 0x92;
  public final static int BME280_REGISTER_DIG_P4 = 0x94;
  public final static int BME280_REGISTER_DIG_P5 = 0x96;
  public final static int BME280_REGISTER_DIG_P6 = 0x98;
  public final static int BME280_REGISTER_DIG_P7 = 0x9A;
  public final static int BME280_REGISTER_DIG_P8 = 0x9C;
  public final static int BME280_REGISTER_DIG_P9 = 0x9E;

  public final static int BME280_REGISTER_DIG_H1 = 0xA1;
  public final static int BME280_REGISTER_DIG_H2 = 0xE1;
  public final static int BME280_REGISTER_DIG_H3 = 0xE3;
  public final static int BME280_REGISTER_DIG_H4 = 0xE4;
  public final static int BME280_REGISTER_DIG_H5 = 0xE5;
  public final static int BME280_REGISTER_DIG_H6 = 0xE6;
  public final static int BME280_REGISTER_DIG_H7 = 0xE7;

  public final static int BME280_REGISTER_CHIPID = 0xD0;
  public final static int BME280_REGISTER_VERSION = 0xD1;
  public final static int BME280_REGISTER_SOFTRESET = 0xE0;

  public final static int BME280_REGISTER_CONTROL_HUM = 0xF2;
  public final static int BME280_REGISTER_CONTROL = 0xF4;
  public final static int BME280_REGISTER_CONFIG = 0xF5;
  public final static int BME280_REGISTER_PRESSURE_DATA = 0xF7;
  public final static int BME280_REGISTER_TEMP_DATA = 0xFA;
  public final static int BME280_REGISTER_HUMIDITY_DATA = 0xFD;

  private int dig_T1 = 0;
  private int dig_T2 = 0;
  private int dig_T3 = 0;

  private int dig_P1 = 0;
  private int dig_P2 = 0;
  private int dig_P3 = 0;
  private int dig_P4 = 0;
  private int dig_P5 = 0;
  private int dig_P6 = 0;
  private int dig_P7 = 0;
  private int dig_P8 = 0;
  private int dig_P9 = 0;

  private int dig_H1 = 0;
  private int dig_H2 = 0;
  private int dig_H3 = 0;
  private int dig_H4 = 0;
  private int dig_H5 = 0;
  private int dig_H6 = 0;

  private float tFine = 0.0f;

  private int address;
  private int mode = BME280_OSAMPLE_8;
  private float standardSeaLevelPressure = 101325.0f; // in Pa (1013.25 hPa)

  protected float temp = 0.0f; // most recent sensor readings, set by update()
  protected float press = 0.0f;
  protected float hum = 0.0f;

  public BME280(String dev) {
    this(dev, DEFAULT_ADDR);
  }

  public BME280(String dev, int address) {
    super(dev);
    this.address = address;

    // Soft reset
    command(BME280_REGISTER_SOFTRESET, (byte)0xB6);
    // Wait for the chip to wake up
    delay(300);

    try {
      readCalibrationData();
      // showCalibrationData();
    } catch (Exception ex) {
      ex.printStackTrace();
    }

    command(BME280_REGISTER_CONTROL, (byte)0x3F);
    tFine = 0.0f;
  }

  /**
   * Read and update all sensors values
   */
  public void update() {
    // The order used to read the data is important!
    // 1.temperature, 2.pressure (analog to altitude), 3.humidity.

    try {
      temp = readTemperature();
    } catch (Exception ex) {
      System.err.println(ex.getMessage());
      ex.printStackTrace();
    }

    try {
      press = readPressure();
    } catch (Exception ex) {
      System.err.println(ex.getMessage());
      ex.printStackTrace();
    }

    try {
      hum = readHumidity();
    } catch (Exception ex) {
      System.err.println(ex.getMessage());
      ex.printStackTrace();
    }
  }

  /**
   * Returns the temperature in degrees celsius
   */
  public float temperature() {
    return temp;
  }

  /**
   * Returns the pressure in Pa
   */
  public float pressure() {
    return press;
  }

  /**
   * Returns the altitude in meters
   * @param pressure as returned by pressure()
   */
  public float altitude(float pressure) {
    double altitude = 0.0;
    if (standardSeaLevelPressure != 0) {
      altitude = 44330.0 * (1.0 - Math.pow(pressure / standardSeaLevelPressure, 0.1903));
    }
    return (float)altitude;
  }

  /**
   * Returns the altitude in meters
   * @param pressure as returned by pressure() in Pa
   * @param temperature as returned by temperature() in Celcius
   */
  public float altitude(float pressure, float temperature) {
    double altitude = 0.0;
    if (standardSeaLevelPressure != 0) {
      altitude = ((Math.pow(standardSeaLevelPressure / pressure, 1 / 5.257)  - 1) * (temperature + 273.25)) / 0.0065;
    }
    return (float)altitude;
  }

  /**
   * Returns the humidity in percent
   */
  public float humidity() {
    return hum;
  }

  /**
   * Set the standard sea level pressure used for calculating altitude()
   * Defaults to 101325 Pa (1013.25 hPa)
   */
  public void setStandardSeaLevelPressure(float pressure) {
    standardSeaLevelPressure = pressure;
  }

  protected float readTemperature() {
    // Returns the compensated temperature in degrees celcius
    float UT = readRawTemp();
    float var1 = 0.0f;
    float var2 = 0.0f;
    float temp = 0.0f;

    // Read raw temp before aligning it with the calibration values
    var1 = (UT / 16384.0f - dig_T1 / 1024.0f) * (float) dig_T2;
    var2 = ((UT / 131072.0f - dig_T1 / 8192.0f) * (UT / 131072.0f - dig_T1 / 8192.0f)) * (float) dig_T3;
    tFine = (int) (var1 + var2);
    temp = (var1 + var2) / 5120.0f;
    // println("DBG: Calibrated temperature = " + temp + " C");
    return temp;
  }

  protected float readPressure() {
    // Returns the compensated pressure in Pascal
    int adc = readRawPressure();
    // println("ADC:" + adc + ", tFine:" + tFine);
    float var1 = (tFine / 2.0f) - 64000.0f;
    float var2 = var1 * var1 * (dig_P6 / 32768.0f);
    var2 = var2 + var1 * dig_P5 * 2.0f;
    var2 = (var2 / 4.0f) + (dig_P4 * 65536.0f);
    var1 = (dig_P3 * var1 * var1 / 524288.0f + dig_P2 * var1) / 524288.0f;
    var1 = (1.0f + var1 / 32768.0f) * dig_P1;
    if (var1 == 0f) {
      return 0.0f;
    }
    float p = 1048576.0f - adc;
    p = ((p - var2 / 4096.0f) * 6250.0f) / var1;
    var1 = dig_P9 * p * p / 2147483648.0f;
    var2 = p * dig_P8 / 32768.0f;
    p = p + (var1 + var2 + dig_P7) / 16.0f;
    // println("DBG: Pressure = " + p + " Pa");
    return p;
  }

  protected float readHumidity() {
    // Returns the compensated humidity in percent
    int adc = readRawHumidity();
    float h = tFine - 76800.0f;
    h = (adc - (dig_H4 * 64.0f + dig_H5 / 16384.8f * h)) *
        (dig_H2 / 65536.0f * (1.0f + dig_H6 / 67108864.0f * h * (1.0f + dig_H3 / 67108864.0f * h)));
    h = h * (1.0f - dig_H1 * h / 524288.0f);
    if (h > 100) {
      h = 100;
    } else if (h < 0) {
      h = 0;
    }
    // println("DBG: Humidity = " + h);
    return h;
  }

  private void readCalibrationData() {
    // Reads the calibration data from the IC
    dig_T1 = readU16LE(BME280_REGISTER_DIG_T1);
    dig_T2 = readS16LE(BME280_REGISTER_DIG_T2);
    dig_T3 = readS16LE(BME280_REGISTER_DIG_T3);

    dig_P1 = readU16LE(BME280_REGISTER_DIG_P1);
    dig_P2 = readS16LE(BME280_REGISTER_DIG_P2);
    dig_P3 = readS16LE(BME280_REGISTER_DIG_P3);
    dig_P4 = readS16LE(BME280_REGISTER_DIG_P4);
    dig_P5 = readS16LE(BME280_REGISTER_DIG_P5);
    dig_P6 = readS16LE(BME280_REGISTER_DIG_P6);
    dig_P7 = readS16LE(BME280_REGISTER_DIG_P7);
    dig_P8 = readS16LE(BME280_REGISTER_DIG_P8);
    dig_P9 = readS16LE(BME280_REGISTER_DIG_P9);

    dig_H1 = readU8(BME280_REGISTER_DIG_H1);
    dig_H2 = readS16LE(BME280_REGISTER_DIG_H2);
    dig_H3 = readU8(BME280_REGISTER_DIG_H3);
    dig_H6 = readS8(BME280_REGISTER_DIG_H7);

    int h4 = readS8(BME280_REGISTER_DIG_H4);
    h4 = (h4 << 24) >> 20;
    dig_H4 = h4 | (readU8(BME280_REGISTER_DIG_H5) & 0x0F);

    int h5 = readS8(BME280_REGISTER_DIG_H6);
    h5 = (h5 << 24) >> 20;
    dig_H5 = h5 | (readU8(BME280_REGISTER_DIG_H5) >> 4 & 0x0F);
  }

  private String displayRegister(int reg) {
    return String.format("0x%s (%d)", lpad(Integer.toHexString(reg & 0xFFFF).toUpperCase(), 4, "0"), reg);
  }

  private void showCalibrationData() {
    // Displays the calibration values for debugging purposes
    println("======================");
    println("DBG: T1 = " + displayRegister(dig_T1));
    println("DBG: T2 = " + displayRegister(dig_T2));
    println("DBG: T3 = " + displayRegister(dig_T3));
    println("----------------------");
    println("DBG: P1 = " + displayRegister(dig_P1));
    println("DBG: P2 = " + displayRegister(dig_P2));
    println("DBG: P3 = " + displayRegister(dig_P3));
    println("DBG: P4 = " + displayRegister(dig_P4));
    println("DBG: P5 = " + displayRegister(dig_P5));
    println("DBG: P6 = " + displayRegister(dig_P6));
    println("DBG: P7 = " + displayRegister(dig_P7));
    println("DBG: P8 = " + displayRegister(dig_P8));
    println("DBG: P9 = " + displayRegister(dig_P9));
    println("----------------------");
    println("DBG: H1 = " + displayRegister(dig_H1));
    println("DBG: H2 = " + displayRegister(dig_H2));
    println("DBG: H3 = " + displayRegister(dig_H3));
    println("DBG: H4 = " + displayRegister(dig_H4));
    println("DBG: H5 = " + displayRegister(dig_H5));
    println("DBG: H6 = " + displayRegister(dig_H6));
    println("======================");
  }

  private void command(int reg, byte val) {
    super.beginTransmission(address);
    super.write(reg);
    super.write(val);
    super.endTransmission();
  }

  private int readRawTemp() {
    // Returns the raw (uncompensated) temperature
    int meas = mode;
    // println(String.format("readRawTemp: 1 - meas=%d", meas));
    command(BME280_REGISTER_CONTROL_HUM, (byte) meas); // HUM ?
    meas = mode << 5 | mode << 2 | 1;
    // println(String.format("readRawTemp: 2 - meas=%d", meas));
    command(BME280_REGISTER_CONTROL, (byte) meas);

    double sleepTime = 0.00125 + 0.0023 * (1 << mode);
    sleepTime = sleepTime + 0.0023 * (1 << mode) + 0.000575;
    sleepTime = sleepTime + 0.0023 * (1 << mode) + 0.000575;
    delay((int)Math.round(sleepTime * 1000));
    int msb = readU8(BME280_REGISTER_TEMP_DATA);
    int lsb = readU8(BME280_REGISTER_TEMP_DATA + 1);
    int xlsb = readU8(BME280_REGISTER_TEMP_DATA + 2);
    int raw = ((msb << 16) | (lsb << 8) | xlsb) >> 4;
    // println("DBG: Raw Temp: " + (raw & 0xFFFF) + ", " + raw + String.format(", msb: 0x%04X lsb: 0x%04X xlsb: 0x%04X", msb, lsb, xlsb));
    return raw;
  }

  private int readRawPressure() {
    // Returns the raw (uncompensated) pressure
    int msb = readU8(BME280_REGISTER_PRESSURE_DATA);
    int lsb = readU8(BME280_REGISTER_PRESSURE_DATA + 1);
    int xlsb = readU8(BME280_REGISTER_PRESSURE_DATA + 2);
    int raw = ((msb << 16) | (lsb << 8) | xlsb) >> 4;
    // println("DBG: Raw Press: " + (raw & 0xFFFF) + ", " + raw + String.format(", msb: 0x%04X lsb: 0x%04X xlsb: 0x%04X", msb, lsb, xlsb));
    return raw;
  }

  private int readRawHumidity() {
    // Returns the raw (uncompensated) humidity
    int msb = readU8(BME280_REGISTER_HUMIDITY_DATA);
    int lsb = readU8(BME280_REGISTER_HUMIDITY_DATA + 1);
    int raw = (msb << 8) | lsb;
    return raw;
  }

  private int readU16LE(int register) {
    super.beginTransmission(address);
    super.write((byte)register);
    byte[] ba = super.read(2);
    super.endTransmission();
    return ((ba[1] & 0xFF) << 8) + (ba[0] & 0xFF); // Little Endian
  }

  private int readS16LE(int register) {
    super.beginTransmission(address);
    super.write((byte)register);
    byte[] ba = super.read(2);
    super.endTransmission();

    int lo = ba[0] & 0xFF;
    int hi = ba[1] & 0xFF;
    if (hi > 127)
      hi -= 256;
    return (hi << 8) + lo; // Little Endian
  }

  private int readU8(int register) {
    super.beginTransmission(address);
    super.write(register);
    byte[] ba = super.read(1);
    super.endTransmission();
    return (int)(ba[0] & 0xFF);
  }

  private int readS8(int register) {
    int val = readU8(register);
    if (val > 127)
      val -= 256;
    return val;
  }

  private String rpad(String s, int len, String pad) {
    String str = s;
    while (str.length() < len) {
      str += pad;
    }
    return str;
  }

  private String lpad(String s, int len, String pad) {
    String str = s;
    while (str.length() < len) {
      str = pad + str;
    }
    return str;
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Geometry/Icosahedra/Dimension3D.pde
class Dimension3D{
   float w, h, d;

   Dimension3D(float w, float h, float d){
     this.w=w;
     this.h=h;
     this.d=d;
  }
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Visualization Code/HandWashing/Hand.pde

// -----------------------------
// HAND CLASS
// -----------------------------

class TheHand {

  PShape img;
  color c1;

  int deviceID;
  int xPos;
  int yPos;
  int xPos2;
  int yPos2;
  int prevX;
  int prevY;
  float xspeed;
  float rotation;
  int scale1;
  int scale2;
  int size1 = 50;
  int size2= 200;

  // Constructor
  TheHand(color tempC, int Xpos, int Ypos, int oldXpos, int oldYpos, String svgFile) {
    c1 = tempC;
    xPos = Xpos;
    yPos = Ypos;
    prevX = oldXpos;
    prevY = oldYpos;
    scale1 = int(random(size1, size2));
    scale2 = int(random(size1 + 50, size2 + 50));
    rotation = random(3);
    img = loadShape(svgFile);

  }

  void display() {
    pushMatrix(); pushStyle();

    img.disableStyle();
    translate(prevX, prevY);
    rotate(rotation);
    fill(c1);
    noStroke();
    shapeMode(CENTER);
    shape(img, 0, 0, scale1, scale1);

    popMatrix(); popStyle();
  }
} /* End of Class Hand */

// -----------------------------
// HAND FUNCTION
// -----------------------------

void drawHands() {
  pushMatrix(); pushStyle();

  for (int i = 0; i <= hands.size(); i++) {
    if ((i+1) == hands.size()) {
      tempHand = (TheHand)hands.get(i);
      tempHand.display();
      //tempHand.animate();
    }
    if (i < (hands.size()-1)){
      tempHand = (TheHand)hands.get(i);
      tempHand.display();
    }
  }

  popMatrix(); popStyle();
}
void growHand() {
  pushMatrix(); pushStyle();
  if(hands.size() != 0)
  {
    for (int i = 0; i < hands.size(); i++) {

      tempHand = (TheHand)hands.get(i);
        if(tempHand.scale1 < tempHand.scale2){
          tempHand.scale1 = tempHand.scale1 + 1;
       }
      }
  }

  popMatrix(); popStyle();
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Lights/Reflection/Reflection.pde
/**
 * Reflection
 * by <NAME>.
 *
 * Vary the specular reflection component of a material
 * with the horizontal position of the mouse.
 */

void setup() {
  size(640, 360, P3D);
  noStroke();
  colorMode(RGB, 1);
  fill(0.4);
}

void draw() {
  background(0);
  translate(width / 2, height / 2);
  // Set the specular color of lights that follow
  lightSpecular(1, 1, 1);
  directionalLight(0.8, 0.8, 0.8, 0, 0, -1);
  float s = mouseX / float(width);
  specular(s, s, s);
  sphere(120);
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Shaders/ImageMask/ImageMask.pde
/**
 * Image Mask
 *
 * Move the mouse to reveal the image through the dynamic mask.
 */

PShader maskShader;
PImage srcImage;
PGraphics maskImage;

void setup() {
  size(640, 360, P2D);
  srcImage = loadImage("leaves.jpg");
  maskImage = createGraphics(srcImage.width, srcImage.height, P2D);
  maskImage.noSmooth();
  maskShader = loadShader("mask.glsl");
  maskShader.set("mask", maskImage);
  background(255);
}

void draw() {
  maskImage.beginDraw();
  maskImage.background(0);
  if (mouseX != 0 && mouseY != 0) {
    maskImage.noStroke();
    maskImage.fill(255, 0, 0);
    maskImage.ellipse(mouseX, mouseY, 50, 50);
  }
  maskImage.endDraw();

  shader(maskShader);
  image(srcImage, 0, 0, width, height);
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/README.md
The examples without a credit line were written by <NAME> or <NAME> and they are in the public domain. <NAME>'s examples are in the public domain. We appreciate a link back to the original and/or an acknowledgement when they are used.  The copyrights for other credited files remains with the original authors.
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Image/BackgroundImage/BackgroundImage.pde
/**
 * Background Image.
 *
 * This example presents the fastest way to load a background image
 * into Processing. To load an image as the background, it must be
 * the same width and height as the program.
 */

PImage bg;
int y;

void setup() {
  size(640, 360);
  // The background image must be the same size as the parameters
  // into the size() method. In this program, the size of the image
  // is 640 x 360 pixels.
  bg = loadImage("moonwalk.jpg");
}

void draw() {
  background(bg);

  stroke(226, 204, 0);
  line(0, y, width, y);

  y++;
  if (y > height) {
    y = 0;
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Visualization Code/HandWashing/Graphics.pde

// -----------------------------
// GRAPHICS
// -----------------------------

void displayCount() {
  pushMatrix(); pushStyle();

  int currentCount = allHandsThisDay * 2;

  textFont(large);
  textAlign(LEFT);

  // Drop Shadow
  fill(dropShadowColor);
  text(currentCount + " CLEAN HANDS TODAY", textPositionX + 2, textPositionY + 2);

  // Text
  fill(textColor);
  text(currentCount + " CLEAN HANDS TODAY", textPositionX, textPositionY);

  popMatrix(); popStyle();
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Visualization Code/HandWashing/Splat.pde

// -----------------------------
// SPLAT CLASS
// -----------------------------

class TheSplat {

  PShape img;
  color c1;

  int deviceID;

  int xPos;
  int yPos;
  int prevX;
  int prevY;
  float rotation;
  int scale1 = 50;
  int scale2 = int(random(50, 150));

  // Constructor
  TheSplat(color tempC, int Xpos, int Ypos, int OldX, int OldY, String svgFile) {
    c1 = tempC;
    xPos = Xpos;
    yPos = Ypos;
    prevX = OldX;
    prevY = OldY;
    rotation = random(3);
    img = loadShape(svgFile);

  }

  void display() {
    pushMatrix(); pushStyle();

    img.disableStyle();
    translate(prevX, prevY);
    rotate(rotation);
    fill(c1);
    noStroke();
    shapeMode(CENTER);
    shape(img, 0, 0, scale1, scale1);

    popMatrix(); popStyle();
  }

} /* End of Class Splat */

// -----------------------------
// SPLAT FUNCTION
// -----------------------------

void drawSplatter() {
  pushMatrix(); pushStyle();
  if(splatter.size() != 0)
  {
  for (int i = 0; i < splatter.size(); i++) {

    tempSplat = (TheSplat)splatter.get(i);
    tempSplat.display();
  }
  }

  popMatrix(); popStyle();
}

void growSplat() {
  pushMatrix(); pushStyle();
  if(splatter.size() != 0)
  {
    for (int i = 0; i < splatter.size(); i++) {

      tempSplat = (TheSplat)splatter.get(i);
        if(tempSplat.scale1 < 250){
          tempSplat.scale1 = tempSplat.scale1 + 20;
       }
      }
  }

  popMatrix(); popStyle();
}

void checkSplatterTime() {

  if(splatter.size() == 0){
    splatterStart = millis();
  }
  if((millis() - splatterStart) >= 1000 ) {
    //
    splatterStart = millis();
    // Increase Second
    tempSplatSec ++;
    // Calculate Minute
    // Reset
    if (tempSplatSec >= maxTempSplatCount) {
      if(splatter.size() != 0){
        int removedSplatter = splatter.size();
        if(removedSplatter > 1){
          removedSplatter = removedSplatter / 2;
        }
        for(int i = 0; i < removedSplatter; i++){

          splatter.remove(i);
        }
        tempSplatSec = 0;
      }

    }

  }

}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/io/examples/AnalogDigital_I2C_ADS1X15/ADS1X15.pde
import processing.io.I2C;

// ADS1015 and ADS1115 are Analog-to-Digital converters using I2C
// they have four channels and 12 and 16 bits of resolution respectively
// datasheets: http://www.ti.com/lit/ds/symlink/ads1015.pdf
//             http://www.ti.com/lit/ds/symlink/ads1115.pdf

class ADS1015 extends ADS1X15 {
  ADS1015(String dev, int address) {
    super(dev, address);
    bitShift = 4;
    conversionDelay = 1;
  }

  // returns a number between -1.0 and 1.0
  float analogRead(int channel) {
    return readSingleEnded(channel) / 2047.0;
  }
}

class ADS1115 extends ADS1X15 {
  ADS1115(String dev, int address) {
    super(dev, address);
    bitShift = 0;
    conversionDelay = 8;
  }

  // returns a number between -1.0 and 1.0
  float analogRead(int channel) {
    return readSingleEnded(channel) / 32767.0;
  }
}

class ADS1X15 extends I2C {
  int address;
  int bitShift;         // bits to shift the result to the right
  int conversionDelay;  // in ms
  int channel;          // last channel used
  int range;            // see below

  // possible voltage ranges
  static final int INTERNAL_6V144 = 0;  // +/- 6.144V
  static final int INTERNAL_4V096 = 1;  // +/- 4.096V (library default)
  static final int INTERNAL_2V048 = 2;  // +/- 2.048V
  static final int INTERNAL_1V024 = 3;  // +/- 1.024V
  static final int INTERNAL_0V512 = 4;  // +/- 0.512V
  static final int INTERNAL_0V256 = 5;  // +/- 0.256V

  ADS1X15(String dev, int address) {
    super(dev);
    this.address = address;
    this.channel = -1;
    this.range = INTERNAL_4V096;
  }

  // be careful not to make the input voltage exceed VCC + 0.3V
  // this is regardless of the selected input range
  void analogReference(int type) {
    if (type < 0 || 7 < type) {
      throw new RuntimeException("Invalid range setting");
    }
    range = type;
  }

  int readSingleEnded(int channel) {
    if (channel < 0 || 3 < channel) {
      System.err.println("The channel needs to be from 0 to 3");
      throw new IllegalArgumentException("Unexpected channel");
    }

    if (channel != this.channel) {
      int config = 0x0183;                    // start with the default value from datasheet
      config &= ~0x100;                       // enable continuous readings
      config |= (range << 9);                 // set selected range (gain)
      config |= (1 << 14) | (channel << 12);  // set single-ended and channel
      config |= (1 << 15);                    // start a single conversion
      writeRegister(0x01, config);            // write to the configuration register at 0x01

      // when the channel switched we need to wait for the upcoming
      // conversion to finish
      delay(conversionDelay);

      // save the channel so that we don't need to do the same for
      // subsequent reads from the same channel
      this.channel = channel;
    }

    return readS16(0x00) >> bitShift;  // read from the conversion register at 0x00
    // the ADS1015 will have its 12-bit result in the upper bits, shift those right by four
  }

  protected void writeRegister(int register, int value) {
    beginTransmission(address);
    write(register);
    write(value >> 8);
    write(value & 0xFF);
    endTransmission();
  }

  protected int readS16(int register) {
    beginTransmission(address);
    write(register);
    byte[] in = read(2);
    return (in[0] << 8) | in[1];
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/src/processing/mode/java/pdex/JavaTextArea.java
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
Part of the Processing project - http://processing.org
Copyright (c) 2012-16 The Processing Foundation

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package processing.mode.java.pdex;

import java.awt.EventQueue;
import java.awt.Point;
import java.awt.event.ComponentListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.BitSet;
import java.util.Collections;
import java.util.List;

import javax.swing.DefaultListModel;
import javax.swing.SwingWorker;

import processing.app.Messages;
import processing.app.Platform;
import processing.app.syntax.PdeTextArea;
import processing.app.syntax.TextAreaDefaults;
import processing.mode.java.JavaEditor;
import processing.mode.java.JavaInputHandler;
import processing.mode.java.JavaMode;
import processing.mode.java.tweak.ColorControlBox;
import processing.mode.java.tweak.Handle;

/**
 * TextArea implementation for Java Mode. Primary differences from PdeTextArea
 * are completions, suggestions, and tweak handling.
 */
public class JavaTextArea extends PdeTextArea {
  private CompletionPanel suggestion;

  public JavaTextArea(TextAreaDefaults defaults, JavaEditor editor) {
    super(defaults, new JavaInputHandler(editor), editor);

    suggestionGenerator = new CompletionGenerator();

    tweakMode = false;
  }

  public JavaEditor getJavaEditor() {
    return (JavaEditor) editor;
  }

  @Override
  protected JavaTextAreaPainter createPainter(final TextAreaDefaults defaults) {
    return new JavaTextAreaPainter(this, defaults);
  }

  // used by Tweak Mode
  protected JavaTextAreaPainter getJavaPainter() {
    return (JavaTextAreaPainter) painter;
  }

  /**
   * Handles KeyEvents for TextArea (code completion begins from here).
   * TODO Needs explanation of why this implemented with an override
   *      of processKeyEvent() instead of using listeners.
   */
  @Override
  public void processKeyEvent(KeyEvent evt) {
    if (evt.getKeyCode() == KeyEvent.VK_ESCAPE) {
      if (suggestion != null){
        if (suggestion.isVisible()){
          Messages.log("ESC key");
          hideSuggestion();
          evt.consume();
          return;
        }
      }

    } else if (evt.getKeyCode() == KeyEvent.VK_ENTER &&
               evt.getID() == KeyEvent.KEY_PRESSED) {
      if (suggestion != null &&
          suggestion.isVisible() &&
          suggestion.insertSelection(CompletionPanel.KEYBOARD_COMPLETION)) {
        evt.consume();
        // Still try to show suggestions after inserting if it's
        // the case of overloaded methods. See #2755
        if (suggestion.isVisible()) {
          prepareSuggestions(evt);
        }
        return;
      }
    }

    if (evt.getID() == KeyEvent.KEY_PRESSED) {
      switch (evt.getKeyCode()) {
      case KeyEvent.VK_DOWN:
        if (suggestion != null)
          if (suggestion.isVisible()) {
            //log("KeyDown");
            suggestion.moveDown();
            return;
          }
        break;
      case KeyEvent.VK_UP:
        if (suggestion != null)
          if (suggestion.isVisible()) {
            //log("KeyUp");
            suggestion.moveUp();
            return;
          }
        break;
      case KeyEvent.VK_BACK_SPACE:
        Messages.log("BK Key");
        break;
      case KeyEvent.VK_SPACE:
        if (suggestion != null) {
          if (suggestion.isVisible()) {
            Messages.log("Space bar, hide completion list");
            suggestion.setInvisible();
          }
        }
        break;
      }
    }
    super.processKeyEvent(evt);

    // code completion disabled if Java tabs present
    if (!getJavaEditor().hasJavaTabs()) {
      if (evt.getID() == KeyEvent.KEY_TYPED) {
        processCompletionKeys(evt);
      } else if (!Platform.isMacOS() && evt.getID() == KeyEvent.KEY_RELEASED) {
        processCompletionKeys(evt);
      } else if (Platform.isMacOS() && evt.getID() == KeyEvent.KEY_RELEASED) {
        processControlSpace(evt);
      }
    }
  }

  // Special case for OS X, where Ctrl-Space is not detected as KEY_TYPED
  // https://github.com/processing/processing/issues/2699
  private void processControlSpace(final KeyEvent event) {
    if (event.getKeyCode() == KeyEvent.VK_SPACE && event.isControlDown()) {
      // Provide completions only if it's enabled
      if (JavaMode.codeCompletionsEnabled) {
        Messages.log("[KeyEvent]" + KeyEvent.getKeyText(event.getKeyCode()) + "  |Prediction started");
        fetchPhrase();
      }
    }
  }

  private void processCompletionKeys(final KeyEvent event) {
    char keyChar = event.getKeyChar();
    int keyCode = event.getKeyCode();
    if (keyChar == KeyEvent.VK_ENTER ||
        keyChar == KeyEvent.VK_ESCAPE ||
        keyChar == KeyEvent.VK_TAB ||
        (event.getID() == KeyEvent.KEY_RELEASED &&
            keyCode != KeyEvent.VK_LEFT && keyCode != KeyEvent.VK_RIGHT)) {
      // ignore
    } else if (keyChar == ')') {
      // https://github.com/processing/processing/issues/2741
      hideSuggestion();

    } else if (keyChar == '.') {
      if (JavaMode.codeCompletionsEnabled) {
        Messages.log("[KeyEvent]" + KeyEvent.getKeyText(event.getKeyCode()) + "  |Prediction started");
        fetchPhrase();
      }
    } else if (keyChar == ' ') { // Trigger on Ctrl-Space
      if (!Platform.isMacOS() && JavaMode.codeCompletionsEnabled &&
          (event.isControlDown() || event.isMetaDown())) {
        // Provide completions only if it's enabled
        if (JavaMode.codeCompletionsEnabled) {
          // Removed for https://github.com/processing/processing/issues/3847
          //try {
          //  getDocument().remove(getCaretPosition() - 1, 1); // Remove the typed space
          Messages.log("[KeyEvent]" + event.getKeyChar() + "  |Prediction started");
          fetchPhrase();
          //} catch (BadLocationException e) {
          //  e.printStackTrace();
          //}
        }
      } else {
        hideSuggestion(); // hide on spacebar
      }
    } else {
      if (JavaMode.codeCompletionsEnabled) {
        prepareSuggestions(event);
      }
    }
  }

  /** Kickstart auto-complete suggestions */
  private void prepareSuggestions(final KeyEvent evt) {
    // Provide completions only if it's enabled
    if (JavaMode.codeCompletionsEnabled &&
        (JavaMode.ccTriggerEnabled ||
        (suggestion != null && suggestion.isVisible()))) {
      Messages.log("[KeyEvent]" + evt.getKeyChar() + "  |Prediction started");
      fetchPhrase();
    }
  }

  CompletionGenerator suggestionGenerator;

  SwingWorker<Void, Void> suggestionWorker = null;

  volatile boolean suggestionRunning = false;
  volatile boolean suggestionRequested = false;

  /**
   * Retrieves the current word typed just before the caret.
   * Then triggers code completion for that word.
   * @param evt - the KeyEvent which triggered this method
   */
  protected void fetchPhrase() {
    if (suggestionRunning) {
      suggestionRequested = true;
      return;
    }

    suggestionRunning = true;
    suggestionRequested = false;

    final String text;
    final int caretLineIndex;
    final int caretLinePosition;
    {
      // Get caret position
      int caretPosition = getCaretPosition();
      if (caretPosition < 0) {
        suggestionRunning = false;
        return;
      }

      // Get line index
      caretLineIndex = getCaretLine();
      if (caretLineIndex < 0) {
        suggestionRunning = false;
        return;
      }

      // Get text of the line
      String lineText = getLineText(caretLineIndex);
      if (lineText == null) {
        suggestionRunning = false;
        return;
      }

      // Get caret position on the line
      caretLinePosition = getCaretPosition() - getLineStartOffset(caretLineIndex);
      if (caretLinePosition <= 0) {
        suggestionRunning = false;
        return;
      }

      // Get part of the line to the left of the caret
      if (caretLinePosition > lineText.length()) {
        suggestionRunning = false;
        return;
      }
      text = lineText.substring(0, caretLinePosition);
    }

    // Adjust line number for tabbed sketches
    //int codeIndex = editor.getSketch().getCodeIndex(getJavaEditor().getCurrentTab());
    int codeIndex = editor.getSketch().getCurrentCodeIndex();
    int lineStartOffset = editor.getTextArea().getLineStartOffset(caretLineIndex);

    getJavaEditor().getPreprocessingService().whenDone(ps -> {
      int lineNumber = ps.tabOffsetToJavaLine(codeIndex, lineStartOffset);

      String phrase = null;
      DefaultListModel<CompletionCandidate> defListModel = null;

      try {
        Messages.log("phrase parse start");
        phrase = parsePhrase(text);
        Messages.log("phrase: " + phrase);
        if (phrase != null) {
          List<CompletionCandidate> candidates;

          candidates = suggestionGenerator.preparePredictions(ps, phrase, lineNumber);

          if (!suggestionRequested) {

    //        // don't show completions when the outline is visible
    //        boolean showSuggestions =
    //          astGenerator.sketchOutline == null || !astGenerator.sketchOutline.isVisible();

    //        if (showSuggestions && phrase != null &&
            if (candidates != null && !candidates.isEmpty()) {
              Collections.sort(candidates);
              defListModel = CompletionGenerator.filterPredictions(candidates);
              Messages.log("Got: " + candidates.size() + " candidates, " + defListModel.size() + " filtered");
            }
          }

        }

        final String finalPhrase = phrase;
        final DefaultListModel<CompletionCandidate> finalDefListModel = defListModel;

        EventQueue.invokeLater(() -> {

          suggestionRunning = false;
          if (suggestionRequested) {
            Messages.log("completion invalidated");
            fetchPhrase();
            return;
          }

          Messages.log("completion finishing");

          if (finalDefListModel != null) {
            showSuggestion(finalDefListModel, finalPhrase);
          } else {
            hideSuggestion();
          }
        });
      } catch (Exception e) {
        Messages.loge("error while preparing suggestions", e);
      }
    });
  }

  protected static String parsePhrase(final String lineText) {
    boolean overloading = false;

    { // Check if we can provide suggestions for this phrase ending
      String trimmedLineText = lineText.trim();
      if (trimmedLineText.length() == 0) return null;

      char lastChar = trimmedLineText.charAt(trimmedLineText.length() - 1);
      if (lastChar == '.') {
        trimmedLineText = trimmedLineText.substring(0, trimmedLineText.length() - 1).trim();
        if (trimmedLineText.length() == 0) return null;
        lastChar = trimmedLineText.charAt(trimmedLineText.length() - 1);
        switch (lastChar) {
          case ')':
          case ']':
          case '"':
            break; // We can suggest for these
          default:
            if (!Character.isJavaIdentifierPart(lastChar)) {
              return null; // Not something we can suggest
            }
            break;
        }
      } else if (lastChar == '(') {
        overloading = true; // We can suggest overloaded methods
      } else if (!Character.isJavaIdentifierPart(lastChar)) {
        return null; // Not something we can suggest
      }
    }

    final int currentCharIndex = lineText.length() - 1;

    { // Check if the caret is in the comment
      int commentStart = lineText.indexOf("//", 0);
      if (commentStart >= 0 && currentCharIndex > commentStart) {
        return null;
      }
    }

    // Index the line
    BitSet isInLiteral = new BitSet(lineText.length());
    BitSet isInBrackets = new BitSet(lineText.length());

    { // Mark parts in literals
      boolean inString = false;
      boolean inChar = false;
      boolean inEscaped = false;

      for (int i = 0; i < lineText.length(); i++) {
        if (!inEscaped) {
          switch (lineText.charAt(i)) {
            case '\"':
              if (!inChar) inString = !inString;
              break;
            case '\'':
              if (!inString) inChar = !inChar;
              break;
            case '\\':
              if (inString || inChar) {
                inEscaped = true;
              }
              break;
          }
        } else {
          inEscaped = false;
        }
        isInLiteral.set(i, inString || inChar);
      }
    }

    if (isInLiteral.get(currentCharIndex)) return null;

    { // Mark parts in top level brackets
      int depth = overloading ? 1 : 0;
      int bracketStart = overloading ? lineText.length() : 0;
      int squareDepth = 0;
      int squareBracketStart = 0;

      bracketLoop: for (int i = lineText.length() - 1; i >= 0; i--) {
        if (!isInLiteral.get(i)) {
          switch (lineText.charAt(i)) {
            case ')':
              if (depth == 0) bracketStart = i;
              depth++;
              break;
            case '(':
              depth--;
              if (depth == 0) {
                isInBrackets.set(i, bracketStart);
              } else if (depth < 0) {
                break bracketLoop;
              }
              break;
            case ']':
              if (squareDepth == 0) squareBracketStart = i;
              squareDepth++;
              break;
            case '[':
              squareDepth--;
              if (squareDepth == 0) {
                isInBrackets.set(i, squareBracketStart);
              } else if (squareDepth < 0) {
                break bracketLoop;
              }
              break;
          }
        }
      }

      if (depth > 0) isInBrackets.set(0, bracketStart);
      if (squareDepth > 0) isInBrackets.set(0, squareBracketStart);
    }

    // Walk the line from the end while it makes sense
    int position = currentCharIndex;
    parseLoop: while (position >= 0) {
      int currChar = lineText.charAt(position);
      switch (currChar) {
        case '.': // Grab it
          position--;
          break;
        case '[':
          break parseLoop; // End of scope
        case ']': // Grab the whole region in square brackets
          position = isInBrackets.previousClearBit(position-1);
          break;
        case '(':
          if (isInBrackets.get(position)) {
            position--; // This checks for first bracket while overloading
            break;
          }
          break parseLoop; // End of scope
        case ')': // Grab the whole region in brackets
          position = isInBrackets.previousClearBit(position-1);
          break;
        case '"': // Grab the whole literal and quit
          position = isInLiteral.previousClearBit(position - 1);
          break parseLoop;
        default:
          if (Character.isJavaIdentifierPart(currChar)) {
            position--; // Grab the identifier
          } else if (Character.isWhitespace(currChar)) {
            position--; // Grab whitespace too
          } else {
            break parseLoop; // Got a char ending the phrase
          }
          break;
      }
    }

    position++;

    // Extract phrase
    String phrase = lineText.substring(position, lineText.length()).trim();
    Messages.log(phrase);

    if (phrase.length() == 0 || Character.isDigit(phrase.charAt(0))) {
      return null; // Can't suggest for numbers or empty phrases
    }
    return phrase;
  }

  /**
   * Calculates location of caret and displays the suggestion pop-up.
   */
  protected void showSuggestion(DefaultListModel<CompletionCandidate> listModel, String subWord) {
    // TODO can this be ListModel instead? why is size() in DefaultListModel
    // different from getSize() in ListModel (or are they, really?)
    hideSuggestion();

    if (listModel.size() != 0) {
      int position = getCaretPosition();
      try {
        Point location =
          new Point(offsetToX(getCaretLine(),
                              position - getLineStartOffset(getCaretLine())),
                    lineToY(getCaretLine()) + getPainter().getLineHeight());
        suggestion = new CompletionPanel(this, position, subWord,
                                         listModel, location, getJavaEditor());
        requestFocusInWindow();

      } catch (Exception e) {
        e.printStackTrace();
      }
    } else {
      Messages.log("TextArea: No suggestions to show.");
    }
  }

  /** Hides suggestion popup */
  public void hideSuggestion() {
    if (suggestion != null) {
      suggestion.setInvisible();
      //log("Suggestion hidden.");
      suggestion = null; // TODO: check if we dispose the window properly
    }
  }

  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

  // TWEAK MODE

  // save input listeners to stop/start text edit
  protected ComponentListener[] baseCompListeners;
  protected MouseListener[] baseMouseListeners;
  protected MouseMotionListener[] baseMotionListeners;
  protected KeyListener[] baseKeyListeners;
  protected boolean tweakMode;

  /* remove all standard interaction listeners */
  public void tweakRemoveListeners() {
    if (baseCompListeners == null) {
      // First time in tweak mode, grab the default listeners. Moved from the
      // constructor since not all listeners may have been added at that point.
      baseCompListeners = painter.getComponentListeners();
      baseMouseListeners = painter.getMouseListeners();
      baseMotionListeners = painter.getMouseMotionListeners();
      baseKeyListeners = editor.getKeyListeners();
    }
    ComponentListener[] componentListeners = painter.getComponentListeners();
    MouseListener[] mouseListeners = painter.getMouseListeners();
    MouseMotionListener[] mouseMotionListeners = painter.getMouseMotionListeners();
    KeyListener[] keyListeners = editor.getKeyListeners();

    for (ComponentListener cl : componentListeners) {
      painter.removeComponentListener(cl);
    }
    for (MouseListener ml : mouseListeners) {
      painter.removeMouseListener(ml);
    }
    for (MouseMotionListener mml : mouseMotionListeners) {
      painter.removeMouseMotionListener(mml);
    }
    for (KeyListener kl : keyListeners) {
      editor.removeKeyListener(kl);
    }
  }

  public void startTweakMode() {
    // ignore if we are already in interactiveMode
    if (!tweakMode) {
      tweakRemoveListeners();
      getJavaPainter().startTweakMode();
      this.editable = false;
      this.caretBlinks = false;
      this.setCaretVisible(false);
      tweakMode = true;
    }
  }

  public void stopTweakMode() {
    // ignore if we are not in interactive mode
    if (tweakMode) {
      tweakRemoveListeners();
      tweakRestoreBaseListeners();
      getJavaPainter().stopTweakMode();
      editable = true;
      caretBlinks = true;
      setCaretVisible(true);
      tweakMode = false;
    }
  }

  private void tweakRestoreBaseListeners() {
    // add the original text-edit listeners
    for (ComponentListener cl : baseCompListeners) {
      painter.addComponentListener(cl);
    }
    for (MouseListener ml : baseMouseListeners) {
      painter.addMouseListener(ml);
    }
    for (MouseMotionListener mml : baseMotionListeners) {
      painter.addMouseMotionListener(mml);
    }
    for (KeyListener kl : baseKeyListeners) {
      editor.addKeyListener(kl);
    }
  }

  public void updateInterface(List<List<Handle>> handles,
                              List<List<ColorControlBox>> colorBoxes) {
    getJavaPainter().updateTweakInterface(handles, colorBoxes);
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Shape/LoadDisplayOBJ/LoadDisplayOBJ.pde
/**
 * Load and Display an OBJ Shape.
 *
 * The loadShape() command is used to read simple SVG (Scalable Vector Graphics)
 * files and OBJ (Object) files into a Processing sketch. This example loads an
 * OBJ file of a rocket and displays it to the screen.
 */

PShape rocket;

float ry;

public void setup() {
  size(640, 360, P3D);

  rocket = loadShape("rocket.obj");
}

public void draw() {
  background(0);
  lights();

  translate(width/2, height/2 + 100, -200);
  rotateZ(PI);
  rotateY(ry);
  shape(rocket);

  ry += 0.02;
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Transform/Arm/Arm.pde
/**
 * Arm.
 *
 * The angle of each segment is controlled with the mouseX and
 * mouseY position. The transformations applied to the first segment
 * are also applied to the second segment because they are inside
 * the same pushMatrix() and popMatrix() group.
*/

float x, y;
float angle1 = 0.0;
float angle2 = 0.0;
float segLength = 100;

void setup() {
  size(640, 360);
  strokeWeight(30);
  stroke(255, 160);

  x = width * 0.3;
  y = height * 0.5;
}

void draw() {
  background(0);

  angle1 = (mouseX/float(width) - 0.5) * -PI;
  angle2 = (mouseY/float(height) - 0.5) * PI;

  pushMatrix();
  segment(x, y, angle1);
  segment(segLength, 0, angle2);
  popMatrix();
}

void segment(float x, float y, float a) {
  translate(x, y);
  rotate(a);
  line(0, 0, segLength, 0);
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Demos/Graphics/LowLevelGLVboInterleaved/LowLevelGLVboInterleaved.pde
// Draws a triangle using low-level OpenGL calls.

import java.nio.*;

PShader sh;

float[] attribs;

FloatBuffer attribBuffer;

int attribVboId;

final static int VERT_CMP_COUNT = 4; // vertex component count (x, y, z, w) -> 4
final static int CLR_CMP_COUNT = 4;  // color component count (r, g, b, a) -> 4

public void setup() {
  size(640, 360, P3D);

  // Loads a shader to render geometry w/out
  // textures and lights.
  sh = loadShader("frag.glsl", "vert.glsl");

  attribs = new float[24];
  attribBuffer = allocateDirectFloatBuffer(24);

  PGL pgl = beginPGL();

  IntBuffer intBuffer = IntBuffer.allocate(1);
  pgl.genBuffers(1, intBuffer);

  attribVboId = intBuffer.get(0);

  endPGL();
}

public void draw() {

  PGL pgl = beginPGL();

  background(0);

  // The geometric transformations will be automatically passed
  // to the shader.
  rotate(frameCount * 0.01f, width, height, 0);

  updateGeometry();
  sh.bind();

  // get "vertex" attribute location in the shader
  final int vertLoc = pgl.getAttribLocation(sh.glProgram, "vertex");
  // enable array for "vertex" attribute
  pgl.enableVertexAttribArray(vertLoc);

  // get "color" attribute location in the shader
  final int colorLoc = pgl.getAttribLocation(sh.glProgram, "color");
  // enable array for "color" attribute
  pgl.enableVertexAttribArray(colorLoc);

  /*
    BUFFER LAYOUT from updateGeometry()

    xyzwrgbaxyzwrgbaxyzwrgba...

    |v1       |v2       |v3       |...
    |0   |4   |8   |12  |16  |20  |...
    |xyzw|rgba|xyzw|rgba|xyzw|rgba|...

    stride (values per vertex) is 8 floats
    vertex offset is 0 floats (starts at the beginning of each line)
    color offset is 4 floats (starts after vertex coords)

       |0   |4   |8
    v1 |xyzw|rgba|
    v2 |xyzw|rgba|
    v3 |xyzw|rgba|
       |...
   */
  final int stride       = (VERT_CMP_COUNT + CLR_CMP_COUNT) * Float.BYTES;
  final int vertexOffset =                                0 * Float.BYTES;
  final int colorOffset  =                   VERT_CMP_COUNT * Float.BYTES;

  // bind VBO
  pgl.bindBuffer(PGL.ARRAY_BUFFER, attribVboId);
  // fill VBO with data
  pgl.bufferData(PGL.ARRAY_BUFFER, Float.BYTES * attribs.length, attribBuffer, PGL.DYNAMIC_DRAW);
  // associate currently bound VBO with "vertex" shader attribute
  pgl.vertexAttribPointer(vertLoc, VERT_CMP_COUNT, PGL.FLOAT, false, stride, vertexOffset);
  // associate currently bound VBO with "color" shader attribute
  pgl.vertexAttribPointer(colorLoc, CLR_CMP_COUNT, PGL.FLOAT, false, stride, colorOffset);
  // unbind VBO
  pgl.bindBuffer(PGL.ARRAY_BUFFER, 0);

  pgl.drawArrays(PGL.TRIANGLES, 0, 3);

  // disable arrays for attributes before unbinding the shader
  pgl.disableVertexAttribArray(vertLoc);
  pgl.disableVertexAttribArray(colorLoc);

  sh.unbind();

  endPGL();
}

// Triggers a crash when closing the output window using the close button
//public void dispose() {
//  PGL pgl = beginPGL();

//  IntBuffer intBuffer = IntBuffer.allocate(1);
//  intBuffer.put(attribVboId);
//  intBuffer.rewind();
//  pgl.deleteBuffers(1, intBuffer);

//  endPGL();
//}

void updateGeometry() {
  // Vertex 1
  attribs[0] = 0;
  attribs[1] = 0;
  attribs[2] = 0;
  attribs[3] = 1;

  // Color 1
  attribs[4] = 1;
  attribs[5] = 0;
  attribs[6] = 0;
  attribs[7] = 1;

  // Vertex 2
  attribs[8] = width/2;
  attribs[9] = height;
  attribs[10] = 0;
  attribs[11] = 1;

  // Color 2
  attribs[12] = 0;
  attribs[13] = 1;
  attribs[14] = 0;
  attribs[15] = 1;

  // Vertex 3
  attribs[16] = width;
  attribs[17] = 0;
  attribs[18] = 0;
  attribs[19] = 1;

  // Color 3
  attribs[20] = 0;
  attribs[21] = 0;
  attribs[22] = 1;
  attribs[23] = 1;

  attribBuffer.rewind();
  attribBuffer.put(attribs);
  attribBuffer.rewind();
}

FloatBuffer allocateDirectFloatBuffer(int n) {
  return ByteBuffer.allocateDirect(n * Float.BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer();
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Demos/Performance/StaticParticlesRetained/StaticParticlesRetained.pde
PShape particles;
PImage sprite;

int npartTotal = 50000;
float partSize = 20;

int fcount, lastm;
float frate;
int fint = 3;

void setup() {
  size(800, 600, P3D);
  frameRate(60);

  particles = createShape(PShape.GROUP);
  sprite = loadImage("sprite.png");

  for (int n = 0; n < npartTotal; n++) {
    float cx = random(-500, +500);
    float cy = random(-500, +500);
    float cz = random(-500, +500);

    PShape part = createShape();
    part.beginShape(QUAD);
    part.noStroke();
    part.tint(255);
    part.texture(sprite);
    part.normal(0, 0, 1);
    part.vertex(cx - partSize/2, cy - partSize/2, cz, 0, 0);
    part.vertex(cx + partSize/2, cy - partSize/2, cz, sprite.width, 0);
    part.vertex(cx + partSize/2, cy + partSize/2, cz, sprite.width, sprite.height);
    part.vertex(cx - partSize/2, cy + partSize/2, cz, 0, sprite.height);
    part.endShape();
    particles.addChild(part);
  }

  // Writing to the depth buffer is disabled to avoid rendering
  // artifacts due to the fact that the particles are semi-transparent
  // but not z-sorted.
  hint(DISABLE_DEPTH_MASK);
}

void draw () {
  background(0);

  translate(width/2, height/2);
  rotateY(frameCount * 0.01);

  shape(particles);

  fcount += 1;
  int m = millis();
  if (m - lastm > 1000 * fint) {
    frate = float(fcount) / fint;
    fcount = 0;
    lastm = m;
    println("fps: " + frate);
  }
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Motion/Reflection2/Orb.pde
class Orb {
  // Orb has positio and velocity
  PVector position;
  PVector velocity;
  float r;
  // A damping of 80% slows it down when it hits the ground
  float damping = 0.8;

  Orb(float x, float y, float r_) {
    position = new PVector(x, y);
    velocity = new PVector(.5, 0);
    r = r_;
  }

  void move() {
    // Move orb
    velocity.add(gravity);
    position.add(velocity);
  }

  void display() {
    // Draw orb
    noStroke();
    fill(200);
    ellipse(position.x, position.y, r*2, r*2);
  }

  // Check boundaries of window
  void checkWallCollision() {
    if (position.x > width-r) {
      position.x = width-r;
      velocity.x *= -damping;
    }
    else if (position.x < r) {
      position.x = r;
      velocity.x *= -damping;
    }
  }

  void checkGroundCollision(Ground groundSegment) {

    // Get difference between orb and ground
    float deltaX = position.x - groundSegment.x;
    float deltaY = position.y - groundSegment.y;

    // Precalculate trig values
    float cosine = cos(groundSegment.rot);
    float sine = sin(groundSegment.rot);

    /* Rotate ground and velocity to allow
     orthogonal collision calculations */
    float groundXTemp = cosine * deltaX + sine * deltaY;
    float groundYTemp = cosine * deltaY - sine * deltaX;
    float velocityXTemp = cosine * velocity.x + sine * velocity.y;
    float velocityYTemp = cosine * velocity.y - sine * velocity.x;

    /* Ground collision - check for surface
     collision and also that orb is within
     left/rights bounds of ground segment */
    if (groundYTemp > -r &&
      position.x > groundSegment.x1 &&
      position.x < groundSegment.x2 ) {
      // keep orb from going into ground
      groundYTemp = -r;
      // bounce and slow down orb
      velocityYTemp *= -1.0;
      velocityYTemp *= damping;
    }

    // Reset ground, velocity and orb
    deltaX = cosine * groundXTemp - sine * groundYTemp;
    deltaY = cosine * groundYTemp + sine * groundXTemp;
    velocity.x = cosine * velocityXTemp - sine * velocityYTemp;
    velocity.y = cosine * velocityYTemp + sine * velocityXTemp;
    position.x = groundSegment.x + deltaX;
    position.y = groundSegment.y + deltaY;
  }
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/io/examples/Servo_I2C_PCA9685/Servo_I2C_PCA9685.pde
import processing.io.*;
PCA9685 servos;

// see setup.png in the sketch folder for wiring details

void setup() {
  size(400, 300);
  //printArray(I2C.list());
  servos = new PCA9685("i2c-1", 0x40);

  // different servo motors will vary in the pulse width they expect
  // the lines below set the pulse width for 0 degrees to 544 microseconds (μs)
  //                 and the pulse width for 180 degrees to 2400 microseconds
  // these values match the defaults of the Servo library on Arduino
  // but you might need to modify this for your particular servo still
  servos.attach(0, 544, 2400);
  servos.attach(1, 544, 2400);
}

void draw() {
  background(0);
  stroke(255);
  strokeWeight(3);

  // we don't go right to the edge to prevent
  // making the servo unhappy
  float angle = 90 + sin(frameCount / 100.0)*85;
  servos.write(0, angle);
  float y = map(angle, 0, 180, 0, height);
  line(0, y, width/2, y);

  angle = 90 + cos(frameCount / 100.0)*85;
  servos.write(1, 90 + cos(frameCount / 100.0)*85);
  y = map(angle, 0, 180, 0, height);
  line(width/2, y, width, y);
}

void dispose() {
  servos.detach(0);
  servos.detach(1);
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Demos/Graphics/Ribbons/PDB.pde
void readPDB(String filename) {
  String strLines[];

  float xmin, xmax, ymin, ymax, zmin, zmax;

  String xstr, ystr, zstr;
  float x, y, z;
  int res, res0;
  int nmdl;
  String atstr, resstr;

  PShape model;
  ArrayList atoms;
  ArrayList residues;
  HashMap residue;
  PVector v;
  String s;
  strLines = loadStrings(filename);

  models = new ArrayList();

  xmin = ymin = zmin = 10000;
  xmax = ymax = zmax = -10000;

  atoms = null;
  residues = null;
  residue = null;
  model = null;
  res0 = -1;
  nmdl = -1;
  for (int i = 0; i < strLines.length; i++) {
    s = strLines[i];

    if (s.startsWith("MODEL") || (s.startsWith("ATOM") && res0 == -1)) {
      nmdl++;

      res0 = -1;

      atoms = new ArrayList();
      residues = new ArrayList();
    }

    if (s.startsWith("ATOM")) {
      atstr = s.substring(12, 15);
      atstr = atstr.trim();
      resstr = s.substring(22, 26);
      resstr = resstr.trim();
      res = parseInt(resstr);

      xstr = s.substring(30, 37);
      xstr = xstr.trim();
      ystr = s.substring(38, 45);
      ystr = ystr.trim();
      zstr = s.substring(46, 53);
      zstr = zstr.trim();

      x = scaleFactor * parseFloat(xstr);
      y = scaleFactor * parseFloat(ystr);
      z = scaleFactor * parseFloat(zstr);
      v = new PVector(x, y, z);

      xmin = min(xmin, x);
      xmax = max(xmax, x);

      ymin = min(ymin, y);
      ymax = max(ymax, y);

      zmin = min(zmin, z);
      zmax = max(zmax, z);

      atoms.add(v);

      if (res0 != res) {
        if (residue != null) residues.add(residue);
        residue = new HashMap();
      }
      residue.put(atstr, v);

      res0 = res;
    }

    if (s.startsWith("ENDMDL") || s.startsWith("TER")) {
      if (residue != null) residues.add(residue);

      createRibbonModel(residues, model, models);
      float rgyr = calculateGyrRadius(atoms);

      res0 = -1;
      residue = null;
      atoms = null;
      residues = null;
    }
  }

  if (residue != null) {
    if (residue != null) residues.add(residue);

    createRibbonModel(residues, model, models);
    float rgyr = calculateGyrRadius(atoms);

    atoms = null;
    residues = null;
  }

  // Centering models at (0, 0, 0).
  float dx = -0.5f * (xmin + xmax);
  float dy = -0.5f * (ymin + ymax);
  float dz = -0.5f * (zmin + zmax);
  for (int n = 0; n < models.size(); n++) {
    model = (PShape) models.get(n);
    model.translate(dx, dy, dz);
  }

  println("Loaded PDB file with " + models.size() + " models.");
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Shaders/Nebula/Nebula.pde
/**
 * Nebula.
 *
 * From CoffeeBreakStudios.com (CBS)
 * Ported from the webGL version in GLSL Sandbox:
 * http://glsl.heroku.com/e#3265.2
 */

PShader nebula;

void setup() {
  size(640, 360, P2D);
  noStroke();

  nebula = loadShader("nebula.glsl");
  nebula.set("resolution", float(width), float(height));
}

void draw() {
  nebula.set("time", millis() / 500.0);
  shader(nebula);
  // This kind of raymarching effects are entirely implemented in the
  // fragment shader, they only need a quad covering the entire view
  // area so every pixel is pushed through the shader.
  rect(0, 0, width, height);
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Typography/Words/Words.pde
/**
 * Words.
 *
 * The text() function is used for writing words to the screen.
 * The letters can be aligned left, center, or right with the
 * textAlign() function.
 */

PFont f;

void setup() {
  size(640, 360);

  // Create the font
  printArray(PFont.list());
  f = createFont("SourceCodePro-Regular.ttf", 24);
  textFont(f);
}

void draw() {
  background(102);
  textAlign(RIGHT);
  drawType(width * 0.25);
  textAlign(CENTER);
  drawType(width * 0.5);
  textAlign(LEFT);
  drawType(width * 0.75);
}

void drawType(float x) {
  line(x, 0, x, 65);
  line(x, 220, x, height);
  fill(0);
  text("ichi", x, 95);
  fill(51);
  text("ni", x, 130);
  fill(204);
  text("san", x, 165);
  fill(255);
  text("shi", x, 210);
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/serial/test/serial_latency/serial_latency.pde
// Arduino Duemilanove (168) on OS X 10.9
// with either 115200 or 38400 bps
// on Processing 2.0.3 (cu & tty): 24 ms avg, 35 ms max
// on Processing 2.1b1 (cu & tty): 18 ms avg, 35 ms max

import processing.serial.*;
Serial serial;
int start;
byte out = '@';
int last_send = 0;
byte[] in = new byte[32768];
long num_fail = 0;
long num_recv = 0;
int max_latency = 0;

void setup() {
  println(serial.list());
  // change this accordingly
  serial = new Serial(this, serial.list()[0], 115200);
  start = millis();
}

void draw() {
  background(255);
  if (0 < serial.available()) {
    int recv = serial.readBytes(in);
    for (int i=0; i < recv; i++) {
      if (in[i] == out) {
        num_recv++;
        int now = millis();
        if (max_latency < now-last_send) {
          max_latency = now-last_send;
        }
        last_send = 0;
      }
    }
  }
  if (last_send != 0 && 1000 < millis()-last_send) {
    num_fail++;
    last_send = 0;
    println(num_fail+" bytes timed out");
  }
  if (last_send == 0) {
    if (out == 'Z') {
      out = '@';
    }
    serial.write(++out);
    last_send = millis();
  }
  fill(0);
  text(((millis()-start)/(float)num_recv+" ms avg"), 0, height/2);
  text(max_latency+" ms max", 0, height/2+20);
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/serial/examples/SerialDuplex/SerialDuplex.pde
/**
 * Serial Duplex
 * by <NAME>.
 *
 * Sends a byte out the serial port when you type a key
 * listens for bytes received, and displays their value.
 * This is just a quick application for testing serial data
 * in both directions.
 */

import processing.serial.*;

Serial myPort;      // The serial port
int whichKey = -1;  // Variable to hold keystoke values
int inByte = -1;    // Incoming serial data

void setup() {
  size(400, 300);
  // create a font with the third font available to the system:
  PFont myFont = createFont(PFont.list()[2], 14);
  textFont(myFont);

  // List all the available serial ports:
  printArray(Serial.list());

  // I know that the first port in the serial list on my mac
  // is always my  FTDI adaptor, so I open Serial.list()[0].
  // In Windows, this usually opens COM1.
  // Open whatever port is the one you're using.
  String portName = Serial.list()[0];
  myPort = new Serial(this, portName, 9600);
}

void draw() {
  background(0);
  text("Last Received: " + inByte, 10, 130);
  text("Last Sent: " + whichKey, 10, 100);
}

void serialEvent(Serial myPort) {
  inByte = myPort.read();
}

void keyPressed() {
  // Send the keystroke out:
  myPort.write(key);
  whichKey = key;
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Shaders/InfiniteTiles/InfiniteTiles.pde
//-------------------------------------------------------------
// Display endless moving background using a tile texture.
// Contributed by martiSteiger
//-------------------------------------------------------------

PImage tileTexture;
PShader tileShader;

void setup() {
  size(640, 480, P2D);
  textureWrap(REPEAT);
  tileTexture = loadImage("penrose.jpg");
  loadTileShader();
}

void loadTileShader() {
  tileShader = loadShader("scroller.glsl");
  tileShader.set("resolution", float(width), float(height));
  tileShader.set("tileImage", tileTexture);
}

void draw() {
  tileShader.set("time", millis() / 1000.0);
  shader(tileShader);
  rect(0, 0, width, height);
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Curves/ArcLengthParametrization/ArcLengthParametrization.pde
/*
  Arc Length parametrization of curves by <NAME>

  This example shows how to divide a curve into segments
  of an equal length and how to move along the curve with
  constant speed.

  To demonstrate the technique, a cubic Bézier curve is used.
  However, this technique is applicable to any kind of
  parametric curve.
*/

BezierCurve curve;

PVector[] points;
PVector[] equidistantPoints;

float t = 0.0;
float tStep = 0.004;

final int POINT_COUNT = 80;

int borderSize = 40;

void setup() {
  size(640, 360, P2D);

  frameRate(60);
  smooth(8);
  textAlign(CENTER);
  textSize(16);
  strokeWeight(2);

  PVector a = new PVector(   0, 300);
  PVector b = new PVector( 440,   0);
  PVector c = new PVector(-200,   0);
  PVector d = new PVector( 240, 300);

  curve = new BezierCurve(a, b, c, d);

  points = curve.points(POINT_COUNT);
  equidistantPoints = curve.equidistantPoints(POINT_COUNT);
}

void draw() {

  // Show static value when mouse is pressed, animate otherwise
  if (mousePressed) {
    int a = constrain(mouseX, borderSize, width - borderSize);
    t = map(a, borderSize, width - borderSize, 0.0, 1.0);
  } else {
    t += tStep;
    if (t > 1.0) t = 0.0;
  }

  background(255);

  // draw curve and circle using standard parametrization
  pushMatrix();
    translate(borderSize, -50);

    labelStyle();
    text("STANDARD\nPARAMETRIZATION", 120, 310);

    curveStyle();
    beginShape(LINES);
      for (int i = 0; i < points.length - 1; i += 2) {
        vertex(points[i].x, points[i].y);
        vertex(points[i+1].x, points[i+1].y);
      }
    endShape();

    circleStyle();
    PVector pos1 = curve.pointAtParameter(t);
    ellipse(pos1.x, pos1.y, 12, 12);

  popMatrix();

  // draw curve and circle using arc length parametrization
  pushMatrix();
    translate(width/2 + borderSize, -50);

    labelStyle();
    text("ARC LENGTH\nPARAMETRIZATION", 120, 310);

    curveStyle();
    beginShape(LINES);
      for (int i = 0; i < equidistantPoints.length - 1; i += 2) {
        vertex(equidistantPoints[i].x, equidistantPoints[i].y);
        vertex(equidistantPoints[i+1].x, equidistantPoints[i+1].y);
      }
    endShape();

    circleStyle();
    PVector pos2 = curve.pointAtFraction(t);
    ellipse(pos2.x, pos2.y, 12, 12);

  popMatrix();

  // draw seek bar
  pushMatrix();
    translate(borderSize, height - 45);

    int barLength = width - 2 * borderSize;

    barBgStyle();
    line(0, 0, barLength, 0);
    line(barLength, -5, barLength, 5);

    barStyle();
    line(0, -5, 0, 5);
    line(0, 0, t * barLength, 0);

    barLabelStyle();
    text(nf(t, 0, 2), barLength/2, 25);
  popMatrix();

}

// Styles -----

void curveStyle() {
  stroke(170);
  noFill();
}

void labelStyle() {
  noStroke();
  fill(120);
}

void circleStyle() {
  noStroke();
  fill(0);
}

void barBgStyle() {
  stroke(220);
  noFill();
}

void barStyle() {
  stroke(50);
  noFill();
}

void barLabelStyle() {
  noStroke();
  fill(120);
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Advanced Data/XMLYahooWeather/XMLYahooWeather.pde
/**
 * Loading XML Data
 * by <NAME>.
 *
 * This example demonstrates how to use loadXML()
 * to retrieve data from an XML document via a URL
 */

// We're going to store the temperature
int temperature = 0;
// We're going to store text about the weather
String weather = "";

// Yahoo weather uses something called A WOEID (Where On Earth IDentifier)
// https://en.wikipedia.org/wiki/WOEID
// This is the WOEID for zip code 10003
String zip = "10003";
String woeid = "12761335";

PFont font;

void setup() {
  size(600, 360);

  font = createFont("Merriweather-Light.ttf", 28);
  textFont(font);

  // The URL for the XML document
  String url = "http://query.yahooapis.com/v1/public/yql?format=xml&q=select+*+from+weather.forecast+where+woeid=" + woeid + "+and+u='F'";

  // Load the XML document
  XML xml = loadXML(url);

  // Grab the element we want
  XML forecast = xml.getChild("results/channel/item/yweather:forecast");

  // Get the attributes we want
  temperature = forecast.getInt("high");
  weather = forecast.getString("text");
}

void draw() {
  background(255);
  fill(0);

  // Display all the stuff we want to display
  text("Zip: " + zip, width*0.15, height*0.33);
  text("Today’s high: " + temperature + "°F", width*0.15, height*0.5);
  text("Forecast: " + weather, width*0.15, height*0.66);

}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Arrays/Array2D/Array2D.pde
/**
 * Array 2D.
 *
 * Demonstrates the syntax for creating a two-dimensional (2D) array.
 * Values in a 2D array are accessed through two index values.
 * 2D arrays are useful for storing images. In this example, each dot
 * is colored in relation to its distance from the center of the image.
 */

float[][] distances;
float maxDistance;
int spacer;

void setup() {
  size(640, 360);
  maxDistance = dist(width/2, height/2, width, height);
  distances = new float[width][height];
  for (int y = 0; y < height; y++) {
    for (int x = 0; x < width; x++) {
      float distance = dist(width/2, height/2, x, y);
      distances[x][y] = distance/maxDistance * 255;
    }
  }
  spacer = 10;
  strokeWeight(6);
  noLoop();  // Run once and stop
}

void draw() {
  background(0);
  // This embedded loop skips over values in the arrays based on
  // the spacer variable, so there are more values in the array
  // than are drawn here. Change the value of the spacer variable
  // to change the density of the points
  for (int y = 0; y < height; y += spacer) {
    for (int x = 0; x < width; x += spacer) {
      stroke(distances[x][y]);
      point(x + spacer/2, y + spacer/2);
    }
  }
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Form/Primitives3D/Primitives3D.pde
/**
 * Primitives 3D.
 *
 * Placing mathematically 3D objects in synthetic space.
 * The lights() method reveals their imagined dimension.
 * The box() and sphere() functions each have one parameter
 * which is used to specify their size. These shapes are
 * positioned using the translate() function.
 */

size(640, 360, P3D);
background(0);
lights();

noStroke();
pushMatrix();
translate(130, height/2, 0);
rotateY(1.25);
rotateX(-0.4);
box(100);
popMatrix();

noFill();
stroke(255);
pushMatrix();
translate(500, height*0.35, -200);
sphere(280);
popMatrix();

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/io/examples/DigitalAnalog_I2C_MCP4725/MCP4725.pde
import processing.io.I2C;

// MCP4725 is a Digital-to-Analog converter using I2C
// datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/22039d.pdf

class MCP4725 extends I2C {
  int address;

  // there can be more than one device connected to the bus
  // as long as they have different addresses
  MCP4725(String dev, int address) {
    super(dev);
    this.address = address;
  }

  // outputs voltages from 0V to the supply voltage
  // (works with 3.3V and 5V)
  void setAnalog(float fac) {
    fac = constrain(fac, 0.0, 1.0);
    // convert to 12 bit value
    int val = int(4095 * fac);
    beginTransmission(address);
    write(val >> 8);
    write(val & 255);
    endTransmission();
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Image/Pointillism/Pointillism.pde
/**
 * Pointillism
 * by <NAME>.
 *
 * Mouse horizontal location controls size of dots.
 * Creates a simple pointillist effect using ellipses colored
 * according to pixels in an image.
 */

PImage img;
int smallPoint, largePoint;

void setup() {
  size(640, 360);
  img = loadImage("moonwalk.jpg");
  smallPoint = 4;
  largePoint = 40;
  imageMode(CENTER);
  noStroke();
  background(255);
}

void draw() {
  float pointillize = map(mouseX, 0, width, smallPoint, largePoint);
  int x = int(random(img.width));
  int y = int(random(img.height));
  color pix = img.get(x, y);
  fill(pix, 128);
  ellipse(x, y, pointillize, pointillize);
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/pdf/library.properties
name = PDF Export
version = 1
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/src/antlr/TokenStreamCopyingHiddenTokenFilter.java
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */

package antlr;

import antlr.collections.impl.BitSet;

/**
 * This class provides TokenStreamHiddenTokenFilters with the concept of
 * tokens which can be copied so that they are seen by both the hidden token
 * stream as well as the parser itself.  This is useful when one wants to use
 * an existing parser (like the Java parser included with ANTLR) that throws
 * away some tokens to create a parse tree which can be used to spit out
 * a copy of the code with only minor modifications.
 *
 * This code is partially derived from the public domain ANLTR TokenStream
 */
public class TokenStreamCopyingHiddenTokenFilter
  extends TokenStreamHiddenTokenFilter
  implements TokenStream {

  protected BitSet copyMask;
  CommonHiddenStreamToken hiddenCopy = null;

  public TokenStreamCopyingHiddenTokenFilter(TokenStream input) {
    super(input);
    copyMask = new BitSet();
  }

  /**
   * Indicate that all tokens of type tokenType should be copied.  The copy
   * is put in the stream of hidden tokens, and the original is returned in the
   * stream of normal tokens.
   *
   * @param tokenType   integer representing the token type to copied
   */
  public void copy(int tokenType) {
    copyMask.add(tokenType);
  }

  /**
   * Create a clone of the important parts of the given token.  Note that this
   * does NOT copy the hiddenBefore and hiddenAfter fields.
   *
   * @param t   token to partially clone
   * @return    newly created partial clone
   */
  public CommonHiddenStreamToken partialCloneToken(CommonHiddenStreamToken t) {

    CommonHiddenStreamToken u = new CommonHiddenStreamToken(t.getType(),
                                                            t.getText());
    u.setColumn(t.getColumn());
    u.setLine(t.getLine());
    u.setFilename(t.getFilename());

    return u;
  }

  public void linkAndCopyToken(CommonHiddenStreamToken prev,
                               CommonHiddenStreamToken monitored) {
    // create a copy of the token in the lookahead for use as hidden token
    hiddenCopy = partialCloneToken(LA(1));

    // attach copy to the previous token, whether hidden or monitored
    prev.setHiddenAfter(hiddenCopy);

    // if previous token was hidden, set the hiddenBefore pointer of the
    // copy to point back to it
    if (prev != monitored) {
      hiddenCopy.setHiddenBefore(prev);
    }

    // we don't want the non-hidden copy to link back to the hidden
    // copy on the next pass through this function, so we leave
    // lastHiddenToken alone

    //System.err.println("hidden copy: " + hiddenCopy.toString());

    return;
  }

  private void consumeFirst() throws TokenStreamException {
    consume(); // get first token of input stream

    // Handle situation where hidden or discarded tokens
    // appear first in input stream
    CommonHiddenStreamToken p=null;

    // while hidden, copied, or discarded scarf tokens
    while ( hideMask.member(LA(1).getType()) ||
            discardMask.member(LA(1).getType()) ||
            copyMask.member(LA(1).getType()) ) {

      // if we've hit one of the tokens that needs to be copied, we copy it
      // and then break out of the loop, because the parser needs to see it
      // too
      //
      if (copyMask.member(LA(1).getType())) {

        // copy the token in the lookahead
        hiddenCopy = partialCloneToken(LA(1));

        // if there's an existing token before this, link that and the
        // copy together
        if (p != null) {
          p.setHiddenAfter(hiddenCopy);
          hiddenCopy.setHiddenBefore(p); // double-link
        }

        lastHiddenToken = hiddenCopy;
        if (firstHidden == null) {
          firstHidden = hiddenCopy;
        }

        // we don't want to consume this token, because it also needs to
        // be passed through to the parser, so break out of the while look
        // entirely
        //
        break;
      } else if (hideMask.member(LA(1).getType())) {
        if (p != null) {
          p.setHiddenAfter(LA(1));
          LA(1).setHiddenBefore(p); // double-link
        }
        p = LA(1);

        lastHiddenToken = p;
        if (firstHidden == null) {
          firstHidden = p; // record hidden token if first
        }
      }
      consume();
    }
  }

  /** Return the next monitored token.
   *  Test the token following the monitored token.
   *  If following is another monitored token, save it
   *  for the next invocation of nextToken (like a single
   *  lookahead token) and return it then.
   *  If following is unmonitored, nondiscarded (hidden)
   *  channel token, add it to the monitored token.
   *
   *  Note: EOF must be a monitored Token.
   */
  public Token nextToken() throws TokenStreamException {
    // handle an initial condition; don't want to get lookahead
    // token of this splitter until first call to nextToken
    if (LA(1) == null) {
      consumeFirst();
    }

    //System.err.println();

    // we always consume hidden tokens after monitored, thus,
    // upon entry LA(1) is a monitored token.
    CommonHiddenStreamToken monitored = LA(1);

    // point to hidden tokens found during last invocation
    monitored.setHiddenBefore(lastHiddenToken);
    lastHiddenToken = null;

    // Look for hidden tokens, hook them into list emanating
    // from the monitored tokens.
    consume();
    CommonHiddenStreamToken prev = monitored;

    // deal with as many not-purely-monitored tokens as possible
    while ( hideMask.member(LA(1).getType()) ||
            discardMask.member(LA(1).getType()) ||
            copyMask.member(LA(1).getType()) ) {

      if (copyMask.member(LA(1).getType())) {

        // copy the token and link it backwards
        if (hiddenCopy != null) {
          linkAndCopyToken(hiddenCopy, monitored);
        } else {
          linkAndCopyToken(prev, monitored);
        }

        // we now need to parse it as a monitored token, so we return, which
        // avoids the consume() call at the end of this loop.  the next call
        // will parse it as a monitored token.
        //System.err.println("returned: " + monitored.toString());
        return monitored;

      } else if (hideMask.member(LA(1).getType())) {

        // attach the hidden token to the monitored in a chain
        // link forwards
        prev.setHiddenAfter(LA(1));

        // link backwards
        if (prev != monitored) { //hidden cannot point to monitored tokens
          LA(1).setHiddenBefore(prev);
        } else if (hiddenCopy != null) {
          hiddenCopy.setHiddenAfter(LA(1));
          LA(1).setHiddenBefore(hiddenCopy);
          hiddenCopy = null;
        }

        //System.err.println("hidden: " + prev.getHiddenAfter().toString() + "\" after: " + prev.toString());
        prev = lastHiddenToken = LA(1);
      }

      consume();
    }

    // remember the last hidden token for next time around
    if (hiddenCopy != null) {
      lastHiddenToken = hiddenCopy;
      hiddenCopy = null;
    }

    //System.err.println("returned: " + monitored.toString());
    return monitored;
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Create Shapes/PolygonPShapeOOP/Star.pde
// A class to describe a Star shape

class Star {

  // The PShape object
  PShape s;
  // The location where we will draw the shape
  float x, y;
  float speed;

  Star() {
    x = random(100, width-100);
    y = random(100, height-100);
    speed = random(0.5, 3);
    // First create the shape
    s = createShape();
    s.beginShape();
    // You can set fill and stroke
    s.fill(255, 204);
    s.noStroke();
    // Here, we are hardcoding a series of vertices
    s.vertex(0, -50);
    s.vertex(14, -20);
    s.vertex(47, -15);
    s.vertex(23, 7);
    s.vertex(29, 40);
    s.vertex(0, 25);
    s.vertex(-29, 40);
    s.vertex(-23, 7);
    s.vertex(-47, -15);
    s.vertex(-14, -20);
    // The shape is complete
    s.endShape(CLOSE);
  }

  void move() {
    // Demonstrating some simple motion
    x += speed;
    if (x > width+100) {
      x = -100;
    }
  }

  void display() {
    // Locating and drawing the shape
    pushMatrix();
    translate(x, y);
    shape(s);
    popMatrix();
  }
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Fractals and L-Systems/PenroseSnowflake/LSystem.pde
class LSystem
{
  int steps = 0;

  String axiom;
  String rule;
  String production;

  float startLength;
  float drawLength;
  float theta;

  int generations;

  LSystem() {
    axiom = "F";
    rule = "F+F-F";
    startLength = 90.0;
    theta = radians(120.0);
    reset();
  }

  void reset() {
    production = axiom;
    drawLength = startLength;
    generations = 0;
  }

  int getAge() {
    return generations;
  }

  void render() {
    translate(width/2, height/2);
    steps += 5;
    if (steps > production.length()) {
      steps = production.length();
    }
    for (int i = 0; i < steps; i++) {
      char step = production.charAt(i);
      if (step == 'F') {
        rect(0, 0, -drawLength, -drawLength);
        noFill();
        translate(0, -drawLength);
      }
      else if (step == '+') {
        rotate(theta);
      }
      else if (step == '-') {
        rotate(-theta);
      }
      else if (step == '[') {
        pushMatrix();
      }
      else if (step == ']') {
        popMatrix();
      }
    }
  }

  void simulate(int gen) {
    while (getAge() < gen) {
      production = iterate(production, rule);
    }
  }

  String iterate(String prod_, String rule_) {
    drawLength = drawLength * 0.6;
    generations++;
    String newProduction = prod_;
    newProduction = newProduction.replaceAll("F", rule_);
    return newProduction;
  }
}

<file_sep>/Data and System Management/app/models.py
from . import db
import datetime
from sqlalchemy import DateTime

class Pump(db.Model):
    __tablename__ = 'pumps'
    id = db.Column(db.Integer, primary_key=True)
    payload = db.Column(db.String)
    location = db.Column(db.String)
    volt = db.Column(db.Integer)

    def __repr__(self):
        return str(self.payload)

class Trigger(db.Model):
    __tablename__ = 'trigger'
    id = db.Column(db.Integer, primary_key=True)
    datetime = db.Column(DateTime, default=datetime.datetime.now)
    pump = db.Column(db.String)

    def __repr__(self):
        return str(self.datetime)
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/io/examples/AnalogDigital_SPI_MCP3008/MCP3008.pde
import processing.io.SPI;

// MCP3008 is a Analog-to-Digital converter using SPI
// other than the MCP3001, this has 8 input channels
// datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/21295d.pdf

class MCP3008 extends SPI {

  MCP3008(String dev) {
    super(dev);
    settings(500000, SPI.MSBFIRST, SPI.MODE0);
  }

  // returns a number between 0.0 and 1.0
  float analogRead(int channel) {
    if (channel < 0 ||  7 < channel) {
      System.err.println("The channel needs to be from 0 to 7");
      throw new IllegalArgumentException("Unexpected channel");
    }
    byte[] out = { 0, 0, 0 };
    // encode the channel number in the first byte
    out[0] = (byte)(0x18 | channel);
    byte[] in = transfer(out);
    int val = ((in[1] & 0x03) << 8) | (in[2] & 0xff);
    // val is between 0 and 1023
    return val/1023.0;
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Geometry/SpaceJunk/SpaceJunk.pde
/**
 * Space Junk
 * by <NAME> (zoom suggestion by <NAME>).
 *
 * Rotating cubes in space using a custom Cube class.
 * Color controlled by light sources. Move the mouse left
 * and right to zoom.
 */

// Used for oveall rotation
float angle;

// Cube count-lower/raise to test performance
int limit = 500;

// Array for all cubes
Cube[] cubes = new Cube[limit];

void setup() {
  size(640, 360, P3D);
  background(0);
  noStroke();

  // Instantiate cubes, passing in random vals for size and postion
  for (int i = 0; i < cubes.length; i++){
    cubes[i] = new Cube(int(random(-10, 10)), int(random(-10, 10)),
                        int(random(-10, 10)), int(random(-140, 140)),
                        int(random(-140, 140)), int(random(-140, 140)));
  }
}

void draw(){
  background(0);
  fill(200);

  // Set up some different colored lights
  pointLight(51, 102, 255, 65, 60, 100);
  pointLight(200, 40, 60, -65, -60, -150);

  // Raise overall light in scene
  ambientLight(70, 70, 10);

  // Center geometry in display windwow.
  // you can changlee 3rd argument ('0')
  // to move block group closer(+) / further(-)
  translate(width/2, height/2, -200 + mouseX * 0.65);

  // Rotate around y and x axes
  rotateY(radians(angle));
  rotateX(radians(angle));

  // Draw cubes
  for (int i = 0; i < cubes.length; i++){
    cubes[i].drawCube();
  }

  // Used in rotate function calls above
  angle += 0.2;
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/pdf/examples/MousePress/MousePress.pde
 /**
 * Mouse Press.
 *
 * Saves one PDF of the contents of the display window
 * each time the mouse is pressed.
 */

import processing.pdf.*;

boolean saveOneFrame = false;

void setup() {
  size(600, 600);
  frameRate(24);
}

void draw() {
  if(saveOneFrame == true) {
    beginRecord(PDF, "Line.pdf");
  }

  background(255);
  stroke(0, 20);
  strokeWeight(20.0);
  line(mouseX, 0, width-mouseY, height);

  if(saveOneFrame == true) {
    endRecord();
    saveOneFrame = false;
  }
}

void mousePressed() {
  saveOneFrame = true;
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Cellular Automata/Wolfram/CA.pde
class CA {

  int[] cells;     // An array of 0s and 1s
  int generation;  // How many generations?
  int scl;         // How many pixels wide/high is each cell?

  int[] rules;     // An array to store the ruleset, for example {0,1,1,0,1,1,0,1}

  CA(int[] r) {
    rules = r;
    scl = 1;
    cells = new int[width/scl];
    restart();
  }

  // Set the rules of the CA
  void setRules(int[] r) {
    rules = r;
  }

  // Make a random ruleset
  void randomize() {
    for (int i = 0; i < 8; i++) {
      rules[i] = int(random(2));
    }
  }

  // Reset to generation 0
  void restart() {
    for (int i = 0; i < cells.length; i++) {
      cells[i] = 0;
    }
    cells[cells.length/2] = 1;    // We arbitrarily start with just the middle cell having a state of "1"
    generation = 0;
  }

  // The process of creating the new generation
  void generate() {
    // First we create an empty array for the new values
    int[] nextgen = new int[cells.length];
    // For every spot, determine new state by examing current state, and neighbor states
    // Ignore edges that only have one neighor
    for (int i = 1; i < cells.length-1; i++) {
      int left = cells[i-1];   // Left neighbor state
      int me = cells[i];       // Current state
      int right = cells[i+1];  // Right neighbor state
      nextgen[i] = executeRules(left,me,right); // Compute next generation state based on ruleset
    }
    // Copy the array into current value
    for (int i = 1; i < cells.length-1; i++) {
      cells[i] = nextgen[i];
    }
    //cells = (int[]) nextgen.clone();
    generation++;
  }

  // This is the easy part, just draw the cells, fill 255 for '1', fill 0 for '0'
  void render() {
    for (int i = 0; i < cells.length; i++) {
      if (cells[i] == 1) {
        fill(255);
      } else {
        fill(0);
      }
      noStroke();
      rect(i*scl,generation*scl, scl,scl);
    }
  }

  // Implementing the Wolfram rules
  // Could be improved and made more concise, but here we can explicitly see what is going on for each case
  int executeRules (int a, int b, int c) {
    if (a == 1 && b == 1 && c == 1) { return rules[0]; }
    if (a == 1 && b == 1 && c == 0) { return rules[1]; }
    if (a == 1 && b == 0 && c == 1) { return rules[2]; }
    if (a == 1 && b == 0 && c == 0) { return rules[3]; }
    if (a == 0 && b == 1 && c == 1) { return rules[4]; }
    if (a == 0 && b == 1 && c == 0) { return rules[5]; }
    if (a == 0 && b == 0 && c == 1) { return rules[6]; }
    if (a == 0 && b == 0 && c == 0) { return rules[7]; }
    return 0;
  }

  // The CA is done if it reaches the bottom of the screen
  boolean finished() {
    if (generation > height/scl) {
       return true;
    } else {
       return false;
    }
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Image Processing/Extrusion/Extrusion.pde
/**
 * Extrusion.
 *
 * Converts a flat image into spatial data points and rotates the points
 * around the center.
 */

PImage a;
boolean onetime = true;
int[][] aPixels;
int[][] values;
float angle;

void setup() {
  size(640, 360, P3D);

  aPixels = new int[width][height];
  values = new int[width][height];
  noFill();

  // Load the image into a new array
  // Extract the values and store in an array
  a = loadImage("ystone08.jpg");
  a.loadPixels();
  for (int i = 0; i < a.height; i++) {
    for (int j = 0; j < a.width; j++) {
      aPixels[j][i] = a.pixels[i*a.width + j];
      values[j][i] = int(blue(aPixels[j][i]));
    }
  }
}

void draw() {
  background(0);
  translate(width/2, height/2, -height/2);
  scale(2.0);

  // Update and constrain the angle
  angle += 0.005;
  rotateY(angle);

  // Display the image mass
  for (int i = 0; i < a.height; i += 4) {
    for (int j = 0; j < a.width; j += 4) {
      stroke(values[j][i], 255);
      line(j-a.width/2, i-a.height/2, -values[j][i], j-a.width/2, i-a.height/2, -values[j][i]-10);
    }
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Demos/Graphics/LowLevelGLVboSeparate/LowLevelGLVboSeparate.pde
// Draws a triangle using low-level OpenGL calls.

import java.nio.*;

PShader sh;

float[] vertices;
float[] colors;

FloatBuffer vertexBuffer;
FloatBuffer colorBuffer;

int vertexVboId;
int colorVboId;

final static int VERT_CMP_COUNT = 4; // vertex component count (x, y, z, w) -> 4
final static int CLR_CMP_COUNT = 4;  // color component count (r, g, b, a) -> 4

public void setup() {
  size(640, 360, P3D);

  // Loads a shader to render geometry w/out
  // textures and lights.
  sh = loadShader("frag.glsl", "vert.glsl");

  vertices = new float[12];
  colors = new float[12];

  vertexBuffer = allocateDirectFloatBuffer(12);
  colorBuffer = allocateDirectFloatBuffer(12);

  PGL pgl = beginPGL();

  // allocate buffer big enough to get all VBO ids back
  IntBuffer intBuffer = IntBuffer.allocate(2);
  pgl.genBuffers(2, intBuffer);

  vertexVboId = intBuffer.get(0);
  colorVboId = intBuffer.get(1);

  endPGL();
}

public void draw() {

  PGL pgl = beginPGL();

  background(0);

  // The geometric transformations will be automatically passed
  // to the shader.
  rotate(frameCount * 0.01f, width, height, 0);

  updateGeometry();
  sh.bind();

  // get "vertex" attribute location in the shader
  final int vertLoc = pgl.getAttribLocation(sh.glProgram, "vertex");
  // enable array for "vertex" attribute
  pgl.enableVertexAttribArray(vertLoc);

  // get "color" attribute location in the shader
  final int colorLoc = pgl.getAttribLocation(sh.glProgram, "color");
  // enable array for "color" attribute
  pgl.enableVertexAttribArray(colorLoc);

  /*
    BUFFER LAYOUT from updateGeometry()

    Vertex buffer:

      xyzwxyzwxyzw...

      |v1  |v2  |v3  |...
      |0   |4   |8   |...
      |xyzw|xyzw|xyzw|...

    Color buffer:

      rgbargbargba...

      |v1  |v2  |v3  |...
      |0   |4   |8   |...
      |rgba|rgba|rgba|...

    stride (values per vertex) is 4 floats in both cases
    vertex offset is 0 floats in both cases
   */
  final int vertexStride = VERT_CMP_COUNT * Float.BYTES;
  final int colorStride  =  CLR_CMP_COUNT * Float.BYTES;
  final int vertexOffset =              0 * Float.BYTES;
  final int colorOffset  =              0 * Float.BYTES;

  { // VERTEX
    // bind VBO
    pgl.bindBuffer(PGL.ARRAY_BUFFER, vertexVboId);
    // fill VBO with data
    pgl.bufferData(PGL.ARRAY_BUFFER, Float.BYTES * vertices.length, vertexBuffer, PGL.DYNAMIC_DRAW);
    // associate currently bound VBO with shader attribute
    pgl.vertexAttribPointer(vertLoc, VERT_CMP_COUNT, PGL.FLOAT, false, vertexStride, vertexOffset);
  }

  { // COLOR
    // bind VBO
    pgl.bindBuffer(PGL.ARRAY_BUFFER, colorVboId);
    // fill bound VBO with data
    pgl.bufferData(PGL.ARRAY_BUFFER, Float.BYTES * colors.length, colorBuffer, PGL.DYNAMIC_DRAW);
    // associate currently bound VBO with shader attribute
    pgl.vertexAttribPointer(colorLoc, CLR_CMP_COUNT, PGL.FLOAT, false, colorStride, colorOffset);
  }

  // unbind VBOs
  pgl.bindBuffer(PGL.ARRAY_BUFFER, 0);

  pgl.drawArrays(PGL.TRIANGLES, 0, 3);

  // disable arrays for attributes before unbinding the shader
  pgl.disableVertexAttribArray(vertLoc);
  pgl.disableVertexAttribArray(colorLoc);

  sh.unbind();

  endPGL();
}

// Triggers a crash when closing the output window using the close button
//public void dispose() {
//  PGL pgl = beginPGL();

//  IntBuffer intBuffer = IntBuffer.allocate(2);
//  intBuffer.put(vertexVboId);
//  intBuffer.put(colorVboId);
//  intBuffer.rewind();
//  pgl.deleteBuffers(2, intBuffer);

//  endPGL();
//}

void updateGeometry() {
  // Vertex 1
  vertices[0] = 0;
  vertices[1] = 0;
  vertices[2] = 0;
  vertices[3] = 1;

  colors[0] = 1;
  colors[1] = 0;
  colors[2] = 0;
  colors[3] = 1;

  // Vertex 2
  vertices[4] = width/2;
  vertices[5] = height;
  vertices[6] = 0;
  vertices[7] = 1;

  colors[4] = 0;
  colors[5] = 1;
  colors[6] = 0;
  colors[7] = 1;

  // Vertex 3
  vertices[8] = width;
  vertices[9] = 0;
  vertices[10] = 0;
  vertices[11] = 1;

  colors[8] = 0;
  colors[9] = 0;
  colors[10] = 1;
  colors[11] = 1;

  vertexBuffer.rewind();
  vertexBuffer.put(vertices);
  vertexBuffer.rewind();

  colorBuffer.rewind();
  colorBuffer.put(colors);
  colorBuffer.rewind();
}

FloatBuffer allocateDirectFloatBuffer(int n) {
  return ByteBuffer.allocateDirect(n * Float.BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer();
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Transform/Scale/Scale.pde
/**
 * Scale
 * by <NAME>.
 *
 * Paramenters for the scale() function are values specified
 * as decimal percentages. For example, the method call scale(2.0)
 * will increase the dimension of the shape by 200 percent.
 * Objects always scale from the origin.
 */

float a = 0.0;
float s = 0.0;

void setup() {
  size(640, 360);
  noStroke();
  rectMode(CENTER);
  frameRate(30);
}

void draw() {

  background(102);

  a = a + 0.04;
  s = cos(a)*2;

  translate(width/2, height/2);
  scale(s);
  fill(51);
  rect(0, 0, 50, 50);

  translate(75, 0);
  fill(255);
  scale(s);
  rect(0, 0, 50, 50);
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Advanced Data/ArrayListClass/ArrayListClass.pde
/**
 * ArrayList of objects
 * by <NAME>.
 *
 * This example demonstrates how to use a Java ArrayList to store
 * a variable number of objects.  Items can be added and removed
 * from the ArrayList.
 *
 * Click the mouse to add bouncing balls.
 */

ArrayList<Ball> balls;
int ballWidth = 48;

void setup() {
  size(640, 360);
  noStroke();

  // Create an empty ArrayList (will store Ball objects)
  balls = new ArrayList<Ball>();

  // Start by adding one element
  balls.add(new Ball(width/2, 0, ballWidth));
}

void draw() {
  background(255);

  // With an array, we say balls.length, with an ArrayList, we say balls.size()
  // The length of an ArrayList is dynamic
  // Notice how we are looping through the ArrayList backwards
  // This is because we are deleting elements from the list
  for (int i = balls.size()-1; i >= 0; i--) {
    // An ArrayList doesn't know what it is storing so we have to cast the object coming out
    Ball ball = balls.get(i);
    ball.move();
    ball.display();
    if (ball.finished()) {
      // Items can be deleted with remove()
      balls.remove(i);
    }

  }

}

void mousePressed() {
  // A new ball object is added to the ArrayList (by default to the end)
  balls.add(new Ball(mouseX, mouseY, ballWidth));
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Demos/Graphics/MeshTweening/data/vert.glsl
uniform mat4 transformMatrix;
uniform float tween;

attribute vec4 position;
attribute vec4 tweened;
attribute vec4 color;

varying vec4 vertColor;

void main() {
  gl_Position = transformMatrix * ((1.0 - tween) * position + tween * tweened);

  vertColor = color;
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/File IO/SaveFile1/SaveFile1.pde
/**
 * SaveFile 1
 *
 * Saving files is a useful way to store data so it can be viewed after a
 * program has stopped running. The saveStrings() function writes an array
 * of strings to a file, with each string written to a new line. This file
 * is saved to the sketch's folder.
 */

int[] x = new int[0];
int[] y = new int[0];

void setup()
{
  size(200, 200);
}

void draw()
{
  background(204);
  stroke(0);
  noFill();
  beginShape();
  for (int i = 0; i < x.length; i++) {
    vertex(x[i], y[i]);
  }
  endShape();
  // Show the next segment to be added
  if (x.length >= 1) {
    stroke(255);
    line(mouseX, mouseY, x[x.length-1], y[x.length-1]);
  }
}

void mousePressed() { // Click to add a line segment
  x = append(x, mouseX);
  y = append(y, mouseY);
}

void keyPressed() { // Press a key to save the data
  String[] lines = new String[x.length];
  for (int i = 0; i < x.length; i++) {
    lines[i] = x[i] + "\t" + y[i];
  }
  saveStrings("lines.txt", lines);
  exit(); // Stop the program
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/pdf/examples/ManyPDFs/ManyPDFs.pde
/**
 * Many PDFs.
 *
 * Saves one PDF file each each frame while the mouse is pressed.
 * When the mouse is released, the PDF creation stops.
 */

import processing.pdf.*;

boolean savePDF = false;

void setup() {
  size(600, 600);
  frameRate(24);
}

void draw() {
  if(savePDF == true) {
    beginRecord(PDF, "lines" + frameCount + ".pdf");
  }
  background(255);
  stroke(0, 20);
  strokeWeight(20.0);
  line(mouseX, 0, width-mouseY, height);
  if(savePDF == true) {
    endRecord();
  }
}

void mousePressed() {
  savePDF = true;
}

void mouseReleased() {
  savePDF = false;
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Structure/Coordinates/Coordinates.pde
/**
 * Coordinates.
 *
 * All shapes drawn to the screen have a position that is
 * specified as a coordinate. All coordinates are measured
 * as the distance from the origin in units of pixels.
 * The origin [0, 0] is the coordinate is in the upper left
 * of the window and the coordinate in the lower right is
 * [width-1, height-1].
 */

// Sets the screen to be 640 pixels wide and 360 pixels high
size(640, 360);

// Set the background to black and turn off the fill color
background(0);
noFill();

// The two parameters of the point() method each specify coordinates.
// The first parameter is the x-coordinate and the second is the Y
stroke(255);
point(width * 0.5, height * 0.5);
point(width * 0.5, height * 0.25);

// Coordinates are used for drawing all shapes, not just points.
// Parameters for different functions are used for different purposes.
// For example, the first two parameters to line() specify
// the coordinates of the first endpoint and the second two parameters
// specify the second endpoint
stroke(0, 153, 255);
line(0, height*0.33, width, height*0.33);

// By default, the first two parameters to rect() are the
// coordinates of the upper-left corner and the second pair
// is the width and height
stroke(255, 153, 0);
rect(width*0.25, height*0.1, width * 0.5, height * 0.8);
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/io/examples/Display_I2C_SSD1306/SSD1306.pde
import processing.io.I2C;

// SSD1306 is a small, inexpensive 128x64 pixels monochrome OLED display
// available online as "0.96" 128x64 OLED display", SKU 346540
// or from Adafruit
// datasheet: https://www.adafruit.com/datasheets/SSD1306.pdf

class SSD1306 extends I2C {
  int address;

  // there can be more than one device connected to the bus
  // as long as they have different addresses
  SSD1306(String dev, int address) {
    super(dev);
    this.address = address;
    init();
  }

  protected void init() {
    writeCommand(0xae);         // turn display off
    writeCommand(0xa8, 0x3f);   // set multiplex ratio to the highest setting
    writeCommand(0x8d, 0x14);   // enable charge pump
    writeCommand(0x20, 0x00);   // set memory addressing mode to horizontal
    writeCommand(0xd5, 0x80);   // set display clock divide ratio & oscillator frequency to default
    writeCommand(0xd3, 0x00);   // no display offset
    writeCommand(0x40 | 0x00);  // set default display start line

    // use the following two lines to flip the display
    writeCommand(0xa0 | 0x01);  // set segment re-map
    writeCommand(0xc8);         // set COM output scan direction

    writeCommand(0xda, 0x12);   // set COM pins hardware configuration
    writeCommand(0xd9, 0xf1);   // set pre-charge period to 241x DCLK
    writeCommand(0xdB, 0x40);   // set VCOMH deselect level
    writeCommand(0xa4);         // display RAM content (not all-on)
    writeCommand(0xa6);         // set normal (not-inverted) display

    // set this since we don't have access to the OLED's reset pins (?)
    writeCommand(0x21, 0, 127); // set column address
    writeCommand(0x22, 0, 7);   // set page address

    writeCommand(0x81, 0xcf);   // set contrast
    writeCommand(0x2e);         // deactivate scroll
    writeCommand(0xaf);         // turn display on
  }

  void invert(boolean inverted) {
    if (inverted) {
      writeCommand(0xa7);
    } else {
      writeCommand(0xa6);
    }
  }

  void sendImage(PImage img) {
    sendImage(img, 0, 0);
  }

  void sendImage(PImage img, int startX, int startY) {
    byte[] frame = new byte[1024];
    img.loadPixels();
    for (int y=startY; y < height && y-startY < 64; y++) {
      for (int x=startX; x < width && x-startX < 128; x++) {
        if (128 <= brightness(img.pixels[y*img.width+x])) {
          // this isn't the normal (scanline) mapping, but 8 pixels below each other at a time
          // white pixels have their bit turned on
          frame[x + (y/8)*128] |= (1 << (y % 8));
        }
      }
    }
    sendFramebuffer(frame);
  }

  void sendFramebuffer(byte[] buf) {
    if (buf.length != 1024) {
      System.err.println("The framebuffer should be 1024 bytes long, with one bit per pixel");
      throw new IllegalArgumentException("Unexpected buffer size");
    }

    writeCommand(0x00 | 0x0); // set start address
    writeCommand(0x10 | 0x0); // set higher column start address
    writeCommand(0x40 | 0x0); // set start line

    // send the frame buffer as 16 byte long packets
    for (int i=0; i < buf.length/16; i++) {
      super.beginTransmission(address);
      super.write(0x40);  // indicates data write
      for (int j=0; j < 16; j++) {
        super.write(buf[i*16+j]);
      }
      super.endTransmission();
    }
  }

  protected void writeCommand(int arg1) {
    super.beginTransmission(address);
    super.write(0x00);    // indicates command write
    super.write(arg1);
    super.endTransmission();
  }

  protected void writeCommand(int arg1, int arg2) {
    super.beginTransmission(address);
    super.write(0x00);
    super.write(arg1);
    super.write(arg2);
    super.endTransmission();
  }

  protected void writeCommand(int arg1, int arg2, int arg3) {
    super.beginTransmission(address);
    super.write(0x00);
    super.write(arg1);
    super.write(arg2);
    super.write(arg3);
    super.endTransmission();
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Transform/RotatePushPop/RotatePushPop.pde
/**
 * Rotate Push Pop.
 *
 * The push() and pop() functions allow for more control over transformations.
 * The push function saves the current coordinate system to the stack
 * and pop() restores the prior coordinate system.
 */

float a;                 // Angle of rotation
float offset = PI/24.0;  // Angle offset between boxes
int num = 12;            // Number of boxes

void setup() {
  size(640, 360, P3D);
  noStroke();
}

void draw() {

  lights();

  background(0, 0, 26);
  translate(width/2, height/2);

  for(int i = 0; i < num; i++) {
    float gray = map(i, 0, num-1, 0, 255);
    pushMatrix();
    fill(gray);
    rotateY(a + offset*i);
    rotateX(a/2 + offset*i);
    box(200);
    popMatrix();
  }

  a += 0.01;
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Shaders/Deform/Deform.pde
/**
 * Deform.
 *
 * A GLSL version of the oldschool 2D deformation effect, by <NAME>.
 * Ported from the webGL version available in ShaderToy:
 * http://www.iquilezles.org/apps/shadertoy/
 * (Look for Deform under the Plane Deformations Presets)
 *
 */

PImage tex;
PShader deform;

void setup() {
  size(640, 360, P2D);

  textureWrap(REPEAT);
  tex = loadImage("tex1.jpg");

  deform = loadShader("deform.glsl");
  deform.set("resolution", float(width), float(height));
}

void draw() {
  deform.set("time", millis() / 1000.0);
  deform.set("mouse", float(mouseX), float(mouseY));
  shader(deform);
  image(tex, 0, 0, width, height);
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Geometry/Vertices/Vertices.pde
/**
 * Vertices
 * by <NAME>.
 *
 * Draw a cylinder centered on the y-axis, going down
 * from y=0 to y=height. The radius at the top can be
 * different from the radius at the bottom, and the
 * number of sides drawn is variable.
 */

void setup() {
  size(640, 360, P3D);
}

void draw() {
  background(0);
  lights();
  translate(width / 2, height / 2);
  rotateY(map(mouseX, 0, width, 0, PI));
  rotateZ(map(mouseY, 0, height, 0, -PI));
  noStroke();
  fill(255, 255, 255);
  translate(0, -40, 0);
  drawCylinder(10, 180, 200, 16); // Draw a mix between a cylinder and a cone
  //drawCylinder(70, 70, 120, 64); // Draw a cylinder
  //drawCylinder(0, 180, 200, 4); // Draw a pyramid
}

void drawCylinder(float topRadius, float bottomRadius, float tall, int sides) {
  float angle = 0;
  float angleIncrement = TWO_PI / sides;
  beginShape(QUAD_STRIP);
  for (int i = 0; i < sides + 1; ++i) {
    vertex(topRadius*cos(angle), 0, topRadius*sin(angle));
    vertex(bottomRadius*cos(angle), tall, bottomRadius*sin(angle));
    angle += angleIncrement;
  }
  endShape();

  // If it is not a cone, draw the circular top cap
  if (topRadius != 0) {
    angle = 0;
    beginShape(TRIANGLE_FAN);

    // Center point
    vertex(0, 0, 0);
    for (int i = 0; i < sides + 1; i++) {
      vertex(topRadius * cos(angle), 0, topRadius * sin(angle));
      angle += angleIncrement;
    }
    endShape();
  }

  // If it is not a cone, draw the circular bottom cap
  if (bottomRadius != 0) {
    angle = 0;
    beginShape(TRIANGLE_FAN);

    // Center point
    vertex(0, tall, 0);
    for (int i = 0; i < sides + 1; i++) {
      vertex(bottomRadius * cos(angle), tall, bottomRadius * sin(angle));
      angle += angleIncrement;
    }
    endShape();
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Visualization Code/HandWashing/Germs.pde
// -----------------------------
// GERMS
// -----------------------------

boolean useGerms;

void CreateGermArray(){
    for(int i = 0; i < germSize; i++){

    int prevX = newX;
    int prevY = newY;

    float upperXlimit = width * 0.95;
    float lowerXlimit = width * 0.05;
    float upperYlimit = height * 0.85;
    float lowerYlimit = height * 0.15;
    newX = round(random(lowerXlimit, upperXlimit));
    newY = round(random(lowerYlimit, upperYlimit));

    int germSVGNumber = int(random(0,6));
    hands.add(new TheHand(paletteGerms[germSVGNumber], newX, newY, prevX, prevY, germs[int(random(0,12))]));
    }
}

void AddGerm(){

      int prevX = newX;
      int prevY = newY;

      float upperXlimit = width * 0.95;
      float lowerXlimit = width * 0.05;
      float upperYlimit = height * 0.85;
      float lowerYlimit = height * 0.15;
      newX = round(random(lowerXlimit, upperXlimit));
      newY = round(random(lowerYlimit, upperYlimit));

      int germSVGNumber = int(random(0,6));
      hands.add(new TheHand(paletteGerms[germSVGNumber], newX, newY, prevX, prevY, germs[int(random(0,12))]));
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/mode/readme.txt
Packages from Eclipse 4.5.2:
http://download.eclipse.org/eclipse/downloads/

File listing at:
http://download.eclipse.org/eclipse/updates/4.5/R-4.5.2-201602121500/plugins/?d

The jdtCompilerAdapter.jar is extracted from org.eclipse.jdt.core.jar to provide
the JDTCompilerAdapter class, which is the Ant task for the JDT compiler.
The jdi.jar and jdimodel.jar files are unpacked from org.eclipse.jdt.debug.jar.

This Mode does not use ecj.jar from the original Java mode, because its files are contained in the JARs below.

For 3.0 alpha 11, the signature files were removed from oorg.eclipse.jdt.core.jar to fix a signing conflict with Android Mode and Ant.
https://github.com/processing/processing/pull/3324

. . .

http://download.eclipse.org/eclipse/updates/4.5/R-4.5.2-201602121500/plugins/com.ibm.icu_54.1.1.v201501272100.jar

http://download.eclipse.org/eclipse/updates/4.5/R-4.5.2-201602121500/plugins/org.eclipse.core.contenttype_3.5.0.v20150421-2214.jar

http://download.eclipse.org/eclipse/updates/4.5/R-4.5.2-201602121500/plugins/org.eclipse.core.jobs_3.7.0.v20150330-2103.jar

http://download.eclipse.org/eclipse/updates/4.5/R-4.5.2-201602121500/plugins/org.eclipse.core.resources_3.10.1.v20150725-1910.jar

http://download.eclipse.org/eclipse/updates/4.5/R-4.5.2-201602121500/plugins/org.eclipse.core.runtime_3.11.1.v20150903-1804.jar

http://download.eclipse.org/eclipse/updates/4.5/R-4.5.2-201602121500/plugins/org.eclipse.equinox.common_3.7.0.v20150402-1709.jar

http://download.eclipse.org/eclipse/updates/4.5/R-4.5.2-201602121500/plugins/org.eclipse.equinox.preferences_3.5.300.v20150408-1437.jar

http://download.eclipse.org/eclipse/updates/4.5/R-4.5.2-201602121500/plugins/org.eclipse.jdt.core_3.11.2.v20160128-0629.jar

http://download.eclipse.org/eclipse/updates/4.5/R-4.5.2-201602121500/plugins/org.eclipse.osgi_3.10.102.v20160118-1700.jar

http://download.eclipse.org/eclipse/updates/4.5/R-4.5.2-201602121500/plugins/org.eclipse.text_3.5.400.v20150505-1044.jar

. . .

Updated 19 January 2015 to fix Java 8 support. The previous versions gave an "Annotation processing got disabled, since it requires a 1.6 compliant JVM" error.

Updated 21 March 2016 to newest version (from R-4.4.1-201409250400 to R-4.5.2-201602121500) as part of updating Java Mode

Finally, the archive site contains additional jars for the 4.5.2 release, including the JDT Core Batch Compiler (ECJ):
http://archive.eclipse.org/eclipse/downloads/drops4/R-4.5.2-201602121500/
<file_sep>/README.md
# Open Source IoT Hand Hygiene Innovation

This project is in active development, updates can be expected to the code and the tutorial guide.

## Project History
This projects started at the Emily Carr University of Art + Design (ECUAD) as an initiative to bring interaction design to hand hygiene through an open-source solution, with an implementation at Vancouver General Hospital. Through time the project has evolved, and W21C has since taken the lead in the project. In 2017 the project was implemented in a unit at Foothills Medical Centre in Calgary and in 2019 the current version of hardware was implemented in Alberta Children’s Hospital.

## W21C
W21C is a research and innovation initiative based in the University of Calgary (UCalgary) and the Calgary Zone of Alberta Health Services (AHS). W21C conducts health systems research with the overarching mandate to improve patient safety and quality of care. Through this strategic research and innovation agenda, we hope to make care better for our communities, both now and in the future.

# Project Parts
### Sensor Hardware
Circuit with NodeMCU and code in C using Arduino IDE

### Networking and Message Transmission
Messaging and networking using the MQTT protocol. Install with open-source Mosquitto.

### Data and System Management
Python web application.

### Interaction Design Visualizations
Visualization in Processing.
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/src/processing/mode/java/pdex/Rename.java
package processing.mode.java.pdex;

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JRootPane;
import javax.swing.JTextField;
import javax.swing.WindowConstants;
import javax.swing.text.BadLocationException;

import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.IBinding;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.SimpleName;

import processing.app.Language;
import processing.app.Platform;
import processing.app.Sketch;
import processing.app.SketchCode;
import processing.app.syntax.SyntaxDocument;
import processing.app.ui.EditorStatus;
import processing.app.ui.Toolkit;
import processing.mode.java.JavaEditor;
import processing.mode.java.pdex.PreprocessedSketch.SketchInterval;

import static processing.mode.java.pdex.ASTUtils.findAllOccurrences;
import static processing.mode.java.pdex.ASTUtils.getSimpleNameAt;
import static processing.mode.java.pdex.ASTUtils.resolveBinding;

class Rename {
  final JavaEditor editor;
  final PreprocessingService pps;
  final ShowUsage showUsage;

  final JDialog window;
  final JTextField textField;
  final JLabel oldNameLabel;

  IBinding binding;
  PreprocessedSketch ps;

  Rename(JavaEditor editor, PreprocessingService pps, ShowUsage showUsage) {
    this.editor = editor;
    this.pps = pps;
    this.showUsage = showUsage;

    // Add rename option
    JMenuItem renameItem = new JMenuItem(Language.text("editor.popup.rename"));
    renameItem.addActionListener(e -> handleRename());
    editor.getTextArea().getRightClickPopup().add(renameItem);

    window = new JDialog(editor);
    JRootPane rootPane = window.getRootPane();
    window.setTitle("Rename");
    window.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
    Toolkit.registerWindowCloseKeys(rootPane, new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        window.setVisible(false);
      }
    });
    Toolkit.setIcon(window);

    window.setModal(true);
    window.setResizable(false);
    window.addComponentListener(new ComponentAdapter() {
      @Override
      public void componentHidden(ComponentEvent e) {
        binding = null;
        ps = null;
      }
    });
    //window.setSize(Toolkit.zoom(250, 130));
    //window.setLayout(new BoxLayout(window.getContentPane(), BoxLayout.Y_AXIS));
    Box windowBox = Box.createVerticalBox();
    Toolkit.setBorder(windowBox);
    final int GAP = Toolkit.zoom(5);

    { // old name
      Box oldBox = Box.createHorizontalBox();
      oldNameLabel = new JLabel("Current Name: ");
      oldBox.add(oldNameLabel);
      //oldBox.add(Box.createHorizontalStrut(10));
      oldBox.add(Box.createHorizontalGlue());
      windowBox.add(oldBox);
      windowBox.add(Box.createVerticalStrut(GAP));
    }

    { // new name
      Box newBox = Box.createHorizontalBox();
      JLabel newNameLabel = new JLabel("New Name: ");
      newBox.add(newNameLabel);
      newBox.add(textField = new JTextField(20));
      newBox.add(Box.createHorizontalGlue());
      windowBox.add(newBox);
      windowBox.add(Box.createVerticalStrut(GAP*2));
    }

    { // button panel
      JButton showUsageButton = new JButton("Show Usage");
      showUsageButton.addActionListener(e -> {
        showUsage.findUsageAndUpdateTree(ps, binding);
        window.setVisible(false);
      });

      JButton renameButton = new JButton("Rename");
      renameButton.addActionListener(e -> {
        final String newName = textField.getText().trim();
        if (!newName.isEmpty()) {
          if (newName.length() >= 1 &&
              newName.chars().limit(1).allMatch(Character::isUnicodeIdentifierStart) &&
              newName.chars().skip(1).allMatch(Character::isUnicodeIdentifierPart)) {
            rename(ps, binding, newName);
            window.setVisible(false);
          } else {
            String msg = String.format("'%s' is not a valid name", newName);
            JOptionPane.showMessageDialog(editor, msg, "Naming is Hard",
                                          JOptionPane.PLAIN_MESSAGE);
          }
        }
      });
      rootPane.setDefaultButton(renameButton);

      //JPanel panelBottom = new JPanel();
      //panelBottom.setLayout(new BoxLayout(panelBottom, BoxLayout.X_AXIS));
      Box buttonBox = Box.createHorizontalBox();
      //Toolkit.setBorder(panelBottom, 5, 5, 5, 5);

      buttonBox.add(Box.createHorizontalGlue());
      buttonBox.add(showUsageButton);
      if (!Platform.isMacOS()) {
        buttonBox.add(Box.createHorizontalStrut(GAP));
      }
      buttonBox.add(renameButton);
      buttonBox.add(Box.createHorizontalGlue());

      Dimension showDim = showUsageButton.getPreferredSize();
      Dimension renameDim = renameButton.getPreferredSize();
      final int niceSize = Math.max(showDim.width, renameDim.width) + GAP;
      final Dimension buttonDim = new Dimension(niceSize, showDim.height);
      showUsageButton.setPreferredSize(buttonDim);
      renameButton.setPreferredSize(buttonDim);

      windowBox.add(buttonBox);

      //window.add(panelBottom);
    }
    window.add(windowBox);
    window.pack();
    //window.setMinimumSize(window.getSize());
  }

  // Thread: EDT
  void handleRename() {
    int startOffset = editor.getSelectionStart();
    int stopOffset = editor.getSelectionStop();
    int tabIndex = editor.getSketch().getCurrentCodeIndex();

    pps.whenDoneBlocking(ps -> handleRename(ps, tabIndex, startOffset, stopOffset));
  }

  // Thread: worker
  void handleRename(PreprocessedSketch ps, int tabIndex, int startTabOffset, int stopTabOffset) {
    if (ps.hasSyntaxErrors) {
      editor.statusMessage("Cannot rename until syntax errors are fixed",
                           EditorStatus.WARNING);
      return;
    }

    ASTNode root = ps.compilationUnit;

    // Map offsets
    int startJavaOffset = ps.tabOffsetToJavaOffset(tabIndex, startTabOffset);
    int stopJavaOffset = ps.tabOffsetToJavaOffset(tabIndex, stopTabOffset);

    // Find the node
    SimpleName name = getSimpleNameAt(root, startJavaOffset, stopJavaOffset);
    if (name == null) {
      editor.statusMessage("Highlight the class/function/variable name first",
                           EditorStatus.NOTICE);
      return;
    }

    // Find binding
    IBinding binding = resolveBinding(name);
    if (binding == null) {
      editor.statusMessage(name.getIdentifier() + " isn't defined in this sketch, " +
                               "so it cannot be renamed", EditorStatus.ERROR);
      return;
    }

    ASTNode decl = ps.compilationUnit.findDeclaringNode(binding.getKey());
    if (decl == null) {
      editor.statusMessage(name.getIdentifier() + " isn't defined in this sketch, " +
                               "so it cannot be renamed", EditorStatus.ERROR);
      return;
    }

    // Display the rename dialog
    EventQueue.invokeLater(() -> {
      if (!window.isVisible()) {
        this.ps = ps;
        this.binding = binding;
        oldNameLabel.setText("Current name: " + binding.getName());
        textField.setText(binding.getName());
        textField.requestFocus();
        textField.selectAll();
        int x = editor.getX() + (editor.getWidth() - window.getWidth()) / 2;
        int y = editor.getY() + (editor.getHeight() - window.getHeight()) / 2;
        window.setLocation(x, y);
        window.setVisible(true);
        window.toFront();
      }
    });
  }

  // Thread: EDT (we can't allow user to mess with sketch while renaming)
  void rename(PreprocessedSketch ps, IBinding binding, String newName) {
    CompilationUnit root = ps.compilationUnit;

    // Renaming constructor should rename class
    if (binding.getKind() == IBinding.METHOD) {
      IMethodBinding method = (IMethodBinding) binding;
      if (method.isConstructor()) {
        binding = method.getDeclaringClass();
      }
    }

    ASTNode decl = root.findDeclaringNode(binding.getKey());
    if (decl == null) return;

    showUsage.hide();

    List<SimpleName> occurrences = new ArrayList<>();
    occurrences.addAll(findAllOccurrences(root, binding.getKey()));

    // Renaming class should rename all constructors
    if (binding.getKind() == IBinding.TYPE) {
      ITypeBinding type = (ITypeBinding) binding;
      //type = type.getErasure();
      IMethodBinding[] methods = type.getDeclaredMethods();
      Arrays.stream(methods)
          .filter(IMethodBinding::isConstructor)
          .flatMap(c -> findAllOccurrences(root, c.getKey()).stream())
          .forEach(occurrences::add);
    }

    Map<Integer, List<SketchInterval>> mappedNodes = occurrences.stream()
        .map(ps::mapJavaToSketch)
        .filter(ps::inRange)
        .collect(Collectors.groupingBy(interval -> interval.tabIndex));

    Sketch sketch = ps.sketch;

    editor.startCompoundEdit();

    mappedNodes.entrySet().forEach(entry -> {
      int tabIndex = entry.getKey();
      SketchCode sketchCode = sketch.getCode(tabIndex);

      SyntaxDocument document = (SyntaxDocument) sketchCode.getDocument();

      List<SketchInterval> nodes = entry.getValue();
      nodes.stream()
          // Replace from the end so all unprocess offsets stay valid
          .sorted(Comparator.comparing((SketchInterval si) -> si.startTabOffset).reversed())
          .forEach(si -> {
            // Make sure offsets are in bounds
            int documentLength = document.getLength();
            if (si.startTabOffset >= 0 && si.startTabOffset <= documentLength &&
                si.stopTabOffset >= 0 && si.stopTabOffset <= documentLength) {
              // Replace the code
              int length = si.stopTabOffset - si.startTabOffset;
              try {
                document.remove(si.startTabOffset, length);
                document.insertString(si.startTabOffset, newName, null);
              } catch (BadLocationException e) { /* Whatever */ }
            }
          });

      try {
        sketchCode.setProgram(document.getText(0, document.getLength()));
      } catch (BadLocationException e) { /* Whatever */ }
      sketchCode.setModified(true);
    });

    editor.stopCompoundEdit();

    editor.repaintHeader();

    int currentTabIndex = sketch.getCurrentCodeIndex();
    final int currentOffset = editor.getCaretOffset();

    int precedingIntervals =
        (int) mappedNodes.getOrDefault(currentTabIndex, Collections.emptyList())
            .stream()
            .filter(interval -> interval.stopTabOffset < currentOffset)
            .count();
    int intervalLengthDiff = newName.length() - binding.getName().length();
    int offsetDiff = precedingIntervals * intervalLengthDiff;

    editor.getTextArea().setCaretPosition(currentOffset + offsetDiff);
  }

  void dispose() {
    if (window != null) {
      window.dispose();
    }
  }
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Animation/AnimatedSprite/AnimatedSprite.pde
/**
 * Animated Sprite (Shifty + Teddy)
 * by <NAME>.
 *
 * Press the mouse button to change animations.
 * Demonstrates loading, displaying, and animating GIF images.
 * It would be easy to write a program to display
 * animated GIFs, but would not allow as much control over
 * the display sequence and rate of display.
 */

Animation animation1, animation2;

float xpos;
float ypos;
float drag = 30.0;

void setup() {
  size(640, 360);
  background(255, 204, 0);
  frameRate(24);
  animation1 = new Animation("PT_Shifty_", 38);
  animation2 = new Animation("PT_Teddy_", 60);
  ypos = height * 0.25;
}

void draw() {
  float dx = mouseX - xpos;
  xpos = xpos + dx/drag;

  // Display the sprite at the position xpos, ypos
  if (mousePressed) {
    background(153, 153, 0);
    animation1.display(xpos-animation1.getWidth()/2, ypos);
  } else {
    background(255, 204, 0);
    animation2.display(xpos-animation1.getWidth()/2, ypos);
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/io/examples/Compass_I2C_HMC6352/HMC6352.pde
import processing.io.I2C;

// HMC6352 is a digital compass using I2C
// datasheet: https://www.sparkfun.com/datasheets/Components/HMC6352.pdf

class HMC6352 extends I2C {
  int address;

  HMC6352(String dev, int address) {
    super(dev);
    this.address = address;
    setHeadingMode();
  }

  void setHeadingMode() {
    beginTransmission(address);
    // command byte for writing to EEPROM
    write(0x77);
    // address of the output data control byte
    write(0x4e);
    // give us the plain heading
    write(0x00);
    endTransmission();
  }

  float heading() {
    beginTransmission(address);
    // command byte for reading the data
    write(0x41);
    byte[] in = read(2);
    endTransmission();
    // put bytes together to tenth of degrees
    // & 0xff makes sure the byte is not interpreted as a negative value
    int deg = (in[0] & 0xff) << 8 | (in[1] & 0xff);
    // return degrees
    return deg / 10.0;
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Input/Clock/Clock.pde
/**
 * Clock.
 *
 * The current time can be read with the second(), minute(),
 * and hour() functions. In this example, sin() and cos() values
 * are used to set the position of the hands.
 */

int cx, cy;
float secondsRadius;
float minutesRadius;
float hoursRadius;
float clockDiameter;

void setup() {
  size(640, 360);
  stroke(255);

  int radius = min(width, height) / 2;
  secondsRadius = radius * 0.72;
  minutesRadius = radius * 0.60;
  hoursRadius = radius * 0.50;
  clockDiameter = radius * 1.8;

  cx = width / 2;
  cy = height / 2;
}

void draw() {
  background(0);

  // Draw the clock background
  fill(80);
  noStroke();
  ellipse(cx, cy, clockDiameter, clockDiameter);

  // Angles for sin() and cos() start at 3 o'clock;
  // subtract HALF_PI to make them start at the top
  float s = map(second(), 0, 60, 0, TWO_PI) - HALF_PI;
  float m = map(minute() + norm(second(), 0, 60), 0, 60, 0, TWO_PI) - HALF_PI;
  float h = map(hour() + norm(minute(), 0, 60), 0, 24, 0, TWO_PI * 2) - HALF_PI;

  // Draw the hands of the clock
  stroke(255);
  strokeWeight(1);
  line(cx, cy, cx + cos(s) * secondsRadius, cy + sin(s) * secondsRadius);
  strokeWeight(2);
  line(cx, cy, cx + cos(m) * minutesRadius, cy + sin(m) * minutesRadius);
  strokeWeight(4);
  line(cx, cy, cx + cos(h) * hoursRadius, cy + sin(h) * hoursRadius);

  // Draw the minute ticks
  strokeWeight(2);
  beginShape(POINTS);
  for (int a = 0; a < 360; a+=6) {
    float angle = radians(a);
    float x = cx + cos(angle) * secondsRadius;
    float y = cy + sin(angle) * secondsRadius;
    vertex(x, y);
  }
  endShape();
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/io/src/processing/io/SoftwareServo.java
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
  Copyright (c) The Processing Foundation 2015
  Hardware I/O library developed by <NAME>

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General
  Public License along with this library; if not, write to the
  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  Boston, MA  02111-1307  USA
*/

package processing.io;

import processing.core.*;

/**
 *  @webref
 */
public class SoftwareServo {

  public static final int DEFAULT_MIN_PULSE = 544;
  public static final int DEFAULT_MAX_PULSE = 2400;

  protected int pin = -1;           // gpio number (-1 .. not attached)
  protected long handle = -1;       // native thread id (<0 .. not started)
  protected int period = 20000;     // 20 ms (50 Hz)
  protected int minPulse = 0;       // minimum pulse width in microseconds
  protected int maxPulse = 0;       // maximum pulse width in microseconds
  protected int pulse = 0;          // current pulse in microseconds

  /**
   *  Opens a servo motor
   *  @param parent typically use "this"
   *  @webref
   */
  public SoftwareServo(PApplet parent) {
    NativeInterface.loadLibrary();
  }

  /**
   *  Closes a servo motor
   *  @webref
   */
  public void close() {
    detach();
  }

  protected void finalize() throws Throwable {
    try {
      close();
    } finally {
      super.finalize();
    }
  }

  /**
   *  Attaches a servo motor to a GPIO pin
   *  @param pin GPIO pin
   *  @webref
   */
  public void attach(int pin) {
    detach();
    this.pin = pin;
    this.minPulse = DEFAULT_MIN_PULSE;
    this.maxPulse = DEFAULT_MAX_PULSE;
  }

  /**
   *  Attaches a servo motor to a GPIO pin using custom pulse widths
   *  @param minPulse minimum pulse width in microseconds (default: 544, same as on Arduino)
   *  @param maxPulse maximum pulse width in microseconds (default: 2400, same as on Arduino)
   *  @webref
   */
  public void attach(int pin, int minPulse, int maxPulse) {
    detach();
    this.pin = pin;
    this.minPulse = minPulse;
    this.maxPulse = maxPulse;
  }

  /**
   *  Moves a servo motor to a given orientation
   *  @param angle angle in degrees (controls speed and direction on continuous-rotation servos)
   *  @webref
   */
  public void write(float angle) {
    if (attached() == false) {
      System.err.println("You need to call attach(pin) before write(angle).");
      throw new RuntimeException("Servo is not attached");
    }

    if (angle < 0 || 180 < angle) {
      System.err.println("Only degree values between 0 and 180 can be used.");
      throw new IllegalArgumentException("Illegal value");
    }
    pulse = (int)(minPulse + (angle/180.0) * (maxPulse-minPulse));

    if (handle < 0) {
      // start a new thread
      GPIO.pinMode(pin, GPIO.OUTPUT);
      if (NativeInterface.isSimulated()) {
        return;
      }
      handle = NativeInterface.servoStartThread(pin, pulse, period);
      if (handle < 0) {
        throw new RuntimeException(NativeInterface.getError((int)handle));
      }
    } else {
      // thread already running
      int ret = NativeInterface.servoUpdateThread(handle, pulse, period);
      if (ret < 0) {
        throw new RuntimeException(NativeInterface.getError(ret));
      }
    }
  }

  /**
   *  Returns whether a servo motor is attached to a pin
   *  @return true if attached, false is not
   *  @webref
   */
  public boolean attached() {
    return (pin != -1);
  }

  /**
   *  Detatches a servo motor from a GPIO pin
   *  @webref
   */
  public void detach() {
    if (0 <= handle) {
      // stop thread
      int ret = NativeInterface.servoStopThread(handle);
      GPIO.pinMode(pin, GPIO.INPUT);
      handle = -1;
      pin = -1;
      if (ret < 0) {
        throw new RuntimeException(NativeInterface.getError(ret));
      }
    }
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Cellular Automata/GameOfLife/GameOfLife.pde
/**
 * A Processing implementation of Game of Life
 * By <NAME>
 *
 * Press SPACE BAR to pause and change the cell's values with the mouse
 * On pause, click to activate/deactivate cells
 * Press R to randomly reset the cells' grid
 * Press C to clear the cells' grid
 *
 * The original Game of Life was created by <NAME> in 1970.
 */

// Size of cells
int cellSize = 5;

// How likely for a cell to be alive at start (in percentage)
float probabilityOfAliveAtStart = 15;

// Variables for timer
int interval = 100;
int lastRecordedTime = 0;

// Colors for active/inactive cells
color alive = color(0, 200, 0);
color dead = color(0);

// Array of cells
int[][] cells;
// Buffer to record the state of the cells and use this while changing the others in the interations
int[][] cellsBuffer;

// Pause
boolean pause = false;

void setup() {
  size (640, 360);

  // Instantiate arrays
  cells = new int[width/cellSize][height/cellSize];
  cellsBuffer = new int[width/cellSize][height/cellSize];

  // This stroke will draw the background grid
  stroke(48);

  noSmooth();

  // Initialization of cells
  for (int x=0; x<width/cellSize; x++) {
    for (int y=0; y<height/cellSize; y++) {
      float state = random (100);
      if (state > probabilityOfAliveAtStart) {
        state = 0;
      }
      else {
        state = 1;
      }
      cells[x][y] = int(state); // Save state of each cell
    }
  }
  background(0); // Fill in black in case cells don't cover all the windows
}

void draw() {

  //Draw grid
  for (int x=0; x<width/cellSize; x++) {
    for (int y=0; y<height/cellSize; y++) {
      if (cells[x][y]==1) {
        fill(alive); // If alive
      }
      else {
        fill(dead); // If dead
      }
      rect (x*cellSize, y*cellSize, cellSize, cellSize);
    }
  }
  // Iterate if timer ticks
  if (millis()-lastRecordedTime>interval) {
    if (!pause) {
      iteration();
      lastRecordedTime = millis();
    }
  }

  // Create  new cells manually on pause
  if (pause && mousePressed) {
    // Map and avoid out of bound errors
    int xCellOver = int(map(mouseX, 0, width, 0, width/cellSize));
    xCellOver = constrain(xCellOver, 0, width/cellSize-1);
    int yCellOver = int(map(mouseY, 0, height, 0, height/cellSize));
    yCellOver = constrain(yCellOver, 0, height/cellSize-1);

    // Check against cells in buffer
    if (cellsBuffer[xCellOver][yCellOver]==1) { // Cell is alive
      cells[xCellOver][yCellOver]=0; // Kill
      fill(dead); // Fill with kill color
    }
    else { // Cell is dead
      cells[xCellOver][yCellOver]=1; // Make alive
      fill(alive); // Fill alive color
    }
  }
  else if (pause && !mousePressed) { // And then save to buffer once mouse goes up
    // Save cells to buffer (so we opeate with one array keeping the other intact)
    for (int x=0; x<width/cellSize; x++) {
      for (int y=0; y<height/cellSize; y++) {
        cellsBuffer[x][y] = cells[x][y];
      }
    }
  }
}

void iteration() { // When the clock ticks
  // Save cells to buffer (so we opeate with one array keeping the other intact)
  for (int x=0; x<width/cellSize; x++) {
    for (int y=0; y<height/cellSize; y++) {
      cellsBuffer[x][y] = cells[x][y];
    }
  }

  // Visit each cell:
  for (int x=0; x<width/cellSize; x++) {
    for (int y=0; y<height/cellSize; y++) {
      // And visit all the neighbours of each cell
      int neighbours = 0; // We'll count the neighbours
      for (int xx=x-1; xx<=x+1;xx++) {
        for (int yy=y-1; yy<=y+1;yy++) {
          if (((xx>=0)&&(xx<width/cellSize))&&((yy>=0)&&(yy<height/cellSize))) { // Make sure you are not out of bounds
            if (!((xx==x)&&(yy==y))) { // Make sure to to check against self
              if (cellsBuffer[xx][yy]==1){
                neighbours ++; // Check alive neighbours and count them
              }
            } // End of if
          } // End of if
        } // End of yy loop
      } //End of xx loop
      // We've checked the neigbours: apply rules!
      if (cellsBuffer[x][y]==1) { // The cell is alive: kill it if necessary
        if (neighbours < 2 || neighbours > 3) {
          cells[x][y] = 0; // Die unless it has 2 or 3 neighbours
        }
      }
      else { // The cell is dead: make it live if necessary
        if (neighbours == 3 ) {
          cells[x][y] = 1; // Only if it has 3 neighbours
        }
      } // End of if
    } // End of y loop
  } // End of x loop
} // End of function

void keyPressed() {
  if (key=='r' || key == 'R') {
    // Restart: reinitialization of cells
    for (int x=0; x<width/cellSize; x++) {
      for (int y=0; y<height/cellSize; y++) {
        float state = random (100);
        if (state > probabilityOfAliveAtStart) {
          state = 0;
        }
        else {
          state = 1;
        }
        cells[x][y] = int(state); // Save state of each cell
      }
    }
  }
  if (key==' ') { // On/off of pause
    pause = !pause;
  }
  if (key=='c' || key == 'C') { // Clear all
    for (int x=0; x<width/cellSize; x++) {
      for (int y=0; y<height/cellSize; y++) {
        cells[x][y] = 0; // Save all to zero
      }
    }
  }
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Motion/Reflection2/Reflection2.pde
/**
 * Non-orthogonal Collision with Multiple Ground Segments
 * by <NAME>.
 *
 * Based on Keith Peter's Solution in
 * Foundation Actionscript Animation: Making Things Move!
 */

Orb orb;

PVector gravity = new PVector(0,0.05);
// The ground is an array of "Ground" objects
int segments = 40;
Ground[] ground = new Ground[segments];

void setup(){
  size(640, 360);
  // An orb object that will fall and bounce around
  orb = new Orb(50, 50, 3);

  // Calculate ground peak heights
  float[] peakHeights = new float[segments+1];
  for (int i=0; i<peakHeights.length; i++){
    peakHeights[i] = random(height-40, height-30);
  }

  /* Float value required for segment width (segs)
   calculations so the ground spans the entire
   display window, regardless of segment number. */
  float segs = segments;
  for (int i=0; i<segments; i++){
    ground[i]  = new Ground(width/segs*i, peakHeights[i], width/segs*(i+1), peakHeights[i+1]);
  }
}

void draw(){
  // Background
  noStroke();
  fill(0, 15);
  rect(0, 0, width, height);

  // Move and display the orb
  orb.move();
  orb.display();
  // Check walls
  orb.checkWallCollision();

  // Check against all the ground segments
  for (int i=0; i<segments; i++){
    orb.checkGroundCollision(ground[i]);
  }

  // Draw ground
  fill(127);
  beginShape();
  for (int i=0; i<segments; i++){
    vertex(ground[i].x1, ground[i].y1);
    vertex(ground[i].x2, ground[i].y2);
  }
  vertex(ground[segments-1].x2, height);
  vertex(ground[0].x1, height);
  endShape(CLOSE);

}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Fractals and L-Systems/Pentigree/LSystem.pde
class LSystem {

  int steps = 0;

  String axiom;
  String rule;
  String production;

  float startLength;
  float drawLength;
  float theta;

  int generations;

  LSystem() {

    axiom = "F";
    rule = "F+F-F";
    startLength = 90.0;
    theta = radians(120.0);
    reset();
  }

  void reset() {
    production = axiom;
    drawLength = startLength;
    generations = 0;
  }

  int getAge() {
    return generations;
  }

  void render() {
    translate(width/2, height/2);
    steps += 5;
    if (steps > production.length()) {
      steps = production.length();
    }
    for (int i = 0; i < steps; i++) {
      char step = production.charAt(i);
      if (step == 'F') {
        rect(0, 0, -drawLength, -drawLength);
        noFill();
        translate(0, -drawLength);
      }
      else if (step == '+') {
        rotate(theta);
      }
      else if (step == '-') {
        rotate(-theta);
      }
      else if (step == '[') {
        pushMatrix();
      }
      else if (step == ']') {
        popMatrix();
      }
    }
  }

  void simulate(int gen) {
    while (getAge() < gen) {
      production = iterate(production, rule);
    }
  }

  String iterate(String prod_, String rule_) {
    drawLength = drawLength * 0.6;
    generations++;
    String newProduction = prod_;
    newProduction = newProduction.replaceAll("F", rule_);
    return newProduction;
  }
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/src/antlr/ExtendedCommonASTWithHiddenTokens.java
package antlr;

/* ANTLR Translator Generator
 * Project led by <NAME> at http://www.jGuru.com
 * Software rights: http://www.antlr.org/RIGHTS.html
 *
 * $Id$
 */

import java.io.*;

import antlr.collections.*;

/** A CommonAST whose initialization copies hidden token
 *  information from the Token used to create a node.
 */
public class ExtendedCommonASTWithHiddenTokens
    extends CommonASTWithHiddenTokens {

    public ExtendedCommonASTWithHiddenTokens() {
        super();
    }

    public ExtendedCommonASTWithHiddenTokens(Token tok) {
        super(tok);
    }

    public void initialize(AST ast) {
        ExtendedCommonASTWithHiddenTokens a =
	    (ExtendedCommonASTWithHiddenTokens)ast;
        super.initialize(a);
        hiddenBefore = a.getHiddenBefore();
        hiddenAfter = a.getHiddenAfter();
    }

    public String getHiddenAfterString() {

	CommonHiddenStreamToken t;
	StringBuilder hiddenAfterString = new StringBuilder(100);

	for ( t = hiddenAfter ; t != null ; t = t.getHiddenAfter() ) {
	    hiddenAfterString.append(t.getText());
	}

	return hiddenAfterString.toString();
    }

    public String getHiddenBeforeString() {

	antlr.CommonHiddenStreamToken
	    child = null,
	    parent = hiddenBefore;

	// if there aren't any hidden tokens here, quietly return
	//
	if (parent == null) {
	    return "";
	}

	// traverse back to the head of the list of tokens before this node
	do {
	    child = parent;
	    parent = child.getHiddenBefore();
	} while (parent != null);

	// dump that list

	StringBuilder hiddenBeforeString = new StringBuilder(100);

	for ( CommonHiddenStreamToken t = child; t != null ;
	      t = t.getHiddenAfter() ) {
	    hiddenBeforeString.append(t.getText());
	}

	return hiddenBeforeString.toString();
    }

    public void xmlSerializeNode(Writer out) throws IOException {
        StringBuilder sb = new StringBuilder(100);
        sb.append("<");
        sb.append(getClass().getName() + " ");

        sb.append("hiddenBeforeString=\"" +
            encode(getHiddenBeforeString()) +
            "\" text=\"" + encode(getText()) + "\" type=\"" +
            getType() + "\" hiddenAfterString=\"" +
            encode(getHiddenAfterString()) + "\"/>");
        out.write(sb.toString());
    }

    public void xmlSerializeRootOpen(Writer out) throws IOException {
        StringBuilder sb = new StringBuilder(100);
        sb.append("<");
        sb.append(getClass().getName() + " ");
        sb.append("hiddenBeforeString=\"" +
            encode(getHiddenBeforeString()) +
            "\" text=\"" + encode(getText()) + "\" type=\"" +
            getType() + "\" hiddenAfterString=\"" +
            encode(getHiddenAfterString()) + "\">\n");
        out.write(sb.toString());
    }

    public void xmlSerializeRootClose(Writer out)
        throws IOException {
        out.write("</" + getClass().getName() + ">\n");
    }

    public void xmlSerialize(Writer out) throws IOException {
        // print out this node and all siblings
        for (AST node = this;
             node != null;
             node = node.getNextSibling()) {
            if (node.getFirstChild() == null) {
                // print guts (class name, attributes)
                ((BaseAST)node).xmlSerializeNode(out);
            }
            else {
                ((BaseAST)node).xmlSerializeRootOpen(out);

                // print children
                ((BaseAST)node.getFirstChild()).xmlSerialize(out);

                // print end tag
                ((BaseAST)node).xmlSerializeRootClose(out);
            }
        }
    }

}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Objects/Inheritance/Inheritance.pde
/**
 * Inheritance
 *
 * A class can be defined using another class as a foundation. In object-oriented
 * programming terminology, one class can inherit fi elds and methods from another.
 * An object that inherits from another is called a subclass, and the object it
 * inherits from is called a superclass. A subclass extends the superclass.
 */

SpinSpots spots;
SpinArm arm;

void setup() {
  size(640, 360);
  arm = new SpinArm(width/2, height/2, 0.01);
  spots = new SpinSpots(width/2, height/2, -0.02, 90.0);
}

void draw() {
  background(204);
  arm.update();
  arm.display();
  spots.update();
  spots.display();
}

class Spin {
  float x, y, speed;
  float angle = 0.0;
  Spin(float xpos, float ypos, float s) {
    x = xpos;
    y = ypos;
    speed = s;
  }
  void update() {
    angle += speed;
  }
}

class SpinArm extends Spin {
  SpinArm(float x, float y, float s) {
    super(x, y, s);
  }
  void display() {
    strokeWeight(1);
    stroke(0);
    pushMatrix();
    translate(x, y);
    angle += speed;
    rotate(angle);
    line(0, 0, 165, 0);
    popMatrix();
  }
}

class SpinSpots extends Spin {
  float dim;
  SpinSpots(float x, float y, float s, float d) {
    super(x, y, s);
    dim = d;
  }
  void display() {
    noStroke();
    pushMatrix();
    translate(x, y);
    angle += speed;
    rotate(angle);
    ellipse(-dim/2, 0, dim, dim);
    ellipse(dim/2, 0, dim, dim);
    popMatrix();
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/io/library.properties
name = Hardware I/O
authors = The Processing Foundation
url = http://processing.org/reference/libraries/io/index.html
categories = Hardware
sentence = Access peripherals on the Raspberry Pi and other Linux-based computers.
paragraph = For other platforms, this is solely provided in order to build and export sketches that require processing.io.
version = 1
prettyVersion = 1
minRevision = 247
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/src/processing/mode/java/JavaInputHandler.java
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
  Part of the Processing project - http://processing.org

  Copyright (c) 2012-15 The Processing Foundation
  Copyright (c) 2004-12 <NAME> and <NAME>
  Copyright (c) 2001-04 Massachusetts Institute of Technology

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software Foundation,
  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

package processing.mode.java;

import processing.app.Preferences;
import processing.app.Sketch;
import processing.app.syntax.*;
import processing.app.ui.Editor;

import java.awt.*;
import java.awt.event.*;
import java.util.Arrays;

/**
 * Filters key events for tab expansion/indent/etc. This is very old code
 * that we'd love to replace with a smarter parser/formatter, rather than
 * continuing to hack this class.
 */
public class JavaInputHandler extends PdeInputHandler {

  /** ctrl-alt on windows and linux, cmd-alt on mac os x */
  static final int CTRL_ALT = ActionEvent.ALT_MASK |
    Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();

  public JavaInputHandler(Editor editor) {
    super(editor);
  }

  /**
   * Intercepts key pressed events for JEditTextArea.
   *

   * Called by JEditTextArea inside processKeyEvent(). Note that this
   * won't intercept actual characters, because those are fired on
   * keyTyped().
   * @return true if the event has been handled (to remove it from the queue)
   */
  public boolean handlePressed(KeyEvent event) {
    char c = event.getKeyChar();
    int code = event.getKeyCode();

    Sketch sketch = editor.getSketch();
    JEditTextArea textarea = editor.getTextArea();

    if ((event.getModifiers() & InputEvent.META_MASK) != 0) {
      //event.consume();  // does nothing
      return false;
    }

    if ((code == KeyEvent.VK_BACK_SPACE) || (code == KeyEvent.VK_TAB) ||
        (code == KeyEvent.VK_ENTER) || ((c >= 32) && (c < 128))) {
      sketch.setModified(true);
    }

    if ((code == KeyEvent.VK_UP) &&
        ((event.getModifiers() & InputEvent.CTRL_MASK) != 0)) {
      // back up to the last empty line
      char contents[] = textarea.getText().toCharArray();
      //int origIndex = textarea.getCaretPosition() - 1;
      int caretIndex = textarea.getCaretPosition();

      int index = calcLineStart(caretIndex - 1, contents);
      //System.out.println("line start " + (int) contents[index]);
      index -= 2;  // step over the newline
      //System.out.println((int) contents[index]);
      boolean onlySpaces = true;
      while (index > 0) {
        if (contents[index] == 10) {
          if (onlySpaces) {
            index++;
            break;
          } else {
            onlySpaces = true;  // reset
          }
        } else if (contents[index] != ' ') {
          onlySpaces = false;
        }
        index--;
      }
      // if the first char, index will be -2
      if (index < 0) index = 0;

      if ((event.getModifiers() & InputEvent.SHIFT_MASK) != 0) {
        textarea.setSelectionStart(caretIndex);
        textarea.setSelectionEnd(index);
      } else {
        textarea.setCaretPosition(index);
      }
      event.consume();
//      return true;

    } else if ((code == KeyEvent.VK_DOWN) &&
               ((event.getModifiers() & InputEvent.CTRL_MASK) != 0)) {
      char contents[] = textarea.getText().toCharArray();
      int caretIndex = textarea.getCaretPosition();

      int index = caretIndex;
      int lineStart = 0;
      boolean onlySpaces = false;  // don't count this line
      while (index < contents.length) {
        if (contents[index] == 10) {
          if (onlySpaces) {
            index = lineStart;  // this is it
            break;
          } else {
            lineStart = index + 1;
            onlySpaces = true;  // reset
          }
        } else if (contents[index] != ' ') {
          onlySpaces = false;
        }
        index++;
      }

      if ((event.getModifiers() & InputEvent.SHIFT_MASK) != 0) {
        textarea.setSelectionStart(caretIndex);
        textarea.setSelectionEnd(index);
      } else {
        textarea.setCaretPosition(index);
      }
      event.consume();
//      return true;

    } else if (c == 9) {
      if ((event.getModifiers() & InputEvent.SHIFT_MASK) != 0) {
        // if shift is down, the user always expects an outdent
        // http://code.google.com/p/processing/issues/detail?id=458
        editor.handleOutdent();

      } else if (textarea.isSelectionActive()) {
        editor.handleIndent();

      } else if (Preferences.getBoolean("editor.tabs.expand")) {
        int tabSize = Preferences.getInteger("editor.tabs.size");
        textarea.setSelectedText(spaces(tabSize));
        event.consume();

      } else {  // !Preferences.getBoolean("editor.tabs.expand")
        textarea.setSelectedText("\t");
        event.consume();
      }

    } else if (code == 10 || code == 13) {  // auto-indent
      if (Preferences.getBoolean("editor.indent")) {
        char contents[] = textarea.getText().toCharArray();
        int tabSize = Preferences.getInteger("editor.tabs.size");

        // this is the previous character
        // (i.e. when you hit return, it'll be the last character
        // just before where the newline will be inserted)
        int origIndex = textarea.getCaretPosition() - 1;

        // if the previous thing is a brace (whether prev line or
        // up farther) then the correct indent is the number of spaces
        // on that line + 'indent'.
        // if the previous line is not a brace, then just use the
        // identical indentation to the previous line

        // calculate the amount of indent on the previous line
        // this will be used *only if the prev line is not an indent*
        int spaceCount = calcSpaceCount(origIndex, contents);

        // If the last character was a left curly brace, then indent.
        // For 0122, walk backwards a bit to make sure that the there isn't a
        // curly brace several spaces (or lines) back. Also moved this before
        // calculating extraCount, since it'll affect that as well.
        int index2 = origIndex;
        while ((index2 >= 0) &&
               Character.isWhitespace(contents[index2])) {
          index2--;
        }
        if (index2 != -1) {
          // still won't catch a case where prev stuff is a comment
          if (contents[index2] == '{') {
            // intermediate lines be damned,
            // use the indent for this line instead
            spaceCount = calcSpaceCount(index2, contents);
            spaceCount += tabSize;
          }
        }

        // now before inserting this many spaces, walk forward from
        // the caret position and count the number of spaces,
        // so that the number of spaces aren't duplicated again
        int index = origIndex + 1;
        int extraCount = 0;
        while ((index < contents.length) &&
               (contents[index] == ' ')) {
          //spaceCount--;
          extraCount++;
          index++;
        }
        int braceCount = 0;
        while ((index < contents.length) && (contents[index] != '\n')) {
          if (contents[index] == '}') {
            braceCount++;
          }
          index++;
        }

        // Hitting return on a line with spaces *after* the caret
        // can cause trouble. For 0099, was ignoring the case, but this is
        // annoying, so in 0122 we're trying to fix that.
        spaceCount -= extraCount;

        if (spaceCount < 0) {
          // for rev 0122, actually delete extra space
          //textarea.setSelectionStart(origIndex + 1);
          textarea.setSelectionEnd(textarea.getSelectionStop() - spaceCount);
          textarea.setSelectedText("\n");
          textarea.setCaretPosition(textarea.getCaretPosition() + extraCount + spaceCount);
        } else {
          String insertion = "\n" + spaces(spaceCount);
          textarea.setSelectedText(insertion);
          textarea.setCaretPosition(textarea.getCaretPosition() + extraCount);
        }

        // not gonna bother handling more than one brace
        if (braceCount > 0) {
          int sel = textarea.getSelectionStart();
          // sel - tabSize will be -1 if start/end parens on the same line
          // http://dev.processing.org/bugs/show_bug.cgi?id=484
          if (sel - tabSize >= 0) {
            textarea.select(sel - tabSize, sel);
            String s = spaces(tabSize);
            // if these are spaces that we can delete
            if (textarea.getSelectedText().equals(s)) {
              textarea.setSelectedText("");
            } else {
              textarea.select(sel, sel);
            }
          }
        }
      } else {
        // Enter/Return was being consumed by somehow even if false
        // was returned, so this is a band-aid to simply fire the event again.
        // http://dev.processing.org/bugs/show_bug.cgi?id=1073
        textarea.setSelectedText(String.valueOf(c));
      }
      // mark this event as already handled (all but ignored)
      event.consume();
//      return true;

    } else if (c == '}') {
      if (Preferences.getBoolean("editor.indent")) {
        // first remove anything that was there (in case this multiple
        // characters are selected, so that it's not in the way of the
        // spaces for the auto-indent
        if (textarea.getSelectionStart() != textarea.getSelectionStop()) {
          textarea.setSelectedText("");
        }

        // if this brace is the only thing on the line, outdent
        char contents[] = textarea.getText().toCharArray();
        // index to the character to the left of the caret
        int prevCharIndex = textarea.getCaretPosition() - 1;

        // backup from the current caret position to the last newline,
        // checking for anything besides whitespace along the way.
        // if there's something besides whitespace, exit without
        // messing any sort of indenting.
        int index = prevCharIndex;
        boolean finished = false;
        while ((index != -1) && (!finished)) {
          if (contents[index] == 10) {
            finished = true;
            index++;
          } else if (contents[index] != ' ') {
            // don't do anything, this line has other stuff on it
            return false;
          } else {
            index--;
          }
        }
        if (!finished) return false;  // brace with no start
        int lineStartIndex = index;

        int pairedSpaceCount = calcBraceIndent(prevCharIndex, contents); //, 1);
        if (pairedSpaceCount == -1) return false;

        textarea.setSelectionStart(lineStartIndex);
        textarea.setSelectedText(spaces(pairedSpaceCount));

        // mark this event as already handled
        event.consume();
        return true;
      }
    }
    return false;
  }

  public boolean handleTyped(KeyEvent event) {
    char c = event.getKeyChar();

    if ((event.getModifiers() & InputEvent.CTRL_MASK) != 0) {
      // on linux, ctrl-comma (prefs) being passed through to the editor
      if (c == KeyEvent.VK_COMMA) {
        event.consume();
        return true;
      }
      // https://github.com/processing/processing/issues/3847
      if (c == KeyEvent.VK_SPACE) {
        event.consume();
        return true;
      }
    }
    return false;
  }

  /**
   * Return the index for the first character on this line.
   */
  protected int calcLineStart(int index, char contents[]) {
    // backup from the current caret position to the last newline,
    // so that we can figure out how far this line was indented
    /*int spaceCount = 0;*/
    boolean finished = false;
    while ((index != -1) && (!finished)) {
      if ((contents[index] == 10) ||
          (contents[index] == 13)) {
        finished = true;
        //index++; // maybe ?
      } else {
        index--;  // new
      }
    }
    // add one because index is either -1 (the start of the document)
    // or it's the newline character for the previous line
    return index + 1;
  }

  /**
   * Calculate the number of spaces on this line.
   */
  protected int calcSpaceCount(int index, char contents[]) {
    index = calcLineStart(index, contents);

    int spaceCount = 0;
    // now walk forward and figure out how many spaces there are
    while ((index < contents.length) && (index >= 0) &&
           (contents[index++] == ' ')) {
      spaceCount++;
    }
    return spaceCount;
  }

  /**
   * Walk back from 'index' until the brace that seems to be
   * the beginning of the current block, and return the number of
   * spaces found on that line.
   */
  protected int calcBraceIndent(int index, char[] contents) {
    // now that we know things are ok to be indented, walk
    // backwards to the last { to see how far its line is indented.
    // this isn't perfect cuz it'll pick up commented areas,
    // but that's not really a big deal and can be fixed when
    // this is all given a more complete (proper) solution.
    int braceDepth = 1;
    boolean finished = false;
    while ((index != -1) && (!finished)) {
      if (contents[index] == '}') {
        // aww crap, this means we're one deeper
        // and will have to find one more extra {
        braceDepth++;
        //if (braceDepth == 0) {
        //finished = true;
        //}
        index--;
      } else if (contents[index] == '{') {
        braceDepth--;
        if (braceDepth == 0) {
          finished = true;
        }
        index--;
      } else {
        index--;
      }
    }
    // never found a proper brace, be safe and don't do anything
    if (!finished) return -1;

    // check how many spaces on the line with the matching open brace
    //int pairedSpaceCount = calcSpaceCount(index, contents);
    return calcSpaceCount(index, contents);
  }

  static private String spaces(int count) {
    char[] c = new char[count];
    Arrays.fill(c, ' ');
    return new String(c);
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Shape/GetChild/GetChild.pde
/**
 * Get Child.
 *
 * SVG files can be made of many individual shapes.
 * Each of these shapes (called a "child") has its own name
 * that can be used to extract it from the "parent" file.
 * This example loads a map of the United States and creates
 * two new PShape objects by extracting the data from two states.
 */

PShape usa;
PShape michigan;
PShape ohio;

void setup() {
  size(640, 360);
  usa = loadShape("usa-wikipedia.svg");
  michigan = usa.getChild("MI");
  ohio = usa.getChild("OH");
}

void draw() {
  background(255);

  // Draw the full map
  shape(usa, -600, -180);

  // Disable the colors found in the SVG file
  michigan.disableStyle();
  // Set our own coloring
  fill(0, 51, 102);
  noStroke();
  // Draw a single state
  shape(michigan, -600, -180); // Wolverines!

  // Disable the colors found in the SVG file
  ohio.disableStyle();
  // Set our own coloring
  fill(153, 0, 0);
  noStroke();
  // Draw a single state
  shape(ohio, -600, -180);  // Buckeyes!
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/io/examples/Environment_I2C_BME280/Environment_I2C_BME280.pde
import processing.io.*;
BME280 bme280;

// see setup.png in the sketch folder for wiring details

void setup() {
  size(720, 320);
  textSize(72);

  //printArray(I2C.list());
  bme280 = new BME280("i2c-1", 0x77);
}

void draw() {
  background(0);
  stroke(255);

  bme280.update();
  float temp = bme280.temperature();
  float hum = bme280.humidity();
  float press = bme280.pressure();
  text(String.format("Temp:  %.02f\272C", temp), 10, 75);
  text(String.format("Hum:   %.02f %%", hum), 10, 150);
  text(String.format("Press: %.02f hPa", press / 100f), 10, 225);

  // pressure can be used to calculate the altitude like so
  float alt = bme280.altitude(press, temp);
  text(String.format("Alt: %.02f m", alt), 10, 300);
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Shaders/InfiniteTiles/data/scroller.glsl
//---------------------------------------------------------
// Display endless moving background using a tile texture.
// Contributed by martiSteiger
//---------------------------------------------------------

uniform float time;
uniform vec2 resolution;
uniform sampler2D tileImage;

#define TILES_COUNT_X 4.0

void main() {
  vec2 pos = gl_FragCoord.xy - vec2(4.0 * time);
  vec2 p = (resolution - TILES_COUNT_X * pos) / resolution.x;
  vec3 col = texture2D (tileImage, p).xyz;
  gl_FragColor = vec4 (col, 1.0);
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Color/Relativity/Relativity.pde
/**
 * Relativity.
 *
 * Each color is perceived in relation to other colors. The top and bottom
 * bars each contain the same component colors, but a different display order
 * causes individual colors to appear differently.
 */

color a, b, c, d, e;

void setup() {
  size(640, 360);
  noStroke();
  a = color(165, 167, 20);
  b = color(77, 86, 59);
  c = color(42, 106, 105);
  d = color(165, 89, 20);
  e = color(146, 150, 127);
  noLoop();  // Draw only one time
}

void draw() {
  drawBand(a, b, c, d, e, 0, width/128);
  drawBand(c, a, d, b, e, height/2, width/128);
}

void drawBand(color v, color w, color x, color y, color z, int ypos, int barWidth) {
  int num = 5;
  color[] colorOrder = { v, w, x, y, z };
  for(int i = 0; i < width; i += barWidth*num) {
    for(int j = 0; j < num; j++) {
      fill(colorOrder[j]);
      rect(i+j*barWidth, ypos, barWidth, height/2);
    }
  }
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/src/processing/mode/java/runner/MessageStream.java
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
  Part of the Processing project - http://processing.org

  Copyright (c) 2004-08 <NAME> and <NAME>
  Copyright (c) 2001-04 Massachusetts Institute of Technology

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software Foundation,
  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

package processing.mode.java.runner;

import java.io.*;

/**
 * OutputStream to handle stdout/stderr messages.
 *

 * This is used by Editor, System.err is set to
 * new PrintStream(new MessageStream()).
 * It's also used by Compiler.
 */
class MessageStream extends OutputStream {

  MessageConsumer messageConsumer;

  public MessageStream(MessageConsumer messageConsumer) {
    this.messageConsumer = messageConsumer;
  }

  public void close() { }

  public void flush() { }

  public void write(byte b[]) {
    // this never seems to get called
    System.out.println("leech1: " + new String(b));
  }

  public void write(byte b[], int offset, int length) {
    //System.out.println("leech2: " + new String(b));
    this.messageConsumer.message(new String(b, offset, length));
  }

  public void write(int b) {
    // this never seems to get called
    System.out.println("leech3: '" + ((char)b) + "'");
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Data/DatatypeConversion/DatatypeConversion.pde
/**
 * Datatype Conversion.
 *
 * It is sometimes beneficial to convert a value from one type of
 * data to another. Each of the conversion functions converts its parameter
 * to an equivalent representation within its datatype.
 * The conversion functions include int(), float(), char(), byte(), and others.
 */

size(640, 360);
background(0);
noStroke();

textFont(createFont("SourceCodePro-Regular.ttf",24));

char c;    // Chars are used for storing alphanumeric symbols
float f;   // Floats are decimal numbers
int i;     // Integers are values between 2,147,483,647 and -2147483648
byte b;    // Bytes are values between -128 and 128

c = 'A';
f = float(c);      // Sets f = 65.0
i = int(f * 1.4);  // Sets i to 91
b = byte(c / 2);   // Sets b to 32

//println(f);
//println(i);
//println(b);

text("The value of variable c is " + c, 50, 100);
text("The value of variable f is " + f, 50, 150);
text("The value of variable i is " + i, 50, 200);
text("The value of variable b is " + b, 50, 250);<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Math/Sine/Sine.pde
/**
 * Sine.
 *
 * Smoothly scaling size with the sin() function.
 */

float diameter;
float angle = 0;

void setup() {
  size(640, 360);
  diameter = height - 10;
  noStroke();
  fill(255, 204, 0);
}

void draw() {

  background(0);

  float d1 = 10 + (sin(angle) * diameter/2) + diameter/2;
  float d2 = 10 + (sin(angle + PI/2) * diameter/2) + diameter/2;
  float d3 = 10 + (sin(angle + PI) * diameter/2) + diameter/2;

  ellipse(0, height/2, d1, d1);
  ellipse(width/2, height/2, d2, d2);
  ellipse(width, height/2, d3, d3);

  angle += 0.02;
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Data/IntegersFloats/IntegersFloats.pde
/**
 * Integers Floats.
 *
 * Integers and floats are two different kinds of numerical data.
 * An integer (more commonly called an int) is a number without
 * a decimal point. A float is a floating-point number, which means
 * it is a number that has a decimal place. Floats are used when
 * more precision is needed.
 */

int a = 0;      // Create a variable "a" of the datatype "int"
float b = 0.0;  // Create a variable "b" of the datatype "float"

void setup() {
  size(640, 360);
  stroke(255);
}

void draw() {
  background(0);

  a = a + 1;
  b = b + 0.2;
  line(a, 0, a, height/2);
  line(b, height/2, b, height);

  if(a > width) {
    a = 0;
  }
  if(b > width) {
    b = 0;
  }
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Form/ShapePrimitives/ShapePrimitives.pde
/**
 * Shape Primitives.
 *
 * The basic shape primitive functions are triangle(),
 * rect(), quad(), ellipse(), and arc(). Squares are made
 * with rect() and circles are made with ellipse(). Each
 * of these functions requires a number of parameters to
 * determine the shape's position and size.
 */

size(640, 360);
background(0);
noStroke();

fill(204);
triangle(18, 18, 18, 360, 81, 360);

fill(102);
rect(81, 81, 63, 63);

fill(204);
quad(189, 18, 216, 18, 216, 360, 144, 360);

fill(255);
ellipse(252, 144, 72, 72);

fill(204);
triangle(288, 18, 351, 360, 288, 360);

fill(255);
arc(479, 300, 280, 280, PI, TWO_PI);

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/svg/library.properties
name = SVG Export
version = 1
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/io/examples/Display_I2C_SSD1306/Display_I2C_SSD1306.pde
import processing.io.*;

// 0.96" 128x64 OLED display ("SKU 346540")
SSD1306 oled;

void setup() {
  size(128, 64);

  // the display can be set to one of these two addresses: 0x3c (default) or 0x3d
  // (they might be listed as 0x7a and 0x7b on the circuit board)

  // you might need to use a different interface on other SBCs
  oled = new SSD1306("i2c-1", 0x3c);
}

void draw() {
  background(0);
  stroke(255);
  line(0, 0, 127, 63);
  line(0, 63, 127, 0);
  oled.sendImage(get());
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/pdf/README.md
This library uses iText 2.1.7, which is the last LGPL/MPL version of the iText project.

We've used iText for several years. The license for iText has changed for subsequent versions and is no longer compatible with Processing, so we're stuck at 2.x.

At the iText site, there's also some [vague wording](http://lowagie.com/itext2) about legal liability for commercial projects using the 2.x series. It's not clear where this leaves us.

<NAME> did an enormous amount of (free) work with the iText project, and we certainly don't fault him for the new commercial license.

We're using iText in a very limited way--drawing to it like it's a Java Graphics2D object. There might be other options for us in this space, but it's not much of a priority.

<NAME>, 12 October 2013
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Shaders/CustomBlend/CustomBlend.pde
/**
 * Custom Blend
 *
 * The OpenGL-based renderers (P2D and P3D) only support some of the
 * blending modes available in the default renderer. The reason for this
 * is that the blend equations in OpenGL allow for combinations of the
 * form dest_factor * dest_color + src_factor * src_color of the source and
 * destination colors (see this page http://www.opengl.org/wiki/Blending
 * for an extensive discussion of blending in OpenGL).
 * Complex blending modes typically available in photo editing tools,
 * like hard light or dodge, cannot be modeled with those equations.
 * However, we can implement virtually any blending math directly in the
 * fragment shader.
 *
 * This example shows how custom blend shaders can be loaded and used in
 * Processing.
 * For detailed information on how to implement Photoshop-like blending modes,
 * check the following pages (a bit old but still useful):
 * http://www.pegtop.net/delphi/articles/blendmodes/index.htm
 * http://mouaif.wordpress.com/2009/01/05/photoshop-math-with-glsl-shaders/
 *
 */

PImage destImage;
PImage srcImage;
PShader dodge;
PShader burn;
PShader overlay;
PShader difference;

void setup() {
  size(640, 360, P2D);
  destImage = loadImage("leaves.jpg");
  srcImage = loadImage("moonwalk.jpg");

  initShaders();
}

void draw() {
  background(0);

  shader(dodge);
  drawOutput(0, 0, width/2, height/2);
  shader(burn);
  drawOutput(width/2, 0, width/2, height/2);
  shader(overlay);
  drawOutput(0, height/2, width/2, height/2);
  shader(difference);
  drawOutput(width/2, height/2, width/2, height/2);

  noLoop();
}

void initShaders() {
  dodge = loadShader("dodge.glsl");
  burn = loadShader("burn.glsl");
  overlay = loadShader("overlay.glsl");
  difference = loadShader("difference.glsl");

  // The names destination and source come from the OpenGL terminology:
  // destination from the image already in the framebuffer, or "base layer",
  // and source for the image that will be blended into the framebuffer, or
  // "blend layer":
  dodge.set("destSampler", destImage);
  dodge.set("srcSampler", srcImage);
  burn.set("destSampler", destImage);
  burn.set("srcSampler", srcImage);
  overlay.set("destSampler", destImage);
  overlay.set("srcSampler", srcImage);
  difference.set("destSampler", destImage);
  difference.set("srcSampler", srcImage);

  // We set the sizes of de  st and src images, and the rectangular areas
  // from the images that we will use for blending:
  dodge.set("destSize", 640, 360);
  dodge.set("destRect", 100, 50, 200, 200);
  burn.set("destSize", 640, 360);
  burn.set("destRect", 100, 50, 200, 200);
  overlay.set("destSize", 640, 360);
  overlay.set("destRect", 100, 50, 200, 200);
  difference.set("destSize", 640, 360);
  difference.set("destRect", 100, 50, 200, 200);

  dodge.set("srcSize", 640, 360);
  dodge.set("srcRect", 0, 0, 640, 360);
  burn.set("srcSize", 640, 360);
  burn.set("srcRect", 0, 0, 640, 360);
  overlay.set("srcSize", 640, 360);
  overlay.set("srcRect", 0, 0, 640, 360);
  difference.set("srcSize", 640, 360);
  difference.set("srcRect", 0, 0, 640, 360);
}

void drawOutput(float x, float y, float w, float h) {
  pushMatrix();
  translate(x, y);
  noStroke();
  beginShape(QUAD);
  // Although we are not associating a texture to
  // this shape, the uv coordinates will be stored
  // anyways so they can be used in the fragment
  // shader to access the destination and source
  // images.
  vertex(0, 0, 0, 0);
  vertex(w, 0, 1, 0);
  vertex(w, h, 1, 1);
  vertex(0, h, 0, 1);
  endShape();
  popMatrix();
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/tools/MovieMaker/license.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<title>QuickTimeDemo License</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

QuickTimeDemo

License

Table of Contents

Disclaimer

License Fee

License Terms

Copyright

Disclaimer

Use of the QuickTimeDemo is entirely at your own risk. I will not be
    liable for any data
    loss, hardware damage or whatever this program might cause.

Permission to use this release of QuickTimeDemo is granted provided
    you agree with its license terms, and the copyright
    notice and this license notice appear in all copies and in supporting documentation.

License Fee

Use of QuickTimeDemo is free for all uses, including personal use, educational use, and commercial use.

License Terms

You can license QuickTimeDemo under the terms of the Creative Commons Attribution 3.0 license.

    You are free:

to Share — to copy, distribute and transmit the work

 to Remix — to adapt the work

 Under the following conditions:

      Attribution. You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work).

 For any reuse or distribution, you must make clear to others the license terms of this work. The best way to do this is with a link to this web page.

Any of the above conditions can be waived if you get permission from the copyright holder.

Nothing in this license impairs or restricts the author's moral rights.

Copyright

QuickTimeDemo © 2008-2010

 <NAME>, Hausmatt 10, Immensee,
    CH-6405, Switzerland

    http://www.randelshofer.ch/

    <a href="mailto:<EMAIL>"><EMAIL>

    All Rights Reserved.

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/io/examples/AnalogDigital_I2C_ADS1X15/AnalogDigital_I2C_ADS1X15.pde
import processing.io.*;
ADS1015 adc;
// or, alternatively:
// ADS1115 adc;

// see setup.png in the sketch folder for wiring details

void setup() {
  //printArray(I2C.list());

  adc = new ADS1015("i2c-1", 0x48);
  //adc = new ADS1115("i2c-1", 0x48);

  // this sets the measuring range to +/- 4.096 Volts
  // other ranges supported by this chip:
  // INTERNAL_6V144, INTERNAL_2V048, INTERNAL_1V024,
  // INTERNAL_0V512, INTERNAL_0V256
  adc.analogReference(ADS1X15.INTERNAL_4V096);

  // Important: do not attempt to measure voltages higher than
  // the supply voltage (VCC) + 0.3V, meaning that 3.6V is the
  // absolut maximum voltage on the Raspberry Pi. This is
  // irrespective of the analogReference() setting above.
}

void draw() {
  // this will return a number between 0 and 1
  // (as long as your voltage is positive)
  float measured = adc.analogRead(0);

  // multiply with the selected range to get the absolut voltage
  float volts = measured * 4.096;
  println("Analog Input 0 is " + volts + "V");

  background(255);
  fill(measured * 255);
  ellipse(width/2, height/2, width * 0.75, width * 0.75);
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Demos/Performance/StaticParticlesImmediate/StaticParticlesImmediate.pde
PImage sprite;

int npartTotal = 50000;
float partSize = 20;

PVector positions[];

int fcount, lastm;
float frate;
int fint = 3;

void setup() {
  size(800, 600, P3D);
  frameRate(60);

  sprite = loadImage("sprite.png");

  initPositions();

  // Writing to the depth buffer is disabled to avoid rendering
  // artifacts due to the fact that the particles are semi-transparent
  // but not z-sorted.
  hint(DISABLE_DEPTH_MASK);
}

void draw () {
  background(0);

  translate(width/2, height/2);
  rotateY(frameCount * 0.01);

  for (int n = 0; n < npartTotal; n++) {
    drawParticle(positions[n]);
  }

  fcount += 1;
  int m = millis();
  if (m - lastm > 1000 * fint) {
    frate = float(fcount) / fint;
    fcount = 0;
    lastm = m;
    println("fps: " + frate);
  }
}

void drawParticle(PVector center) {
  beginShape(QUAD);
  noStroke();
  tint(255);
  texture(sprite);
  normal(0, 0, 1);
  vertex(center.x - partSize/2, center.y - partSize/2, center.z, 0, 0);
  vertex(center.x + partSize/2, center.y - partSize/2, center.z, sprite.width, 0);
  vertex(center.x + partSize/2, center.y + partSize/2, center.z, sprite.width, sprite.height);
  vertex(center.x - partSize/2, center.y + partSize/2, center.z, 0, sprite.height);
  endShape();
}

void initPositions() {
  positions = new PVector[npartTotal];
  for (int n = 0; n < positions.length; n++) {
    positions[n] = new PVector(random(-500, +500), random(-500, +500), random(-500, +500));
  }
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Geometry/RGBCube/RGBCube.pde
/**
 * RGB Cube.
 *
 * The three primary colors of the additive color model are red, green, and blue.
 * This RGB color cube displays smooth transitions between these colors.
 */

float xmag, ymag = 0;
float newXmag, newYmag = 0;

void setup()  {
  size(640, 360, P3D);
  noStroke();
  colorMode(RGB, 1);
}

void draw()  {
  background(0.5);

  pushMatrix();
  translate(width/2, height/2, -30);

  newXmag = mouseX/float(width) * TWO_PI;
  newYmag = mouseY/float(height) * TWO_PI;

  float diff = xmag-newXmag;
  if (abs(diff) >  0.01) {
    xmag -= diff/4.0;
  }

  diff = ymag-newYmag;
  if (abs(diff) >  0.01) {
    ymag -= diff/4.0;
  }

  rotateX(-ymag);
  rotateY(-xmag);

  scale(90);
  beginShape(QUADS);

  fill(0, 1, 1); vertex(-1,  1,  1);
  fill(1, 1, 1); vertex( 1,  1,  1);
  fill(1, 0, 1); vertex( 1, -1,  1);
  fill(0, 0, 1); vertex(-1, -1,  1);

  fill(1, 1, 1); vertex( 1,  1,  1);
  fill(1, 1, 0); vertex( 1,  1, -1);
  fill(1, 0, 0); vertex( 1, -1, -1);
  fill(1, 0, 1); vertex( 1, -1,  1);

  fill(1, 1, 0); vertex( 1,  1, -1);
  fill(0, 1, 0); vertex(-1,  1, -1);
  fill(0, 0, 0); vertex(-1, -1, -1);
  fill(1, 0, 0); vertex( 1, -1, -1);

  fill(0, 1, 0); vertex(-1,  1, -1);
  fill(0, 1, 1); vertex(-1,  1,  1);
  fill(0, 0, 1); vertex(-1, -1,  1);
  fill(0, 0, 0); vertex(-1, -1, -1);

  fill(0, 1, 0); vertex(-1,  1, -1);
  fill(1, 1, 0); vertex( 1,  1, -1);
  fill(1, 1, 1); vertex( 1,  1,  1);
  fill(0, 1, 1); vertex(-1,  1,  1);

  fill(0, 0, 0); vertex(-1, -1, -1);
  fill(1, 0, 0); vertex( 1, -1, -1);
  fill(1, 0, 1); vertex( 1, -1,  1);
  fill(0, 0, 1); vertex(-1, -1,  1);

  endShape();

  popMatrix();
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Shape/ScaleShape/ScaleShape.pde
/**
 * Scale Shape.
 * Illustration by <NAME>.
 *
 * Move the mouse left and right to zoom the SVG file.
 * This shows how, unlike an imported image, the lines
 * remain smooth at any size.
 */

PShape bot;

void setup() {
  size(640, 360);
  // The file "bot1.svg" must be in the data folder
  // of the current sketch to load successfully
  bot = loadShape("bot1.svg");
}

void draw() {
  background(102);
  translate(width/2, height/2);
  float zoom = map(mouseX, 0, width, 0.1, 4.5);
  scale(zoom);
  shape(bot, -140, -140);
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/serial/library.properties
name = Serial
version = 1

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Cellular Automata/Spore2/Spore2.pde
/**
 * Spore 2
 * by <NAME>.
 *
 * A short program for alife experiments. Click in the window to restart.
 * Each cell is represented by a pixel on the display as well as an entry in
 * the array 'cells'. Each cell has a run() method, which performs actions
 * based on the cell's surroundings.  Cells run one at a time (to avoid conflicts
 * like wanting to move to the same space) and in random order.
 */

World w;
int maxcells = 8000;
int numcells;
Cell[] cells = new Cell[maxcells];
color spore1, spore2, spore3, spore4;
color black = color(0, 0, 0);
// set lower for smoother animation, higher for faster simulation
int runs_per_loop = 10000;

void setup()
{
  size(640, 360);
  frameRate(24);
  reset();
}

void reset() {
  clearScreen();
  w = new World();
  spore1 = color(128, 172, 255);
  spore2 = color(64, 128, 255);
  spore3 = color(255, 128, 172);
  spore4 = color(255, 64, 128);
  numcells = 0;
  seed();
}

void seed()
{
  // Add cells at random places
  for (int i = 0; i < maxcells; i++)
  {
    int cX = int(random(width));
    int cY = int(random(height));
    int c;
    float r = random(1);
    if (r < 0.25) c = spore1;
    else if (r < 0.5) c = spore2;
    else if (r < 0.75) c = spore3;
    else c = spore4;
    if (w.getpix(cX, cY) == black)
    {
      w.setpix(cX, cY, c);
      cells[numcells] = new Cell(cX, cY);
      numcells++;
    }
  }
}

void draw() {
  // Run cells in random order
  for (int i = 0; i < runs_per_loop; i++) {
    int selected = min((int)random(numcells), numcells - 1);
    cells[selected].run();
  }
}

void clearScreen() {
  background(0);
}

class Cell {
  int x, y;
  Cell(int xin, int yin) {
    x = xin;
    y = yin;
  }

  // Perform action based on surroundings
  void run() {
    // Fix cell coordinates
    while(x < 0) {
      x+=width;
    }
    while(x > width - 1) {
      x-=width;
    }
    while(y < 0) {
      y+=height;
    }
    while(y > height - 1) {
      y-=height;
    }

    // Cell instructions
    int myColor = w.getpix(x, y);
    if (myColor == spore1) {
      if (w.getpix(x - 1, y + 1) == black && w.getpix(x + 1, y + 1) == black && w.getpix(x, y + 1) == black) move(0, 1);
      else if (w.getpix(x - 1, y) == spore2 && w.getpix(x - 1, y - 1) != black) move(0, -1);
      else if (w.getpix(x - 1, y) == spore2 && w.getpix(x - 1, y - 1) == black) move(-1, -1);
      else if (w.getpix(x + 1, y) == spore1 && w.getpix(x + 1, y - 1) != black) move(0, -1);
      else if (w.getpix(x + 1, y) == spore1 && w.getpix(x + 1, y - 1) == black) move(1, -1);
      else move((int)random(3) - 1, 0);
    } else if (myColor == spore2) {
      if (w.getpix(x - 1, y + 1) == black && w.getpix(x + 1, y + 1) == black && w.getpix(x, y + 1) == black) move(0, 1);
      else if (w.getpix(x + 1, y) == spore1 && w.getpix(x + 1, y - 1) != black) move(0, -1);
      else if (w.getpix(x + 1, y) == spore1 && w.getpix(x + 1, y - 1) == black) move(1, -1);
      else if (w.getpix(x - 1, y) == spore2 && w.getpix(x - 1, y - 1) != black) move(0, -1);
      else if (w.getpix(x - 1, y) == spore2 && w.getpix(x - 1, y - 1) == black) move(-1, -1);
      else move((int)random(3) - 1, 0);
    }
    else if (myColor == spore3)
    {
      if (w.getpix(x - 1, y - 1) == black && w.getpix(x + 1, y - 1) == black && w.getpix(x, y - 1) == black) move(0, -1);
      else if (w.getpix(x - 1, y) == spore4 && w.getpix(x - 1, y + 1) != black) move(0, 1);
      else if (w.getpix(x - 1, y) == spore4 && w.getpix(x - 1, y + 1) == black) move(-1, 1);
      else if (w.getpix(x + 1, y) == spore3 && w.getpix(x + 1, y + 1) != black) move(0, 1);
      else if (w.getpix(x + 1, y) == spore3 && w.getpix(x + 1, y + 1) == black) move(1, 1);
      else move((int)random(3) - 1, 0);
    }
    else if (myColor == spore4)
    {
      if (w.getpix(x - 1, y - 1) == black && w.getpix(x + 1, y - 1) == black && w.getpix(x, y - 1) == black) move(0, -1);
      else if (w.getpix(x + 1, y) == spore3 && w.getpix(x + 1, y + 1) != black) move(0, 1);
      else if (w.getpix(x + 1, y) == spore3 && w.getpix(x + 1, y + 1) == black) move(1, 1);
      else if (w.getpix(x - 1, y) == spore4 && w.getpix(x - 1, y + 1) != black) move(0, 1);
      else if (w.getpix(x - 1, y) == spore4 && w.getpix(x - 1, y + 1) == black) move(-1, 1);
      else move((int)random(3) - 1, 0);
    }
  }

  // Will move the cell (dx, dy) units if that space is empty
  void move(int dx, int dy) {
    if (w.getpix(x + dx, y + dy) == black) {
      w.setpix(x + dx, y + dy, w.getpix(x, y));
      w.setpix(x, y, color(0));
      x += dx;
      y += dy;
    }
  }
}

//  The World class simply provides two functions, get and set, which access the
//  display in the same way as getPixel and setPixel.  The only difference is that
//  the World class's get and set do screen wraparound ("toroidal coordinates").
class World {

  void setpix(int x, int y, int c) {
    while(x < 0) x+=width;
    while(x > width - 1) x-=width;
    while(y < 0) y+=height;
    while(y > height - 1) y-=height;
    set(x, y, c);
  }

  color getpix(int x, int y) {
    while(x < 0) x+=width;
    while(x > width - 1) x-=width;
    while(y < 0) y+=height;
    while(y > height - 1) y-=height;
    return get(x, y);
  }
}

void mousePressed() {
  reset();
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Image/LoadDisplayImage/LoadDisplayImage.pde
/**
 * Load and Display
 *
 * Images can be loaded and displayed to the screen at their actual size
 * or any other size.
 */

PImage img;  // Declare variable "a" of type PImage

void setup() {
  size(640, 360);
  // The image file must be in the data folder of the current sketch
  // to load successfully
  img = loadImage("moonwalk.jpg");  // Load the image into the program
}

void draw() {
  // Displays the image at its actual size at point (0,0)
  image(img, 0, 0);
  // Displays the image at point (0, height/2) at half of its size
  image(img, 0, height/2, img.width/2, img.height/2);
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/io/examples/AnalogDigital_SPI_MCP3008/AnalogDigital_SPI_MCP3008.pde
import processing.io.*;
MCP3008 adc;

// see setup.png in the sketch folder for wiring details

void setup() {
  //printArray(SPI.list());
  adc = new MCP3008(SPI.list()[0]);
}

void draw() {
  // this will return a number between 0 and 1
  float measured = adc.analogRead(0);

  // multiply with the supply voltage to get an absolute value
  float volts = 3.3 * measured;
  println("Analog Input 0 is " + volts + "V");

  background(255);
  fill(measured * 255);
  ellipse(width/2, height/2, width * 0.75, width * 0.75);
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Image Processing/Explode/Explode.pde
/**
 * Explode
 * by <NAME>.
 *
 * Mouse horizontal location controls breaking apart of image and
 * Maps pixels from a 2D image into 3D space. Pixel brightness controls
 * translation along z axis.
 */

PImage img;       // The source image
int cellsize = 2; // Dimensions of each cell in the grid
int columns, rows;   // Number of columns and rows in our system

void setup() {
  size(640, 360, P3D);
  img = loadImage("eames.jpg");  // Load the image
  columns = img.width / cellsize;  // Calculate # of columns
  rows = img.height / cellsize;  // Calculate # of rows
}

void draw() {
  background(0);
  // Begin loop for columns
  for ( int i = 0; i < columns; i++) {
    // Begin loop for rows
    for ( int j = 0; j < rows; j++) {
      int x = i*cellsize + cellsize/2;  // x position
      int y = j*cellsize + cellsize/2;  // y position
      int loc = x + y*img.width;  // Pixel array location
      color c = img.pixels[loc];  // Grab the color
      // Calculate a z position as a function of mouseX and pixel brightness
      float z = (mouseX / float(width)) * brightness(img.pixels[loc]) - 20.0;
      // Translate to the location, set fill and stroke, and draw the rect
      pushMatrix();
      translate(x + 200, y + 100, z);
      fill(c, 204);
      noStroke();
      rectMode(CENTER);
      rect(0, 0, cellsize, cellsize);
      popMatrix();
    }
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/pdf/examples/LargePage/LargePage.pde
/**
 * Large Page.
 *
 * Saves one frame as a PDF with a size larger
 * than the screen. When PDF is used as the renderer
 * (the third parameter of size) the display window
 * does not open. The file is saved to the sketch folder.
 * You can open it by "Sketch->Show Sketch Folder."
 */

import processing.pdf.*;

void setup()
{
  size(2000, 2000, PDF, "Line.pdf");
}

void draw()
{
  background(255);
  stroke(0, 20);
  strokeWeight(20.0);
  line(200, 0, width/2, height);

  exit();  // Quit the program
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/lib/welcome/sketchbook.html

    <title> Welcome to Processing 3 </title>
    <link rel="stylesheet" type="text/css" href="style.css"> </style>

Welcome to Processing 3

      Read about what’s new in 3.0 →

      Note that some sketches from Processing 2 may not be compatible.
      What has changed?

        Since older sketches may not be compatible, we recommend creating a new sketchbook folder, so Processing 2 and 3 can happily coexist. This is a one-time process. Read more about it.

            Click here to create a new sketchbook folder for Processing 3 (recommended!)

            Otherwise, your existing sketchbook folder will be used for both old and new sketches (may cause conflicts with installed libraries)

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/io/src/native/Makefile
TARGET := libprocessing-io.so
OBJS := impl.o
CC := gcc

# prefix with -m32 to compile for linux32
CFLAGS := -std=gnu99 -fPIC -g -ffast-math
CFLAGS += -I$(shell dirname $(shell realpath $(shell which javac)))/../include
CFLAGS += -I$(shell dirname $(shell realpath $(shell which javac)))/../include/linux
LDFLAGS := -shared

$(TARGET): $(OBJS)
	$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@

iface.h:
	javah -classpath .. -o iface.h processing.io.NativeInterface

clean:
	rm -f $(TARGET) $(OBJS)

.PHONY: iface.h clean
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Input/Constrain/Constrain.pde
/**
 * Constrain.
 *
 * Move the mouse across the screen to move the circle.
 * The program constrains the circle to its box.
 */

float mx;
float my;
float easing = 0.05;
int radius = 24;
int edge = 100;
int inner = edge + radius;

void setup() {
  size(640, 360);
  noStroke();
  ellipseMode(RADIUS);
  rectMode(CORNERS);
}

void draw() {
  background(51);

  if (abs(mouseX - mx) > 0.1) {
    mx = mx + (mouseX - mx) * easing;
  }
  if (abs(mouseY - my) > 0.1) {
    my = my + (mouseY- my) * easing;
  }

  mx = constrain(mx, inner, width - inner);
  my = constrain(my, inner, height - inner);
  fill(76);
  rect(edge, edge, width-edge, height-edge);
  fill(255);
  ellipse(mx, my, radius, radius);
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/io/examples/Touch_I2C_MPR121/Touch_I2C_MPR121.pde
import processing.io.*;
MPR121 touch;

// see setup.png in the sketch folder for wiring details

void setup() {
  size(600, 200);
  //printArray(I2C.list());
  touch = new MPR121("i2c-1", 0x5a);
}

void draw() {
  background(204);
  noStroke();

  touch.update();

  for (int i=0; i < 12; i++) {
    if (touch.touched(i)) {
      fill(255, 0, 0);
    } else {
      fill(255, 255, 255);
    }
    ellipse((width/12) * (i+0.5), height/2, 20, 20);
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/io/examples/SimpleResistorSensor/SimpleResistorSensor.pde
import processing.io.*;

// using a capacitor that gets charged and discharged, while
// measuring the time it takes, is an inexpensive way to
// read the value of an (analog) resistive sensor, such as
// a photocell
// kudos to ladyada for the original tutorial

// see setup.png in the sketch folder for wiring details

int max = 0;
int min = 9999;

void setup() {
}

void draw() {
  int val = sensorRead(4);
  println(val);

  // track largest and smallest reading, to get a sense
  // how we compare
  if (max < val) {
    max = val;
  }
  if (val < min) {
    min = val;
  }

  // convert current reading into a number between 0.0 and 1.0
  float frac = map(val, min, max, 0.0, 1.0);

  background(255 * frac);
}

int sensorRead(int pin) {
  // discharge the capacitor
  GPIO.pinMode(pin, GPIO.OUTPUT);
  GPIO.digitalWrite(pin, GPIO.LOW);
  delay(100);
  // now the capacitor should be empty

  // measure the time takes to fill it
  // up to ~ 1.4V again
  GPIO.pinMode(pin, GPIO.INPUT);
  int start = millis();
  while (GPIO.digitalRead(pin) == GPIO.LOW) {
    // wait
  }

  // return the time elapsed
  // this will vary based on the value of the
  // resistive sensor (lower resistance will
  // make the capacitor charge faster)
  return millis() - start;
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Demos/Tests/ResizeTest/ResizeTest.pde
void setup() {
  size(400, 400, P3D);
  surface.setResizable(true);
}

void draw() {
  background(255, 0, 0);
  ellipse(width/2, height/2, 100, 50);
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Simulate/GravitationalAttraction3D/Sun.pde
// Gravitational Attraction (3D)
// <NAME> <http://www.shiffman.net>

// A class for an attractive body in our world

class Sun {
  float mass;         // Mass, tied to size
  PVector position;   // position
  float G;            // Universal gravitational constant (arbitrary value)

  Sun() {
    position = new PVector(0, 0);
    mass = 20;
    G = 0.4;
  }

  PVector attract(Planet m) {
    PVector force = PVector.sub(position, m.position);    // Calculate direction of force
    float d = force.mag();                               // Distance between objects
    d = constrain(d, 5.0, 25.0);                           // Limiting the distance to eliminate "extreme" results for very close or very far objects
    float strength = (G * mass * m.mass) / (d * d);      // Calculate gravitional force magnitude
    force.setMag(strength);                              // Get force vector --> magnitude * direction
    return force;
  }

  // Draw Sun
  void display() {
    stroke(255);
    noFill();
    pushMatrix();
    translate(position.x, position.y, position.z);
    sphere(mass*2);
    popMatrix();
  }
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Shaders/DomeProjection/DomeProjection.pde
/**
 * DomeProjection
 *
 * This sketch uses use environmental mapping to render the output
 * on a full spherical dome.
 *
 * Based on the FullDomeTemplate code from <NAME>:
 * https://github.com/mphasize/FullDome
 *
 * Note: This example needs desktop-class graphics to function.
 *
 */

import java.nio.IntBuffer;

PShader cubemapShader;
PShape domeSphere;

IntBuffer fbo;
IntBuffer rbo;
IntBuffer envMapTextureID;

int envMapSize = 1024;

void setup() {
  size(640, 640, P3D);
  initCubeMap();
}

void draw() {
  background(0);
  drawCubeMap();
}

void drawScene() {
  background(0);

  stroke(255, 0, 0);
  strokeWeight(2);
  for (int i = -width; i < 2 * width; i += 50) {
    line(i, -height, -100, i, 2 *height, -100);
  }
  for (int i = -height; i < 2 * height; i += 50) {
    line(-width, i, -100, 2 * width, i, -100);
  }

  lights();
  noStroke();
  translate(mouseX, mouseY, 200);
  rotateX(frameCount * 0.01);
  rotateY(frameCount * 0.01);
  box(100);
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Input/MouseSignals/MouseSignals.pde
/**
 * Mouse Signals.
 *
 * Move and click the mouse to generate signals.
 * The top row is the signal from "mouseX",
 * the middle row is the signal from "mouseY",
 * and the bottom row is the signal from "mousePressed".
 */

int[] xvals;
int[] yvals;
int[] bvals;

void setup()
{
  size(640, 360);
  noSmooth();
  xvals = new int[width];
  yvals = new int[width];
  bvals = new int[width];
}

int arrayindex = 0;

void draw()
{
  background(102);

  for(int i = 1; i < width; i++) {
    xvals[i-1] = xvals[i];
    yvals[i-1] = yvals[i];
    bvals[i-1] = bvals[i];
  }
  // Add the new values to the end of the array
  xvals[width-1] = mouseX;
  yvals[width-1] = mouseY;
  if(mousePressed) {
    bvals[width-1] = 0;
  } else {
    bvals[width-1] = 255;
  }

  fill(255);
  noStroke();
  rect(0, height/3, width, height/3+1);

  for(int i=1; i<width; i++) {
    stroke(255);
    point(i, map(xvals[i],0,width,0,height/3-1));
    stroke(0);
    point(i, height/3+yvals[i]/3);
    stroke(255);
    line(i, 2*height/3+bvals[i]/3, i, (2*height/3+bvals[i-1]/3));
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Create Shapes/BeginEndContour/BeginEndContour.pde
/**
 * BeginEndContour
 *
 * How to cut a shape out of another using beginContour() and endContour()
 */

PShape s;

void setup() {
  size(640, 360, P2D);

  // Make a shape
  s = createShape();
  s.beginShape();
  s.fill(0);
  s.stroke(255);
  s.strokeWeight(2);
  // Exterior part of shape
  s.vertex(-100,-100);
  s.vertex(100,-100);
  s.vertex(100,100);
  s.vertex(-100,100);

  // Interior part of shape
  s.beginContour();
  s.vertex(-10,-10);
  s.vertex(-10,10);
  s.vertex(10,10);
  s.vertex(10,-10);
  s.endContour();

  // Finishing off shape
  s.endShape(CLOSE);
}

void draw() {
  background(52);
  // Display shape
  translate(width/2, height/2);
  // Shapes can be rotated
  s.rotate(0.01);
  shape(s);
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Objects/CompositeObjects/CompositeObjects.pde
/**
 * Composite Objects
 *
 * An object can include several other objects. Creating such composite objects
 * is a good way to use the principles of modularity and build higher levels of
 * abstraction within a program.
 */

EggRing er1, er2;

void setup() {
  size(640, 360);
  er1 = new EggRing(width*0.45, height*0.5, 0.1, 120);
  er2 = new EggRing(width*0.65, height*0.8, 0.05, 180);
}

void draw() {
  background(0);
  er1.transmit();
  er2.transmit();
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Demos/Performance/Esfera/Esfera.pde
/**
 * Esfera
 * by <NAME>.
 *
 * Distribucion aleatoria uniforme sobre la superficie de una esfera.
 */

int cuantos = 16000;
Pelo[] lista ;
float radio = 200;
float rx = 0;
float ry =0;

void setup() {
  size(1024, 768, P3D);

  radio = height/3.5;

  lista = new Pelo[cuantos];
  for (int i = 0; i < lista.length; i++) {
    lista[i] = new Pelo();
  }
  noiseDetail(3);
}

void draw() {
  background(0);

  float rxp = (mouseX-(width/2)) * 0.005;
  float ryp = (mouseY-(height/2)) * 0.005;
  rx = rx*0.9 + rxp*0.1;
  ry = ry*0.9 + ryp*0.1;

  translate(width/2, height/2);
  rotateY(rx);
  rotateX(ry);
  fill(0);
  noStroke();
  sphere(radio);

  for (int i = 0; i < lista.length; i++) {
    lista[i].dibujar();
  }

}

class Pelo
{
  float z = random(-radio, radio);
  float phi = random(TWO_PI);
  float largo = random(1.15, 1.2);
  float theta = asin(z/radio);

  Pelo() { // what's wrong with a constructor here
    z = random(-radio, radio);
    phi = random(TWO_PI);
    largo = random(1.15, 1.2);
    theta = asin(z/radio);
  }

  void dibujar() {

    float off = (noise(millis() * 0.0005, sin(phi))-0.5) * 0.3;
    float offb = (noise(millis() * 0.0007, sin(z) * 0.01)-0.5) * 0.3;

    float thetaff = theta+off;
    float phff = phi+offb;
    float x = radio * cos(theta) * cos(phi);
    float y = radio * cos(theta) * sin(phi);
    float z = radio * sin(theta);

    float xo = radio * cos(thetaff) * cos(phff);
    float yo = radio * cos(thetaff) * sin(phff);
    float zo = radio * sin(thetaff);

    float xb = xo * largo;
    float yb = yo * largo;
    float zb = zo * largo;

    strokeWeight(1);
    beginShape(LINES);
    stroke(0);
    vertex(x, y, z);
    stroke(200, 150);
    vertex(xb, yb, zb);
    endShape();
  }
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Typography/Letters/Letters.pde
/**
 * Letters.
 *
 * Draws letters to the screen. This requires loading a font,
 * setting the font, and then drawing the letters.
 */

PFont f;

void setup() {
  size(640, 360);
  background(0);

  // Create the font
  printArray(PFont.list());
  f = createFont("SourceCodePro-Regular.ttf", 24);
  textFont(f);
  textAlign(CENTER, CENTER);
}

void draw() {
  background(0);

  // Set the left and top margin
  int margin = 10;
  translate(margin*4, margin*4);

  int gap = 46;
  int counter = 35;

  for (int y = 0; y < height-gap; y += gap) {
    for (int x = 0; x < width-gap; x += gap) {

      char letter = char(counter);

      if (letter == 'A' || letter == 'E' || letter == 'I' || letter == 'O' || letter == 'U') {
        fill(255, 204, 0);
      }
      else {
        fill(255);
      }

      // Draw the letter to the screen
      text(letter, x, y);

      // Increment the counter
      counter++;
    }
  }
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Motion/CircleCollision/Ball.pde
class Ball {
  PVector position;
  PVector velocity;

  float radius, m;

  Ball(float x, float y, float r_) {
    position = new PVector(x, y);
    velocity = PVector.random2D();
    velocity.mult(3);
    radius = r_;
    m = radius*.1;
  }

  void update() {
    position.add(velocity);
  }

  void checkBoundaryCollision() {
    if (position.x > width-radius) {
      position.x = width-radius;
      velocity.x *= -1;
    } else if (position.x < radius) {
      position.x = radius;
      velocity.x *= -1;
    } else if (position.y > height-radius) {
      position.y = height-radius;
      velocity.y *= -1;
    } else if (position.y < radius) {
      position.y = radius;
      velocity.y *= -1;
    }
  }

  void checkCollision(Ball other) {

    // Get distances between the balls components
    PVector distanceVect = PVector.sub(other.position, position);

    // Calculate magnitude of the vector separating the balls
    float distanceVectMag = distanceVect.mag();

    // Minimum distance before they are touching
    float minDistance = radius + other.radius;

    if (distanceVectMag < minDistance) {
      float distanceCorrection = (minDistance-distanceVectMag)/2.0;
      PVector d = distanceVect.copy();
      PVector correctionVector = d.normalize().mult(distanceCorrection);
      other.position.add(correctionVector);
      position.sub(correctionVector);

      // get angle of distanceVect
      float theta  = distanceVect.heading();
      // precalculate trig values
      float sine = sin(theta);
      float cosine = cos(theta);

      /* bTemp will hold rotated ball positions. You
       just need to worry about bTemp[1] position*/
      PVector[] bTemp = {
        new PVector(), new PVector()
      };

      /* this ball's position is relative to the other
       so you can use the vector between them (bVect) as the
       reference point in the rotation expressions.
       bTemp[0].position.x and bTemp[0].position.y will initialize
       automatically to 0.0, which is what you want
       since b[1] will rotate around b[0] */
      bTemp[1].x  = cosine * distanceVect.x + sine * distanceVect.y;
      bTemp[1].y  = cosine * distanceVect.y - sine * distanceVect.x;

      // rotate Temporary velocities
      PVector[] vTemp = {
        new PVector(), new PVector()
      };

      vTemp[0].x  = cosine * velocity.x + sine * velocity.y;
      vTemp[0].y  = cosine * velocity.y - sine * velocity.x;
      vTemp[1].x  = cosine * other.velocity.x + sine * other.velocity.y;
      vTemp[1].y  = cosine * other.velocity.y - sine * other.velocity.x;

      /* Now that velocities are rotated, you can use 1D
       conservation of momentum equations to calculate
       the final velocity along the x-axis. */
      PVector[] vFinal = {
        new PVector(), new PVector()
      };

      // final rotated velocity for b[0]
      vFinal[0].x = ((m - other.m) * vTemp[0].x + 2 * other.m * vTemp[1].x) / (m + other.m);
      vFinal[0].y = vTemp[0].y;

      // final rotated velocity for b[0]
      vFinal[1].x = ((other.m - m) * vTemp[1].x + 2 * m * vTemp[0].x) / (m + other.m);
      vFinal[1].y = vTemp[1].y;

      // hack to avoid clumping
      bTemp[0].x += vFinal[0].x;
      bTemp[1].x += vFinal[1].x;

      /* Rotate ball positions and velocities back
       Reverse signs in trig expressions to rotate
       in the opposite direction */
      // rotate balls
      PVector[] bFinal = {
        new PVector(), new PVector()
      };

      bFinal[0].x = cosine * bTemp[0].x - sine * bTemp[0].y;
      bFinal[0].y = cosine * bTemp[0].y + sine * bTemp[0].x;
      bFinal[1].x = cosine * bTemp[1].x - sine * bTemp[1].y;
      bFinal[1].y = cosine * bTemp[1].y + sine * bTemp[1].x;

      // update balls to screen position
      other.position.x = position.x + bFinal[1].x;
      other.position.y = position.y + bFinal[1].y;

      position.add(bFinal[0]);

      // update velocities
      velocity.x = cosine * vFinal[0].x - sine * vFinal[0].y;
      velocity.y = cosine * vFinal[0].y + sine * vFinal[0].x;
      other.velocity.x = cosine * vFinal[1].x - sine * vFinal[1].y;
      other.velocity.y = cosine * vFinal[1].y + sine * vFinal[1].x;
    }
  }

  void display() {
    noStroke();
    fill(204);
    ellipse(position.x, position.y, radius*2, radius*2);
  }
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Demos/Tests/OffscreenTest/OffscreenTest.pde
PGraphics pg;

void setup() {
  size(400, 400, P3D);

  pg = createGraphics(400, 400, P3D);
  pg.smooth(4);
}

void draw() {
  background(0);

  pg.beginDraw();
  pg.background(255, 0, 0);
  pg.ellipse(mouseX, mouseY, 100, 100);
  pg.endDraw();

  image(pg, 0, 0, 400, 400);
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Shaders/Landscape/Landscape.pde
/**
 * Elevated
 * https://www.shadertoy.com/view/MdX3Rr by <NAME>
 * Created by <NAME> - iq/2013
 * License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
 * Processing port by <NAME>.
 */

PShader landscape;

void setup() {
  size(640, 360, P2D);
  noStroke();

  // This GLSL code shows how to use shaders from
  // shadertoy in Processing with minimal changes.
  landscape = loadShader("landscape.glsl");
  landscape.set("resolution", float(width), float(height));
}

void draw() {
  background(0);

  landscape.set("time", millis() / 1000.0);
  shader(landscape);
  rect(0, 0, width, height);

  if (frameCount % 10 == 0) {  // every 10th frame
    println("frame: " + frameCount + " - fps: " + frameRate);
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Demos/Tests/NoBackgroundTest/NoBackgroundTest.pde
void setup() {
  size(400, 400, P2D);
  background(255, 0, 0);
  fill(255, 150);
}

void draw() {
  ellipse(mouseX, mouseY, 100, 100);
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Simulate/Chain/Chain.pde
/**
 * Chain.
 *
 * One mass is attached to the mouse position and the other
 * is attached the position of the other mass. The gravity
 * in the environment pulls down on both.
 */

Spring2D s1, s2;

float gravity = 9.0;
float mass = 2.0;

void setup() {
  size(640, 360);
  fill(255, 126);
  // Inputs: x, y, mass, gravity
  s1 = new Spring2D(0.0, width/2, mass, gravity);
  s2 = new Spring2D(0.0, width/2, mass, gravity);
}

void draw() {
  background(0);
  s1.update(mouseX, mouseY);
  s1.display(mouseX, mouseY);
  s2.update(s1.x, s1.y);
  s2.display(s1.x, s1.y);
}

class Spring2D {
  float vx, vy; // The x- and y-axis velocities
  float x, y; // The x- and y-coordinates
  float gravity;
  float mass;
  float radius = 30;
  float stiffness = 0.2;
  float damping = 0.7;

  Spring2D(float xpos, float ypos, float m, float g) {
    x = xpos;
    y = ypos;
    mass = m;
    gravity = g;
  }

  void update(float targetX, float targetY) {
    float forceX = (targetX - x) * stiffness;
    float ax = forceX / mass;
    vx = damping * (vx + ax);
    x += vx;
    float forceY = (targetY - y) * stiffness;
    forceY += gravity;
    float ay = forceY / mass;
    vy = damping * (vy + ay);
    y += vy;
  }

  void display(float nx, float ny) {
    noStroke();
    ellipse(x, y, radius*2, radius*2);
    stroke(255);
    line(x, y, nx, ny);
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/reference/css/processing.css
/*	Part of bugzilla.processing.org customs.

	Original author: <NAME>, http://www.multiblah.com/

	Last Modified: 07.04.2005 - 10:30 Uhr by <NAME> <<EMAIL>>
*/

/* ================ GENERAL CSS ==================

Mostly original stuff from existing site */

body {
	margin				: 0;
	padding				: 0;

	background-color	: #FFFFFF; /* #333322 */

	font-family			: Verdana, Geneva, Arial, Helvetica, sans-serif;
	font-size			: 100%;
	font-weight			: normal;
	line-height			: normal;
	color				: #333333;
}

img
{
	border: 0px solid #000000;
}

a {
	text-decoration: underline;
	font-weight: normal;
	color: #3399CC;
}

a:hover
a:active {
	text-decoration: underline;
	font-weight: normal;
	color: #3399CC;
}

a:visited,
a:link:visited {
	text-decoration: underline;
	font-weight: normal;
	color: #3399CC;
}

#container {
	width: 750px;
	border: 1px none red;
	margin-left: 0px;
	background-color: white;
}

/* ================ HEADER ================== */
#header {
	width: 750px;
	height: 50px;
	overflow: hidden;
	/*background-image:  url("../img/processing_beta.gif");
	background-repeat: no-repeat;
	background-position: left center;*/
	background-color: #000000;
}

#header h1 {
		display: none;
		float: left;
	}

/* Info / FAQ */
#header-info {
	text-align: right;
	float: right;
	width: 200px;
	color: white;
	font-size: 0.7em;
	padding-right: 20px;
	padding-top: 5px;
	padding-bottom: 20px;
	height: 25px;
}

#header-info a:link,
#header-info a
{
	color: #CCCCBE;
}

/* ================ NAVBAR ================== */

#navigation,
#footer {

	font-size: 0.7em;
	color: #CCCCBE;
	/* margin-bottom: 25px; */
}
/*
#navigation a {
	color			: white;
	text-decoration	: underline;
	}

.navBar
	{
	height			: 20px;
	padding			: 5px 0px 0px 55px;
	margin			: 0px;
	}

#mainnav
	{
	background-color		: #333323;
	}

#mainnav_noSub
	{
	background-color		: #5A5A46;
	}

#subnav
	{
	padding					: 5px 0 5px 40px;
	margin-left				: 160px;

	background-color		: #5A5A46;
	background-image		:  url("../img/nav_bottomarrow.gif");
	background-position		: left center;
	background-repeat		: no-repeat;
	}
*/
/*
#subnavAdmin {
	background-color: #95957F;
	background-image:  url("../img/nav_bottomarrow.gif");
	background-position: left center;
	background-repeat: no-repeat;

	height: 15px;
	padding: 5px 0 5px 40px;
	margin-left: 160px;
}
*/

/* ================ CONTENT ================== */
/*
.content {
	float			: right;
	width			: 695px;
	/*margin-top      : 40px;
	font-size		: 0.7em;
	border			: 1px none red;
}
*/

.content em {
	color			: #999966;
	font-style		: normal;
}

/* ================ FOOTER ================== */

#footer {
	clear: both;
	padding-top: 100px;
}

#footer a {
	color: white;
}

#footer #copyright,
#footer #colophon {
	padding: 5px 0 5px 50px;
	}

#footer #copyright {
	background-color: #5A5A4E;
}

#footer #colophon {
	background-color: #000000;
}

#footer #colophon a {
	text-decoration: underline;
	color: white;
}

/* ================ HEADINGS ================== */

h1, h2, h3, h4, h5, h6
	{
	margin-bottom 		: 5px;

	color				: #5A5A46;
	font-family			: Verdana, Geneva, Arial, Helvetica, sans-serif;
	font-weight			: normal;

	line-height			: normal;
	}

h1, h2, h3, h4
	{
	word-spacing		: 0.2em;
	}

h4, h5, h6
{
	font-weight			: bold;
}

/* Font Sizes */

h1 { font-size			: 2em; 		}
h2 { font-size			: 1.85em; 	}
h3 { font-size			: 1.7em; 	}
h4 { font-size			: 1.5em; 	}
h5 { font-size			: 1.25em; 	}
h6 { font-size			: 1em; 		}

p { font-size			: 1em; 		}

/* ================ OTHER ================== */

pre {
	font-family			: "Courier New", Courier, monospace;
	font-size			: 11px;
	line-height			: normal; color: #000000;
}

code {
	font-family			: "Courier New", Courier, monospace;
	font-size			: 11px;
	line-height			: normal; color: #000000;
}

/* ================ CUSTOM IDs ================== */

#front-courses
	{
	clear				: both;
	padding-top			: 10px;
	}

/* ================ CUSTOM CLASSES ================== */

.inputnav {
	font-family			: Verdana, Geneva, Arial, Helvetica, sans-serif;
	font-size			: 11px;
	font-weight			: normal;
	color				: #333333;
}

.titles {
	font-family			: Verdana, Geneva, Arial, Helvetica, sans-serif;
	font-size			: 19px;
	font-weight			: normal;
	color				: #5A5A46;
}

.caption {
	font-family			: Verdana, Geneva, Arial, Helvetica, sans-serif;
	font-size			: 10px;
	font-style			: normal;
	font-weight			: normal;
}

/* ================ EXHIBITION ================== */

.author
	{
	font-weight			: bold;
	color				: #666666;
	}

.curatedImg
	{
	margin-bottom		: -2px;
	}

.curatedBlock
	{
	width				: 225px;
	margin				: 0px;
	}

.curatedBlock p
	{
	padding-top			: 2px;
	padding-right		: 25px;
	margin-bottom		: 0px;
	}

/* ================ COLUMNS ================== */

.doubleColumnWide
	{
	width				: 360px;
	margin-right		: 30px;
	}

/* exhibition -> curated */
.doubleColumnWide
	{
	width				: 450px;
	}

.singleColumn
	{
	width				: 220px;
	}

/* exhibition -> networklinks */
.singleColumnNarrow
	{
	width				: 195px;
	}

.tripleColumn
	{
	width				: 620px;
	margin				: -20px 0px 0px 0px;
	}

.messageColumn {
	width: 400px;
}

.right { float: right; }
.left {	float: left; }
.clear { clear: both; }

/* thumbnail list in exhibiton
reformats a ul */

ul#thumbnail-list, ul#thumbnail-list li, ul#thumbnail-list li a {
	margin: 0; padding: 0;
	display:block;
}
ul#thumbnail-list li {
	margin: 0; padding: 0;
	width: 72px;
	height: 72px;
	display: block;
	margin-right: 1px;
	margin-bottom: 1px;
	float: left;
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Demos/Graphics/Planets/Planets.pde
// Planets, by <NAME>
//
// Sun and mercury textures from http://planetpixelemporium.com
// Star field picture from http://www.galacticimages.com/

PImage starfield;

PShape sun;
PImage suntex;

PShape planet1;
PImage surftex1;
PImage cloudtex;

PShape planet2;
PImage surftex2;

void setup() {
  size(1024, 768, P3D);

  starfield = loadImage("starfield.jpg");
  suntex = loadImage("sun.jpg");
  surftex1 = loadImage("planet.jpg");

  // We need trilinear sampling for this texture so it looks good
  // even when rendered very small.
  //PTexture.Parameters params1 = PTexture.newParameters(ARGB, TRILINEAR);
  surftex2 = loadImage("mercury.jpg");

  /*
  // The clouds texture will "move" having the values of its u
  // texture coordinates displaced by adding a constant increment
  // in each frame. This requires REPEAT wrapping mode so texture
  // coordinates can be larger than 1.
  //PTexture.Parameters params2 = PTexture.newParameters();
  //params2.wrapU = REPEAT;
  cloudtex = createImage(512, 256);

  // Using 3D Perlin noise to generate a clouds texture that is seamless on
  // its edges so it can be applied on a sphere.
  cloudtex.loadPixels();
  Perlin perlin = new Perlin();
  for (int j = 0; j < cloudtex.height; j++) {
    for (int i = 0; i < cloudtex.width; i++) {
      // The angle values corresponding to each u,v pair:
      float u = float(i) / cloudtex.width;
      float v = float(j) / cloudtex.height;
      float phi = map(u, 0, 1, TWO_PI, 0);
      float theta = map(v, 0, 1, -HALF_PI, HALF_PI);
      // The x, y, z point corresponding to these angles:
      float x = cos(phi) * cos(theta);
      float y = sin(theta);
      float z = sin(phi) * cos(theta);
      float n = perlin.noise3D(x, y, z, 1.2, 2, 8);
      cloudtex.pixels[j * cloudtex.width + i] = color(255, 255,  255, 255 * n * n);
    }
  }
  cloudtex.updatePixels();
  */

  noStroke();
  fill(255);
  sphereDetail(40);

  sun = createShape(SPHERE, 150);
  sun.setTexture(suntex);

  planet1 = createShape(SPHERE, 150);
  planet1.setTexture(surftex1);

  planet2 = createShape(SPHERE, 50);
  planet2.setTexture(surftex2);
}

void draw() {
  // Even we draw a full screen image after this, it is recommended to use
  // background to clear the screen anyways, otherwise A3D will think
  // you want to keep each drawn frame in the framebuffer, which results in
  // slower rendering.
  background(0);

  // Disabling writing to the depth mask so the
  // background image doesn't occludes any 3D object.
  hint(DISABLE_DEPTH_MASK);
  image(starfield, 0, 0, width, height);
  hint(ENABLE_DEPTH_MASK);

  pushMatrix();
  translate(width/2, height/2, -300);

  pushMatrix();
  rotateY(PI * frameCount / 500);
  shape(sun);
  popMatrix();

  pointLight(255,  255,  255,  0,  0,  0);
  rotateY(PI * frameCount / 300);
  translate(0, 0, 300);

  shape(planet2);

  popMatrix();

  noLights();
  pointLight(255,  255,  255,  0,  0,  -150);

  translate(0.75 * width,  0.6 * height,  50);
  shape(planet1);
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Data/VariableScope/VariableScope.pde
/**
 * Variable Scope.
 *
 * Variables have a global or local "scope".
 * For example, variables declared within either the
 * setup() or draw() functions may be only used in these
 * functions. Global variables, variables declared outside
 * of setup() and draw(), may be used anywhere within the program.
 * If a local variable is declared with the same name as a
 * global variable, the program will use the local variable to make
 * its calculations within the current scope. Variables are localized
 * within each block, the space between a { and }.
 */

int a = 80;  // Create a global variable "a"

void setup() {
  size(640, 360);
  background(0);
  stroke(255);
  noLoop();
}

void draw() {
  // Draw a line using the global variable "a"
  line(a, 0, a, height);

  // Create a new variable "a" local to the for() statement
  for (int a = 120; a < 200; a += 2) {
    line(a, 0, a, height);
  }

  // Create a new variable "a" local to the draw() function
  int a = 300;
  // Draw a line using the new local variable "a"
  line(a, 0, a, height);

  // Make a call to the custom function drawAnotherLine()
  drawAnotherLine();

  // Make a call to the custom function setYetAnotherLine()
  drawYetAnotherLine();
}

void drawAnotherLine() {
  // Create a new variable "a" local to this method
  int a = 320;
  // Draw a line using the local variable "a"
  line(a, 0, a, height);
}

void drawYetAnotherLine() {
  // Because no new local variable "a" is set,
  // this line draws using the original global
  // variable "a", which is set to the value 80.
  line(a+2, 0, a+2, height);
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Control/Iteration/Iteration.pde
/**
 * Iteration.
 *
 * Iteration with a "for" structure to construct repetitive forms.
 */

int y;
int num = 14;

size(640, 360);
background(102);
noStroke();

// White bars
fill(255);
y = 60;
for(int i = 0; i < num/3; i++) {
  rect(50, y, 475, 10);
  y+=20;
}

// Gray bars
fill(51);
y = 40;
for(int i = 0; i < num; i++) {
  rect(405, y, 30, 10);
  y += 20;
}
y = 50;
for(int i = 0; i < num; i++) {
  rect(425, y, 30, 10);
  y += 20;
}

// Thin lines
y = 45;
fill(0);
for(int i = 0; i < num-1; i++) {
  rect(120, y, 40, 1);
  y+= 20;
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Textures/TextureCube/TextureCube.pde
/**
 * Texture Cube
 * by <NAME>.
 *
 * Drag mouse to rotate cube. Demonstrates use of u/v coords in
 * vertex() and effect on texture(). The textures get distorted using
 * the P3D renderer as you can see, but they look great using OPENGL.
*/

PImage tex;
float rotx = PI/4;
float roty = PI/4;

void setup() {
  size(640, 360, P3D);
  tex = loadImage("berlin-1.jpg");
  textureMode(NORMAL);
  fill(255);
  stroke(color(44,48,32));
}

void draw() {
  background(0);
  noStroke();
  translate(width/2.0, height/2.0, -100);
  rotateX(rotx);
  rotateY(roty);
  scale(90);
  TexturedCube(tex);
}

void TexturedCube(PImage tex) {
  beginShape(QUADS);
  texture(tex);

  // Given one texture and six faces, we can easily set up the uv coordinates
  // such that four of the faces tile "perfectly" along either u or v, but the other
  // two faces cannot be so aligned.  This code tiles "along" u, "around" the X/Z faces
  // and fudges the Y faces - the Y faces are arbitrarily aligned such that a
  // rotation along the X axis will put the "top" of either texture at the "top"
  // of the screen, but is not otherwised aligned with the X/Z faces. (This
  // just affects what type of symmetry is required if you need seamless
  // tiling all the way around the cube)

  // +Z "front" face
  vertex(-1, -1,  1, 0, 0);
  vertex( 1, -1,  1, 1, 0);
  vertex( 1,  1,  1, 1, 1);
  vertex(-1,  1,  1, 0, 1);

  // -Z "back" face
  vertex( 1, -1, -1, 0, 0);
  vertex(-1, -1, -1, 1, 0);
  vertex(-1,  1, -1, 1, 1);
  vertex( 1,  1, -1, 0, 1);

  // +Y "bottom" face
  vertex(-1,  1,  1, 0, 0);
  vertex( 1,  1,  1, 1, 0);
  vertex( 1,  1, -1, 1, 1);
  vertex(-1,  1, -1, 0, 1);

  // -Y "top" face
  vertex(-1, -1, -1, 0, 0);
  vertex( 1, -1, -1, 1, 0);
  vertex( 1, -1,  1, 1, 1);
  vertex(-1, -1,  1, 0, 1);

  // +X "right" face
  vertex( 1, -1,  1, 0, 0);
  vertex( 1, -1, -1, 1, 0);
  vertex( 1,  1, -1, 1, 1);
  vertex( 1,  1,  1, 0, 1);

  // -X "left" face
  vertex(-1, -1, -1, 0, 0);
  vertex(-1, -1,  1, 1, 0);
  vertex(-1,  1,  1, 1, 1);
  vertex(-1,  1, -1, 0, 1);

  endShape();
}

void mouseDragged() {
  float rate = 0.01;
  rotx += (pmouseY-mouseY) * rate;
  roty += (mouseX-pmouseX) * rate;
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Math/IncrementDecrement/IncrementDecrement.pde
/**
 * Increment Decrement.
 *
 * Writing "a++" is equivalent to "a = a + 1".
 * Writing "a--" is equivalent to "a = a - 1".
 */

int a;
int b;
boolean direction;

void setup() {
  size(640, 360);
  colorMode(RGB, width);
  a = 0;
  b = width;
  direction = true;
  frameRate(30);
}

void draw() {
  a++;
  if(a > width) {
    a = 0;
    direction = !direction;
  }
  if(direction == true){
    stroke(a);
  } else {
    stroke(width-a);
  }
  line(a, 0, a, height/2);

  b--;
  if(b < 0) {
    b = width;
  }
  if(direction == true) {
    stroke(width-b);
  } else {
    stroke(b);
  }
  line(b, height/2+1, b, height);
}
<file_sep>/Data and System Management/app/main/views.py
from . import main
from .. import db
from .forms import RequestData, PumpForm, RequestExport
from ..models import Pump, Trigger
import datetime

import pyexcel as pe
import matplotlib.pyplot as plt
from flask import render_template, redirect, url_for, flash, request, Response,make_response
from io import StringIO
import csv
import ast

pumps = []
totals = []
average = []

def creategraph(topic, start, end, pumps, type):
    data = Trigger.query.filter(Trigger.datetime >= start, Trigger.datetime <= end).all()
    print("this is the data:", data)
    ys = []
    xs = []
    y = start
    count = 0
    pumpcount = len(pumps)
    pumpcounts = [0] * pumpcount
    pumpsnested = []
    global pump_total

    for each in pumps:
        pumpsnested.append([])

    if topic == 'hour':
        while y < end:
            ymax = y + datetime.timedelta(minutes=1)
            for each in data:
                if each.pump in pumps:
                    if y < each.datetime < ymax:
                        count += 1
                        temp = pumps.index(each.pump)
                        pumpcounts[temp] += 1
                    else:
                        continue
            for index, each in enumerate(pumpcounts):
                pumpsnested[index].append(each)
            ys.append(count)
            count = 0
            pumpcounts = [0] * pumpcount
            y += datetime.timedelta(minutes=1)

        # X-Axis
        x = start
        while x < end:
            xs.append(x.strftime('%H:%M'))
            x += datetime.timedelta(minutes=1)

        color = 'dimgrey'

    elif topic == 'day':
        while y < end:
            ymax = y + datetime.timedelta(hours=1)

            for each in data:
                if each.pump in pumps:
                    if y < each.datetime < ymax:
                        count += 1
                        temp = pumps.index(each.pump)
                        pumpcounts[temp] += 1
                    else:
                        continue

            for index, each in enumerate(pumpcounts):
                pumpsnested[index].append(each)
            ys.append(count)
            count = 0
            pumpcounts = [0] * pumpcount

            y += datetime.timedelta(hours=1)

        # X-Axis
        x = start
        while x < end:
            xs.append(x.strftime('%H:%M'))
            x += datetime.timedelta(hours=1)
        color = 'dimgrey'

    elif topic == 'week':
        while y < end:
            ymax = y + datetime.timedelta(days=1)
            for each in data:
                if each.pump in pumps:
                    if y < each.datetime < ymax:
                        count += 1
                        temp = pumps.index(each.pump)
                        pumpcounts[temp] += 1
                    else:
                        continue
            for index, each in enumerate(pumpcounts):
                pumpsnested[index].append(each)
            ys.append(count)
            count = 0
            pumpcounts = [0] * pumpcount

            y += datetime.timedelta(days=1)

        # X-Axis
        x = start
        while x < end:
            xs.append(x.strftime('%a'))
            x += datetime.timedelta(days=1)

        color = 'dimgrey'

    elif topic == 'month':
        while y < end:
            ymax = y + datetime.timedelta(days=1)
            for each in data:
                if each.pump in pumps:
                    if y < each.datetime < ymax:
                        count += 1
                        temp = pumps.index(each.pump)
                        pumpcounts[temp] += 1
                    else:
                        continue
            for index, each in enumerate(pumpcounts):
                pumpsnested[index].append(each)
            ys.append(count)
            count = 0
            pumpcounts = [0] * pumpcount

            y += datetime.timedelta(days=1)

        # X-Axis
        x = start
        while x < end:
            xs.append(x.strftime('%x'))
            x += datetime.timedelta(days=1)

        color = 'dimgrey'

    elif topic == 'custom':

        while y < end:
            ymax = y + datetime.timedelta(days=1)
            for each in data:
                if each.pump in pumps:
                    if y < each.datetime < ymax:
                        count += 1
                        temp = pumps.index(each.pump)
                        pumpcounts[temp] += 1
                    else:
                        continue
            for index, each in enumerate(pumpcounts):
                pumpsnested[index].append(each)
            ys.append(count)
            count = 0
            pumpcounts = [0] * pumpcount

            y += datetime.timedelta(days=1)

        # X-Axis
        x = start
        while x < end:
            xs.append(x.strftime('%x'))
            x += datetime.timedelta(days=1)

        color = 'dimgrey'

    else:
        print("I gave up because this was my topic: {}.".format(topic))
        return

    if type == 'line':
        plt.style.use('seaborn-dark')
        plt.plot(xs, ys, color=color, label='Total use')
        n = 0
        totals = []
        for each in pumpsnested:
            totals.append(sum(each))
            ys = each
            label = "Pump {}".format(pumps[n])
            n += 1
            try:
                plt.plot(xs, ys, label=label)
                plt.xlabel('Time/Date')
                plt.ylabel('Times used')
            except:
                print('I screwed up the {}'.format(topic))
                continue

    elif type == 'bar':
        plt.style.use('seaborn-dark')
        totals = []
        for each in pumpsnested:
            totals.append(sum(each))
        print(totals)
        for i in range(0, pumpcount):
            plt.bar(pumps[i], totals[i], color=plt.cm.jet(1. * i / len(totals)))

        plt.xlabel('Pump IDs')
        plt.ylabel('Times used')

    else:
        print("I gave up because this was my type: {}.".format(type))
        return

    plt.legend(bbox_to_anchor=(1, 1),
               bbox_transform=plt.gcf().transFigure)
    plt.xticks(rotation='vertical')
    if topic != 'custom':
        plt.title('Use this {}'.format(topic))
    else:
        plt.title('Use between {} and {}'.format(start.strftime('%x'),end.strftime('%x')))
    # plt.savefig('app/static/images/plot_{}.png'.format(topic))
    plt.savefig('app/static/images/mainGraph.png')
    plt.clf()
    delta = end - start
    average = []
    for each in totals:
        each = each/delta.days
        average.append(int(each))
    print(pumps, totals, average)
    return pumps, totals, average

# Index page
@main.route('/', methods=['GET', 'POST'])
def index():
    global pumps, totals, average
    # Load battery levels
    battery = [each.volt for each in Pump.query.all()]
    pumps = [each.payload for each in Pump.query.all()]
    print(battery)
    battery_p = []
    for each in battery:
        p = ((each-2000)/1000)*100
        if p > 100:
            p = 100
        elif p < 0:
            p = 0
        battery_p.append(int(p))

    print(battery_p)

    # Data plotting of last week
    now = datetime.datetime.now()
    weekquery = now - datetime.timedelta(days=7)

    ALL = [str(each.payload) for each in Pump.query.all()]

    form = RequestData()
    form.pump.choices = [(str(each.payload), str(each.payload)) for each in Pump.query.all()]

    pumps, totals, average= creategraph('week', weekquery, now, ALL, 'line')

    if request.method == 'POST':

        pumps = form.pump.data
        if pumps == []:
            pumps = ALL

        topic = form.topic.data
        if topic == 'custom':
            if form.date1.data == None:
                topic = 'week'
                d1 = now - datetime.timedelta(days=7)
                d2 = now
            else:
                date1 = form.date1.data
                d1 = datetime.datetime.combine(date1, datetime.datetime.min.time())
                date2 = form.date2.data
                d2 = datetime.datetime.combine(date2, datetime.datetime.min.time()) + datetime.timedelta(days=1)
        else:
            d2 = now
            if topic == 'hour':
                d1 = now - datetime.timedelta(hours=1)
            if topic == 'day':
                d1 = now - datetime.timedelta(days=1)
            if topic == 'week':
                d1 = now - datetime.timedelta(days=7)
            if topic == 'month':
                d1 = now - datetime.timedelta(days=30)

        type = form.type.data
        print(topic, d1, d2, pumps, type)
        pumps, totals, average = creategraph(topic, d1, d2, pumps, type)
        return redirect(url_for('main.custom', pumps=pumps, totals=totals, average=average))

    return render_template('index.html', form=form, battery=battery_p, pumps=pumps, totals=totals, average=average)

@main.route('/config', methods=['GET', 'POST'])
def config():
    form = PumpForm()
    pumps = Pump.query.all()
    if form.validate_on_submit():
        pump = Pump(payload=form.payload.data,
                    location=form.location.data,
                    )
        db.session.add(pump)
        db.session.commit()
        return redirect(url_for('main.config'))
    return render_template('config.html', form=form, pumps=pumps)

@main.route('/custom', methods=['GET', 'POST'])
def custom():
    global pumps, totals, average
    form = RequestData()
    form.pump.choices = [(str(each.payload), str(each.payload)) for each in Pump.query.all()]

    if request.method == 'POST':
        now = datetime.datetime.now()
        ALL = [str(each.payload) for each in Pump.query.all()]

        pumps = form.pump.data
        if pumps == []:
            pumps = ALL

        topic = form.topic.data

        if topic == 'custom':
            if form.date1.data == None:
                topic = 'week'
                d1 = now - datetime.timedelta(days=7)
                d2 = now
            else:
                date1 = form.date1.data
                d1 = datetime.datetime.combine(date1, datetime.datetime.min.time())
                if form.date2.data == None:
                    d2 = now
                else:
                    date2 = form.date2.data
                    d2 = datetime.datetime.combine(date2, datetime.datetime.min.time()) + datetime.timedelta(days=1)
        else:
            d2 = now
            if topic == 'hour':
                d1 = now - datetime.timedelta(hours=1)
            if topic == 'day':
                d1 = now - datetime.timedelta(days=1)
            if topic == 'week':
                d1 = now - datetime.timedelta(days=7)
            if topic == 'month':
                d1 = now - datetime.timedelta(days=30)

        type = form.type.data
        print(topic, d1, d2, pumps, type)
        pumps, totals, average = creategraph(topic, d1, d2, pumps, type)
        return redirect(url_for('main.custom', pumps=pumps, totals=totals, average=average))
    return render_template('custom.html', form=form, pumps=pumps, totals=totals, average=average)

@main.route('/export', methods=['GET', 'POST'])
def export():
    form = RequestExport()

    if request.method == 'POST':
        now = datetime.datetime.now()

        if form.date1.data == None:
            topic = 'week'
            d1 = now - datetime.timedelta(days=7)
            d2 = now
        else:
            date1 = form.date1.data
            d1 = datetime.datetime.combine(date1, datetime.datetime.min.time())
            if form.date2.data == None:
                d2 = now
            else:
                date2 = form.date2.data
                d2 = datetime.datetime.combine(date2, datetime.datetime.min.time()) + datetime.timedelta(days=1)

        return redirect(url_for('main.csv', d1=d1, d2=d2))
    return render_template('export.html', form=form)

@main.route('/download/<d1>/<d2>.csv')
def csv(d1, d2):
    query = Trigger.query.filter(Trigger.datetime >= d1, Trigger.datetime <= d2).all()
    data = [(each.datetime, each.pump)for each in query]
    sheet = pe.Sheet(data)
    io = StringIO()
    sheet.save_to_memory("csv", io)
    output = make_response(io.getvalue())
    output.headers["Content-Disposition"] = "attachment; filename=export.csv"
    output.headers["Content-type"] = "text/csv"
    return output

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Textures/TextureQuad/TextureQuad.pde
/**
 * Texture Quad.
 *
 * Load an image and draw it onto a quad. The texture() function sets
 * the texture image. The vertex() function maps the image to the geometry.
 */

PImage img;

void setup() {
  size(640, 360, P3D);
  img = loadImage("berlin-1.jpg");
  noStroke();
}

void draw() {
  background(0);
  translate(width / 2, height / 2);
  rotateY(map(mouseX, 0, width, -PI, PI));
  rotateZ(PI/6);
  beginShape();
  texture(img);
  vertex(-100, -100, 0, 0, 0);
  vertex(100, -100, 0, img.width, 0);
  vertex(100, 100, 0, img.width, img.height);
  vertex(-100, 100, 0, 0, img.height);
  endShape();
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/src/processing/mode/java/pdex/CompletionCandidate.java
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
Part of the Processing project - http://processing.org
Copyright (c) 2012-18 The Processing Foundation

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package processing.mode.java.pdex;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;

import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;

// TODO when building the label in some variants in this file,
// getReturnType2() is used instead of getReturnType().
// need to check whether that's identical in how it performs,
// and if so, use makeLabel() and makeCompletion() more [fry 180326]
// https://help.eclipse.org/neon/index.jsp?topic=%2Forg.eclipse.jdt.doc.isv%2Freference%2Fapi%2Forg%2Feclipse%2Fjdt%2Fcore%2Fdom%2FMethodDeclaration.html

public class CompletionCandidate implements Comparable<CompletionCandidate> {
  private final String elementName;
  private final String label; // the toString value
  private final String completion;
  private final Object wrappedObject;
  private final int type;

  static final int PREDEF_CLASS = 0;
  static final int PREDEF_FIELD = 1;
  static final int PREDEF_METHOD = 2;
  static final int LOCAL_CLASS = 3;
  static final int LOCAL_METHOD = 4;
  static final int LOCAL_FIELD = 5;
  static final int LOCAL_VAR = 6;

  CompletionCandidate(Method method) {
    // return value ignored? [fry 180326]
    method.getDeclaringClass().getName();
    elementName = method.getName();
    label = makeLabel(method);
    completion = makeCompletion(method);
    type = PREDEF_METHOD;
    wrappedObject = method;
  }

  CompletionCandidate(SingleVariableDeclaration svd) {
    completion = svd.getName().toString();
    elementName = svd.getName().toString();
    type = (svd.getParent() instanceof FieldDeclaration) ?
      LOCAL_FIELD : LOCAL_VAR;
    label = svd.getName() + " : " + svd.getType();
    wrappedObject = svd;
  }

  CompletionCandidate(VariableDeclarationFragment  vdf) {
    completion = vdf.getName().toString();
    elementName = vdf.getName().toString();
    type = (vdf.getParent() instanceof FieldDeclaration) ?
      LOCAL_FIELD : LOCAL_VAR;
    label = vdf.getName() + " : " + CompletionGenerator.extracTypeInfo2(vdf);
    wrappedObject = vdf;
  }

  CompletionCandidate(MethodDeclaration method) {
    elementName = method.getName().toString();
    type = LOCAL_METHOD;

    @SuppressWarnings("unchecked")
    List<ASTNode> params = (List<ASTNode>)
      method.getStructuralProperty(MethodDeclaration.PARAMETERS_PROPERTY);

    { // label
      StringBuilder labelBuilder = new StringBuilder(elementName);
      labelBuilder.append('(');
      for (int i = 0; i < params.size(); i++) {
        labelBuilder.append(params.get(i).toString());
        if (i < params.size() - 1) {
          labelBuilder.append(',');
        }
      }
      labelBuilder.append(')');
      if (method.getReturnType2() != null) {
        labelBuilder.append(" : ");
        labelBuilder.append(method.getReturnType2());
      }
      label = labelBuilder.toString();
    }

    { // completion
      StringBuilder compBuilder = new StringBuilder(elementName);
      compBuilder.append('(');

      for (int i = 0; i < params.size(); i++) {
        if (i < params.size() - 1) {
          compBuilder.append(',');
        }
      }
      if (params.size() == 1) {
        compBuilder.append(' ');
      }
      compBuilder.append(')');
      completion = compBuilder.toString();
    }

    wrappedObject = method;
  }

  CompletionCandidate(TypeDeclaration td) {
    type = LOCAL_CLASS;
    elementName = td.getName().toString();
    label = elementName;
    completion = elementName;
    wrappedObject = td;
  }

  CompletionCandidate(Field f) {
    f.getDeclaringClass().getName();
    elementName = f.getName();
    type = PREDEF_FIELD;
    label = "" +
      f.getName() + " : " +
      f.getType().getSimpleName() + " - " +
      "" +
      f.getDeclaringClass().getSimpleName() +
      "";
    completion = elementName;
    wrappedObject = f;
  }

  CompletionCandidate(String elementName, String label,
                      String completion, int type) {
    this(elementName, label, completion, type, null);
  }

  private CompletionCandidate(String elementName, String label,
                              String completion, int type,
                              Object wrappedObject) {
    this.elementName = elementName;
    this.label = label;
    this.completion = completion;
    this.type = type;
    this.wrappedObject = wrappedObject;
  }

  Object getWrappedObject() {
    return wrappedObject;
  }

  public String getElementName() {
    return elementName;
  }

  public String getCompletionString() {
    return completion;
  }

  public int getType() {
    return type;
  }

  public String getLabel() {
    return label;
  }

  // TODO this is gross [fry 180326]
  /*
  private String getNoHtmlLabel(){
    if (!label.contains("")) {
      return label;

    } else {
      StringBuilder ans = new StringBuilder(label);
      while (ans.indexOf("<") > -1) {
        int a = ans.indexOf("<"), b = ans.indexOf(">");
        if (a > b) break;
        ans.replace(a, b+1, "");
      }
      return ans.toString();
    }
  }
  */

  boolean startsWith(String newWord) {
//    System.out.println("checking " + newWord);
//    return getNoHtmlLabel().toLowerCase().startsWith(newWord);
    // this seems to be elementName in all cases [fry 180326]
    return elementName.startsWith(newWord);
  }

  CompletionCandidate withLabelAndCompString(String withLabel,
                                             String withCompletion) {
    return new CompletionCandidate(elementName,
                                   withLabel, withCompletion,
                                   type, wrappedObject);
  }

  CompletionCandidate withRegeneratedCompString() {
    if (wrappedObject instanceof MethodDeclaration) {
      MethodDeclaration method = (MethodDeclaration)wrappedObject;

      @SuppressWarnings("unchecked")
      List<ASTNode> params = (List<ASTNode>)
        method.getStructuralProperty(MethodDeclaration.PARAMETERS_PROPERTY);

      // build the html label
      StringBuilder labelBuilder = new StringBuilder(elementName);
      labelBuilder.append('(');
      for (int i = 0; i < params.size(); i++) {
        labelBuilder.append(params.get(i));
        if (i < params.size() - 1) {
          labelBuilder.append(',');
        }
      }
      labelBuilder.append(')');
      if (method.getReturnType2() != null) {
        labelBuilder.append(" : ");
        labelBuilder.append(method.getReturnType2());
      }

      // build the completion str
      StringBuilder compBuilder = new StringBuilder();
      compBuilder.append(method.getName());
      compBuilder.append('(');
      for (int i = 0; i < params.size(); i++) {
        if (i < params.size() - 1) {
          compBuilder.append(',');
        }
      }
      if (params.size() == 1) {
        compBuilder.append(' ');
      }
      compBuilder.append(')');

      return withLabelAndCompString(labelBuilder.toString(), compBuilder.toString());

    } else if (wrappedObject instanceof Method) {
      Method method = (Method) wrappedObject;
      Class<?>[] types = method.getParameterTypes();

      // build html label
      StringBuilder labelBuilder = new StringBuilder();
      labelBuilder.append("");
      labelBuilder.append(method.getName());
      labelBuilder.append('(');

      for (int i = 0; i < types.length; i++) {
        labelBuilder.append(types[i].getSimpleName());
        if (i < types.length - 1) {
          labelBuilder.append(',');
        }
      }
      labelBuilder.append(')');
      if (method.getReturnType() != null) {
        labelBuilder.append(" : " + method.getReturnType().getSimpleName());
      }

      labelBuilder.append(" - ");
      labelBuilder.append(method.getDeclaringClass().getSimpleName());
      labelBuilder.append("");
      labelBuilder.append("");

      // make completion string
      StringBuilder compBuilder = new StringBuilder(method.getName());
      compBuilder.append('(');
      for (int i = 0; i < types.length; i++) {
        if (i < types.length - 1) {
          compBuilder.append(',');
        }
      }
      if (types.length == 1) {
        compBuilder.append(' ');
      }
      compBuilder.append(')');

      return withLabelAndCompString(labelBuilder.toString(), compBuilder.toString());
    }

    // fall-through silently does nothing? [fry 180326]
    return this;
  }

  static private String makeLabel(Method method) {
    Class<?>[] types = method.getParameterTypes();

    StringBuilder labelBuilder = new StringBuilder();
    labelBuilder.append("");
    labelBuilder.append(method.getName());
    labelBuilder.append('(');

    for (int i = 0; i < types.length; i++) {
      labelBuilder.append(types[i].getSimpleName());
      if (i < types.length - 1) {
        labelBuilder.append(',');
      }
    }
    labelBuilder.append(")");
    if (method.getReturnType() != null) {
      labelBuilder.append(" : ");
      labelBuilder.append(method.getReturnType().getSimpleName());
    }
    labelBuilder.append(" - ");
    labelBuilder.append(method.getDeclaringClass().getSimpleName());
    labelBuilder.append("");
    labelBuilder.append("");

    return labelBuilder.toString();
  }

  static private String makeCompletion(Method method) {
    Class<?>[] types = method.getParameterTypes();

    StringBuilder compBuilder = new StringBuilder();
    compBuilder.append(method.getName());
    compBuilder.append('(');

    for (int i = 0; i < types.length; i++) {
      if (i < types.length - 1) {
        compBuilder.append(',');  // wtf? [fry 180326]
      }
    }
    if (types.length == 1) {
      compBuilder.append(' ');
    }
    compBuilder.append(')');
    return compBuilder.toString();
  }

  @Override
  public int compareTo(CompletionCandidate cc) {
    if (type != cc.getType()) {
      return cc.getType() - type;
    }
    return elementName.compareTo(cc.getElementName());
  }

  public String toString() {
    return label;
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Demos/Tests/RedrawTest/RedrawTest.pde
void setup() {
  size(400, 400, P3D);
  noLoop();
}

void draw() {
  background(255, 0, 0);
  ellipse(mouseX, mouseY, 100, 50);
  println("draw");
}

void keyPressed() {
  redraw();
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Motion/CubesWithinCube/CubesWithinCube.pde
/**
 * Cubes Contained Within a Cube
 * by <NAME>.
 *
 * Collision detection against all
 * outer cube's surfaces.
 */

// 20 little internal cubes
Cube[] cubies = new Cube[20];

// Size of outer cube
float bounds = 300;

void setup() {
  size(640, 360, P3D);

  for (int i = 0; i < cubies.length; i++) {
    // Cubies are randomly sized
    float cubieSize = random(5, 15);
    cubies[i] =  new Cube(cubieSize, cubieSize, cubieSize);
  }

}

void draw() {
  background(50);
  lights();

  // Center in display window
  translate(width/2, height/2, -130);

  // Rotate everything, including external large cube
  rotateX(frameCount * 0.001);
  rotateY(frameCount * 0.002);
  rotateZ(frameCount * 0.001);
  stroke(255);

  // Outer transparent cube, just using box() method
  noFill();
  box(bounds);

  // Move and rotate cubies
  for (Cube c : cubies) {
    c.update();
    c.display();
  }
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Visualization Code/HandWashing/Timer.pde

// -----------------------------
// TIMER
// -----------------------------

void checkTime() {

  //
  if((millis() - start) >= 1000 ) {
    //
    start = millis();
    // Increase Second
    tempSec ++;
    // Calculate Minute
    tempMin = tempSec / 60;
    // Reset
    if (count == maxVerticalHands || tempSec >= maxTempCount) {

      //GERM IMPLENTATION
       if(useGerms == true){
         AddGerm();
       }

      resetTimer();
      count = 0;
    }

  }

  // Semi-Timeout
  if(tempMin >= halfTimeOut) {
    drawState = 2;
  }

  // Timeout
  if(tempMin >= fullTimeOut) {
    drawState = 3;
  }

  // Sub Draw State
  if(drawState == 2 || drawState == 3) {
    if(tempMin > lastMin) {
      println("Now Showing SubState " + subDrawState);
      subDrawState++;
      if(subDrawState >= 3) subDrawState = 1;
    }
  }

  // Reset lastMin
  lastMin = tempMin;

} /*   */

// -----------------------------

void resetTimer() {

  tempSec = 0;
  tempMin = 0;

}

// -----------------------------
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Motion/BouncyBubbles/BouncyBubbles.pde
/**
 * Bouncy Bubbles
 * based on code from <NAME>.
 *
 * Multiple-object collision.
 */

int numBalls = 12;
float spring = 0.05;
float gravity = 0.03;
float friction = -0.9;
Ball[] balls = new Ball[numBalls];

void setup() {
  size(640, 360);
  for (int i = 0; i < numBalls; i++) {
    balls[i] = new Ball(random(width), random(height), random(30, 70), i, balls);
  }
  noStroke();
  fill(255, 204);
}

void draw() {
  background(0);
  for (Ball ball : balls) {
    ball.collide();
    ball.move();
    ball.display();
  }
}

class Ball {

  float x, y;
  float diameter;
  float vx = 0;
  float vy = 0;
  int id;
  Ball[] others;

  Ball(float xin, float yin, float din, int idin, Ball[] oin) {
    x = xin;
    y = yin;
    diameter = din;
    id = idin;
    others = oin;
  }

  void collide() {
    for (int i = id + 1; i < numBalls; i++) {
      float dx = others[i].x - x;
      float dy = others[i].y - y;
      float distance = sqrt(dx*dx + dy*dy);
      float minDist = others[i].diameter/2 + diameter/2;
      if (distance < minDist) {
        float angle = atan2(dy, dx);
        float targetX = x + cos(angle) * minDist;
        float targetY = y + sin(angle) * minDist;
        float ax = (targetX - others[i].x) * spring;
        float ay = (targetY - others[i].y) * spring;
        vx -= ax;
        vy -= ay;
        others[i].vx += ax;
        others[i].vy += ay;
      }
    }
  }

  void move() {
    vy += gravity;
    x += vx;
    y += vy;
    if (x + diameter/2 > width) {
      x = width - diameter/2;
      vx *= friction;
    }
    else if (x - diameter/2 < 0) {
      x = diameter/2;
      vx *= friction;
    }
    if (y + diameter/2 > height) {
      y = height - diameter/2;
      vy *= friction;
    }
    else if (y - diameter/2 < 0) {
      y = diameter/2;
      vy *= friction;
    }
  }

  void display() {
    ellipse(x, y, diameter, diameter);
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/src/processing/mode/java/debug/FieldNode.java
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
  Part of the Processing project - http://processing.org

  Copyright (c) 2012-16 The Processing Foundation

  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  version 2, as published by the Free Software Foundation.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software Foundation,
  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

package processing.mode.java.debug;

import com.sun.jdi.ClassNotLoadedException;
import com.sun.jdi.Field;
import com.sun.jdi.InvalidTypeException;
import com.sun.jdi.ObjectReference;
import com.sun.jdi.Value;

import processing.app.Messages;

/**
 * Specialized {@link VariableNode} for representing fields. Overrides
 * {@link #setValue} to properly change the value of the encapsulated field.
 */
public class FieldNode extends VariableNode {
  protected Field field;
  protected ObjectReference obj;

  /**
   * Construct a {@link FieldNode}.
   * @param obj a reference to the object containing the field
   */
  public FieldNode(String name, String type, Value value, Field field,
                   ObjectReference obj) {
    super(name, type, value);
    this.field = field;
    this.obj = obj;
  }

  @Override
  public void setValue(Value value) {
    try {
      obj.setValue(field, value);
    } catch (InvalidTypeException ite) {
      Messages.loge(null, ite);
    } catch (ClassNotLoadedException cnle) {
      Messages.loge(null, cnle);
    }
    this.value = value;
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Simulate/MultipleParticleSystems/CrazyParticle.pde
// A subclass of Particle

class CrazyParticle extends Particle {

  // Just adding one new variable to a CrazyParticle
  // It inherits all other fields from "Particle", and we don't have to retype them!
  float theta;

  // The CrazyParticle constructor can call the parent class (super class) constructor
  CrazyParticle(PVector l) {
    // "super" means do everything from the constructor in Particle
    super(l);
    // One more line of code to deal with the new variable, theta
    theta = 0.0;
  }

  // Notice we don't have the method run() here; it is inherited from Particle

  // This update() method overrides the parent class update() method
  void update() {
    super.update();
    // Increment rotation based on horizontal velocity
    float theta_vel = (velocity.x * velocity.mag()) / 10.0f;
    theta += theta_vel;
  }

  // This display() method overrides the parent class display() method
  void display() {
    // Render the ellipse just like in a regular particle
    super.display();
    // Then add a rotating line
    pushMatrix();
    translate(position.x, position.y);
    rotate(theta);
    stroke(255, lifespan);
    line(0, 0, 25, 0);
    popMatrix();
  }
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Advanced Data/HashMapClass/Word.pde
class Word {

  // Store a count for occurences in two different books
  int countDracula;
  int countFranken;
  // Also the total count
  int totalCount;

  // What is the String
  String word;

  // Where is it on the screen
  PVector position;

  Word(String s) {
    position = new PVector(random(width), random(-height, height*2));
    word = s;
  }

  // We will display a word if it appears at least 5 times
  // and only in one of the books
  boolean qualify() {
    if ((countDracula == totalCount || countFranken == totalCount) && totalCount > 5) {
      return true;
    }
    else {
      return false;
    }
  }

  // Increment the count for Dracula
  void incrementDracula() {
    countDracula++;
    totalCount++;
  }

  // Increment the count for Frankenstein
  void incrementFranken() {
    countFranken++;
    totalCount++;
  }

  // The more often it appears, the faster it falls
  void move() {
    float speed = map(totalCount, 5, 25, 0.1, 0.4);
    speed = constrain(speed,0,10);
    position.y += speed;

    if (position.y > height*2) {
      position.y = -height;
    }
  }

  // Depending on which book it gets a color
  void display() {
    if (countDracula > 0) {
      fill(255);
    }
    else if (countFranken > 0) {
      fill(0);
    }
    // Its size is also tied to number of occurences
    float fs = map(totalCount,5,25,2,24);
    fs = constrain(fs,2,48);
    textSize(fs);
    textAlign(CENTER);
    text(word, position.x, position.y);
  }
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Demos/Graphics/MeshTweening/MeshTweening.pde
// Use of custom vertex attributes.
// Inspired by
// http://pyopengl.sourceforge.net/context/tutorials/shader_4.html

PShader sh;
PShape grid;

void setup() {
  size(640, 360, P3D);
  sh = loadShader("frag.glsl", "vert.glsl");
  shader(sh);

  grid = createShape();
  grid.beginShape(QUADS);
  grid.noStroke();
  grid.fill(150);
  float d = 10;
  for (int x = -500; x < 500; x += d) {
    for (int y = -500; y < 500; y += d) {
      grid.fill(255 * noise(x, y));
      grid.attribPosition("tweened", x, y, 100 * noise(x, y));
      grid.vertex(x, y, 0);

      grid.fill(255 * noise(x + d, y));
      grid.attribPosition("tweened", x + d, y, 100 * noise(x + d, y));
      grid.vertex(x + d, y, 0);

      grid.fill(255 * noise(x + d, y + d));
      grid.attribPosition("tweened", x + d, y + d, 100 * noise(x + d, y + d));
      grid.vertex(x + d, y + d, 0);

      grid.fill(255 * noise(x, y + d));
      grid.attribPosition("tweened", x, y + d, 100 * noise(x, y + d));
      grid.vertex(x, y + d, 0);
    }
  }
  grid.endShape();
}

void draw() {
  background(255);

  sh.set("tween", map(mouseX, 0, width, 0, 1));

  translate(width/2, height/2, 0);
  rotateX(frameCount * 0.01);
  rotateY(frameCount * 0.01);

  shape(grid);
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Fractals and L-Systems/PenroseSnowflake/PenroseSnowflakeLSystem.pde
class PenroseSnowflakeLSystem extends LSystem {

  String ruleF;

  PenroseSnowflakeLSystem() {
    axiom = "F3-F3-F3-F3-F";
    ruleF = "F3-F3-F45-F++F3-F";
    startLength = 450.0;
    theta = radians(18);
    reset();
  }

  void useRule(String r_) {
    rule = r_;
  }

  void useAxiom(String a_) {
    axiom = a_;
  }

  void useLength(float l_) {
    startLength = l_;
  }

  void useTheta(float t_) {
    theta = radians(t_);
  }

  void reset() {
    production = axiom;
    drawLength = startLength;
    generations = 0;
  }

  int getAge() {
    return generations;
  }

  void render() {
    translate(width, height);
    int repeats = 1;

    steps += 3;
    if (steps > production.length()) {
      steps = production.length();
    }

    for (int i = 0; i < steps; i++) {
      char step = production.charAt(i);
      if (step == 'F') {
        for (int j = 0; j < repeats; j++) {
          line(0,0,0, -drawLength);
          translate(0, -drawLength);
        }
        repeats = 1;
      }
      else if (step == '+') {
        for (int j = 0; j < repeats; j++) {
          rotate(theta);
        }
        repeats = 1;
      }
      else if (step == '-') {
        for (int j =0; j < repeats; j++) {
          rotate(-theta);
        }
        repeats = 1;
      }
      else if (step == '[') {
        pushMatrix();
      }
      else if (step == ']') {
        popMatrix();
      }
      else if ( (step >= 48) && (step <= 57) ) {
        repeats += step - 48;
      }
    }
  }

  String iterate(String prod_, String rule_) {
    String newProduction = "";
    for (int i = 0; i < prod_.length(); i++) {
      char step = production.charAt(i);
      if (step == 'F') {
        newProduction = newProduction + ruleF;
      }
      else {
        if (step != 'F') {
          newProduction = newProduction + step;
        }
      }
    }
    drawLength = drawLength * 0.4;
    generations++;
    return newProduction;
  }

}
<file_sep>/Data and System Management/HH_Data.py
from app import create_app, db
from app.models import Pump, Trigger

app = create_app()

@app.shell_context_processor
def make_shell_context():
    return dict(db=db, Pump=Pump, Trigger=Trigger)

# def loopapp():
if __name__ == '__main__':
    app.run(host='127.0.0.1')
    # app.run(host='192.168.137.1')

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Demos/Performance/DynamicParticlesImmediate/DynamicParticlesImmediate.pde
PImage sprite;

int npartTotal = 10000;
int npartPerFrame = 25;
float speed = 1.0;
float gravity = 0.05;
float partSize = 20;

int partLifetime;
PVector positions[];
PVector velocities[];
int lifetimes[];

int fcount, lastm;
float frate;
int fint = 3;

void setup() {
  size(640, 480, P3D);
  frameRate(120);

  sprite = loadImage("sprite.png");

  partLifetime = npartTotal / npartPerFrame;
  initPositions();
  initVelocities();
  initLifetimes();

  // Writing to the depth buffer is disabled to avoid rendering
  // artifacts due to the fact that the particles are semi-transparent
  // but not z-sorted.
  hint(DISABLE_DEPTH_MASK);

  // Testing some hints
  //hint(DISABLE_TRANSFORM_CACHE);
  //hint(ENABLE_ACCURATE_2D);
}

void draw () {
  background(0);

  for (int n = 0; n < npartTotal; n++) {
    lifetimes[n]++;
    if (lifetimes[n] == partLifetime) {
      lifetimes[n] = 0;
    }

    if (0 <= lifetimes[n]) {
      float opacity = 1.0 - float(lifetimes[n]) / partLifetime;

      if (lifetimes[n] == 0) {
        // Re-spawn dead particle
        positions[n].x = mouseX;
        positions[n].y = mouseY;

        float angle = random(0, TWO_PI);
        float s = random(0.5 * speed, 0.5 * speed);
        velocities[n].x = s * cos(angle);
        velocities[n].y = s * sin(angle);
      } else {
        positions[n].x += velocities[n].x;
        positions[n].y += velocities[n].y;

        velocities[n].y += gravity;
      }
      drawParticle(positions[n], opacity);
    }
  }

  fcount += 1;
  int m = millis();
  if (m - lastm > 1000 * fint) {
    frate = float(fcount) / fint;
    fcount = 0;
    lastm = m;
    println("fps: " + frate);
  }
}

void drawParticle(PVector center, float opacity) {
  beginShape(QUAD);
  noStroke();
  tint(255, opacity * 255);
  texture(sprite);
  normal(0, 0, 1);
  vertex(center.x - partSize/2, center.y - partSize/2, 0, 0);
  vertex(center.x + partSize/2, center.y - partSize/2, sprite.width, 0);
  vertex(center.x + partSize/2, center.y + partSize/2, sprite.width, sprite.height);
  vertex(center.x - partSize/2, center.y + partSize/2, 0, sprite.height);
  endShape();
}

void initPositions() {
  positions = new PVector[npartTotal];
  for (int n = 0; n < positions.length; n++) {
    positions[n] = new PVector();
  }
}

void initVelocities() {
  velocities = new PVector[npartTotal];
  for (int n = 0; n < velocities.length; n++) {
    velocities[n] = new PVector();
  }
}

void initLifetimes() {
  // Initializing particles with negative lifetimes so they are added
  // progressively into the screen during the first frames of the sketch
  lifetimes = new int[npartTotal];
  int t = -1;
  for (int n = 0; n < lifetimes.length; n++) {
    if (n % npartPerFrame == 0) {
      t++;
    }
    lifetimes[n] = -t;
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Math/Map/Map.pde
/**
 * Map.
 *
 * Use the map() function to take any number and scale it to a new number
 * that is more useful for the project that you are working on. For example, use the
 * numbers from the mouse position to control the size or color of a shape.
 * In this example, the mouse’s x-coordinate (numbers between 0 and 360) are scaled to
 * new numbers to define the color and size of a circle.
 */

void setup() {
  size(640, 360);
  noStroke();
}

void draw() {
  background(0);
  // Scale the mouseX value from 0 to 640 to a range between 0 and 175
  float c = map(mouseX, 0, width, 0, 175);
  // Scale the mouseX value from 0 to 640 to a range between 40 and 300
  float d = map(mouseX, 0, width, 40, 300);
  fill(255, c, 0);
  ellipse(width/2, height/2, d, d);
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Shaders/Conway/Conway.pde
// GLSL version of Conway's game of life, ported from GLSL sandbox:
// http://glsl.heroku.com/e#207.3
// Exemplifies the use of the ppixels uniform in the shader, that gives
// access to the pixels of the previous frame.
PShader conway;
PGraphics pg;

void setup() {
  size(400, 400, P3D);
  pg = createGraphics(400, 400, P2D);
  pg.noSmooth();
  conway = loadShader("conway.glsl");
  conway.set("resolution", float(pg.width), float(pg.height));
}

void draw() {
  conway.set("time", millis()/1000.0);
  float x = map(mouseX, 0, width, 0, 1);
  float y = map(mouseY, 0, height, 1, 0);
  conway.set("mouse", x, y);
  pg.beginDraw();
  pg.background(0);
  pg.shader(conway);
  pg.rect(0, 0, pg.width, pg.height);
  pg.endDraw();
  image(pg, 0, 0, width, height);
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Math/Interpolate/Interpolate.pde
/**
 * Linear Interpolation.
 *
 * Move the mouse across the screen and the symbol will follow.
 * Between drawing each frame of the animation, the ellipse moves
 * part of the distance (0.05) from its current position toward
 * the cursor using the lerp() function
 *
 * This is the same as the Easing under input only with lerp() instead.
 */

float x;
float y;

void setup() {
  size(640, 360);
  noStroke();
}

void draw() {
  background(51);

  // lerp() calculates a number between two numbers at a specific increment.
  // The amt parameter is the amount to interpolate between the two values
  // where 0.0 equal to the first point, 0.1 is very near the first point, 0.5
  // is half-way in between, etc.

  // Here we are moving 5% of the way to the mouse location each frame
  x = lerp(x, mouseX, 0.05);
  y = lerp(y, mouseY, 0.05);

  fill(255);
  stroke(255);
  ellipse(x, y, 66, 66);
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/serial/examples/SerialCallResponse/SerialCallResponse.pde
/**
 * Serial Call-Response
 * by <NAME>.
 *
 * Sends a byte out the serial port, and reads 3 bytes in.
 * Sets foregound color, xpos, and ypos of a circle onstage
 * using the values returned from the serial port.
 * Thanks to <NAME>  and <NAME> for the improvements.
 *
 * Note: This sketch assumes that the device on the other end of the serial
 * port is going to send a single byte of value 65 (ASCII A) on startup.
 * The sketch waits for that byte, then sends an ASCII A whenever
 * it wants more data.
 */

import processing.serial.*;

int bgcolor;			     // Background color
int fgcolor;			     // Fill color
Serial myPort;                       // The serial port
int[] serialInArray = new int[3];    // Where we'll put what we receive
int serialCount = 0;                 // A count of how many bytes we receive
int xpos, ypos;		             // Starting position of the ball
boolean firstContact = false;        // Whether we've heard from the microcontroller

void setup() {
  size(256, 256);  // Stage size
  noStroke();      // No border on the next thing drawn

  // Set the starting position of the ball (middle of the stage)
  xpos = width/2;
  ypos = height/2;

  // Print a list of the serial ports, for debugging purposes:
  printArray(Serial.list());

  // I know that the first port in the serial list on my mac
  // is always my  FTDI adaptor, so I open Serial.list()[0].
  // On Windows machines, this generally opens COM1.
  // Open whatever port is the one you're using.
  String portName = Serial.list()[0];
  myPort = new Serial(this, portName, 9600);
}

void draw() {
  background(bgcolor);
  fill(fgcolor);
  // Draw the shape
  ellipse(xpos, ypos, 20, 20);
}

void serialEvent(Serial myPort) {
  // read a byte from the serial port:
  int inByte = myPort.read();
  // if this is the first byte received, and it's an A,
  // clear the serial buffer and note that you've
  // had first contact from the microcontroller.
  // Otherwise, add the incoming byte to the array:
  if (firstContact == false) {
    if (inByte == 'A') {
      myPort.clear();          // clear the serial port buffer
      firstContact = true;     // you've had first contact from the microcontroller
      myPort.write('A');       // ask for more
    }
  }
  else {
    // Add the latest byte from the serial port to array:
    serialInArray[serialCount] = inByte;
    serialCount++;

    // If we have 3 bytes:
    if (serialCount > 2 ) {
      xpos = serialInArray[0];
      ypos = serialInArray[1];
      fgcolor = serialInArray[2];

      // print the values (for debugging purposes only):
      println(xpos + "\t" + ypos + "\t" + fgcolor);

      // Send a capital A to request new sensor readings:
      myPort.write('A');
      // Reset serialCount:
      serialCount = 0;
    }
  }
}

/*

//  Serial Call and Response
//  by <NAME>
//  Language: Wiring/Arduino

//  This program sends an ASCII A (byte of value 65) on startup
//  and repeats that until it gets some data in.
//  Then it waits for a byte in the serial port, and
//  sends three sensor values whenever it gets a byte in.

//  Thanks to <NAME> for the improvements

//  Created 26 Sept. 2005
//  Updated 18 April 2008

int firstSensor = 0;    // first analog sensor
int secondSensor = 0;   // second analog sensor
int thirdSensor = 0;    // digital sensor
int inByte = 0;         // incoming serial byte

void setup()
{
  // start serial port at 9600 bps:
  Serial.begin(9600);
  pinMode(2, INPUT);   // digital sensor is on digital pin 2
  establishContact();  // send a byte to establish contact until Processing responds
}

void loop()
{
  // if we get a valid byte, read analog ins:
  if (Serial.available() > 0) {
    // get incoming byte:
    inByte = Serial.read();
    // read first analog input, divide by 4 to make the range 0-255:
    firstSensor = analogRead(0)/4;
    // delay 10ms to let the ADC recover:
    delay(10);
    // read second analog input, divide by 4 to make the range 0-255:
    secondSensor = analogRead(1)/4;
    // read  switch, multiply by 155 and add 100
    // so that you're sending 100 or 255:
    thirdSensor = 100 + (155 * digitalRead(2));
    // send sensor values:
    Serial.write(firstSensor);
    Serial.write(secondSensor);
    Serial.write(thirdSensor);
  }
}

void establishContact() {
 while (Serial.available() <= 0) {
      Serial.write('A');   // send a capital A
      delay(300);
  }
}

*/
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/io/examples/SoftwareServoSweep/SoftwareServoSweep.pde
import processing.io.*;

// see setup.png in the sketch folder for wiring details
// for more reliable operation it is recommended to power
// the servo from an external power source, see setup_better.png

SoftwareServo servo1;
SoftwareServo servo2;

void setup() {
  size(400, 300);
  servo1 = new SoftwareServo(this);
  servo1.attach(17);
  servo2 = new SoftwareServo(this);
  servo2.attach(4);
}

void draw() {
  background(0);
  stroke(255);
  strokeWeight(3);

  // we don't go right to the edge to prevent
  // making the servo unhappy
  float angle = 90 + sin(frameCount / 100.0)*85;
  servo1.write(angle);
  float y = map(angle, 0, 180, 0, height);
  line(0, y, width/2, y);

  angle = 90 + cos(frameCount / 100.0)*85;
  servo2.write(90 + cos(frameCount / 100.0)*85);
  y = map(angle, 0, 180, 0, height);
  line(width/2, y, width, y);
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Demos/Tests/SpecsTest/SpecsTest.pde
size(100, 100, P3D);
PGraphicsOpenGL pg = (PGraphicsOpenGL)g;
println(PGraphicsOpenGL.OPENGL_VENDOR);
println(PGraphicsOpenGL.OPENGL_RENDERER);
println(PGraphicsOpenGL.OPENGL_VERSION);
println(PGraphicsOpenGL.GLSL_VERSION);
println(PGraphicsOpenGL.OPENGL_EXTENSIONS);<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Vectors/BouncingBall/BouncingBall.pde
/**
 * Bouncing Ball with Vectors
 * by <NAME>.
 *
 * Demonstration of using vectors to control motion of body
 * This example is not object-oriented
 * See AccelerationWithVectors for an example of how to simulate motion using vectors in an object
 */

PVector location;  // Location of shape
PVector velocity;  // Velocity of shape
PVector gravity;   // Gravity acts at the shape's acceleration

void setup() {
  size(640,360);
  location = new PVector(100,100);
  velocity = new PVector(1.5,2.1);
  gravity = new PVector(0,0.2);

}

void draw() {
  background(0);

  // Add velocity to the location.
  location.add(velocity);
  // Add gravity to velocity
  velocity.add(gravity);

  // Bounce off edges
  if ((location.x > width) || (location.x < 0)) {
    velocity.x = velocity.x * -1;
  }
  if (location.y > height) {
    // We're reducing velocity ever so slightly
    // when it hits the bottom of the window
    velocity.y = velocity.y * -0.95;
    location.y = height;
  }

  // Display circle at location vector
  stroke(255);
  strokeWeight(2);
  fill(127);
  ellipse(location.x,location.y,48,48);
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Create Shapes/PrimitivePShape/PrimitivePShape.pde
/**
 * PrimitivePShape.
 *
 * Using a PShape to display a primitive shape (in this case, ellipse).
 */

// The PShape object
PShape circle;

void setup() {
  size(640, 360, P2D);
  // Creating the PShape as an ellipse
  circle = createShape(ELLIPSE, 0, 0, 100, 50);
}

void draw() {
  background(51);
  // We can dynamically set the stroke and fill of the shape
  circle.setStroke(color(255));
  circle.setStrokeWeight(4);
  circle.setFill(color(map(mouseX, 0, width, 0, 255)));
  // We can use translate to move the PShape
  translate(mouseX, mouseY);
  // Drawing the PShape
  shape(circle);
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Visualization Code/HandWashing/Key.pde

// -----------------------------
// KEY
// -----------------------------

/*KEY LEGEND

  GENERAL
  1,2,3,4,5,6 = Trigger for hand sanitizers when useSerial is set to false
  Z = Change Drawstate
  Y = Change Subdrawstate (type of graph)
  Q = Toggle useGerms

  THEMES
  O = Ocean
  G = Dogs
  A = African animals
  I = Insects
  C = Canadian animals
  T = Transport
  V = Virus/Germs
  H = Hands (original)
  F = Fantasy
  P = Paleontology (dinos)

*/

void keyPressed() {
  println(key);

  // Trigger
  if (keyCode == '1' || key == '2' || key == '3' || key == '4' || key == '5' || key == '6' ) {
    // Get The Key #
    int id = int(KeyEvent.getKeyText(keyCode));
    // Check If The Timer Has Elapsed
    if( sanitizers[id-1].runTimeout() ) {
      sanitizers[id-1].dispenserTriggered(id-1);
    }
    else {
      println("Sorry, But Sanitizer #" + str(id-1) + " Isn't Ready To Be Triggered Again Quite Yet...");
    }
  }

  // Modes
  else if (key == 'z' || key == 'Z') { // Main State
    drawState++;
    if(drawState >= 4) drawState = 1;
  }
  else if (key == 'y' || key == 'Y') { // Sub State
    subDrawState++;
    if(subDrawState >= 3) subDrawState = 1;
  }

  //Assign Theme Manually
  else if( key == 'o' || key == 'O'){
    if(useGerms == false){
      for (int i = hands.size()-1; i >= 0; i--) {
        hands.remove(i);
      }

      for(int i = 0; i < sanitizers.length; i++) {
        // Id, Color
        sanitizers[i] = new Sanitizer(i, paletteOcean[i], oceanCreatures[i]);

      }
    }
  }
  else if( key == 'g' || key == 'G'){
    if(useGerms == false){
      for (int i = hands.size()-1; i >= 0; i--) {
        hands.remove(i);
      }

      for(int i = 0; i < sanitizers.length; i++) {
        // Id, Color
        sanitizers[i] = new Sanitizer(i, paletteDogs[i], dogs[i]);

      }
    }
  }
  else if( key == 'a' || key == 'A'){
     if(useGerms == false){
      for (int i = hands.size()-1; i >= 0; i--) {
        hands.remove(i);
      }

      for(int i = 0; i < sanitizers.length; i++) {
        // Id, Color
        sanitizers[i] = new Sanitizer(i, paletteAfrica[i], africanAnimals[i]);

      }
    }
  }
  else if( key == 'i' || key == 'I'){
     if(useGerms == false){
      for (int i = hands.size()-1; i >= 0; i--) {
        hands.remove(i);
      }

      for(int i = 0; i < sanitizers.length; i++) {
        // Id, Color
        sanitizers[i] = new Sanitizer(i, paletteInsects[i], insects[i]);

      }
    }
  }
  else if( key == 'c' || key == 'C'){
     if(useGerms == false){
      for (int i = hands.size()-1; i >= 0; i--) {
        hands.remove(i);
      }

      for(int i = 0; i < sanitizers.length; i++) {
        // Id, Color
        sanitizers[i] = new Sanitizer(i, paletteCanada[i], canadianAnimals[i]);

      }
    }
  }
  else if( key == 't' || key == 'T'){
    if(useGerms == false){
      for (int i = hands.size()-1; i >= 0; i--) {
        hands.remove(i);
      }

      for(int i = 0; i < sanitizers.length; i++) {
        // Id, Color
        sanitizers[i] = new Sanitizer(i, paletteTransport[i], transport[i]);

      }
    }
  }
  else if(key == 'v' || key == 'V'){

    if(useGerms == false){
      for (int i = hands.size()-1; i >= 0; i--) {
        hands.remove(i);
      }

      for(int i = 0; i < sanitizers.length; i++) {
        // Id, Color
        sanitizers[i] = new Sanitizer(i, paletteGerms[i], germs[i]);

      }
    }
  }
  else if(key == 'h' || key == 'H'){

    if(useGerms == false){
      for (int i = hands.size()-1; i >= 0; i--) {
        hands.remove(i);
      }

      for(int i = 0; i < sanitizers.length; i++) {
        // Id, Color
        sanitizers[i] = new Sanitizer(i, palette[i], "Shapes/hand.svg");

      }
    }
  }
  else if(key == 'f' || key == 'F'){

    if(useGerms == false){
      for (int i = hands.size()-1; i >= 0; i--) {
        hands.remove(i);
      }

      for(int i = 0; i < sanitizers.length; i++) {
        // Id, Color
        sanitizers[i] = new Sanitizer(i, paletteFantasy[i], fantasy[i]);

      }
    }
  }
  else if(key == 'p' || key == 'P'){

    if(useGerms == false){
      for (int i = hands.size()-1; i >= 0; i--) {
        hands.remove(i);
      }

      for(int i = 0; i < sanitizers.length; i++) {
        // Id, Color
        sanitizers[i] = new Sanitizer(i, paletteGerms[i], dinos[i]);
      }
    }
  }
  else if(key == 'q' || key == 'Q'){

    useGerms = !useGerms;

    if(useGerms == true){
      for (int i = hands.size()-1; i >= 0; i--) {
        hands.remove(i);
      }
      splatter = new ArrayList();
      CreateGermArray();
  }
    else{

      if (splatter.size() != 0){
        for(int i = splatter.size()-1; i >= 0; i--){
        splatter.remove(i);
        }
      }
      for (int i = hands.size()-1; i >= 0; i--) {
        hands.remove(i);

      }

      for(int i = 0; i < sanitizers.length; i++) {
        // Id, Color
        sanitizers[i] = new Sanitizer(i, palette[i], "Shapes/hand.svg");
      }
    }
  }

}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Demos/Performance/CubicGridRetained/CubicGridRetained.pde
/* CubicGridRetained
 *
 * You may need to increase the maximum available memory in the
 * Processing preferences menu.
*/
float boxSize = 20;
float margin = boxSize*2;
float depth = 400;
color boxFill;

PShape grid;

int fcount, lastm;
float frate;
int fint = 3;

void setup() {
  size(640, 360, P3D);
  frameRate(60);
  noSmooth();
  noStroke();

  grid = createShape(GROUP);

  // Build grid using multiple translations
  for (float i =- depth/2+margin; i <= depth/2-margin; i += boxSize){
    for (float j =- height+margin; j <= height-margin; j += boxSize){
      for (float k =- width+margin; k <= width-margin; k += boxSize){
        // Base fill color on counter values, abs function
        // ensures values stay within legal range
        boxFill = color(abs(i), abs(j), abs(k), 50);
        PShape cube = createShape(BOX, boxSize, boxSize, boxSize);
        cube.setFill(boxFill);
        cube.translate(k, j, i);
        grid.addChild(cube);
      }
    }
  }
}

void draw() {
  background(255);

  hint(DISABLE_DEPTH_TEST);

  // Center and spin grid
  pushMatrix();
  translate(width/2, height/2, -depth);
  rotateY(frameCount * 0.01);
  rotateX(frameCount * 0.01);

  shape(grid);
  popMatrix();

  hint(ENABLE_DEPTH_TEST);

  fcount += 1;
  int m = millis();
  if (m - lastm > 1000 * fint) {
    frate = float(fcount) / fint;
    fcount = 0;
    lastm = m;
    println("fps: " + frate);
  }
  fill(0);
  text("fps: " + frate, 10, 20);
}
<file_sep>/Data and System Management/MessageReceiver.py
import paho.mqtt.client as mqtt
import os
from sqlalchemy.orm import sessionmaker

from app.models import Trigger, Pump

from sqlalchemy import create_engine
basedir = os.path.abspath(os.path.dirname(__file__))
engine = create_engine('sqlite:///' + os.path.join(basedir, 'data.sqlite'), echo=True)

Session = sessionmaker(bind=engine)
session = Session()

pump = '01'
username = "MQTT_Username"
password = "<PASSWORD>"
dispenserID = 0

def record_data(topic, payload):
    if topic == 'pumpID':
        trigger = Trigger(pump=payload,
                          )
        session.add(trigger)
        session.commit()
        return
    elif topic == 'volt':
        global pump
        print('Battery level for pump {} is {}'.format(pump, payload))
        temp = session.query(Pump).get(pump)
        print('temp')
        temp.volt = payload
        session.commit()
        return

# Define event callbacks
def on_connect(client, userdata, flags, rc):
    print("rc: " + str(rc))

def on_message(client, obj, msg):
    print(msg.topic + " " + str(msg.qos) + " " + str(msg.payload))
    topic = str(msg.topic)
    if topic == 'pumpID':
        payload = str(msg.payload)
        payload = payload[2:-1]
        record_data(topic, payload)
        global pump
        pump = payload
    elif topic == 'volt':
        payload = str(msg.payload)
        payload = payload[2:-1]
        record_data(topic, payload)

def on_publish(client, obj, mid):
    print("mid: " + str(mid))

def on_subscribe(client, obj, mid, granted_qos):
    print("Subscribed: " + str(mid) + " " + str(granted_qos))

def on_log(client, obj, level, string):
    print(string)

mqttc = mqtt.Client()
# Assign event callbacks
mqttc.on_message = on_message
mqttc.on_connect = on_connect
mqttc.on_publish = on_publish
mqttc.on_subscribe = on_subscribe

# Connect to the mosquitto broker
mqttc.username_pw_set(username, password)
mqttc.connect('127.0.0.1', 1883)
mqttc.subscribe('pumpID', 0)
mqttc.subscribe('volt', 0)

# Continue the network loop, exit when an error occurs
rc = 0
while rc == 0:
    rc = mqttc.loop()
print("rc: " + str(rc))<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Create Shapes/WigglePShape/WigglePShape.pde
/**
 * WigglePShape.
 *
 * How to move the individual vertices of a PShape
 */

// A "Wiggler" object
Wiggler w;

void setup() {
  size(640, 360, P2D);
  w = new Wiggler();
}

void draw() {
  background(255);
  w.display();
  w.wiggle();
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Camera/Orthographic/Orthographic.pde
/**
 * Perspective vs. Ortho
 *
 * Move the mouse left to right to change the "far"
 * parameter for the perspective() and ortho() functions.
 * This parameter sets the maximum distance from the
 * origin away from the viewer and will clip the geometry.
 * Click a mouse button to switch between the perspective and
 * orthographic projections.
 */

boolean showPerspective = false;

void setup() {
  size(600, 360, P3D);
  noFill();
  fill(255);
  noStroke();
}

void draw() {
  lights();
  background(0);
  float far = map(mouseX, 0, width, 120, 400);
  if (showPerspective == true) {
    perspective(PI/3.0, float(width)/float(height), 10, far);
  } else {
    ortho(-width/2.0, width/2.0, -height/2.0, height/2.0, 10, far);
  }
  translate(width/2, height/2, 0);
  rotateX(-PI/6);
  rotateY(PI/3);
  box(180);
}

void mousePressed() {
  showPerspective = !showPerspective;
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Create Shapes/ParticleSystemPShape/ParticleSystemPShape.pde
/**
 * ParticleSystemPShape
 *
 * A particle system optimized for drawing using PShape
 */

// Particle System object
ParticleSystem ps;
// A PImage for particle's texture
PImage sprite;

void setup() {
  size(640, 360, P2D);
  // Load the image
  sprite = loadImage("sprite.png");
  // A new particle system with 10,000 particles
  ps = new ParticleSystem(10000);

  // Writing to the depth buffer is disabled to avoid rendering
  // artifacts due to the fact that the particles are semi-transparent
  // but not z-sorted.
  hint(DISABLE_DEPTH_MASK);

}

void draw () {
  background(0);
  // Update and display system
  ps.update();
  ps.display();

  // Set the particle system's emitter location to the mouse
  ps.setEmitter(mouseX,mouseY);

  // Display frame rate
  fill(255);
  textSize(16);
  text("Frame rate: " + int(frameRate),10,20);

}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Simulate/Springs/Springs.pde
/**
 * Springs.
 *
 * Move the mouse over one of the circles and click to re-position.
 * When you release the mouse, it will snap back into position.
 * Each circle has a slightly different behavior.
 */

int num = 3;
Spring[] springs = new Spring[num];

void setup() {
  size(640, 360);
  noStroke();
  springs[0] = new Spring(240, 260, 40, 0.98, 8.0, 0.1, springs, 0);
  springs[1] = new Spring(320, 210, 120, 0.95, 9.0, 0.1, springs, 1);
  springs[2] = new Spring(180, 170, 200, 0.90, 9.9, 0.1, springs, 2);
}

void draw() {
  background(51);

  for (Spring spring : springs) {
    spring.update();
    spring.display();
  }
}

void mousePressed() {
  for (Spring spring : springs) {
    spring.pressed();
  }
}

void mouseReleased() {
  for (Spring spring : springs) {
    spring.released();
  }
}

class Spring {
  // Screen values
  float xpos, ypos;
  float tempxpos, tempypos;
  int size = 20;
  boolean over = false;
  boolean move = false;

  // Spring simulation constants
  float mass;       // Mass
  float k = 0.2;    // Spring constant
  float damp;       // Damping
  float rest_posx;  // Rest position X
  float rest_posy;  // Rest position Y

  // Spring simulation variables
  //float pos = 20.0; // Position
  float velx = 0.0;   // X Velocity
  float vely = 0.0;   // Y Velocity
  float accel = 0;    // Acceleration
  float force = 0;    // Force

  Spring[] friends;
  int me;

  // Constructor
  Spring(float x, float y, int s, float d, float m,
  float k_in, Spring[] others, int id) {
    xpos = tempxpos = x;
    ypos = tempypos = y;
    rest_posx = x;
    rest_posy = y;
    size = s;
    damp = d;
    mass = m;
    k = k_in;
    friends = others;
    me = id;
  }

  void update() {
    if (move) {
      rest_posy = mouseY;
      rest_posx = mouseX;
    }

    force = -k * (tempypos - rest_posy);  // f=-ky
    accel = force / mass;                 // Set the acceleration, f=ma == a=f/m
    vely = damp * (vely + accel);         // Set the velocity
    tempypos = tempypos + vely;           // Updated position

    force = -k * (tempxpos - rest_posx);  // f=-ky
    accel = force / mass;                 // Set the acceleration, f=ma == a=f/m
    velx = damp * (velx + accel);         // Set the velocity
    tempxpos = tempxpos + velx;           // Updated position

    if ((overEvent() || move) && !otherOver() ) {
      over = true;
    } else {
      over = false;
    }
  }

  // Test to see if mouse is over this spring
  boolean overEvent() {
    float disX = tempxpos - mouseX;
    float disY = tempypos - mouseY;
    if (sqrt(sq(disX) + sq(disY)) < size/2 ) {
      return true;
    } else {
      return false;
    }
  }

  // Make sure no other springs are active
  boolean otherOver() {
    for (int i=0; i<num; i++) {
      if (i != me) {
        if (friends[i].over == true) {
          return true;
        }
      }
    }
    return false;
  }

  void display() {
    if (over) {
      fill(153);
    } else {
      fill(255);
    }
    ellipse(tempxpos, tempypos, size, size);
  }

  void pressed() {
    if (over) {
      move = true;
    } else {
      move = false;
    }
  }

  void released() {
    move = false;
    rest_posx = xpos;
    rest_posy = ypos;
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Demos/Performance/QuadRendering/QuadRendering.pde

public void setup() {
  size(800, 600, P2D);

  noStroke();
  fill(0, 1);
}

public void draw() {
  background(255);
  for (int i = 0; i < 50000; i++) {
    float x = random(width);
    float y = random(height);
    rect(x, y, 30, 30);
  }
  if (frameCount % 10 == 0) println(frameRate);
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Demos/Graphics/Ribbons/Ribbons.pde
// Ribbons, by <NAME>
// ArcBall class by Ariel, V3ga and <NAME> (flight404)
// This sketch loads 3D atomic coordinates of a protein molecule
// from a file in PDB format (http://www.pdb.org/) and displays
// the structure using a ribbon representation.

String pdbFile = "4HHB.pdb"; // PDB file to read
//String pdbFile = "1CBS.pdb";
//String pdbFile = "2POR.pdb";

// Some parameters to control the visual appearance:
float scaleFactor = 10;          // Size factor
int renderMode = 1;             // 0 = lines, 1 = flat ribbons
int ribbonDetail = 4;           // Ribbon detail: from 1 (lowest) to 4 (highest)
float helixDiam = 10;           // Helix diameter.
int[] ribbonWidth = {10, 7, 2}; // Ribbon widths for helix, strand and coil
color ribbonColor = color(0, 102, 153, 255); // Ribbon color

// All the molecular models read from the PDB file (it could contain more than one)
ArrayList models;

Arcball arcball;

void setup() {
  size(1024, 768, P3D);

  arcball = new Arcball(width/2, height/2, 600);
  readPDB(pdbFile);
}

void draw() {
  background(0);

  ambient(80);
  lights();

  translate(width/2, height/2, 200);
  arcball.run();

  for (int i = 0; i < models.size(); i++) {
    shape((PShape)models.get(i));
  }
}

void mousePressed(){
  arcball.mousePressed();
}

void mouseDragged(){
  arcball.mouseDragged();
}<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Shape/DisableStyle/DisableStyle.pde
/**
 * Ignore Styles.
 * Illustration by <NAME>.
 *
 * Shapes are loaded with style information that tells them how
 * to draw (the color, stroke weight, etc.) The disableStyle()
 * method of PShape turns off this information. The enableStyle()
 * method turns it back on.
 */

PShape bot;

void setup() {
  size(640, 360);
  // The file "bot1.svg" must be in the data folder
  // of the current sketch to load successfully
  bot = loadShape("bot1.svg");
  noLoop();
}

void draw() {
  background(102);

  // Draw left bot
  bot.disableStyle();  // Ignore the colors in the SVG
  fill(0, 102, 153);    // Set the SVG fill to blue
  stroke(255);          // Set the SVG fill to white
  shape(bot, 20, 25, 300, 300);

  // Draw right bot
  bot.enableStyle();
  shape(bot, 320, 25, 300, 300);
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/io/examples/Light_I2C_TSL2561/TSL2561.pde
import processing.io.I2C;

// TSL2561 is light sensor using I2C
// datasheet: https://cdn-shop.adafruit.com/datasheets/TSL2561.pdf
// code contributed by @OlivierLD

public class TSL2561 extends I2C {

  public final static int TSL2561_ADDRESS = 0x39;

  public final static int TSL2561_ADDRESS_LOW = 0x29;
  public final static int TSL2561_ADDRESS_FLOAT = 0x39;
  public final static int TSL2561_ADDRESS_HIGH = 0x49;

  public final static int TSL2561_COMMAND_BIT = 0x80;
  public final static int TSL2561_WORD_BIT = 0x20;
  public final static int TSL2561_CONTROL_POWERON = 0x03;
  public final static int TSL2561_CONTROL_POWEROFF = 0x00;

  public final static int TSL2561_REGISTER_CONTROL = 0x00;
  public final static int TSL2561_REGISTER_TIMING = 0x01;
  public final static int TSL2561_REGISTER_CHAN0_LOW = 0x0C;
  public final static int TSL2561_REGISTER_CHAN0_HIGH = 0x0D;
  public final static int TSL2561_REGISTER_CHAN1_LOW = 0x0E;
  public final static int TSL2561_REGISTER_CHAN1_HIGH = 0x0F;
  public final static int TSL2561_REGISTER_ID = 0x0A;

  public final static int TSL2561_GAIN_1X = 0x00;
  public final static int TSL2561_GAIN_16X = 0x10;

  public final static int TSL2561_INTEGRATIONTIME_13MS = 0x00; // rather 13.7ms
  public final static int TSL2561_INTEGRATIONTIME_101MS = 0x01;
  public final static int TSL2561_INTEGRATIONTIME_402MS = 0x02;

  public final static double TSL2561_LUX_K1C = 0.130;   // (0x0043)  // 0.130 * 2^RATIO_SCALE
  public final static double TSL2561_LUX_B1C = 0.0315;  // (0x0204)  // 0.0315 * 2^LUX_SCALE
  public final static double TSL2561_LUX_M1C = 0.0262;  // (0x01ad)  // 0.0262 * 2^LUX_SCALE
  public final static double TSL2561_LUX_K2C = 0.260;   // (0x0085)  // 0.260 * 2^RATIO_SCALE
  public final static double TSL2561_LUX_B2C = 0.0337;  // (0x0228)  // 0.0337 * 2^LUX_SCALE
  public final static double TSL2561_LUX_M2C = 0.0430;  // (0x02c1)  // 0.0430 * 2^LUX_SCALE
  public final static double TSL2561_LUX_K3C = 0.390;   // (0x00c8)  // 0.390 * 2^RATIO_SCALE
  public final static double TSL2561_LUX_B3C = 0.0363;  // (0x0253)  // 0.0363 * 2^LUX_SCALE
  public final static double TSL2561_LUX_M3C = 0.0529;  // (0x0363)  // 0.0529 * 2^LUX_SCALE
  public final static double TSL2561_LUX_K4C = 0.520;   // (0x010a)  // 0.520 * 2^RATIO_SCALE
  public final static double TSL2561_LUX_B4C = 0.0392;  // (0x0282)  // 0.0392 * 2^LUX_SCALE
  public final static double TSL2561_LUX_M4C = 0.0605;  // (0x03df)  // 0.0605 * 2^LUX_SCALE
  public final static double TSL2561_LUX_K5C = 0.65;    // (0x014d)  // 0.65 * 2^RATIO_SCALE
  public final static double TSL2561_LUX_B5C = 0.0229;  // (0x0177)  // 0.0229 * 2^LUX_SCALE
  public final static double TSL2561_LUX_M5C = 0.0291;  // (0x01dd)  // 0.0291 * 2^LUX_SCALE
  public final static double TSL2561_LUX_K6C = 0.80;    // (0x019a)  // 0.80 * 2^RATIO_SCALE
  public final static double TSL2561_LUX_B6C = 0.0157;  // (0x0101)  // 0.0157 * 2^LUX_SCALE
  public final static double TSL2561_LUX_M6C = 0.0180;  // (0x0127)  // 0.0180 * 2^LUX_SCALE
  public final static double TSL2561_LUX_K7C = 1.3;     // (0x029a)  // 1.3 * 2^RATIO_SCALE
  public final static double TSL2561_LUX_B7C = 0.00338; // (0x0037)  // 0.00338 * 2^LUX_SCALE
  public final static double TSL2561_LUX_M7C = 0.00260; // (0x002b)  // 0.00260 * 2^LUX_SCALE
  public final static double TSL2561_LUX_K8C = 1.3;     // (0x029a)  // 1.3 * 2^RATIO_SCALE
  public final static double TSL2561_LUX_B8C = 0.000;   // (0x0000)  // 0.000 * 2^LUX_SCALE
  public final static double TSL2561_LUX_M8C = 0.000;   // (0x0000)  // 0.000 * 2^LUX_SCALE

  private int gain = TSL2561_GAIN_1X;
  private int integration = TSL2561_INTEGRATIONTIME_402MS;
  private int pause = 800;

  private int address;

  public TSL2561(String dev) {
    this(dev, TSL2561_ADDRESS);
  }

  public TSL2561(String dev, int address) {
    super(dev);
    this.address = address;
    start();
  }

  public void start() {
    command(TSL2561_COMMAND_BIT, (byte) TSL2561_CONTROL_POWERON);
  }

  public void stop() {
    command(TSL2561_COMMAND_BIT, (byte) TSL2561_CONTROL_POWEROFF);
  }

  public void setGain() {
    setGain(TSL2561_GAIN_1X);
  }

  public void setGain(int gain) {
    setGain(gain, TSL2561_INTEGRATIONTIME_402MS);
  }

  public void setGain(int gain, int integration) {
    if (gain != TSL2561_GAIN_1X && gain != TSL2561_GAIN_16X) {
      throw new IllegalArgumentException("Invalid gain value");
    }
    if (gain != this.gain || integration != this.integration) {
      command(TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, (byte) (gain | integration));
      //println("Setting low gain");
      this.gain = gain;
      this.integration = integration;
      delay(pause); // pause for integration (pause must be bigger than integration time)
    }
  }

  /**
   * Read visible+IR diode from the I2C device
   */
  public int readFull() {
    int reg = TSL2561_COMMAND_BIT | TSL2561_REGISTER_CHAN0_LOW;
    return readU16(reg);
  }

  /**
   * Read IR only diode from the I2C device
   */
  public int readIR() {
    int reg = TSL2561_COMMAND_BIT | TSL2561_REGISTER_CHAN1_LOW;
    return readU16(reg);
  }

  /**
   * Device lux range 0.1 - 40,000+
   * see https://learn.adafruit.com/tsl2561/overview
   */
  public float lux() {
    int ambient = this.readFull();
    int ir = this.readIR();

    //println("IR Result: " + ir);
    //println("Ambient Result: " + ambient);

    if (ambient >= 0xffff || ir >= 0xffff) {
      throw new RuntimeException("Gain too high, values exceed range");
    }
    double ratio = (ir / (float) ambient);

    /*
     * For the values below, see https://github.com/adafruit/_TSL2561/blob/master/_TSL2561_U.h
     */
    float lux = 0.0f;
    if ((ratio >= 0) && (ratio <= TSL2561_LUX_K4C)) {
      lux = (float)((TSL2561_LUX_B1C * ambient) - (0.0593 * ambient * (Math.pow(ratio, 1.4))));
    } else if (ratio <= TSL2561_LUX_K5C) {
      lux = (float)((TSL2561_LUX_B5C * ambient) - (TSL2561_LUX_M5C * ir));
    } else if (ratio <= TSL2561_LUX_K6C) {
      lux = (float)((TSL2561_LUX_B6C * ambient) - (TSL2561_LUX_M6C * ir));
    } else if (ratio <= TSL2561_LUX_K7C) {
      lux = (float)((TSL2561_LUX_B7C * ambient) - (TSL2561_LUX_M7C * ir));
    } else if (ratio > TSL2561_LUX_K8C) {
      lux = 0.0f;
    }
    return lux;
  }

  private void command(int register, byte value) {
    beginTransmission(address);
    write(register);
    write(value);
    endTransmission();
  }

  private int readU8(int register) {
    beginTransmission(this.address);
    write(register);
    byte[] ba = read(1);
    endTransmission();
    return (int)(ba[0] & 0xFF);
  }

  private int readU16(int register) {
    int lo = readU8(register);
    int hi = readU8(register + 1);
    int result = (hi << 8) + lo; // Big Endian
    //println("(U16) I2C: Device " + toHex(TSL2561_ADDRESS) + " returned " + toHex(result) + " from reg " + toHex(register));
    return result;
  }

  private String toHex(int i) {
    String s = Integer.toString(i, 16).toUpperCase();
    while (s.length() % 2 != 0) {
      s = "0" + s;
    }
    return "0x" + s;
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Math/Noise2D/Noise2D.pde
/**
 * Noise2D
 * by <NAME>.
 *
 * Using 2D noise to create simple texture.
 */

float increment = 0.02;

void setup() {
  size(640, 360);
}

void draw() {

  loadPixels();

  float xoff = 0.0; // Start xoff at 0
  float detail = map(mouseX, 0, width, 0.1, 0.6);
  noiseDetail(8, detail);

  // For every x,y coordinate in a 2D space, calculate a noise value and produce a brightness value
  for (int x = 0; x < width; x++) {
    xoff += increment;   // Increment xoff
    float yoff = 0.0;   // For every xoff, start yoff at 0
    for (int y = 0; y < height; y++) {
      yoff += increment; // Increment yoff

      // Calculate noise and scale by 255
      float bright = noise(xoff, yoff) * 255;

      // Try using this line instead
      //float bright = random(0,255);

      // Set each pixel onscreen to a grayscale value
      pixels[x+y*width] = color(bright);
    }
  }

  updatePixels();
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Image Processing/Zoom/Zoom.pde
/**
 * Zoom.
 *
 * Move the cursor over the image to alter its position. Click and press
 * the mouse to zoom. This program displays a series of lines with their
 * heights corresponding to a color value read from an image.
 */

PImage img;
int[][] imgPixels;
float sval = 1.0;
float nmx, nmy;
int res = 5;

void setup() {
  size(640, 360, P3D);
  noFill();
  stroke(255);
  img = loadImage("ystone08.jpg");
  imgPixels = new int[img.width][img.height];
  for (int i = 0; i < img.height; i++) {
    for (int j = 0; j < img.width; j++) {
      imgPixels[j][i] = img.get(j, i);
    }
  }
}

void draw() {
  background(0);

  nmx += (mouseX-nmx)/20;
  nmy += (mouseY-nmy)/20;

  if(mousePressed) {
    sval += 0.005;
  }
  else {
    sval -= 0.01;
  }

  sval = constrain(sval, 1.0, 2.0);

  translate(width/2 + nmx * sval-100, height/2 + nmy*sval - 100, -50);
  scale(sval);
  rotateZ(PI/9 - sval + 1.0);
  rotateX(PI/sval/8 - 0.125);
  rotateY(sval/8 - 0.125);

  translate(-width/2, -height/2, 0);

  for (int i = 0; i < img.height; i += res) {
    for (int j = 0; j < img.width; j += res) {
      float rr = red(imgPixels[j][i]);
      float gg = green(imgPixels[j][i]);
      float bb = blue(imgPixels[j][i]);
      float tt = rr+gg+bb;
      stroke(rr, gg, gg);
      line(i, j, tt/10-20, i, j, tt/10 );
    }
  }
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Web/EmbeddedLinks/EmbeddedLinks.pde
/**
 * Loading URLs.
 *
 * Click on the button to open a URL in a browser
 */

boolean overButton = false;

void setup() {
  size(640, 360);
}

void draw() {
  background(204);

  if (overButton == true) {
    fill(255);
  } else {
    noFill();
  }
  rect(105, 60, 75, 75);
  line(135, 105, 155, 85);
  line(140, 85, 155, 85);
  line(155, 85, 155, 100);
}

void mousePressed() {
  if (overButton) {
    link("http://www.processing.org");
  }
}

void mouseMoved() {
  checkButtons();
}

void mouseDragged() {
  checkButtons();
}

void checkButtons() {
  if (mouseX > 105 && mouseX < 180 && mouseY > 60 && mouseY <135) {
    overButton = true;
  } else {
    overButton = false;
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Motion/CircleCollision/CircleCollision.pde
/**
 * Circle Collision with Swapping Velocities
 * by <NAME>.
 *
 * Based on Keith Peter's Solution in
 * Foundation Actionscript Animation: Making Things Move!
 */

Ball[] balls =  {
  new Ball(100, 400, 20),
  new Ball(700, 400, 80)
};

void setup() {
  size(640, 360);
}

void draw() {
  background(51);

  for (Ball b : balls) {
    b.update();
    b.display();
    b.checkBoundaryCollision();
  }

  balls[0].checkCollision(balls[1]);
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/File IO/SaveOneFrame/SaveOneImage.pde
/**
 * Save One Image
 *
 * The save() function allows you to save an image from the
 * display window. In this example, save() is run when a mouse
 * button is pressed. The image "line.tif" is saved to the
 * same folder as the sketch's program file.
 */

void setup() {
  size(200, 200);
}

void draw() {
  background(204);
  line(0, 0, mouseX, height);
  line(width, 0, 0, mouseY);
}

void mousePressed() {
  save("line.tif");
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Shaders/BlurFilter/BlurFilter.pde
/**
 * Blur Filter
 *
 * Change the default shader to apply a simple, custom blur filter.
 *
 * Press the mouse to switch between the custom and default shader.
 */

PShader blur;

void setup() {
  size(640, 360, P2D);
  blur = loadShader("blur.glsl");
  stroke(255, 0, 0);
  rectMode(CENTER);
}

void draw() {
  filter(blur);
  rect(mouseX, mouseY, 150, 150);
  ellipse(mouseX, mouseY, 100, 100);
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Visualization Code/HandWashing/Clock.pde

// -----------------------------
// CLOCK
// -----------------------------

void displayClock() {
  pushMatrix(); pushStyle();

  /*** DATE ***/

  // Style
  textFont(small);
  textAlign(RIGHT);

  // Date
  theDate  = new SimpleDateFormat("EEEEEEEE").format(date);
  theYear  = new SimpleDateFormat("yyyy").format(date);
  theMonth = new SimpleDateFormat("MMMMMMMMM").format(date);
  theDay   = new SimpleDateFormat("dd").format(date);

  theDate = theDate.toUpperCase();
  theMonth = theMonth.toUpperCase();

  String date = theDate + ", " + theMonth + " " + theDay;

  // Drop Shadow
  fill(dropShadowColor, 200);
  text(date, datePositionX + 2, datePositionY + 2);

  // Text
  fill(textColor, 200);
  text(date, datePositionX, datePositionY);

  /*** TIME ***/

  // Style
  textFont(large);
  textAlign(RIGHT);

  // Time
  theHour = nf(hour(), 2);
  theMin  = nf(minute(), 2);
  theSec  =  nf(second(), 2);

  if(hour() >= 12) {
    theMeridiem = "PM";
  }
  else if(hour() < 12) {
    theMeridiem = "AM";
  }

  time = theHour + ":" + theMin + " " + theMeridiem;

  // Drop Shadow
  fill(dropShadowColor, 200);
  text(time, timePositionX + 2, timePositionY + 2);

  // Text
  fill(textColor, 200);
  text(time, timePositionX, timePositionY);

  // Reset Data
  if ((int(theHour) == 01) && ((int(theMin) == 23  )) && ((int(theSec) == 40))) {
    println("Time's up: theDay is " + theDay + " theDate is " + theDate);

    println("Just Resetting The Day");
    resetData();

  }

  // Get New Calendar
  if ((int(theHour) == 00) && ((int(theMin) == 00  )) && ((int(theSec) == 00))) {
    getCalendar();
  }

  popMatrix(); popStyle();
}

// -----------------------------

void getCalendar() {

  calendar = Calendar.getInstance();
  date  = new java.util.Date(calendar.getTimeInMillis());

}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Fractals and L-Systems/PenroseTile/PenroseLSystem.pde
class PenroseLSystem extends LSystem {

  int steps = 0;
  float somestep = 0.1;
  String ruleW;
  String ruleX;
  String ruleY;
  String ruleZ;

  PenroseLSystem() {
    axiom = "[X]++[X]++[X]++[X]++[X]";
    ruleW = "YF++ZF4-XF[-YF4-WF]++";
    ruleX = "+YF--ZF[3-WF--XF]+";
    ruleY = "-WF++XF[+++YF++ZF]-";
    ruleZ = "--YF++++WF[+ZF++++XF]--XF";
    startLength = 460.0;
    theta = radians(36);
    reset();
  }

  void useRule(String r_) {
    rule = r_;
  }

  void useAxiom(String a_) {
    axiom = a_;
  }

  void useLength(float l_) {
    startLength = l_;
  }

  void useTheta(float t_) {
    theta = radians(t_);
  }

  void reset() {
    production = axiom;
    drawLength = startLength;
    generations = 0;
  }

  int getAge() {
    return generations;
  }

  void render() {
    translate(width/2, height/2);
    int pushes = 0;
    int repeats = 1;
    steps += 12;
    if (steps > production.length()) {
      steps = production.length();
    }

    for (int i = 0; i < steps; i++) {
      char step = production.charAt(i);
      if (step == 'F') {
        stroke(255, 60);
        for (int j = 0; j < repeats; j++) {
          line(0, 0, 0, -drawLength);
          noFill();
          translate(0, -drawLength);
        }
        repeats = 1;
      }
      else if (step == '+') {
        for (int j = 0; j < repeats; j++) {
          rotate(theta);
        }
        repeats = 1;
      }
      else if (step == '-') {
        for (int j =0; j < repeats; j++) {
          rotate(-theta);
        }
        repeats = 1;
      }
      else if (step == '[') {
        pushes++;
        pushMatrix();
      }
      else if (step == ']') {
        popMatrix();
        pushes--;
      }
      else if ( (step >= 48) && (step <= 57) ) {
        repeats = (int)step - 48;
      }
    }

    // Unpush if we need too
    while (pushes > 0) {
      popMatrix();
      pushes--;
    }
  }

  String iterate(String prod_, String rule_) {
    String newProduction = "";
    for (int i = 0; i < prod_.length(); i++) {
      char step = production.charAt(i);
      if (step == 'W') {
        newProduction = newProduction + ruleW;
      }
      else if (step == 'X') {
        newProduction = newProduction + ruleX;
      }
      else if (step == 'Y') {
        newProduction = newProduction + ruleY;
      }
      else if (step == 'Z') {
        newProduction = newProduction + ruleZ;
      }
      else {
        if (step != 'F') {
          newProduction = newProduction + step;
        }
      }
    }

    drawLength = drawLength * 0.5;
    generations++;
    return newProduction;
  }

}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Image Processing/LinearImage/LinearImage.pde
/**
 * Linear Image.
 *
 * Click and drag mouse up and down to control the signal.
 * Press and hold any key to watch the scanning.
 */

PImage img;
int direction = 1;

float signal;

void setup() {
  size(640, 360);
  stroke(255);
  img = loadImage("sea.jpg");
  img.loadPixels();
  loadPixels();
}

void draw() {
  if (signal > img.height-1 || signal < 0) {
    direction = direction * -1;
  }
  if (mousePressed == true) {
    signal = abs(mouseY % img.height);
  }
  else {
    signal += (0.3*direction);
  }

  if (keyPressed == true) {
    set(0, 0, img);
    line(0, signal, img.width, signal);
  }
  else {
    int signalOffset = int(signal)*img.width;
    for (int y = 0; y < img.height; y++) {
      arrayCopy(img.pixels, signalOffset, pixels, y*width, img.width);
    }
    updatePixels();
  }
}

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Interaction/Follow1/Follow1.pde
/**
 * Follow 1
 * based on code from <NAME>.
 *
 * A line segment is pushed and pulled by the cursor.
 */

float x = 100;
float y = 100;
float angle1 = 0.0;
float segLength = 50;

void setup() {
  size(640, 360);
  strokeWeight(20.0);
  stroke(255, 100);
}

void draw() {
  background(0);

  float dx = mouseX - x;
  float dy = mouseY - y;
  angle1 = atan2(dy, dx);
  x = mouseX - (cos(angle1) * segLength);
  y = mouseY - (sin(angle1) * segLength);

  segment(x, y, angle1);
  ellipse(x, y, 20, 20);
}

void segment(float x, float y, float a) {
  pushMatrix();
  translate(x, y);
  rotate(a);
  line(0, 0, segLength, 0);
  popMatrix();
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Basics/Data/Variables/Variables.pde
/**
 * Variables.
 *
 * Variables are used for storing values. In this example, change
 * the values of variables to affect the composition.
 */

size(640, 360);
background(0);
stroke(153);
strokeWeight(4);
strokeCap(SQUARE);

int a = 50;
int b = 120;
int c = 180;

line(a, b, a+c, b);
line(a, b+10, a+c, b+10);
line(a, b+20, a+c, b+20);
line(a, b+30, a+c, b+30);

a = a + c;
b = height-b;

line(a, b, a+c, b);
line(a, b+10, a+c, b+10);
line(a, b+20, a+c, b+20);
line(a, b+30, a+c, b+30);

a = a + c;
b = height-b;

line(a, b, a+c, b);
line(a, b+10, a+c, b+10);
line(a, b+20, a+c, b+20);
line(a, b+30, a+c, b+30);

<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/examples/Topics/Shaders/GlossyFishEye/GlossyFishEye.pde
/**
 * Glossy Fish Eye
 *
 * A fish-eye shader is used on the main surface and
 * a glossy specular reflection shader is used on the
 * offscreen canvas.
 */

PShader fisheye;
PShader glossy;
PGraphics canvas;
PImage img;
PShape ball;

boolean useFishEye = true;

void setup() {
  size(640, 640, P3D);
  canvas = createGraphics(width, height, P3D);

  fisheye = loadShader("FishEye.glsl");
  fisheye.set("aperture", 180.0);

  glossy = loadShader("GlossyFrag.glsl", "GlossyVert.glsl");
  glossy.set("AmbientColour", 0.0, 0.0, 0.0);
  glossy.set("DiffuseColour", 0.9, 0.2, 0.2);
  glossy.set("SpecularColour", 1.0, 1.0, 1.0);
  glossy.set("AmbientIntensity", 1.0);
  glossy.set("DiffuseIntensity", 1.0);
  glossy.set("SpecularIntensity", 0.7);
  glossy.set("Roughness", 0.7);
  glossy.set("Sharpness", 0.0);

  ball = createShape(SPHERE, 50);
  ball.setStroke(false);
}

void draw() {
  canvas.beginDraw();
  canvas.shader(glossy);
  canvas.noStroke();
  canvas.background(0);
  canvas.pushMatrix();
  canvas.rotateY(frameCount * 0.01);
  canvas.pointLight(204, 204, 204, 1000, 1000, 1000);
  canvas.popMatrix();
  for (float x = 0; x < canvas.width + 100; x += 100) {
    for (float y = 0; y < canvas.height + 100; y += 100) {
      for (float z = 0; z < 400; z += 100) {
        canvas.pushMatrix();
        canvas.translate(x, y, -z);
        canvas.shape(ball);
        canvas.popMatrix();
      }
    }
  }
  canvas.endDraw();

  if (useFishEye == true) {
    shader(fisheye);
  }
  image(canvas, 0, 0, width, height);
}

void mousePressed() {
  if (useFishEye) {
    useFishEye = false;
    resetShader();
  } else {
    useFishEye = true;
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/libraries/io/examples/Touch_I2C_MPR121/MPR121.pde
import processing.io.I2C;

// MPR121 is a capacitive-touch sensor controller with 12 channels
// datasheet: https://www.nxp.com/docs/en/data-sheet/MPR121.pdf

class MPR121 extends I2C {
  int address;
  int touched;

  // registers used (there are more)
  static final int EFD0LB = 0x04; // ELE0 Electrode Filtered Data LSB
  static final int E0TTH = 0x41;  // ELE0 Touch Threshold
  static final int E0RTH = 0x42;  // ELE0 Release Threshold
  static final int E0BV = 0x1e;   // ELE0 Baseline Value
  static final int MHDR = 0x2b;   // MHD Rising
  static final int NHDR = 0x2c;   // NHD Amount Rising
  static final int NCLR = 0x2d;   // NCL Rising
  static final int MHDF = 0x2f;   // MHD Falling
  static final int NHDF = 0x30;   // NHD Amount Falling
  static final int NCLF = 0x31;   // NCL Falling
  static final int CDT = 0x5d;    // Filter/Global CDT Configuration
  static final int ECR = 0x5e;    // Electrode Configuration
  static final int SRST = 0x80;   // Soft Reset

  // there can be more than one device connected to the bus
  // as long as they have different addresses
  // possible addresses: 0x5a (default) - 0x5d
  MPR121(String dev, int address) {
    super(dev);
    this.address = address;
    reset();
  }

  void update() {
    beginTransmission(address);
    write(0x00);
    byte[] in = read(2);
    // & 0xff makes sure the byte is not interpreted as a negative value
    touched = (in[1] & 0xff) << 8 | (in[0] & 0xff);
  }

  boolean touched(int channel) {
    if (channel < 0 || 11 < channel) {
      return false;
    }
    if ((touched & (1 << channel)) != 0) {
      return true;
    } else {
      return false;
    }
  }

  void threshold(int touch, int release) {
    for (int i=0; i < 12; i++) {
      threshold(touch, release, i);
    }
  }

  void threshold(int touch, int release, int channel) {
    if (channel < 0 || 11 < channel) {
      return;
    }
    touch = constrain(touch, 0, 255);
    release = constrain(release, 0, 255);
    writeRegister(E0TTH + 2*channel, touch);
    writeRegister(E0RTH + 2*channel, release);
  }

  int analogRead(int channel) {
    if (channel < 0 || 11 < channel) {
      return 0;
    }
    beginTransmission(address);
    write(EFD0LB + 2*channel);
    byte[] in = read(2);
    return (in[1] & 0xff) << 8 | (in[0] & 0xff);
  }

  int analogReadBaseline(int channel) {
    if (channel < 0 || 11 < channel) {
      return 0;
    }
    beginTransmission(address);
    write(E0BV + channel);
    byte[] in = read(1);
    return (in[0] & 0xff) << 2;
  }

  void reset() {
    writeRegister(SRST, 0x63);
    delay(1);
    threshold(12, 6);
    // set baseline filtering control registers (see p. 12)
    writeRegister(MHDR, 0x01);
    writeRegister(NHDR, 0x01);
    writeRegister(NCLR, 0x0e);
    writeRegister(MHDF, 0x01);
    writeRegister(NHDF, 0x05);
    writeRegister(NCLF, 0x01);
    // change sample interval to 1ms period from default 16ms
    writeRegister(CDT, 0x20);
    // start sampling
    writeRegister(ECR, 0x8f);
  }

  void writeRegister(int register, int value) {
    beginTransmission(address);
    write(register);
    write(value);
    endTransmission();
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Libraries/mqtt/library.properties
name=MQTT
category=I/O
authors=[<NAME>](https://github.com/256dpi)
url=https://github.com/256dpi/processing-mqtt
sentence=MQTT library for Processing based on the Eclipse Paho project.
paragraph=
version=16
prettyVersion=1.6.3
lastUpdated=0
minRevision=0
maxRevision=0
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Processing/modes/java/src/processing/mode/java/preproc/SurfaceInfo.java
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
  SizeInfo - parsed elements of a size() or fullScreen() call
  Part of the Processing project - http://processing.org

  Copyright (c) 2015 The Processing Foundation

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software Foundation,
  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

package processing.mode.java.preproc;

import processing.app.Messages;
import processing.core.PApplet;
import processing.data.StringList;

public class SurfaceInfo {
  StringList statements = new StringList();

  String width;
  String height;
  String renderer;
  String path;

  String display;
  /** null for nothing in setup(), 0 for noSmooth(), N for smooth(N) */
  //Integer quality;
//  String smooth;

  boolean hasOldSyntax() {
    if (width.equals("screenWidth") ||
        width.equals("screenHeight") ||
        height.equals("screenHeight") ||
        height.equals("screenWidth")) {
      final String message =
        "The screenWidth and screenHeight variables are named\n" +
        "displayWidth and displayHeight in Processing 3.\n" +
        "Or you can use the fullScreen() method instead of size().";
      Messages.showWarning("Time for a quick update", message, null);
      return true;
    }
    if (width.equals("screen.width") ||
        width.equals("screen.height") ||
        height.equals("screen.height") ||
        height.equals("screen.width")) {
      final String message =
        "The screen.width and screen.height variables are named\n" +
        "displayWidth and displayHeight in Processing 3.\n" +
        "Or you can use the fullScreen() method instead of size().";
      Messages.showWarning("Time for a quick update", message, null);
      return true;
    }
    return false;
  }

  boolean hasBadSize() {
    if (!width.equals("displayWidth") &&
        !width.equals("displayHeight") &&
        PApplet.parseInt(width, -1) == -1) {
      return true;
    }
    if (!height.equals("displayWidth") &&
        !height.equals("displayHeight") &&
        PApplet.parseInt(height, -1) == -1) {
      return true;
    }
    return false;
  }

  void checkEmpty() {
    if (renderer != null) {
      if (renderer.length() == 0) {  // if empty, set null
        renderer = null;
      }
    }
    if (path != null) {
      if (path.length() == 0) {
        path = null;
      }
    }
    if (display != null) {
      if (display.length() == 0) {
        display = null;
      }
    }
  }

//  public String getStatements() {
//    return statements.join(" ");
//  }

  public StringList getStatements() {
    return statements;
  }

  /**
   * Add an item that will be moved from size() into the settings() method.
   * This needs to be the exact version of the statement so that it can be
   * matched against and removed from the size() method in the code.
   */
  public void addStatement(String stmt) {
    statements.append(stmt);
  }

  public void addStatements(StringList list) {
    statements.append(list);
  }

  /** @return true if there's code to be inserted for a settings() method. */
  public boolean hasSettings() {
    return statements.size() != 0;
  }

  /** @return the contents of the settings() method to be inserted */
  public String getSettings() {
    return statements.join(" ");
  }

  // Added for Android Mode to check whether OpenGL is in use
  // https://github.com/processing/processing/issues/4441
  /**
   * Return the renderer specified (null if none specified).
   * @since 3.2.2
   */
  public String getRenderer() {
    return renderer;
  }
}
<file_sep>/Visualization Code/09-09-2019 Processing Visualization Code/Visualization Code/HandWashing/MQTT.pde

// -----------------------------
// MQTT Message Handling
// -----------------------------

MQTTClient client;

void clientConnected() {
  println("client connected");
}

void messageReceived(String topic, byte[] payload) {
  println("new message: " + topic + " - " + new String(payload));
  String msg = new String(payload);
  msg = (msg == null) ? null : msg.trim();
  println(msg);
  String[] components = split(msg, ',');
  Integer temp;
  Integer index;
  temp = Integer.valueOf(components[0]);

  while (temp>6) {
    temp = temp -6;
  }

  index = temp;

  int id = index;
  println(theHour);

  if (id >= 1 && id <= 7) { // is not equal to noise
    if (index == 1 || index == 2 || index == 3 || index == 4 || index == 5 || index == 6 ) {
      // Check If The Timer Has Elapsed
      if ( sanitizers[id-1].runTimeout() ) {
        sanitizers[id-1].dispenserTriggered(id-1);

      } else {
        println("Sorry, But Sanitizer #" + str(id-1) + " Isn't Ready To Be Triggered Again Quite Yet...");
      }
    }
  }
}

void connectionLost() {
  println("connection lost");
}

languages:
Makefile
C++
HTML
Ant Build System
INI
C
Java
Markdown
Processing
JavaScript
Python
Text
GLSL
CSS

repo_language: Makefile