Dǝve Derıso

Google sites is intended to simplify the process of making a web site. However, the documentation can actually make the process harder than it needs to be. For example, changing the calendar on a pre-made template can drive people crazy. This example will hopefully make the process of changing site features easier.

A while back, I shared a Google site template that allows people to organize group projects.

This example will involve changing the calendar page on this site.

Step 1

Go to the site and click on the calendar page.

Step 2

Look for the “Edit Page” Button at the top right-hand corner.

Step 3

Notice that the calendar turns into a ‘placeholder’ and that a save button appears in the top right-hand corner of the screen.

Step 4

Whenever a widget (like a calendar or checklist) turns into a placeholder (ie light brown box), you can click on it. When you click on it, a little bar menu pops up on the top or bottom of the calendar. Look for the icon that has a gear or sprocket or whatever (it means ‘settings’). Click this.

Step 5

In the properties menu, a variety of options are available. At the top, you should see “Display another Calendar.” Click this.

Step 6

If your calendar doesn’t show automatically, paste a link to your calendar here. (For instructions on getting a link to put here, see the Google Calendar Documentation

Python can be cross-compiled as an objective-c application (a native OSX app) using a neat little utility called “py2applet.” Py2applet works off of the “pyobjc” bridge, supports Tkinter, and can quickly be implemented with a few commands on in the terminal.

Here are the steps: (Everything is done in terminal)

1. Download “pyobjc”

easy_install pyobjc==2.2

Note: You will most likely get an error when you try to run pyapplet after you install it. This has something to do with the native copy of python on OSX missing the proper files. To solve the problem, run the following copy.

cp /Library/Python/2.6/site-packages/py2app-0.5.2-py2.6.egg/py2app/apptemplate/prebuilt/main-fat \
/Library/Python/2.6/site-packages/py2app-0.5.2-py2.6.egg/py2app/apptemplate/prebuilt/main-i386

2. Write your python script

Try this example. Copy the code below into textedit and save it as “example.py”.

#!/usr/bin/python
import sys
from Tkinter import *
root = Tk()

def setUpGui():
	gui_title_text = Label(root, text="Type Something Below:")
	gui_title_text.pack()
	global gui_input_text 
	gui_input_text = Entry(root, width=50)
	gui_input_text.focus_set() 
	gui_input_text.pack()
	gui_button = Button(root, text="Show Text", width=10, command=showOutputText)
	gui_button.pack()
	root.mainloop()

def showOutputText():
	gui_output_text = Text(root)
	gui_output_text.insert(0.0, gui_input_text.get())
	gui_output_text.pack()

setUpGui()

Then try executing it in python.

python example.py

If this works, continue to step 3 and compile the app. Here’s how it should look:


3. Create a makefile and then compile the app

py2applet --make-setup example.py
python setup.py py2app -A
Note: If you change your code and need to recompile, it’s good practice to delete your makefile, dist folder, and build folder before repeating this step.

Try running the app, and if it works, viola! you have a binary version of your python script, ready for distribution!

The Research Project Template
I have had to make my fair share of research websites for different labs (for example cidia.ucsd.edu). There’s no point building a new site over and over again for different projects when there’s services like Google Sites that readily offer a free template and hosting.
The problem is, none of the templates on google sites were any good for organizing a research project. In my opinion —and this is totally subjective, a good research site should have the following characteristics:
Design Characteristics of a Good Research Project WebsiteEasy to find out whats important (such as announcements or due dates)
Easy to find files (centrally located)
Easy to coordinate group work (delegate tasks and monitor task progress)
Easy to edit (multiple users can contribute)
Easy to track changes (find out who’s deleting your stuff and beat them with a calculator)
Have a clean, modern, and simple appearance (so people use it)

Back in November, I created a site to organize the autism project at the Institute for Neural Computation, and decided that I didn’t want to have to do this over and over. So, I shared my work with the world and created a public template. I’m very excited to hear that someone has used it. I hope that it gets used and is enjoyed by flustered scientists around the globe!

https://sites.google.com/site/researchprojecttemplate

The Research Project Template

I have had to make my fair share of research websites for different labs (for example cidia.ucsd.edu). There’s no point building a new site over and over again for different projects when there’s services like Google Sites that readily offer a free template and hosting.

The problem is, none of the templates on google sites were any good for organizing a research project. In my opinion —and this is totally subjective, a good research site should have the following characteristics:

Design Characteristics of a Good Research Project Website
  1. Easy to find out whats important (such as announcements or due dates)
  2. Easy to find files (centrally located)
  3. Easy to coordinate group work (delegate tasks and monitor task progress)
  4. Easy to edit (multiple users can contribute)
  5. Easy to track changes (find out who’s deleting your stuff and beat them with a calculator)
  6. Have a clean, modern, and simple appearance (so people use it)

Back in November, I created a site to organize the autism project at the Institute for Neural Computation, and decided that I didn’t want to have to do this over and over. So, I shared my work with the world and created a public template. I’m very excited to hear that someone has used it. I hope that it gets used and is enjoyed by flustered scientists around the globe!

https://sites.google.com/site/researchprojecttemplate

I have been struggling to find a precise way to produce accurate time events to synchronize the data from an EEG system I have been building to visual stimuli. Being able to read precise time measures is great, but reliably reproducing accurate intervals of time has proven to be a daunting task that many researchers have struggled with.

Eprime is expensive and somewhat medieval, flash is unreliable (for time), and although python can access microseconds, its graphical capabilities are confusing. Thankfully, the newer versions of Java allow for nanosecond sampling from the CPU clock (and I’ve read rumors that picoseconds will soon be possible in the next Java version, although I am somewhat skeptical…3.3 psec is how long it takes light to travel 1 mm!). With nanosecond capability, it is possible to create a timer that produces accurate time interval events to display stimuli on the computer screen for very specific amounts of time while recording brain waves. Using the Processing environment (processing.org), I was able to write a simple program that produces an accurate 1ms time interval, based on and verified by the nanosecond resolution system timer.

To test the accuracy and precision of the intervals produced, three trials were run where the precise nanosecond timing of 700 one-millisecond intervals were recorded. Simple descriptive analysis of the 2100 samples revealed that the mean interval lasted 0.001099731 seconds, having a standard deviation of 0.000465145 seconds (N=2100, M= 0.001099731, SD=0.000465145). I should note here that a MacBook Air with an Intel Core Duo 1.6GHz and 2GB of RAM was used to preform the test.

On a better system, I’m sure one could push for microsecond intervals, but thats unnecessary for EEG research as microseconds are beyond the speed of any known cognitive and neural processes (at least those I’m aware of).

Here is my code with an example N400 task:

//NanoTimer  10-1-2010
//By: Dave Deriso, dderiso@ucsd.edu
//Creative Commons, Non-Commercial License
//http://creativecommons.org/licenses/by-nc-sa/3.0/

long startNano = System.nanoTime();
long now;
float delta;
int t=0;
float w,h;

void setup() {
  size(300, 300);
  background(255, 255, 255);
  frameRate(1E11); //boosts program speed, improves accuracy
  
  smooth();
  // Set "ink" color, font, and alignment for rendering text.
  fill(0);  // Black
  // setup the font (system default sans serif)
  textFont(createFont("SansSerif",18));
  textAlign(CENTER);
  w = width/2;
  h = height/2;
}

void draw()
{
  now = System.nanoTime() - startNano;
  delta = now*1E-9;
  if (delta > .001) //vary this btwn 1sec to 1ms (.001)
  {
    println(delta);
    
    //trigger your event here
    t++;
    present();
    
    startNano = System.nanoTime();
  }
  //delay(1/10); //reduce process demand by duty cycling
}

void present()
{
  if (t==1){text("Billy likes to", w, h);}
  if (t==2000){clearSc(); text("kick", w, h);}
  if (t==3000){clearSc(); text("the big red", w, h);}
  if (t==3500){clearSc(); text("walrus", w, h);}
  if (t==3515){clearSc();}
}

void clearSc()
{
  background(255, 255, 255);
}


If all goes well, your output should resemble the following (in seconds): 

0.001017
0.001002
0.001002
0.001006
0.001003
0.001006
0.001009
0.001019
0.001034
0.001026
0.001022
0.001028

Note that the .001 sec should come up each time and that the microsecond variability shouldn’t affect the intended purpose.

For everyone trying to read or write .csv files (or excel-compatible) in flash, this should be useful. It lets you access data in a spreadsheet using the (row, column) syntax.

Here is an example of its implementation:

import com.utils.CSVParser;

public var spreadSheet:CSVParser = new CSVParser();
spreadSheet.fileOpen(); //opens a new csv file using the open dialogue
trace(spreadSheet.data); //traces the whole .csv file
trace( spreadSheet.pull(1,7) ); //traces the 1st row, 7th column

Here is the code itself:

package com.utils
{
	import flash.display.Sprite;
	
	import flash.filesystem.FileStream;
	import flash.filesystem.File;
	import flash.filesystem.FileMode;
	import flash.net.FileFilter;
	import flash.events.Event;
	
	public class CSVParser extends Sprite
	{
			public var fileToOpen:File = new File();
			public var fileData:String;

			public var rows:Array;
			public var data:Array;
		
			public function CSVParser():void
			{
				//fileOpen(); //should be called when needed
			}
			
			public function fileOpen():void 
			{
				try 
				{
					var txtFilter:FileFilter = new FileFilter("Text", "*.csv"); //;*.txt;*.xml"
					fileToOpen.browseForOpen("Open", [txtFilter]);
					fileToOpen.addEventListener(Event.SELECT, fileSelected);
					//fileToOpen.addEventListener(Event.CANCEL, fileOpenError);
				}

				catch (error:Error)
				{
					trace("Failed:", error.message);
					//throw new CustomError("nullArray is null");
					//fileOpen();
				}
			}

			public function fileSelected(event:Event):void 
			{
				var stream:FileStream = new FileStream();
				stream.open(fileToOpen, FileMode.READ);
				fileData = stream.readUTFBytes(stream.bytesAvailable);

				data = parseCSV(fileData);
				
				//format is in data[rows][columns], the ex below are equivalent
				//trace(data[0][6]);
				//trace(pull(1,7));
			}

			public function parseCSV(fileContents:String):Array 
			{
				//divide each line in the CSV file to a new array
				rows = fileContents.split("\n"); //rows.length;
		
				var parsedData:Array = new Array(rows.length);
				
				for(var i:int=0; i < rows.length; i++)
				{
					var line:Array = rows[i].split(",");
					parsedData[i]=line;
				}
				
				return parsedData;
			}	
			
			public function pull(row:int, col:int):*
			{
				return data[row-1][col-1];
			}
			
	}
}

I just spent my afternoon designing a simple active EEG electrode amplifier. I used the non-inverting amplifier design with 2 op-amps. I also used the active low pass filter method to let everything below 200Hz go unattenuated. This is a first version, beta if you will, so please feel free to comment or make suggestions. To view an interactive simulation, click the link below:

Interactive Simulation:
http://files.davidderiso.com/tumblr/posts/active_electrode_circuit.html

Theory:
Non-Inverting Amp: http://hyperphysics.phy-astr.gsu.edu/hbase/electronic/opampvar.html#c3

Active Low Pass Filter: http://en.wikipedia.org/wiki/Low-pass_filter#Active_electronic_realization

Because there is no simple tutorial for getting the apa package in LaTeX to work (all of the information is loosely spread out across the internet), I decided to make a tutorial for the absolute beginner having some familiarity with the OSX terminal.

What is LaTeX and why is it useful for my research?

LaTeX is a type of markup (like HTML) that will turn your text into a beautifully typeset document. The advantage of using a markup-based text generator over a word processor (like MS Word) is that I don’t have to think about the formatting. The LaTeX engine will autmatically move my text around and into the proper formatting for APA, Chicago, MLS, etc. This way I can focus on the content instead of the formatting.

I’ve sumed up the last 6 hours of my day figuring out how to implement LaTeX with OSX 10.6 for an APA style paper.

1. Download MacTex at http://www.tug.org/mactex/

2. Create a directory for packages

go to the terminal:

mkdir -p ~/Library/texmf/tex/latex/
mkdir -p ~/Library/texmf/bibtex/bst/ 

3. Download the LaTeX APA packages:

apa package (zip file) from http://tug.ctan.org/tex-archive/macros/latex/contrib/apa/  

endfloat
 package (zip file) from http://tug.ctan.org/tex-archive/macros/latex/contrib/endfloat/

4. Unzip all of the above files and copy each directory to the ~/Library/texmf/tex/latex/ folder created in step 2
5. Download the BibTeX APA packages:

apacite
 package (zip file) from http://tug.ctan.org/tex-archive/biblio/bibtex/contrib/apacite/
6. Unzip apacite and copy the directory to the~/Library/texmf/bibtex/bst/ folder created in step 2
7. Generates the apacite files necessary for making bibliographies from the apacite.ins file.
 
Terminal:
cd  ~/Library/texmf/bibtex/bst/apacite
tex apacite.ins
8. Go into the ~/Library/texmf/tex/latex/apa folder and copy
apaexample.tex
examplebib.bib
to some folder on your computer (ex. ~/Documents/my_folder/
9. Open the apaexample.tex file with TeXShop by right-clicking the file and selecting “Open With” -> “TexShop”
10. Click on the “Typeset” button (make sure “LaTeX” is visible from the drop-down menu.) 
11. A screen should pop up. Ignore it. Go back and select ”BibTeX” from the drop-down menu. Click on the “Typeset” button.
The output pdf should now have 8 pages, but is missing the reference section. 
12. Again, close the pop-up and then change the drop-down back to “LaTeX”. Click on the “Typeset” button.The output pdf should now have 9 pages, and includes the reference section. 
13. Some sources say to repeat step 12 (re-run LaTeX) 2-3 times for good measure. I don’t know if that makes a difference, but I do it anyway for good measure :)
14. To use the jou feature, you need to download and install the base35 and mdwfonts packages from ctan

mkdir -p ~/Library/texmf/fonts/type1/  #(for base35)
mkdir -p ~/Library/texmf/fonts/tfm/ #(for mdwfonts)
mkdir -p ~/Library/texmf/fonts/vf/ #(for mdwfonts)
Troubleshooting:

If you are ever missing a file and your LaTeX source wont compile, open the log file output and find the missing file. For example, I was missing, “usyr.pfb”. All you need to do is open the terminal and type

kpsewhich —show-path usyr.pfb 

Then, find the path that looks like

:/Users/davederiso/Library/texmf/fonts/type1//

Make this missing directory and then search for that missing file on ctan (link), download it and unzip it and copy the file to that directory.

Note: I also use the fantastic TextMate program for generating my LaTeX document, but you can use anything you like to make them (such as textedit). Also, Skim has been recommended by multiple sources as an excellent pdf viewer and can convert some of the LaTeX formats to pdf.

Useful Resource: http://www.let.uu.nl/~Hugo.Quene/personal/tools/latex.hqall.html

This here script does what everybody’s been looking for. A simple flash webcam app that uploads images from your webcam to the web. It also lets you download the image you just took.

Here’s a working demo.

Here’s the source files.

Here’s how it works:

  1. The flash code creates the camera and takes the picture as bitmapdata
  2. This bitmapdata is fed into a jpeg encoder (in the flash app)
  3. The encoded jpeg is then pushed out of flash into a php script on your server
  4. The php script saves a copy on the server and then pops up a download link

Here is the code:

AS3:

	package  {

		import fl.controls.Button;
		import fl.controls.TextArea;
		import flash.display.LoaderInfo;
		import flash.display.BitmapData;
		import flash.display.Bitmap;
		import flash.display.MovieClip;
		import flash.display.Stage;
		import flash.display.StageAlign;
	        import flash.display.StageScaleMode;	
		import flash.events.MouseEvent;
		import flash.events.StatusEvent;
		import flash.geom.Matrix;
		import flash.media.Camera;
		import flash.media.Video;
		import flash.net.navigateToURL;
		import flash.net.URLRequest;
		import flash.net.URLLoader;
	        import flash.net.URLRequestHeader;
	        import flash.net.URLRequestMethod;
		import flash.utils.ByteArray;
		import com.adobe.images.JPGEncoder;


		public class WebCamUploader extends MovieClip {

			// public Properties:
			public var spinner:Spinner;
			public var video:Video;
			public var camera:Camera;
			public var bitmap:Bitmap;
			public var bitmapData:BitmapData;
			public var snapShot:BitmapData;
			public var xVar:Number;
			public var yVar:Number;
			public var inventoryName:String;

			public function WebCamUploader() { 
				configUI();
			}

			public function configUI():void {
				stage.scaleMode = StageScaleMode.NO_SCALE;
				stage.align = StageAlign.TOP_LEFT;

				inventoryName_txt.text = "enter part # here";

				spinner = new Spinner();
				spinner.x = 214 - spinner.width >> 1;
				spinner.y = 255 - spinner.height - 40 >> 1;

				uploadPic.addEventListener(MouseEvent.MOUSE_UP, uploadPhoto, false, 0, true);
				deletePic.addEventListener(MouseEvent.MOUSE_UP, deletePhoto, false, 0, true);
				takePic.addEventListener(MouseEvent.MOUSE_UP, takeSnapShot, false, 0, true);

				connectCamera();
			}

			public function connectCamera():void {
				camera = Camera.getCamera();
				camera.setQuality(0, 100);
				camera.setMode(500, 500, 5, true);

				xVar = (500 - camera.width)/2;
				yVar = 26 + (500 - camera.width)/2;

				if (camera != null) {
	                video = new Video(camera.height, camera.width);
					video.attachCamera(camera);
					video.x = xVar;
					video.y = yVar;
					addChild(video);

					camera.addEventListener(StatusEvent.STATUS, onCameraStatus, false, 0, true);

					size_txt.text = "h: "+ camera.height + " w: " + camera.width + " fps: 5";
	            } else {
	                //handleError(false, "Error, You need a camera.");
	            }
			}

			public function onCameraStatus(p_event:StatusEvent):void {
				camera.removeEventListener(StatusEvent.STATUS, onCameraStatus);

				switch (p_event.code) {
					case "Camera.Muted":
						//handleError(false, "Error, Camera not found or denied. Unable to use Application. \nTo allow the Camera, reload the page.");
					case "Camera.Unmuted":
						// Camera accepted and Successfull;
						break;
				}
			}

			public function takeSnapShot(event:MouseEvent):void {

				snapShot = new BitmapData(video.width, video.height);
				snapShot.draw(video, new Matrix());
				bitmapData = snapShot;
				bitmap = new Bitmap(snapShot,"auto", true);

				bitmap.x = xVar;
				bitmap.y = yVar;

				addChild(bitmap);			
			}

			public function deletePhoto(event:MouseEvent):void {
				removeChild(bitmap);
			}

			public function uploadPhoto(event:MouseEvent):void {
				showSpinner(true);
				uploadPhotoPhp();
			}

			public function uploadPhotoPhp():void {

				var jpgEncoder:JPGEncoder = new JPGEncoder(85);
				var jpgStream:ByteArray = jpgEncoder.encode(bitmapData);
				var header:URLRequestHeader = new URLRequestHeader("Content-type", "application/octet-stream");

				if (inventoryName_txt.text == "enter part # here")
				{
					inventoryName = "part";
				}else
				{
					inventoryName = inventoryName_txt.text;
				}

				var jpgURLRequest:URLRequest = new URLRequest("jpg_encoder_download.php?name="+inventoryName+".jpg");

				jpgURLRequest.requestHeaders.push(header);
				jpgURLRequest.method = URLRequestMethod.POST;
				jpgURLRequest.data = jpgStream;
				navigateToURL(jpgURLRequest, "_blank");
				showSpinner(false);
				removeChild(bitmap);
			}

			public function showSpinner(p_loading:Boolean):void {
				if(p_loading) {
					addChild(spinner);
					spinner.play();
				} else {
					removeChild(spinner);
					spinner.stop();
				}
			}


		}
	}

PHP:

<?php

if ( isset ( $GLOBALS["HTTP_RAW_POST_DATA"] )) {
	
	date_default_timezone_set('PST');
	$today = date("M-j-Y-H-i-s");
	
	$filename = $_GET['name'];
	
	if ($filename == "part.jpg")
	{
		$filename = "part-".$today.".jpg";
	}
	
	$filepath = "../parts/".$filename;
	
	// get bytearray
	$im = $GLOBALS["HTTP_RAW_POST_DATA"];
	
	// add headers for download dialog-box
	header('Content-Type: image/jpeg');
	header("Content-Disposition: attachment; filename=".$filename);
	
	$fd = fopen($filepath,"w");
	fputs($fd,$im);
	fclose($fd);
	
	echo $im;
	
}  else echo 'An error occured.';

?> 

Credits:

Webcam AS3 code adapted from GK Sinner and Adobe: link

Encoding and passing the bitmap data to PHP for download adapted from Henry Jones: link

The rest was figured out by experimentation.

Mysql is a database language. Writing working php scripts for it is about as entertaining as navigating the VA bureaucracy. It blows.

I wanted to move the whole inventory site over to Koso. But after an hour of trying to get the Koso server to try and access my server’s msql database, I decided to say screw it and wrote an iframe script to just port the whole site into one html file on Koso.

Iframes are also lame. I couldn’t get the site to fill the whole screen, it would be a small box in the corner. Soooo, I wrote a java script. Failed. Wrote an HTML scritpt. Failed. Finally, good ol’ CSS fixed it. Now its up!

The only way I can to connect to my damn Mysql database is to use ‘localhost’:

<?php
include("variables.php");
mysql_connect('localhost',$username,$password);
@mysql_select_db($database) or die( "Unable to select database"); 
echo 'Connected successfully';
mysql_close();
?> 

The only way I could get the iFRAME to work was to use CSS:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>

  <title>Paulus Lab Inventory</title>
	
  <style type="text/css" media="screen">
  html, body {
     position: absolute;
     height: 100%;
     max-height: 100%;
     width: 100%;
     margin: 0;
     padding: 0;
   }
   iframe {
     position: absolute;
     height: 100%;
     width: 100%;
     border: none;
   }
   #container {
     position: absolute;
    top: 0; 
	bottom: 0;
     width: 100%;
     overflow: hidden ;
   }
}
  </style>
	
</head>

<body>
  <div id="container">
    <iframe src="http://www.yoursite.com/yourdatabase.php" FRAMEBORDER="0"></iframe>
  </div>

</body>
</html>
Designed By Dave Deriso © 2010