Tuesday, March 28, 2006

Ruby is just so beautiful

took about 90 minutes, since I had to learn about rubyzip:

=begin
# Simple script to retrieve all properties files, package them in the target directory,
# and add a comment to the top and bottom informing developers #to place entries at the bottom
# requires rubyzip (http://rubyzip.sourceforge.net/)
=end

require 'date'
require 'zip/zip'

class Properties_Packager

DECORATION = "#============================================="

HEADER_COMMENT =
DECORATION +
"\n#Please place all new additions at the bottom of the file\n" +
DECORATION

FOOTER_COMMENT =
DECORATION +
"\n#Packaged and processed on " + (Time.now.to_s ) + ". Please place all new entries after this section\n" +
DECORATION

@prop_files
attr_reader :prop_files, :HEADER_COMMENT

def initialize
@prop_files = []
@header_comment
end

private
def legit_file file
! (file.index("env.") != nil ||
file.index("junit") != nil ||
file.index("project.") != nil ||
file.index("#") != nil)
end


public
def obtain_properties_files(directory)
current_dir = Dir.open(directory)

for file in current_dir
next if(file == "." ||
file==".." ||
file=="target")

path = current_dir.path + "/" + file

if File.directory?(path)
obtain_properties_files(path)
else
if (legit_file file and file.index("properties") != nil)
puts "Adding " + path
@prop_files << path
end
end
@prop_files
end
@prop_files
end

def add_comments files
files.each do |file|
contents_buffer = []
current_lines = IO.readlines(file.to_s)

possible_header = current_lines[0]

if(! possible_header.strip.eql? DECORATION)

contents_buffer << HEADER_COMMENT
end

contents_buffer << IO.readlines(file.to_s).to_s
contents_buffer << FOOTER_COMMENT

open_file = File.open(file,"r+")
open_file.puts(contents_buffer)
open_file.close
end
end

def put_files_in_zip files, out_file_name

#if the file exists, erase it
if File.exists?(out_file_name)
File.delete(out_file_name)
puts "DELETED old zip file"
end

zipfile = Zip::ZipFile.new out_file_name, true
files.each do |file|
puts "zipping " + file.to_s
zipfile.add file, file.to_s
end
zipfile.close

end
end

zip_file = 'target/packaged_properties.zip'

packager = Properties_Packager.new
props = packager.obtain_properties_files('src/webapp')
packager.add_comments props
packager.put_files_in_zip props, zip_file

puts "Properties package ready for delivery #{zip_file}"


Thursday, March 23, 2006

Gentoo and Rails 1.0, sqlite3, fastcgi and lighttpd

emerged sqlite3 and sqlite3-ruby
added USE flags, fcgi lighttpd
emerged ruby-fcgi lighttpd
uncommented "mod_fastcgi" and "mod_redirect" in /etc/lighttpd.conf

emerged rails

yankes and configured lserver and lighttpd.conf per http://www.bigbold.com/snippets/posts/show/303

executed "rails todoapp"
copied lighttpd.config to todoapp/config and lserver to todoapp/script
updated config/database.yaml---
development:
adapter: sqlite3
database: db/database_dev.db
test:
adapter: sqlite3
database: db/database_test.db

production:
adapter: sqlite3
database: db/database_prod.db
---

executed "script/generate migration InitialSetup"


updated db/migrate/001_initial_setup.rb---
class InitialSetup < text ="">"some new task", :date =>"11-21-1978", :done =>0
end

def self.down
drop_Table :todos
end
end

execute "rake migrate", and for some reason this hangs the first time, ctrl-c kills but it ran successfully...
execute "script/generate model Todo"

install ajax_scaffold-2.2.1.gem
execute "script/generate ajax_scaffold Todo"
execute "script/lserver"

point browser to http://localhost:8000/Todos

Wednesday, March 15, 2006

baud rate calcuation

CXL04LP3 accelerometer running with interface card at 38400 baud. Need to setup SCI2 in order the run at that rate. Calculation (page 169) is is BAUD RATE = BUSCLK/([SBR12:SBR0] × 16)

The 32K_9S08GB60_Mon.asm file (AN2140SW1) states, ";baud38400: equ 31 ;sets rate to 38,400-0.9% baud". And we know that SCI2BDH_SBR8 is 31(MC9S08GB60.h). So, SCI2BDLH=SCI2BDH_SBR8

Friday, March 03, 2006

MySQL character inserts

Interestingly, if there VARCHAR column with a record containing ',' and the attempt is made to insert ', ', MySQL reports that this is a duplicate key, thereby trimming the insertion. Tested and reproduced on 4.1.3-beta-standard.

Wednesday, February 15, 2006

Servo HCS08 working

First lesson learned, you can't manipulate the duty of the TPM within a keyboard interrupt:

void interrupt Vkeyboard intSWITCH1(){
if(SWITCH1 == DOWN){

TPM2C0V = ZERO;

}
if(SWITCH2 == DOWN){
TPM2C0V = ONE_EIGHTY;

}
if(SWITCH3 == DOWN){
TPM2C0V = TPM2C0V -1;
}
if(SWITCH4 == DOWN){
TPM2C0V = TPM2C0V+1;
}
timer2chnl0 = TPM2C0V;*/
KBI1SC_KBACK = 1;//ack

}
This will not work! Wish I knew why, but it won't. In order to properly affect the duty cycle the code must be in the main for loop. Hope I have time to investigate why the software interrupt doesn't function...

Secondly, the original configuration of flipping the bit on PTDF2, again with an interrupt (timer 2 channel 0) was producing aberrations in the PWM! The aberrations were rhythmic in nature and we blamed them on internal software latency; again, wish I knew more about this, but the fact of the matter is that the code was simply this:

void interrupt VTimer2Chnl0 intTimer2Chnl0(){

PTFD_PTFD2 = ~PTFD_PTFD2;

TPM2C0SC_CH0F = 0;
}
. Perhaps this is related to the fact that LED3 is by default wired to the output of PTDF2, and its operation was hosing with the PWM.

Lastly, the the modulation count was still the same for the direct timer output (which for timer 2 channel 0 is PTD3, see http://www.freescale.com/files/microcontrollers/doc/data_sheet/MC9S08GB60.pdf), so:

#define half_ms_duty_50hz (TPM2MOD - (TPM2MOD/40) -2)
#define ONE_EIGHTY half_ms_duty_50hz

void initICG(){
/*configure Internal Clock Generator [ICG]*/
/*MFD[]={4,6,8,10,12,14,16,18}*/
ICGC2_MFD = 7; /*32KHz crystal, demo board.
For 4MHz crystal (eval board):
ICGC2_MFD = 3
*/
ICGC2_RFD = 0; /* RFD[]={1,2,4,8,16,32,64,128}*/
//ICGC1 = 0b00110000;
ICGC1 = 0b00111000;
/*32KHz crystal, demo board.
For 4MHz crystal (eval board):
ICGC1 = 0b01111000;
*/
while((ICGS1_LOCK==0)||(ICGS1_ERCS==0)){
/*Ensure COP doesn't reset device whilst waiting for clock lock*/
__RESET_WATCHDOG(); /* kicks the dog */
}
ICGC2_LOCRE = 1; /*enable reset if clock fails*/

}

void initTimer2Chnl0_50hz(){
TPM2C0SC_CH0IE = 1; //enable channel

TPM2SC_CLKSA = 1;/*Select BUS clock*/
TPM2SC_CLKSB = 0;

TPM2SC_PS = PRESCALAR;/*clock source divided by prescalar*/
TPM2MOD = 1475;/*counter value, counts up to*/

TPM2SC_CPWMS = 1;
/*configure PWM mode and pulse*/
TPM2C0SC_MS0B = 1; /*MS0B=1, MS0A=0; << Edge align PWM*/
TPM2C0SC_ELS0A = 1; /*Select low as true*/

TPM2C0V = ONE_EIGHTY;
}



Once I get the code cleaned up and more presentable, I'll post the entire thing for future replication.

Wednesday, February 08, 2006

remove CVS tag

cvs update -dPA

Monday, February 06, 2006

Ethereal for OS X 10.4(Tiger) on a G3 iBook

Installed Fink and FinkCommander. From FinkCommander installed
Ethereal, but I was getting errors in execution (/sw/bin/ethereal).
Looked like some library issues. Pulled down the ethereal source and
read the Readme.macos and realized that FinkCommander installed shared
libraries.
Had to install the core libraries, and not the sh ones to get Ethereal
to load, that is

GLib 2.4.0
Pango 1.4.0
GTK+ 2.4.0
ATK 1.6.0
Changed permissions of the bpf (sudo a+r bpf*) devices per
http://wiki.ethereal.com/CaptureSetup/CapturePrivileges

Saturday, February 04, 2006

Servo info

Excellent link that describes how servos operate: http://www.servocity.com/html/how_do_servos_work_.html
-----
Servos are controlled by sending them a pulse of variable width. The control wire is used to send this pulse. The parameters for this pulse are that it has a minimum pulse, a maximum pulse, and a repetition rate. Given the rotation constraints of the servo, neutral is defined to be the position where the servo has exactly the same amount of potential rotation in the clockwise direction as it does in the counter clockwise direction. It is important to note that different servos will have different constraints on their rotation but they all have a neutral position, and that position is always around 1.5 milliseconds (ms).

The angle is determined by the duration of a pulse that is applied to the control wire. This is called Pulse width Modulation. The servo expects to see a pulse every 20 ms. The length of the pulse will determine how far the motor turns. For example, a 1.5 ms pulse will make the motor turn to the 90 degree position (neutral position).

When these servos are commanded to move they will move to the position and hold that position. If an external force pushes against the servo while the servo is holding a position, the servo will resist from moving out of that position. The maximum amount of force the servo can exert is the torque rating of the servo. Servos will not hold their position forever though; the position pulse must be repeated to instruct the servo to stay in position.

-----

So the goal for using the HCS08 board is to control the servo operation programatically via a timer. So how to find the duty cycle of a given period that equates to the required PWM?

According to this site the servo expects to see a pulse every 20ms, in which case that would equate to 1/.02 = 50hz. So once the timer is configured for the appropriate frequency, the duty cycle can then be adjusted as needed to control the servo. A pulse with a duty cycle of 5% @ .02s would be 1ms, which would then move the servo in the counter clockwise position, according to the first site, at 0 degrees. Whereas if the duty cycle were 10%, 2ms, the servo would rotate the shaft to 180 degrees. Adjusting the duty to 7.5%, 1.5ms, would return the shaft to neutral position.

Monday, January 30, 2006

74HCT32 Quad 2 input OR Gate

Here's the tech stuff:
http://jameco.com/wcsstore/Jameco/Products/ProdDS/246457TI.pdf

Product link:
http://jameco.com/webapp/wcs/stores/servlet/ProductDisplay?langId=-1&storeId=10001&catalogId=10001&productId=246457

Monday, January 23, 2006

Two timers and a fade

The following code demonstrates the difference between the two timers on HCS08 and their respective channels. LED1 is on Timer1 Channel1 and LED3 is on Timer2 Channel0. Their interrupt functions are identical, but their behavior is different due to their respective timers and duties. Pressing SWITCH1 will increase pulseMod and thus decrease the blink rate, whereas pressing SWITCH2 will decrease pulseMod and increase the blink rate. Lastly, LED5 is a good example of exercising the duty cycle. It's duty is being decremented/incremented through the main loop and will thus decrease/increase the duty (time of period) that the led is on.
---------------------
#include <hidef.h> /* for EnableInterrupts macro */
#include "derivative.h" /* include peripheral declarations */
#include "M68DEMO908gb60.h"
#define PRESCALAR 7
//#define MODULUS 32768
//#define MODULUS 16384
//#define MODULUS 8192
//#define MODULUS 4096
#define MODULUS 2048
#define DUTY75 (MODULUS-(MODULUS/4))
#define DUTY25 (MODULUS/4)
#define DUTY50 (MODULUS/2)
long cntr=0;
long cntr2=0;
int goUp = 0;
int goUp2 = 0;
long cntr3 = 0;
long timer2chnl0 = 0;
long pulseMod = 25;
int fadeTime = 4;

void MCU_init(void); /* Device initialization function declaration */

void speedUpOrSlowDown(){
    if(SWITCH3==DOWN){      
       TPM1C0V = TPM1C0V/2;
    } else if(SWITCH4 == DOWN){
      if(TPM1C0V <= (MODULUS/2))
        TPM1C0V = TPM1C0V*2;
    }
}


void  interrupt VTimer1Chnl1 intTimer1Chnl1(){//for every period of zone out on LED5, this intterupt is set 500 times
 
 if(cntr3 %pulseMod ==0 )
   LED1 = ~LED1 ;
 cntr3++;
 TPM1C1SC_CH1F = 0; //reset interrupt
}

void initTimer1Chnl1(){
   /*configure PWM mode and pulse*/
  TPM1C1SC = 1;
  TPM1C1SC_MS1B = 1; /*MS0B=1, MS0A=0; << Edge align PWM*/
  TPM1C1SC_ELS1A = 1; /*Select low as true*/
  TPM1SC_PS1 = PRESCALAR;/*clock source divided by prescalar*/
  TPM1C1V = DUTY50;

  TPM1C1SC_CH1IE = 1;//turn on interrupt
}



void initTimer1Chnl0(){//LED5
   /*Initialize timer TPM1 channel, assumes not touched since reset!*/
  TPM1SC_CLKSA = 1;/*Select BUS clock*/
  TPM1SC_CLKSB = 0;

  TPM1SC_PS0 = PRESCALAR;/*clock source divided by prescalar*/
  TPM1MOD = MODULUS;/*counter value, counts up to*/
  TPM1SC_CPWMS = 1;
  /*configure PWM mode and pulse*/
  TPM1C0SC_MS0B = 1; /*MS0B=1, MS0A=0; << Edge align PWM*/
  TPM1C0SC_ELS0A = 1; /*Select low as true*/
  //TPM1C0V = DUTY75;/*select final divider (duty cycle)*/
  TPM1C0V = 16;/*select final divider (duty cycle)*/
 
}


void interrupt VTimer2Chnl0 intTimer2Chnl0(){
 if(timer2chnl0 % pulseMod ==0)
  LED3 = ~LED3;
 
 timer2chnl0++;
 TPM2C0SC_CH0F = 0;
}

void initTimer2Chnl0(){
  TPM2C0SC_CH0IE = 1;  //enable channel
   
  TPM2SC_CLKSA = 1;/*Select BUS clock*/
  TPM2SC_CLKSB = 0;

  TPM2SC_PS = PRESCALAR;/*clock source divided by prescalar*/
  TPM2MOD = 8192;/*counter value, counts up to*/
  TPM2SC_CPWMS = 1;
  /*configure PWM mode and pulse*/
  TPM2C0SC_MS0B = 1; /*MS0B=1, MS0A=0; << Edge align PWM*/
  TPM2C0SC_ELS0A = 1; /*Select low as true*/
  TPM2C0V = TPM2MOD/2;/*select final divider (duty cycle)*/
 
}

void initICG(){
  /*configure Internal Clock Generator [ICG]*/
  /*MFD[]={4,6,8,10,12,14,16,18}*/
  ICGC2_MFD = 7; /*32KHz crystal, demo board.
  For 4MHz crystal (eval board):
  ICGC2_MFD = 3
  */
  ICGC2_RFD = 0; /* RFD[]={1,2,4,8,16,32,64,128}*/
  //ICGC1 = 0b00110000;
  ICGC1 = 0b00111000;
  /*32KHz crystal, demo board.
  For 4MHz crystal (eval board):
  ICGC1 = 0b01111000;
  */
  while((ICGS1_LOCK==0)||(ICGS1_ERCS==0)){
  /*Ensure COP doesn't reset device whilst waiting for clock lock*/
  __RESET_WATCHDOG(); /* kicks the dog */
  }
  ICGC2_LOCRE = 1; /*enable reset if clock fails*/
 
}

void initKeyboardInterrupt(){
  KBI1SC_KBIE = 1;  //KBIE =>Keyboard Interrupt Enable
  KBI1PE_KBIPE4 = 1; //Keyboard Interrupt Port Enable 4 (switch1)
  KBI1PE_KBIPE5 = 1; //Keyboard Interrupt Port Enable 5 (switch2)
  KBI1PE_KBIPE6 = 1; //Keyboard Interrupt Port Enable 6 (switch3)
  KBI1PE_KBIPE7 = 1; //Keyboard Interrupt Port Enable 7 (switch4)
}

void interrupt Vkeyboard intSWITCH1(){
 if(SWITCH1 == DOWN){
  pulseMod +=2;
 }
 if(SWITCH2 == DOWN){
  pulseMod -=2;
 }
 KBI1SC_KBACK = 1;//ack
}

void main(void) {

  /* Uncomment this function call after using Device Initialization
     to use the generated code */
  /* MCU_init(); */

  EnableInterrupts; /* enable interrupts */
  PTADD = 0; //initialize as input (Data Direction Register)
  PTAPE = 0xf0; //Pullups on upper 4 bits
  /*initialize bits 0-3 of Port F as outputs (connected to led's)*/
  PTFDD = 0x0f;
  LED1 = OFF;
  LED2 = OFF;
  LED3 = OFF;
  LED4 = OFF;
  LED5 = OFF;
 
  initICG();
 
  initKeyboardInterrupt();
 
  initTimer1Chnl0();//LED5
 
  initTimer1Chnl1();//LED1
 
  initTimer2Chnl0();//LED3

  for(;;) {
    __RESET_WATCHDOG(); /* feeds the dog */
    
      if(goUp==1){
        TPM1C0V = TPM1C0V+fadeTime;
        cntr=0;
        cntr2++;
        if(TPM1C0V >= MODULUS){
          goUp = 0;
        }
      } else{
        //TPM1C0V = TPM1C0V/2;
        TPM1C0V = TPM1C0V-fadeTime;
        cntr2=0;
        cntr++;
        if (TPM1C0V <=0){
          goUp =1;
          TPM1C0V = fadeTime;
        }
      }
     
  } /* loop forever */
  /* please make sure that you never leave this function */
}

Saturday, January 21, 2006

timer fun

#include <hidef.h> /* for EnableInterrupts macro */
#include "derivative.h" /* include peripheral declarations */
#include "M68DEMO908gb60.h"
#define PRESCALAR 7
//#define MODULUS 32768 //16*2048
//#define MODULUS 16384
//#define MODULUS 8192
//#define MODULUS 4096
#define MODULUS 2048
#define DUTY75 (MODULUS-(MODULUS/4))
#define DUTY25 (MODULUS/4)
#define DUTY50 (MODULUS/2)
long cntr=0;
long cntr2=0;
int goUp = 0;
int goUp2 = 0;
long cntr3 = 0;

void MCU_init(void); /* Device initialization function declaration */

void speedUpOrSlowDown(){
    if(SWITCH3==DOWN){      
       TPM1C0V = TPM1C0V/2;
    } else if(SWITCH4 == DOWN){
      if(TPM1C0V <= (MODULUS/2))
        TPM1C0V = TPM1C0V*2;
    }
}


void  interrupt VTimer1Chnl1 intTimer1Chnl1(){//for every period of zone out on LED5, this intterupt is set 500 times
 
 if(cntr3 %50 ==0 )
   LED1 = ~LED1 ;
 cntr3++;
 TPM1C1SC_CH1F = 0; //reset interrupt
}

void initTimer1Chnl1(){
   /*configure PWM mode and pulse*/
  TPM1C1SC = 1;
  TPM1C1SC_MS1B = 1; /*MS0B=1, MS0A=0; << Edge align PWM*/
  TPM1C1SC_ELS1A = 1; /*Select low as true*/
  TPM1SC_PS1 = PRESCALAR;/*clock source divided by prescalar*/
  TPM1C1V = DUTY50;

  TPM1C1SC_CH1IE = 1;//turn on interrupt
}



void initTimer1Chnl0(){//LED5
   /*Initialize timer TPM1 channel, assumes not touched since reset!*/
  TPM1SC_CLKSA = 1;/*Select BUS clock*/
  TPM1SC_CLKSB = 0;

  TPM1SC_PS0 = PRESCALAR;/*clock source divided by prescalar*/
  TPM1MOD = MODULUS;/*counter value, counts up to*/
  TPM1SC_CPWMS = 1;
  /*configure PWM mode and pulse*/
  TPM1C0SC_MS0B = 1; /*MS0B=1, MS0A=0; << Edge align PWM*/
  TPM1C0SC_ELS0A = 1; /*Select low as true*/
  //TPM1C0V = DUTY75;/*select final divider (duty cycle)*/
  TPM1C0V = 16;/*select final divider (duty cycle)*/
 
}


void interrupt VTimer2Chnl0 intTimer2Chnl0(){
 LED3 = ~LED3;
 TPM2C2SC_CH2F = 0;
}

void initTimer2Chnl0(){
   /*Initialize timer TPM1 channel, assumes not touched since reset!*/
  TPM2SC_CLKSA = 1;/*Select BUS clock*/
  TPM2SC_CLKSB = 0;

  TPM2SC_PS = PRESCALAR;/*clock source divided by prescalar*/
  TPM2MOD = 32768;/*counter value, counts up to*/
  TPM2SC_CPWMS = 1;
  /*configure PWM mode and pulse*/
  TPM2C0SC_MS0B = 1; /*MS0B=1, MS0A=0; << Edge align PWM*/
  TPM2C0SC_ELS0A = 1; /*Select low as true*/
  TPM2C0V = TPM2MOD/2;/*select final divider (duty cycle)*/
}

void initICG(){
  /*configure Internal Clock Generator [ICG]*/
  /*MFD[]={4,6,8,10,12,14,16,18}*/
  ICGC2_MFD = 7; /*32KHz crystal, demo board.
  For 4MHz crystal (eval board):
  ICGC2_MFD = 3
  */
  ICGC2_RFD = 0; /* RFD[]={1,2,4,8,16,32,64,128}*/
  //ICGC1 = 0b00110000;
  ICGC1 = 0b00111000;
  /*32KHz crystal, demo board.
  For 4MHz crystal (eval board):
  ICGC1 = 0b01111000;
  */
  while((ICGS1_LOCK==0)||(ICGS1_ERCS==0)){
  /*Ensure COP doesn't reset device whilst waiting for clock lock*/
  __RESET_WATCHDOG(); /* kicks the dog */
  }
  ICGC2_LOCRE = 1; /*enable reset if clock fails*/
 
}

void main(void) {

  /* Uncomment this function call after using Device Initialization
     to use the generated code */
  /* MCU_init(); */

  EnableInterrupts; /* enable interrupts */
  PTADD = 0; //initialize as input (Data Direction Register)
  PTAPE = 0xf0; //Pullups on upper 4 bits
  /*initialize bits 0-3 of Port F as outputs (connected to led's)*/
  PTFDD = 0x0f;
  LED1 = OFF;
  LED2 = OFF;
  LED3 = OFF;
  LED4 = OFF;
  LED5 = OFF;
 
  initICG();
  initTimer1Chnl0();//LED5
 
  initTimer1Chnl1();//LED1
 
  initTimer2Chnl0();//LED3

  for(;;) {
    __RESET_WATCHDOG(); /* feeds the dog */
    
      if(goUp==1){
        TPM1C0V = TPM1C0V+8;
        cntr=0;
        cntr2++;
        if(TPM1C0V >= MODULUS){
          goUp = 0;
        }
      } else{
        //TPM1C0V = TPM1C0V/2;
        TPM1C0V = TPM1C0V-8;
        cntr2=0;
        cntr++;
        if (TPM1C0V <=0){
          goUp =1;
          TPM1C0V = 8;
        }
      }
      
 if(goUp2==1){
        TPM2C0V = TPM2C0V+32;
        if(TPM2C0V >= MODULUS){
          goUp2 = 0;
        }
      } else{
        TPM2C0V = TPM2C0V-32;
        if (TPM2C0V <=0){
          goUp2 =1;
          TPM2C0V = 32;
        }
      }
     
    
    
    
  } /* loop forever */
  /* please make sure that you never leave this function */
}

cvs creation string

cvs import -m "creation" drproj/project proj start

where "drproj/project" is now the name to check out, and proj is the directory of the files to place into the new CVS project.

Monday, January 16, 2006

Interrupts, timer, LED code

Fun time figuring out flags and interrupts to get this work on my M68DEMO908GB60.
-------------------------------
/* File: M68DEMO908GB60.h*/
/* include peripheral declarations */
#include <MC9S08GB60.h>
/*define value for led's when on and off*/
#define ON 0
#define OFF 1
/*define value for switches when up (not pressed) and down (pressed)*/
#define UP 1
#define DOWN 0
/*define led's*/
#define LED1 PTFD_PTFD0
#define LED2 PTFD_PTFD1
#define LED3 PTFD_PTFD2
#define LED4 PTFD_PTFD3
#define LED5 PTDD_PTDD0

/*define switches*/
#define SWITCH1 PTAD_PTAD4
#define SWITCH2 PTAD_PTAD5
#define SWITCH3 PTAD_PTAD6
#define SWITCH4 PTAD_PTAD7

#define Vspi 15
#define Vkeyboard 22
//define Timer1 interrupts
#define VTimer1Overflow 8
#define VTimer1Chnl2 7
#define VTimer1Chnl1 6
#define VTimer1Chnl0 5

//define Timer2 interrupts
#define VTimer2Overflow 14
#define VTimer2Chnl4 13
#define VTimer2Chnl3 12
#define VTimer2Chnl2 11
#define VTimer2Chnl1 10
#define VTimer2Chnl0 9

#define Vatd 23
#define Viic 24
-------------------------------


#include <hidef.h> /* for EnableInterrupts macro */
#include "derivative.h" /* include peripheral declarations */
#include "M68DEMO908GB60.h"

#define PRESCALAR 7
#define MODULUS 32768
#define DUTY75 (MODULUS-(MODULUS/4))
#define DUTY25 (MODULUS/4)
int sequenceNumber = 0;

void resetLEDs(){
 LED1 = OFF;
 LED2 = OFF;
 LED3 = OFF;
 LED4 = OFF;
 LED5 = OFF;
}

void interrupt Vkeyboard intSWITCH1(){
  resetLEDs();
  if(SWITCH1 == DOWN){
    sequenceNumber = 1;
  }else if(SWITCH2 == DOWN){
    sequenceNumber = 2;
  }else if(SWITCH3 == DOWN){
    sequenceNumber = 3;
  }else if(SWITCH4 == DOWN){
    sequenceNumber = 0;
  }
   
  KBI1SC_KBACK = 1;//ack
}

/*
* Reset all LEDs
*/
int ledsAreReset(){
 return ((LED1 == OFF) && (LED2 == OFF)&&(LED3 == OFF)&&(LED4 == OFF)&&(LED5 == OFF));
}

/*
* Light up the LEDs in sequence
*/
void ledLightInSeq(){
  if(((LED1 == OFF) && (LED5 == ON)) || (ledsAreReset())){
     resetLEDs();
     LED1 = ON;
   }else if((LED2 == OFF) && (LED1 == ON)){
     resetLEDs();
     LED2 = ON;
   }else if((LED3 == OFF) && (LED2 == ON)){
     resetLEDs();
     LED3 = ON;
   }else if((LED4 == OFF) && (LED3 == ON)){
     resetLEDs();
     LED4 = ON;
   }else if((LED5 == OFF) && (LED4 == ON)){
     resetLEDs();
     LED5 = ON;
   }
}
/*
* Light up the LEDs in reverse sequence
*/
void ledLightRevSeq(){
  if(((LED5 == OFF) && (LED1 == ON)) || (ledsAreReset())){
     resetLEDs();
     LED5 = ON;
   }else if((LED4 == OFF) && (LED5 == ON)){
     resetLEDs();
     LED4 = ON;
   }else if((LED3 == OFF) && (LED4 == ON)){
     resetLEDs();
     LED3 = ON;
   }else if((LED2 == OFF) && (LED3 == ON)){
     resetLEDs();
     LED2 = ON;
   }else if((LED1 == OFF) && (LED2 == ON)){
     resetLEDs();
     LED1 = ON;
   }
}

/*
* Light LEDs from middle going out
*/
void ledLightMidOut(){
  if(((LED5 == ON) && (LED1 == ON)) || (ledsAreReset())){
    resetLEDs();
    LED3 = ON;
  }else if((LED3 == ON)){
    resetLEDs();
    LED2 = ON;
    LED4 = ON;
  }else if((LED2 == ON) && (LED4 == ON)){
    resetLEDs();
    LED1 = ON;
    LED5 = ON;
  }
}

/*
* Interrupt handler for controlling light sequence based on Timer2 clock overflow
*/
void interrupt VTimer2Overflow intTimer2Ovf(){
 if(sequenceNumber ==1 ){
   ledLightInSeq();  
  
 } else if(sequenceNumber == 2){
   ledLightRevSeq();
 } else if(sequenceNumber == 3){
   ledLightMidOut();
 } else {
   LED1 = ~LED1;
   LED5 = ~LED5;
 }

 TPM2SC_TOF = 0;//ack, change overflow bit
}

/*
* Initialize TPM2
*/
void initTimer2(){
  TPM2SC_TOIE = 1;
  /*Initialize timer TPM1 channel, assumes not touched since reset!*/
  TPM2SC_CLKSA = 1;/*Select BUS clock*/
  TPM2SC_CLKSB = 0;
  TPM2SC_PS = PRESCALAR;/*clock source divided by prescalar*/
  TPM2MOD = MODULUS;/*set Counter modulus*/
  /*configure PWM mode and pulse*/
  TPM2C0SC_MS0B = 1; /*MS0B=1, MS0A=0; << Edge align PWM*/
  TPM2C0SC_ELS0A = 1; /*Select low as true*/
 

  TPM2C0V = DUTY75;//sets number that if matched by counter, will set channel flag

}

void initLedStuff(){
  PTADD = 0; //initialize as input (Data Direction Register)
  PTAPE = 0xf0; //Pullups on upper 4 bits
  /*initialize bits 0-3 of Port D&F as outputs (connected to led's)*/
  PTFDD = 0x0f;
  PTDDD = 0x0f;
  resetLEDs();
}

void initKeyboardInterrupt(){
  KBI1SC_KBIE = 1;  //KBIE =>Keyboard Interrupt Enable
  KBI1PE_KBIPE4 = 1; //Keyboard Interrupt Port Enable 4 (switch1)
  KBI1PE_KBIPE5 = 1; //Keyboard Interrupt Port Enable 5 (switch2)
  KBI1PE_KBIPE6 = 1; //Keyboard Interrupt Port Enable 6 (switch3)
  KBI1PE_KBIPE7 = 1; //Keyboard Interrupt Port Enable 7 (switch4)
}

/*
* Sample code from docs
*/
void manageDuty(){
   if(SWITCH3==DOWN){
      /*Switch pressed*/
      if(SWITCH4==DOWN){/**/
        TPM1C0V = DUTY75;/**/
        LED3 = ON;/**/
        LED4 = OFF;/**/
      }else{
        TPM1C0V = DUTY25;/**/
        LED3 = OFF;/**/
        LED4 = ON;/**/
      }
    }
}



void MCU_init(void); /* Device initialization function declaration */

void main(void) {

  /* Uncomment this function call after using Device Initialization
     to use the generated code */
  /* MCU_init(); */

  EnableInterrupts; /* enable interrupts */
  initLedStuff();
  initTimer2();
  initKeyboardInterrupt();
 
 
  for(;;) {
    __RESET_WATCHDOG(); /* feeds the dog */
   
    
  } /* loop forever */
 
}

Thursday, January 12, 2006

Freescale HCS908

The onboard demos work as described in the "Getting Started with the M68DEMO908GB60 rev 02)", but the file M68DEMO908GB60demo.mcp does not exist, there is not a "M68DEMS.zip" file included on the demo board CD. UPDATE: M68DEMS.zip is included on the CD underneath the Code Warrior package. But, even still, the code did not contain what was referenced.

Referencing the AN2616_Getting_Started_With_HCS08_and_CodeWarrior references (p4)AN2616SW.zip, which also does not exist with the bundled software. Sheesh.

So the HCS908 is debuggable, out of box, using the db9 serial connector with SCI1.

New project creation:
By selecting "P&E Full Chip Simulation", "P&amp;E Hardware Debugging" and "Motorola Serial Monitor", it will be possible to use either simulation, the serial monitor within the HCS08 FLASH, or BDM to debug code.There is no code overhead as a result of choosing multiple connection methods.

To enable serial monitor connection press switch 4 and switch the power on, set the target to be "Monitor". Once the debugger appears a couple modal dialogs should quickly appear and disappear showing that the FLASH is being erased. If this doesn't happen then there is likely a communications problem and the simulator will then run the program.

Here's the first go at LED manipulation:

#include <hidef.h> /* for EnableInterrupts macro */
#include <MC9S08GB60.h> /* include peripheral declarations */

#define ON 0
#define OFF 1

#define UP 1
#define DOWN 0

#define LED1 PTFD_PTFD0
#define LED2 PTFD_PTFD1
#define LED3 PTFD_PTFD2
#define LED4 PTFD_PTFD3
#define LED5 PTFD_PTFD4

#define SWITCH1 PTAD_PTAD4
#define SWITCH2 PTAD_PTAD5
#define SWITCH3 PTAD_PTAD6
#define SWITCH4 PTAD_PTAD7
long approxTwoSeconds = 100000;


void delay(long millis){
long cnt=0;
for(cnt=0; cnt<millis; cnt++){
//wait
}
}
static void pulse(long flashTime){
LED1 = ON;
LED2 = ON;
LED3 = ON;
LED4 = ON;
LED5 = ON;
delay(flashTime);
LED1 = OFF;
LED2 = OFF;
LED3 = OFF;
LED4 = OFF;
LED5 = OFF;
delay(flashTime);
LED1 = ON;
LED2 = ON;
LED3 = ON;
LED4 = ON;
LED5 = ON;
delay(flashTime);
LED1 = OFF;
LED2 = OFF;
LED3 = OFF;
LED4 = OFF;
LED5 = OFF;
delay(flashTime);


}

static void simpleSequence(long delayBetweenLights){

LED1 = ON;
delay(delayBetweenLights);
LED1 = OFF;

LED2 = ON;
delay(delayBetweenLights);
LED2 = OFF;

LED3 = ON;
delay(delayBetweenLights);
LED3 = OFF;

LED4 = ON;
delay(delayBetweenLights);
LED4 = OFF;

LED5 = ON;
delay(delayBetweenLights);
LED5 = OFF;



}
void main(void) {
int cnt = 0;

EnableInterrupts; /* enable interrupts */
/* include your code here */
PTADD = 0;//initialize input
PTAPE=0xF0;//Pullups on upper 4 bits
PTFDD=0x0F; //initializes ports 0,1,2,3 of Port F as outputs (which are connected to the LEDs)
LED1=OFF;
LED2=OFF;
LED3=OFF;
LED4=OFF;
LED5=OFF;

for(;;) {

__RESET_WATCHDOG(); /* feeds the dog */

simpleSequence(approxTwoSeconds);
pulse(10000);
}

}

Thursday, January 05, 2006

Nullable fields in a unique constraint, BAD

Can't have a unique constraint with a nullable field and treat that nullable as a "unique" value.

(Oracle) http://www.adp-gmbh.ch/ora/misc/integrity_constraints.html ,
http://www.techonthenet.com/oracle/unique.php

(Postgresql)http://www.postgresql.org/docs/8.1/interactive/indexes-unique.html

(MySQL5) http://dev.mysql.com/doc/refman/5.0/en/create-table.html

A UNIQUE index is one in which all values in the index must be distinct. An error occurs if you try to add a new row with a key that matches an existing row. The exception to this is that if a column in the index is allowed to contain NULL values, it can contain multiple NULL values. This exception does not apply to BDB tables, for which an indexed column allows only a single NULL.

Wednesday, December 14, 2005

Eliminating session persistence on Tomcat shutdown

Thanks to this post, adding:

<Manager pathname=""/>

to the DefaultContext will disable Tomcat's default behavior of saving the session upon shutdown.

UPDATE
lousy, this didn't work.

Friday, November 11, 2005

SQL TIMESTAMP headache

So, the truth comes out. Oracle and MySQL appear to not hand back TIMESTAMP as millisecond values. After numerous tests (all Java) in multiple timezones we've decided we're not going insane. The databases appear to not deliver TIMESTAMP as milliseconds, but as a String, always. Even from native console applications. There may be milliseconds that reside underneath, but they represent the String and cannot be retrieved. So, no, the TIMESTAMP going is not *always* normalized to UTC (could only get that to be the case when the db box was UTC and the JVM connecting via JDBC was also UTC). We tried multiple scenarios connecting in different timezones and continually found ourselves asking why the date appeared coming back differently in all places if it was really just stored in milliseconds. Perhaps it is, but it's not being given back that way. And the String is transformed by the JVM into the appropriate milliseconds to represent the toString (on the java.util.Date/java.sql.Timestamp) the JVM thinks it should show in your timezone.

At this point the question becomes, "So, how does this work with internationally replicated/distributed databases servicing multiple international JVMs?" It doesn't work, and after several days of testing, we're feeling confident enough to conclude this: the millis are (sometimes) being adjusted by the JDBC drivers to show you what it thinks you expect--so if you're really expecting UTC, then all the boxes' timezones should be GMT/UTC! That's sort of an issue if you plan on using servers in multiple places throughout the world to handle multiple web applications--which is exactly what we cannot assume.

So, the solution is simple:store the milliseconds as a long. Since Java (and most other sane languages) calculates date based upon the Unix Epoch, it makes sense. Furthermore, there's no guess work as to db timezone, connection timezone, driver millisecond manipulation--it's not a concern anymore.

When does the format of a date being storing in the database really matter? Depends on the need for precision, depends on the need of the application and it also depends on the requirement driving it in the first place. When the requirement dictates international interaction, the first thing that should come to mind is to store the date in a common time: GMT. Other consideration should be given to viewers and manipulators, what do they expect to see the time as? Locally or universal? If the answer for all of these questions point to an international need, the above solution is a simplistic and intuitive approach to resolving the design decision.

-------------begin Hibernate UserType-------------
package org.lds.sql;

import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.sql.Types;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Date;
import java.util.TimeZone;
import net.sf.hibernate.Hibernate;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.UserType;
import org.lds.env.utils.DateUtils;


/**
* Custom Hibernate type for precise UTC millisecond persistance and retrieval using a Timestamp.
* All values represent the given time from the Unix Epoch, 1 Jan 1970 00:00:00.000
* See http://en.wikipedia.org/wiki/Unix_epoch for more info.
* Credit: Rob @ "http://www.hibernate.org/100.html
*
*/
public class UtcTimestamp extends Timestamp implements UserType {
/**
* Gets the value of SQL_TYPES
*
* @return the value of SQL_TYPES
*/
public static int[] getSQL_TYPES() {
return UtcTimestamp.SQL_TYPES;
}


/**
* SQL type.
*/
private static final int[] SQL_TYPES = { Types.BIGINT };

/**
* Creates a new UtcTimestamp instance at this moment.
*
*/
public UtcTimestamp(){
super(System.currentTimeMillis());
}

/**
* With the given milliseconds.
*
* @param utcMillis a long value
*/
public UtcTimestamp(long utcMillis){
super(utcMillis);
}

/**
* Make a copy of the Timestamp.
* @see UserType#deepCopy(java.lang.Object)
*/
public Object deepCopy(Object obj) throws HibernateException {
return (obj == null) ? null : new Timestamp(((Timestamp)obj).getTime());
}

/**
* Compare via {@link Object#equals(java.lang.Object)}.
* @see UserType#equals(java.lang.Object, java.lang.Object)
*/
public boolean equals(Object x, Object y) {
return (x == null) ? (y == null) : x.equals(y);
}

/**
* Timestamps are mutable.
* @see net.sf.hibernate.UserType#isMutable()
*/
public boolean isMutable() {
return true;
}

/**
* Return an instance of the Timestamp or null if no value is specified.
* @see net.sf.hibernate.UserType#nullSafeGet(java.sql.ResultSet, java.lang.String[], java.lang.Object)
*/
public Object nullSafeGet(ResultSet rs, String[] columns, Object owner)
throws HibernateException, SQLException {

long value = rs.getLong(columns[0]);
Timestamp timestamp;

if(rs.wasNull()) {
timestamp = null;
} else {
timestamp = new UtcTimestamp(value);
}
return timestamp;

}

/**
* Set an instance of the Timestamp into the database field.
* @see net.sf.hibernate.UserType#nullSafeSet(java.sql.PreparedStatement, java.lang.Object, int)
*/
public void nullSafeSet(PreparedStatement statement, Object value, int index)
throws HibernateException, SQLException {

if(value == null) {
statement.setNull(index, Types.BIGINT);
} else {
Timestamp timestamp = (Timestamp)value;
statement.setLong(index, timestamp.getTime());
}
}

/**
* Return the {@link Timestamp} class.
* @see net.sf.hibernate.UserType#returnedClass()
*/
public Class returnedClass() {
return org.lds.sql.UtcTimestamp.class;
}

/**
* Return the supported SQL types.
* @see net.sf.hibernate.UserType#sqlTypes()
*/
public int[] sqlTypes() {
return SQL_TYPES;
}

/**
* All dates return their value in GMT time.
*
* @return a String value
*/
public String toString(){
SimpleDateFormat dateFormat = new SimpleDateFormat(DateUtils.DATE_FORMAT);

dateFormat.setTimeZone(DateUtils.GMT);

return dateFormat.format(this);
}

/**
* Obtain a UtcTimestamp from a Date.
*
* @param date a java.util.Date value
* @return an UtcTimestamp value
*/
public static UtcTimestamp valueOf(java.util.Date date){
UtcTimestamp utcTimestamp = new UtcTimestamp(date.getTime());

return utcTimestamp;

}

}
-------------end Hibernate UserType-------------

External firewire dvd burner

I have a Toshiba SD-R5372 that I wanted to use to backup my system. Didn't take too much effort to get it working last night. I added SCSI CDROM support as a module and also 1394 SBP as a module (the other 1394 options I already had built-in to the kernel).

Emerged the latest k3b, reboot, modprobe sbp2 and modprobe sr_mod.
Plugged in the burner and watched /var/log/messages recognize it.
Added a device in k3b as /dev/sr0
Burned 4G in 20 minutes.

Once the burning was complete I mounted the drive as "mount /dev/sr0 /mnt/dvdrw" and verified the disc has my files!

Wednesday, November 09, 2005

Vonage, how easy

Number transfer took 20 days exactly. Called up AT&T and the phone service was shutoff today. Walked out side, opened up the panel, disconnect my wires (light blue and white blue for me). Walked in, plugged the phone line from the Vonage router into the wall. Picked up the phone plugged into the wall downstairs and have been calling out (and receiving) ever since. Sweet.

Secondly, Melissa has been talking to family in Idaho while I'm downloading two Sun apps @ 245KBps! Wow.

Further confirmation all dates are UTC millis, regardless of db timezone settings

(08:36:39) Russ: have a second?
(08:36:51) jamisbuck: sure
(08:36:57) Russ: do you use Mysql much?
(08:37:02) Russ: or Oracle?
(08:37:05) jamisbuck: mysql
(08:37:07) jamisbuck: I used oracle at byu
(08:37:17) Russ: great; done much with timestamps in mysql?
(08:37:22) jamisbuck: no, I avoid them
(08:37:26) jamisbuck: they don't act very intuitively
(08:37:36) Russ: intuitively...meaning?
(08:38:00) jamisbuck: updating the row automatically updates the timestamp, even if it was not explicitly requested
(08:38:03) jamisbuck: which goes counter to my way of thinking
(08:38:12) Russ: ah, right, only for the first column though ;)
(08:38:19) Russ: so, that aside
(08:38:45) Russ: do you explicitly set the timezone of your Mysql server to something other than the default SYSTEM?
(08:38:51) jamisbuck: no
(08:39:15) jamisbuck: we always store the times as utc, and explicitly transform them ourselves to the customer's time zone on display
(08:39:25) Russ: okay, that's exactly what I wanted to chat with you about
(08:39:30) Russ: the concept of storing them as UTC
(08:39:52) Russ: isn't *any* timestamp (or date/datetime for that matter) stored in UTC as millis from the epoch?
(08:40:26) jamisbuck: I have no idea :( but I'm pretty sure mysql dates/datetimes aren't limited to the epoch
(08:40:44) Russ: correct, they're not, the negative values work retroactively
(08:41:49) Russ: I'm struggling with storing time as UTC. Given a Calendar object in Java for today 9 Nov 00:00:00.000 GMT, I can store that in the database as my timestamp and verify the millis going in are the millis coming out--which is what I would expect if the date is indeed stored in UTC.
(08:42:07) Russ: The kicker is, any time I view that date via mysql console (or otherwise), the String representation is MST
(08:42:15) Russ: that is, 8 Nov 17:00:00:00.000
(08:42:30) Russ: not such a big deal, except that it can be confusing to convince that the date is correctly stored
(08:42:35) Russ: when not evaluating the millis
(08:42:35) jamisbuck: what is the timezone for your system?
(08:42:39) Russ: MST7MDT
(08:42:43) jamisbuck: yah, ours is utc
(08:42:52) Russ: I even changed that
(08:42:53) jamisbuck: I bet mysql is converting the date to the system's zone on output
(08:42:57) Russ: that's what I'm thinking
(08:43:10) Russ: I changed everything I could find, *except* my local timezone, and I get the same result
(08:43:20) Russ: even remote connections, from a different time zone
(08:43:36) Russ: which again points to the mysql server on my box "translating" the appropriate time
(08:43:49) jamisbuck: right
(08:43:50) Russ: so, theoretically, if I change my system timezone to UTC, I'll see the String I expect?
(08:44:01) jamisbuck: let me check something quick
(08:44:18) Russ: thanks for your input on this, I've been about on the verge of insanity of verification of this
(08:45:16) Russ: and the only remaining reason is that my system timezone is involved in the String representation
(08:45:31) jamisbuck: ok, I take it back, our servers have CST as the time zone, and mysql is configured to use SYSTEM as the time zone
(08:45:41) jamisbuck: but when I select a date via the mysql console, it doesn't show me any TZ information
(08:45:46) Russ: correct
(08:45:50) jamisbuck: 2004-04-11 07:07:37
(08:46:06) Russ: which if you get the millis, and view the UTC representation, will be the offset of CST
(08:46:22) jamisbuck: k, well, it has never bitten us in our rails apps
(08:46:29) jamisbuck: the times go in and come out correctly
(08:46:32) Russ: exactly
(08:46:41) Russ: as long as you use the millis, and not the string reported, that should be the case
(08:46:52) jamisbuck: to be honest, I use script/console more than I use mysql
(08:47:14) Russ: don't follow...you mean the console mysql executable?
(08:47:34) jamisbuck: I use my rails' app's script/console, istead of the mysql client program
(08:47:37) Russ: gotcha
(08:48:15) Russ: well thanks a bunch for your confirmation--my expectation is that whatever driver is managing the connection and result sets returns the millis any time a date/time/timestamp is retrieved
(08:48:37) Russ: the String representation is the secondary, because of the TZ offset calculations
(08:48:47) jamisbuck: alright, glad I could help
(08:48:48) Russ: which brings me around to, why set the timezone on a database?
(08:49:25) jamisbuck: I seem to remember that you can set some properties on the client connection. Maybe some of those specify how to deal with time zones
(08:49:38) jamisbuck: but it doesn't seem like it would help much if you are dealing with dates in multiple time zones
(08:49:44) Russ: exactly
(08:50:00) Russ: in Java you can muck with the millis going in if you provide the connection timezone
(08:50:18) Russ: and the JDBC driver will essentially "translate" the GMT millis to represent the timezone equivalent
(08:50:20) Russ: if that makes sense
(08:50:24) jamisbuck: yah
(08:50:29) Russ: anyhow, thanks again
(08:50:38) Russ: I wondered how Ruby dealt with it
(08:50:50) Russ: and it you've definitely confirmed my expectation
(08:50:52) Russ: have a good one!
(08:50:57) jamisbuck: you too!

GMT time and my headache

So say you care about a given date, like today, 9 Nov. It means so much to you that you want to store it in the database. Turns out if you're using Java, then what you're really storing is the GMT millis of the date and the database is storing that date in the same format. In other words, regardless of the time zone in which you reside, or where the database resides, 9 Nov GMT is 9 Nov GMT.

Regardless of my posts earlier about storing GMT dates in the database, I'm not so conviced that we *weren't* doing that in the first place. Fact is, using the Calendar in the PreparedStatement really only hoses with the millis being stored and my verification that "the right timestamp" was being stored was purely based on the String representation. In all actuality, if millis going in == millis coming out, then the date that is being stored at the moment indicated by the millis is very much indeed being stored in GTM.

But what about the settings for getting Oracle (alter database time_zone=xyz) or Mysql (mysqld_safe --default-time-zone=xyz)? I dunno what bearing that actually has. What I do know is that regardless of the time zone that Mysql is initiaiized with, the String representation of any date always appears as MST. For example, I have a date representing today (9 Nov 00:00:00.000 GMT). I persist this via JDBC and then immediately request back the value of the timestamp. Both sets of millis are identical. However, the date shown from toString() shows 8 Nov 17:00:00.000 since Java knows that JVM's timezone is MST7MDT. Likewise, if I access that same record and look at the date through the mysql command console, I see the same date!

What does this mean? I can explain the Java representation since it's using the timezone of my box (and Bryan and I tested it when he set his Apple to Tokyo time and we verified millis were correct, but String was appropriate for the Tokyo timezone), but I cannot explain the mysql console. Furthermore, why can't I just see millis? Something is translating those millis into MST7MDT. Still need to test this on Oracle. But, for the time being, I'm quite confused about the notion of storing timestamps in GMT when it appears that the Oracle/Mysql are doing exactly that anyway (as indicated by my tests, which I should post).

Tuesday, November 08, 2005

Oracle 9i GMT dates

Oracle made it too easy, here's the test code producing desired results:


import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.TimeZone;
import java.sql.ResultSet;

public class TestOracleDate{

public static void main(String[] args){

SQLException exception = null;
Connection con = null;
String connectionString = "jdbc:oracle:thin:@testbox:imstest";
String user = "testuser";
String password = "testpassword";
String database = "testdb";
String uuid="c93d4654-40c2-11da";
String identifier="hoser date test";
String driverClassName="oracle.jdbc.driver.OracleDriver";

try{
Class.forName(driverClassName).newInstance();
}catch(Exception ex){ex.printStackTrace();}
try{
con = DriverManager.getConnection(connectionString,user,password);
String insertString = "INSERT INTO TEST_TABLE (cmn_rswd_identifier,cmn_rswd_statusid,cmn_rswd_mdate,cmn_rswd_cdate,cmn_rswd_uuid) VALUES ('"+identifier+"',1,?,?,'"+uuid+"')";
String deleteString = "DELETE FROM CMN_RESERVED_WORD where cmn_rswd_identifier='"+identifier+"'";
//insert = con.createStatement();
final PreparedStatement insert = con.prepareStatement(insertString);
final PreparedStatement delete = con.prepareStatement(deleteString);
System.out.println("executing: " + deleteString);
delete.executeUpdate();
System.out.println("executing: " + insertString);
TimeZone GMT = TimeZone.getTimeZone("GMT-00:00");
TimeZone MST = TimeZone.getTimeZone("MST7MDT");
System.out.println("First timestamp param, using :" + GMT.getID());
System.out.println("First timestamp param, using :" + MST.getID());
insert.setTimestamp(1,new Timestamp(System.currentTimeMillis()),Calendar.getInstance(GMT));
insert.setTimestamp(2,new Timestamp(System.currentTimeMillis()),Calendar.getInstance(MST));

insert.executeUpdate();

String queryString = "SELECT * FROM CMN_RESERVED_WORD where cmn_rswd_uuid='"+uuid+"'";
Statement query = con.createStatement();
ResultSet rs = query.executeQuery(queryString);
while(rs.next()){
//System.out.println(rs);
System.out.println("-----------------");
System.out.println("cmn_rswd_mdate (positional param 1) " + rs.getTimestamp("cmn_rswd_mdate"));
System.out.println("cmn_rswd_cdate (positional param 2) " + rs.getTimestamp("cmn_rswd_cdate"));
System.out.println("-----------------");
}

}
catch(SQLException ex){
ex.printStackTrace();
}
catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
finally{
try{
if(con != null) con.close();
}catch(Exception ex){ex.printStackTrace();}
}
}
}


Sources:
http://www.oracle.com/technology/products/oracle9i/htdocs/9iober2/obe9ir2/obe-nls/html/datetime/datetime.htm

http://www.dbasupport.com/oracle/ora9i/TimeZone.shtml

GMT dates for Mysql (MST7MDT) via JDBC, success

Finally able to store MST dates as GMT time in the database. Had to load the timezone tables first, /usr/local/mysql/bin/mysql_tzinfo_to_sql /usr/share/zoneinfo/ | /usr/local/mysql/bin/mysql -u root -p mysql. Here's the setup:

mysql 4.1.3-beta-standard

Connector/J:3.1.11-bin OR 3.2.0-alpha-bin

url:
jdbc:mysql://localhost:3306/unity?useUnicode=true&characterEncoding=utf8&useTimezone=true&serverTimezone=MST7MDT

mysql executable: /usr/local/mysql/bin/mysqld_safe --user=root --default-time-zone=MST7MDT &

Prepared statement (Hibernate)code:

public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException{
Timestamp timestamp;
if(value instanceof Timestamp){
timestamp = (Timestamp) value;
}
else{
timestamp = (Timestamp) new LocalizedTimestamp();
}

Calendar gmtCal = Calendar.getInstance(GMT);
//where GMT = TimeZone.getTimeZone("GMT-00:00");

st.setTimestamp(index, timestamp,gmtCal);
}


The catch is that this code will be called on all of our TIMESTAMP types, since we're overriding the existing Hibernate TIMESTAMP type (as LocalizedTimestamp). However, this could be easily resolved by the generated DAOs setting some flag on the LocalizedTimestamp object. As it is, some of us are of the mindset that all the timestamps we store should be GMT, so this still works.

-----------
Update
The alternative, producing the same result, is as follows:
/usr/local/mysql/bin/mysqld_safe --user=root --default-time-zone=UTC &

jdbc:mysql://localhost:3306/unity?useUnicode=true&characterEncoding=utf8&useTimezone=true&serverTimezone=UTC

st.setTimestamp(index, timestamp);

Monday, November 07, 2005

mysql 5 and localized dates

Problems with persisting timestamps in Mysql 5 via JDBC:

3.0.9
Cannot convert value '2004-08-16 12:00:00' from column 4(2004-08-16 12:00:00 ) to TIMESTAMP.

3.1.11
java.sql.SQLException: Invalid value for getInt() - '^A' in column 7

3.2.0 alpha
Caused by: java.sql.SQLException: Unknown type '16 in column 6 of 21 in binary-encoded result set.

with the following code:

st.setTimestamp(index, timestamp,gmtCal);

where st is a PreparedStatement and the gmtCal is a Calendar instance set at GMT.

Also, the URL connection string was:
jdbc:mysql://localhost:3306/unity?useUnicode=true&characterEncoding=utf8&useTimezone=true&serverTimezone=MST7MDT

Tuesday, October 25, 2005

Bike fitting

This was fantastic:
http://www.peterwhitecycles.com/fitting.htm

Tuesday, October 18, 2005

UTF-8, Java, XML and my linux kernel

Posts to Dom4j after receiving "?" instead of unicode chars while parsing XML.
-----------
I've searched and searched for my problem, and this is my last hope.Apache Maven 1.x uses Dom4j for various xml processing and provides a Jelly tag for parsing XML into a DefaultDocument. I'm experiencing Unicode characters being translated into "?" and the hooks are definitely not what I need.

I've replaced the 1.4 version shipped with Maven to 1.6.1 and have
created a simple test goal in order to replicate the behavior. I've
tried to two different ways of parsing the file, one through using a StringReader that's opened a file in UTF-8, and the other using the default xml:parse tag in Jelly. Both with the same results. So, my question is, has anyone else experienced anything similar? Should I be posting my question on the Maven list? Any ideas?

Thanks in advance,
-RR-

UPDATE
Pretty much after I sent my post I realized that this could be a
JVM/System issue. Further testing, and loading NLS into my kernel
resolved the problem. The System.out issue was resolved by setting my LC_ALL="en_US.utf8" and then I proceeded with my kernel modification.

Friday, October 14, 2005

Ruby FileFinder now toast, gse-locate.el is in

I was really getting tired of my little Ruby file finder app due to the cost in performance. If anything else was running it became sluggish and was slow to start. I intended to write a replacement in C using a database, probably SQLite. I was already making plans and designing what I'd need to do. Then Norm suggested I use slocate. Conveniently, there are two Emacs lisp chunks that are already doing that! One is fff.el and the other is gse-locate.

First thing is to create a "locate" database. I wanted to index everything in /ext, so the command was "slocate -U /ext -o ext.files.db". I modified gse-locate to work in linux and the final code is:


;; gse-locate.el
;; Summary: Emacs front-end to 'locate'.
;; Author: Scott Evans
;; Home: http://www.antisleep.com/elisp
;; Time-stamp: <2004.12.22 23:20:59 gse>
;;
;; Commentary:
;; A handy Emacs interface to 'locate'. Having this interface
;; around is great -- it gives you a one-step way to get around a
;; filesystem, and spend a lot less time navigating directory trees.
;;
;; I lifted a lot of the major mode code from Steve Molitor's
;; rec-files.el (or at least from my modified version).
;;
;; I spend most of my time in Windows now, and porting slocate to
;; Cygwin didn't go real well so I wrote my own simple 'locate'
;; replacement for Cygwin (see http://www.antisleep.com/software/loc).
;;
;; Written for/using XEmacs on Windows. Changes are welcome.
;;
;; Installation:
;; (require 'gse-locate)
;; and if you like:
;; (global-set-key '[f10] 'gse-locate)
;;
;;---------------------------------------------------------------------------
;; Change Log
;; ----------
;; 2005.10.11 Modified to use locate and work in Linux -RR
;; 2004.01.18 Actually, -c is bad.
;; 2004.01.18 Use loc -c, take out backslash replacing.
;; 2004.01.18 Add gse-locate-execute-file.
;; 2004.01.18 Change to major mode with keybindings. Add some customization.
;; 2002.04.08 Created.
;;---------------------------------------------------------------------------


;; Unix (and native Cygwin) users can probably just set this
;; to "locate".
(defvar gse-locate-command "locate"
"*\"locate\" shell command. This will be used as an argument to
shell-command, with the search pattern concatenated to it.

This specified program should take a string (or regular expression, if
you intend to use them) as a parameter, and return a list of files to
stdout, one per line.")

(defvar gse-locate-hooks nil
"List of functions to call when entering gse-locate-mode")

(defvar gse-locate-regexp-list
(list "\\.elc"
"\\.class"
"/CVS"
"/target/classes"
"#"
"~"
".cvsignore"
)
"A list of regular expressions that match \"uninteresting\" filenames.
These will be stripped from the locate list before it is displayed.")

;;---------------------------------------------------------------------------

(defvar gse-locate-prev-wconfig nil)
(defvar gse-locate-buf nil)
(defvar gse-locate-history nil)

;;---------------------------------------------------------------------------

(defun gse-locate (pattern)
"Lightweight interface to locate. PATTERN is the string or regexp
that will be passed to locate (see gse-locate-command).

If exactly one file matches, it will be opened. Otherwise a list
of files will be presented (see gse-locate-mode)."
(interactive
(list
(read-from-minibuffer "locate pattern: " nil nil nil
'gse-locate-history)))

(set-buffer (get-buffer-create "*locate*"))
(setq buffer-read-only nil)
(erase-buffer)
(shell-command (concat gse-locate-command " -d /ext/ext.files.db " pattern) t)

;; Clean up stuff we don't want to see.
(let* ((i 0))
(while (< i (length gse-locate-regexp-list))
(let ((cur-regexp (nth i gse-locate-regexp-list)))
(goto-char (point-min))
(delete-matching-lines cur-regexp))
(setq i (+ i 1))))

(let ((number-matches (count-lines (point-min) (point-max))))
(cond
((= number-matches 0)
(message "No matches."))
((= number-matches 1)
;; One match. Open the file.
(find-file (buffer-substring
(point-min)
(progn
(goto-char (point-min))
(end-of-line)
(point))))
)
(t
;; Multiple matches.
(setq gse-locate-prev-wconfig (current-window-configuration))
(goto-char (point-min))
(switch-to-buffer (current-buffer))
(setq gse-locate-buf (current-buffer))
(gse-locate-mode))
))
)

;;---------------------------------------------------------------------------

(defvar gse-locate-mode-map nil
"Keymap for gse-locate-mode.")

(if gse-locate-mode-map
()
(setq gse-locate-mode-map (make-sparse-keymap))
(define-key gse-locate-mode-map "v" 'gse-locate-select-this-window)
(define-key gse-locate-mode-map "\C-m" 'gse-locate-select-this-window)
(define-key gse-locate-mode-map "o" 'gse-locate-select-other-window)
(define-key gse-locate-mode-map " " 'next-line)
(define-key gse-locate-mode-map "n" 'next-line)
(define-key gse-locate-mode-map "p" 'previous-line)
(define-key gse-locate-mode-map "q" 'gse-locate-quit)
(define-key gse-locate-mode-map "1" 'gse-locate-select-1-window)
(define-key gse-locate-mode-map "?" 'describe-mode)

(when (functionp 'mswindows-shell-execute)
(define-key gse-locate-mode-map "X" 'gse-locate-execute-file))
)

;;---------------------------------------------------------------------------

(defun gse-locate-mode ()
"Lightweight major mode to select a file from \"locate\" output.

Special keys:
\\{gse-locate-mode-map}"
(interactive)
(kill-all-local-variables)
(setq major-mode 'gse-locate-mode)
(setq mode-name "Locate")
(use-local-map gse-locate-mode-map)
(setq truncate-lines t)
(setq buffer-read-only t)
(run-hooks 'gse-locate-hooks))

;;---------------------------------------------------------------------------

(defun gse-locate-current-file ()
(save-excursion
(beginning-of-line)
(buffer-substring
(point)
(search-forward-regexp "$"))))

;;---------------------------------------------------------------------------

(defun gse-locate-find-file (file-name &optional find-function)
"Open file if it exists."
(when (not find-function)
(setq find-function 'find-file))

(if (file-exists-p file-name)
(funcall find-function file-name)
(error "%s%s%s" "File '" file-name "' does not exist!")))

;;---------------------------------------------------------------------------

(defun gse-locate-select-this-window ()
"Select this line's file in this window."
(interactive)
(gse-locate-find-file (gse-locate-current-file)))

;;---------------------------------------------------------------------------

(defun gse-locate-select-other-window ()
"Select this line's file in this window."
(interactive)
(gse-locate-find-file (gse-locate-current-file) 'find-file-other-window))

;;---------------------------------------------------------------------------

(defun gse-locate-select-1-window ()
"Select this line's buffer, alone, in full frame."
(interactive)
(gse-locate-find-file (gse-locate-current-file))
(bury-buffer (other-buffer))
(delete-other-windows))

;;---------------------------------------------------------------------------

(defun gse-locate-quit ()
"Close gse-locate buffer."
(interactive)
(let ((buf (get-buffer gse-locate-buf)))
(and buf (bury-buffer buf)))
(set-window-configuration gse-locate-prev-wconfig))

;;---------------------------------------------------------------------------

(defun gse-locate-execute-file ()
"Launch this line's file. Currently windows-only (and probably
XEmacs-only)."
(interactive)

(let ((file-name (gse-locate-current-file)))
(if (file-exists-p file-name)
(mswindows-shell-execute nil file-name)
(error "%s%s%s" "File '" file-name "' does not exist!"))))

;;---------------------------------------------------------------------------

(provide 'gse-locate)



Monday, October 10, 2005

jde-usages, this is great

Quite happy to have run across the jde-usages plugin for the Java Development Environment for Emacs. The usages plugin works great with the prj.el generated from Maven. The only tweak I've found is adding classpaths of other projects that depend on the one in which you're working. Primarily this is useful for refactoring methods and seeing which classes will be affected. Usages is also quite handy building trees of subclass/implementations. Once the cache is running it's quite speedy.

Friday, October 07, 2005

Beagle 0.1.1 in Gentoo

Following these instructions (http://gentoo-wiki.com/HOWTO_Beagle) I downloaded app-misc/beagle-0.1.1.ebuild,files/beagle-0.1.1-null-task-source.patch,files/beagle-0.1.1-uri-serialization.patch and placed them in /usr/portage/app-misc/beagle. Actually, the .patch files go in the beagle/files directory.
Then "ebuild /usr/portage/app-misc/beagle/beagle-0.1.1.ebuild digest".

Lastly, my /etc/portage/package.unmask:
dev-lan/mono

and /etc/portage/package.keywords:
sys-apps/dbus ~x86
app-misc/beagle ~x86
dev-lang/mono ~x86
dev-dotnet/libgdiplus ~x86
dev-dotnet/gecko-sharp ~x86
dev-dotnet/gtk-sharp ~x86
dev-libs/gmime ~x86
dev-dotnet/gnome-sharp ~x86
dev-dotnet/art-sharp ~x86
dev-dotnet/gnomevfs-sharp ~x86
dev-dotnet/glade-sharp ~x86
dev-dotnet/gconf-sharp ~x86
media-libs/libexif ~x86

Finally, "emerge -av app-misc/beagle" and selecting "yes".

I haven't upgraded my kernel, with the inotify stuff.

UPDATE
Here's my make.conf:
USE="x86 oss apm arts avi berkdb crypt cups encode foomaticdb gdbm gif gpm gtk gtk2 imlib
jpeg kde gnome libg++ libwww mad mikmod motif mpeg ncurses nls oggvorbis
opengl pam pdflib png python qt quicktime readline sdl slang spell ssl
svga tcpd truetype X xml2 xmms xv zlib gtkhtml svg objc
ruby mono dbus eds"

I tried adding "webservices", but it hosed the build.

Tuesday, September 27, 2005

Location equivalency headaches

Bryan and I came up with this while trying solve migration and location/address integrity issues.

To define how multiple Location subordinates are equivalent, consider the following. The Location (country) USA has "states", "commonwealths", and a "district". It's neighbor to the north, Canada, has "provinces" and "territories". Likewise, the UK has "counties" or "post towns". On a formal level, these could all be called, "level 1 subordinates". If you have a Location table that defines a location by its type (and an id), then you could have the following:

Location
---------
id type name
-- ---- ----
1 country USA
2 country Canada
3 country UK
4 level1 Alabama
5 level1 Manitoba
6 level1 Southhampton
7 level1 Puerto Rico
8 level1 District of Columbia
9 country Mexico

LocationType
------------
id type
-- ----
1 country
2 level1
3 level2
4 level3
5 level4

Note, "level*" indicates a level of subordination. Using a LocationAssociation table you can build a hierarchy of locations and their subordinates.


For address creation, how could you equate like levels and provide an appropriate naming scheme in the context of the country? Here's one possible set of tables providing a solution:

First is a Subordinate Types table that defines the types you will use to identify subordinates (any level). This table could have a translatable counterpart that provided localized identifiers (I18n) per row, thus enabling translations for a single word, in multiple languages. (This is beneficial in the following model because it constrains translation to a single word and the context is derived based on equivalency relation.)

Subordinate Types
-----------------
id type
-- ----
1 state
2 province
3 territory
4 county
5 district
6 commonwealth

The Subordinate Equivalence table will relate a location, a locationType, specify if the row is a default (more on this in a moment), subordinateType, and a pointer to a localized string used to identify that component in the native country (locationId). This table realizes the equivalent nature of LocationTypes and SubordinateTypes in context of the owning location (usually country).

Subordinate Equivalence
-----------------------
id locationId locationType defaultBit subordinateType defaultLocalizedStringId
-- ---------- ------------ ---------- --------------- ------------------------
1 1 level1 1 state ->"State"
2 1 level1 0 district ->"District"
3 1 level1 0 commonwealth ->"Commonwealth"
4 2 level1 1 province ->"Province"
5 2 level1 0 territory ->"Territory"
6 3 level1 1 county ->"County"
7 3 level1 0 posttown ->"Post Town"
8 1 level2 1 county ->"County"
9 1 level3 1 city ->"City"
10 2 level3 1 city ->"City"
11 3 level4 1 city ->"City"
12 9 level1 1 state ->"Estado"
13 9 level3 1 city ->"Ciudad"

Thus, this table relates that "level3" is common across USA, Canada, UK, and Mexico. But, "level2" has no associated alternatives *in those countries*. Likewise, the word "county" is used twice, once to show a "county" is "level2" locationType in the USA. BUT, it also shows that it is a "level1" for the UK. So, the UK "county" could be considered equivalent to a USA "state" and Canadian "province" and "territory". This is quite helpful to know in address construction and UI presentation. The "defaultBit" shows which is the default subordinate type for that level, to display to the user.

I18n Benefits:

With the use of the FK to the Subordinate Types table, the i18n value of the subordinate type can be easily fetched. This is most helpful for countries that support multiple languages (ie. Canada or Switzerland).

Likewise, if a user in the USA wants to know what an "Estado" is, we can determine the equivalent through this table and provide an appropriate translation.

Monday, September 26, 2005

Lexmark printing

http://www.downloaddelivery.com/srfilecache/print-drivers-linux-glibc2-x86.deb
as root:
emerge deb2targz
execute deb2targz on the driver
execute the shell script located in usr/local/lexmark/setup.lexprint

execute lexprint to setup the printer

At this point the CUPS entry is created (once the printer is added) and you can print from anywhere that supports CUPS.

Oracle settings

This is what I had to add to my .bashrc to get Oracle drivers/sqlplus working:
#oracle stuff
ORACLE_BASE=/home/russ/apps/oracle
ORACLE_HOME=$ORACLE_BASE/10
TNS_ADMIN=$ORACLE_HOME/tnsnames
export ORACLE_HOME TNS_ADMIN ORACLE_BASE
LD_LIBRARY_PATH=$ORACLE_HOME/basic-client:$ORACLE_HOME/sql-client
export LD_LIBRARY_PATH
SQLPLUS=$ORACLE_HOME/sql-client/sqlplus

Wednesday, September 21, 2005

Opera Adblock. thanks to the wiki

http://nontroppo.org/wiki/OperaPythonAdblock

Here's how I finally got "AdBlock" functionality working in Opera.

In my opera6.ini under "[Image Link Popup Menu]" and "[Image Popup Menu]:

Item, "Destroy image python" = Copy image address & Execute program,"/home/russ/.opera/adblock.py","%c" & Select user CSS file,1 & Deselect user CSS file, 1 & Select user CSS file,1 & Deselect user CSS file, 1

Where adblock.py (universally executable) is:

#!/usr/bin/python
import sys, os

BLOCK_CSS_FILE="/home/russ/.opera/adblock.css"

# read current CSS
try:
cssFile=open(BLOCK_CSS_FILE,"r")
except:
cssStr="\n"
else:
cssStr=cssFile.read()
cssFile.close()

# write new CSS
cssFile=open(BLOCK_CSS_FILE,"w")
if len(sys.argv)==2:
cssFile.writelines('img[src="'+sys.argv[1]+'"]')
elif len(sys.argv)==3:
cssFile.writelines(sys.argv[2]+'"'+sys.argv[1]+'"]')
elif len(sys.argv)==5:
cssFile.writelines(sys.argv[2]+'['+sys.argv[3]+sys.argv[4]+'"'+sys.argv[1]+'"]')
elif len(sys.argv)==4:
cssFile.writelines(sys.argv[2]+'['+sys.argv[3]+'='+'"'+sys.argv[1]+'"]')

if (cssStr=="\n")|(cssStr==""):
cssFile.writelines('\n{display:none !important;}')
else:
cssFile.writelines(',\n')
cssFile.writelines(cssStr)

cssFile.close()


And now that Opera is free without the ad banner, imports FireFox bookmarks, and can now block images this may be a long-term relationship. It's fast and so far I like it.

Forgot that this is also present in opera6.ini:

[Author Display Mode]
Author Font and Colors=1
User Font and Colors=0
User Link Settings=1
Author CSS=1
User CSS=1

[User Display Mode]
User CSS=1
User Link Settings=1
Author CSS=1
Author Font and Colors=1
User Font and Colors=0

[Local CSS Files]
Name 12=Adblock
File 12=adblock.css
Name 13=Overlay
File 13=overlay.css
Active 13=0
Active 12=1

Saturday, September 17, 2005

Divs, Iframes, and Windows rendering

Been a long weekend debugging a bunch of pop-ins that we're using that were hosed because of IE's rendering of Selects. The divs that were being popped-in overlapped some selects are were thus subject to the nasty effect of the Selects bleeding through. I was trying to glean code from the DatePicker.js in Tapestry, but the way it automatically generates the coordinates for the calendar was a little too tricky for what we need. And, I couldn't get it to work right (after 2-3 hours!). Thankfully it was helpful enough to illustrate the necessity of generating an IFrame (which takes rendering precedence) under the div. I had that working except in some cases the iframe was out of synch with the div so the locations appear hosed.

Anyhow, long story short, thanks to this blog from Joe King at MS, it clicked that I was 90% of the way there but was missing only a couple small things. After another hour of tweaking, I have a solution.

Assuming you have a DIV that is your pop-in already placed where you want it to show, it's just a matter of adding the following code and calling "hideOrShowPop" (stupid, yes, I should rename it):


function hideOrShowPop(id){
var popin= document.getElementById(id);
var idToFetch = id + "Active";
var popinActive = document.getElementById(idToFetch);

if(popin.style.visibility=="hidden"){
handlePop(id);
}
else{
popin.style.visibility="hidden";

var clone = document.getElementById("clone"+id);
if(clone != null){
clone.style.visibility="hidden";
clone.removeNode(true);
}
}
}

function handlePop(id){
var popinDiv = document.getElementById(id);
var anchorNode = document.getElementById(id+"Anchor");

popinDiv.style.visibility="visible";
popinDiv.style.display="block";

var cloneDiv = popinDiv.cloneNode(false);
//this is for figuring out how to put the popin ANYWHERE on the screen, currently not working
//var anchorPoint = getLocationPoint(anchorNode);
//popinDiv.style.top = anchorPoint.y;
//popinDiv.style.left = anchorPoint.x;

var width = parseInt(popinDiv.style.width);
var height = parseInt(popinDiv.style.height);

cloneDiv.id = "clone" + id;
try{
cloneDiv.zIndex="3";
cloneDiv.innerHTML = "";
popinDiv.parentNode.appendChild(cloneDiv);
popinDiv.parentNode.appendChild(popinDiv);
} catch(e){
alert("Popin exception caused by id: " + idToFetch + " or " + id);
if(ie)
alert(e.description);
else
alert(e);
}
}


So the code clones the div, then sets the inner node of the cloned div to an iframe. Lastly it's appended to whomever owns the original div, and then the original div is appended after the clone.

Now I can go to bed.

Friday, September 16, 2005

Firefox HTTP sniffer

Credit to Todd T. for this fantastic find:
http://tamperdata.mozdev.org/installation.html

Easily view HTTP traffic from your browser AND edit it before it's sent.

Thursday, September 15, 2005

16080x1050, finally!

Modeline "1680x1050" 147.14 1680 1784 1968 2256 1050 1051 1054 1087

Tapestry: DatePIcker, SSL, and IE

Final solution was adding "src=https:Home.html" to the IFrame, since Home.html was relative. This fixed the annoying security issues, and it left the IFrame in place (so no Selects will ever be hosed when a DatePicker is near). What a dang pain.

Here are the posts I wrote along the way (most recent first):

Branding myself a hasty hoser, the previously posted code did not work (my test page was cached with a previous attempt).

So, for real this time, the fix is: commenting out that line of code for generating the IFrame. Of course, if you have a dropdown underneath it then you'll probably want it, but that's a tradeoff explicitly awaiting IE developers. This fix is quick and dirty, but it works for me since we don't have any Selects near DatePickers.

http://support.microsoft.com/default.aspx?scid=kb;en-us;177378
" However, IFRAME tries to draw on top of SELECT because it is last in the order. To prevent this, the value of the SELECT element's z-index must be greater than that of the IFRAME, or the SELECT element must be last in the list to ensure that the element always draws on top of the IFRAME when the z-indexes are the same. Because of this, z-indexing similar content can be difficult."

IFrame security covered here (Dec 04, which explains why the DatePicker was working fine in IE last year at this time):
http://www.microsoft.com/technet/security/bulletin/ms04-040.mspx

Hopefully I'm done with this topic, apologies for the repeated posts,
-RR-

-----------------
Thanks to this thread, http://thread.gmane.org/gmane.comp.java.tapestry.user/13528, I have changed DatePicker.js:

(previous line)
underDiv.innerHTML = "";

(new code)
underDiv.innerHTML = "";

Works wonderfully.

On 9/15/05, RR wrote:


>opening the DatePicker window yields a security warning in Internet
>Explorer when using an SSL connection. The message is the infamous "This
>page contains both

secure and nonsecure items. Do you want to display
>the non

secure items?".

http://article.gmane.org/gmane.comp.java.tapestry.user/7271/match=+secure+items


In Tapestry 3 I'm having the same problem as above -- wondering if anyone else has experienced it and found a solution? This thread is old and I haven't found anything else related.

What I've tried (and without resolution):

1)added my cert as a trusted cert
2)changed the component render to place an onclick in the image instead of wrapping it as an anchor
3)explicitly added "https:" in front of the rendered src attribute on the img.

Any other ideas out there?

Java TCP Tunnel analyzer

Very slick little GUI in soap-2.3.jar (http://www.ibiblio.org/maven/soap/jars/) for setting up a proxy and monitoring TCP traffic. Basic usage is:

java -cp soap-2.3.jar org.apache.soap.util.net.TcpTunnelGui 9999 localhost 8080

Where "9999" is the local socket, localhost is the destination host to monitor, "8080" is the port to monitor on the destination host. So, to monitor your communication with Gmail you could execute: java -cp soap-2.3.jar org.apache.soap.util.net.TcpTunnelGui 9999 gmail.google.com 80. Then, in your browser, you'd use the following URL:

http://localhost:9999/

However, this will only work if you don't require an HTTP proxy.

Likewise with https with a local secure link and server:
java -cp soap-2.3.jar org.apache.soap.util.net.TcpTunnelGui 8888 localhost 8443
and
https://localhost:8888/

Wednesday, September 14, 2005

3550 entry

Educational goals:
a) Finish my CS degree before I'm 30. Hopefully going to happen in the time frame I'd like. Work, kids, and other responsibilities have outweighed my educational pursuits since I began working full-time in 2000.

b) Obtain a Masters degree in something. While I'd like to think that I'd focus on CS studies once I'm done at UVSC, my wife is pretty sure that we'll be taking a break from school for a while. It'd be all too convient if UVSC offered a Masters program by the time I'm done with my under-grad.

Some interests:

  • Linux

  • Programming

  • Being with my kids

  • Software Development

  • Soccer

  • U.S. History

  • Reading (mostly non-fiction right now)

Friday, September 09, 2005

Tapestry render solution

The solution to my render rant a couple days back has been tedious, but not difficult. Started out with:

/**
* Simple interface declaring required properties for a protected component to (en/dis)abling a component render and its disable(d) state.
*
*/
public interface IProtectedComponent{

/**
* Flag for allowing component render.
*
* @return a Boolean value
*/
public boolean getAllowRender();

}


Then I wrapped all of the default Tapestry components we're using, for example:

/**
* A protected PropertySelection component only rendered if allowedRender is true.
*
*/
public abstract class ProtectedPropertySelection extends PropertySelection implements IProtectedComponent{

protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle){
if(getAllowRender() == true){
super.renderComponent(writer, cycle);
}
}


Did this for:
Any
Button
Checkbox
DatePicker
Insert
DirectLink
LinkSubmit
PageLink
PropertySelection
Submit
TextFiel
ValidField

Then, in the base class pageBeginRender, added the following:

for(Iterator componentIter = components.keySet().iterator(); componentIter.hasNext();){
String componentId = (String)componentIter.next();
IComponent component = getComponent(componentId);
IBinding elementId = component.getBinding(ELEMENT_IDENTIFIER);

if(IProtectedComponent.class.isAssignableFrom(component.getClass())){
IProtectedComponent protectedComponent = (IProtectedComponent)component;
if(elementId != null){
//resolve rights to component
//boolean updateOrExecute = canAccess(elementId, CRUDAction.UPDATE);
boolean updateOrExecute = true;
if(! updateOrExecute){
//boolean canRead = canAccess(elementId, CRUDAction.READ);
boolean canRead = false;
if(!canRead){
//do not render the component
component.setProperty(ELEMENT_ALLOW_RENDER, "false");
component.setProperty(ELEMENT_DISABLE, Boolean.TRUE);
}
else{
//Render the component, but make it disabled
component.setProperty(ELEMENT_ALLOW_RENDER, "true");
component.setProperty(ELEMENT_DISABLE, Boolean.TRUE);
}
}
else{
//Render the component normally
component.setProperty(ELEMENT_ALLOW_RENDER, Boolean.TRUE);
component.setProperty(ELEMENT_DISABLE, Boolean.FALSE);

}
}
}
}

So, I'm basically cycling through all of the components and changing state based upon id attribute and rights to the element. By the time renderComponent is called, the allowRender and disabled properties are set. Thus, this ensures the component is handled properly based upon user rights associated to the id.

Wednesday, September 07, 2005

Tapestry rant

Okay, time to spout off about Tapestry. Situation is this: let's say you have a page with a bunch of components. And this page happens to contain *secure* elements. Requirements state that the component can be viewable/read-only, updateable, or not present. Security model dictates, some time before render, what the state of each component should be. So, next issue is rendering the components. Should be as easy as updating the "disabled" attribute for the read-only, and eliminating/removing/not-rendering the components that are unauthorized.

What are the reasons for Tapestry completely hosing the easibility of this process?! This would be cake in XMLC or Wicket!

1. Components must be defined prior to render. Which means, you need to have the "disabled" parameter set to false on *every* single component you want to protect, at build-time. It is a pain to add a "binding" on at run-time and highly discouraged (http://article.gmane.org/gmane.comp.java.tapestry.user/25209).

2. Tapestry is incapable of removing components at render time. You don't have access to the DOM, you can't set a flag, nothing. I should clarify, this is the case for a) all default Tapestry components b) you can sort of work around this by wrapping the component in a Conditional component.

3. Tapestry default components do not allow render flags. In conjunction with issue #2, you can't just set a flag informing Tapestry to NOT render the component.

So, why does this really tick me off? Because I have many pages on which I now need to implement security (aforementioned implementation). I cannot, out-of-the-box, do what I need. I must go through each component and add the "disabled" attribute (only 130+ of them). I must choose to wrap the components in Conditionals if I don't want them rendered. IMO, this is a ton of work and really defeats the purpose of dynamic page generation.

My acceptable is solution is to go through and create wrapper components for each of the Tapestry components we're using. I'll add a default "disabled" attribute that I can hose with at run-time (so the user doesn't have to add it specifically) and a flag that determines whether the component should render. This is going to take more time than I likely have. Wish I knew about this issues months ago, I *may* have reconsidered my choice of web application framework.

One alternative, Java Server Faces, does exactly what I want in its UIComponentBase:
http://java.sun.com/j2ee/javaserverfaces/1.1_01/docs/api/javax/faces/component/UIComponentBase.html#UIComponentBase()

In conclusion, the more I work with Tapestry the more I feel like my hand is being held and while it provides some nifty aspects (reusable components, form validation), I can accomplish essentially the same thing in some other frameworks. The more I look into JSF, the more I'm realizing its value....

Wednesday, August 24, 2005

IceWM whips Flux

Pros (so far):

Smart window placement
faster startup/smaller footprint
ease of customization, configuration files much simpler
good preference tools
invokable menu by key-binding
gaim doesn't crash (compared to flux 0.9.12)
mouse focus more consistent--this drove me nuts in Flux

Tomcat whips JBoss

In order to deploy CDOL into Tomcat 5.x:

1. download Tomcat 5.x, http://www.reverse.net/pub/apache/jakarta/tomcat-5/v5.0.30/bin/jakarta-tomcat-5.0.30.tar.gz or http://www.reverse.net/pub/apache/jakarta/tomcat-5/v5.0.30/bin/jakarta-tomcat-5.0.30.zip

2. [un] tar/zip the Tomcat download.

3. modify this snippet to correctly point to the right properties file:


type="javax.resource.cci.ConnectionFactory"/>



factory
org.lds.jca.properties.LdapFacadeManagedConnectionFactory


PropertiesFileName
/ext/forge/unity/imsteam/build/rollinsrc.properties




4. modify "//server.xml" file by adding the above snippet, insert it after line 378 (following and before ).

5. modify "//web.xml" by replacing the "" element with:
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" disableUploadTimeout="true"
acceptCount="100" debug="0" scheme="https" secure="true"
keystoreFile="${user.home}/.keystore" keystorPass="yourpassword"
clientAuth="false" sslProtocol="SSL" />


6. copy "~/.maven/repository/commons-logging/jar/commons-logging-1.0.4.jar" into "//common/lib"

7. copy "~/.maven/repository/log4j/jars/1og4j-1.2.8.jar" into "//common/lib"

8. copy "~/.maven/repository/j2ee/jars/j2ee-1.4.jar" into "//common/lib"

9. lastly, to run the build/deploy to build the war and copy into "//webapps"

10. startup tomcat, "//bin/catalina.sh run"


Using Tomcat has sped up my build/deploy time from >=160s to <=30s, hooray for Tomcat.


NOTE:
If you're on Linux and downloaded the JDK from Sun, double-check that "javac" has executable permissions.

Tuesday, August 23, 2005

Localized dates the JDBC way

An investigative coworker (Todd) found this that explains a method of translating a given Calendar object into a GMT Timestamp. Likewise, retrieving the date in a specific locale can be achieved through ResultSet.getTimestamp the Timestamp can be localized. Now that all of the code for *doing* this is already in place it'd be a mighty pain to rip it out and refactor.

Implementing the above is a great option if you need a blanket solution. Frankly, I agree with Todd that we should be storing everything in GMT anyway. At this point in the game that's not feasible and we need specific GMT/Localizable functionality on only a few specific columns. Future situations may present alternative necessities.

Friday, August 19, 2005

Maven and Emacs, the romance and beauty

Hot dog, this is great:
Maven JDEE plugin
and
more functionality here
and here.
That last one is especially great because of the ability to run goals with the Maven console. Really speeds up dev time having it open and instantly executing goals--with the ability to click on compile errors and have them immediately opened and focused in the primary Emacs frame. Loving it so far.

Monday, August 15, 2005

VPN

http://oit.uta.edu/cs/network/vpn/linux/vpn_linux.html
copy to /usr/portage/distfiles
emerge cisco-vpnclient-3des

copy .pcf to /etc/opt/cisco-vpnclient/Profiles

then:
vpnclient connect <profile> user <username>