More awesome free code!

I just have to ask that you send $5 to me via email. Thanks.

It turns out that I needed a way to raise events in my pager from the last post. Like when the page changed, I wanted to display "Page 3 of 5 (9 elements)" (for my test size of 2 elements per page (not likely to happen)). But also, for future reference, if say, to save on load times, only load X pages, we'll call it 5, at a time, so 10 elements, so then when they got to page 4 or 5, the non-pager code can load 10 more elements asynchronously, and call refresh on the pager to update the page count etc. Here's the event object:

var EventList = new Array();

function Event(obj, type){
if (EventList[type]) return;
EventList[type] = true;
this.handlers = new Array();
this.type = type;
this.obj = obj;
this.obj._event = new Array();
this.obj._event[type] = this;

if (typeof(this.obj.addCustomEvent) != "function"){
this.obj.addCustomEvent = function(type, fn){
if (typeof(fn) == "function"){
this._event[type].handlers.push(fn);
return true;
}
return false;
}
}

this.raise = function(sender, args){
for(var i = 0; i < this.handlers.length; i++){
this.handlers[i](sender, args);
}
}
}

// addEvent(obj, "event", func);


function addEvent(obj, evType, fn, useCapture){
if (EventList[evType] && obj.addCustomEvent){
var r = obj.addCustomEvent(evType, fn);
return r;
}
else if (obj.addEventListener){
obj.addEventListener(evType, fn, useCapture);
return true;
} else if (obj.attachEvent){
var r = obj.attachEvent("on"+evType, fn);
return r;
} else {
alert("Handler could not be attached");
}
}


Yup, it only handles on event per object right now. That's easily remedied if I use something other than "obj._event". Like this.obj._event = new Array(); this.obj._event[type] = this;. Will do that soon. UPDATE: Fixed that, and used the EventList array to keep track of custom events, and modified the addEvent function to use that and see if it's a custom event first. This way, if I add custom events to a "div" html element, it will work, whereas before it would have evaluated one of the other ones (attachEvent or addEventListener) before it would have added the event where I wanted it. UPDATE 2: Damn, that still has a shortcoming. To be fixed later, like Tuesday. I'm booked this weekend. If you can point out the shortcoming, I'll give YOU $5 :P A hint would be that you don't have to worry about "click" events, only custom events... but damn near everything has a "click" event.

Notice that I modified the "addEvent" function that I shamelessly stole from QuirksMode.org to check if the object that we're adding the event to has an "addCustomEvent" function on it. If it does, call it, which is added to the object when it creates a new event. This is how the pager uses it:

function Pager(){
this.init = function(divid){
...
this.textspan = null;

this.onPageChanged = new Event(this, "pageChanged");
addEvent(this, "pageChanged", this.internalOnPageChanged);
this.initialized = true;
}
...

this.pageChanged = function(pageNumber){
// change page functionality here...

this.onPageChanged.raise(this, { page : this.currentPage, pages: this.pageCount, total: this.elementCount});
}

...

this.internalOnPageChanged = function(pager, args){
if (pager.textspan){
clearChildren(pager.textspan);
pager.textspan.appendChild(document.createTextNode("Page " + (args.page+1) + " of " + args.pages + " (" + args.total + " elements)"));
}
}



I removed unnecessary code but you get the idea. As always, I found code online to do it, but it was too complicated (KISS = Keep it simple stupid). If I have to add to it I will but it doesn't have to solve all of my problems right now. In my html page that is apart from the pager, I add another handler for "pageChanged" to just test it out. Integrating it seamlessly with the "addEvent" function is crucial, so now I just use the same exact syntax for every event, whether it's custom or not. So this works perfectly:

addEvent(window, "load", loaded);
var pager = new Pager();



function loaded(){
pager.init("pager");
addEvent(pager, "pageChanged", pagerPageChanged);
loadNotes();
}

function pagerPageChanged(p, args){
var i = args.page;
//alert("page changed : " + args.page + " of " + args.pages + " pages, " + args.total + " elements in all");
}


That's from "index.html" because I don't need any kind of server side scripting language with my new Ajax framework. And it's loading data, saving data, deleting data, even will begin to authenticate users soon, on the server. This keeps the custom code on the server down to 0 lines. Yup, no lines of Java pertaining to a "Notes" application (basic and without user authentication or authorization). I like writing Java but this will make things quicker :) When I incorporate YUI! into it, it'll even be beautiful. Ahh, until that day.

Sunburned and brain fried

I wrote a javascript pager tonight. It'll be in use on my new Javascript front end, hopefully coming here soon. It's all AJAX-y. I like it. Here's the code:

function Pager(){
this.init = function(divid){
this.div = document.getElementById(divid);
this.divToPage = document.getElementById(this.div.getAttribute("divtopage"));
this.pageSize = parseInt(this.div.getAttribute("pageSize"));
this.elementCount = this.divToPage.childNodes.length;
this.currentPage = (params(divid+"_page") != null ? parseInt(params(divid+"_page")) : 0);
this.pageCount = this.elementCount == 0 ? 0 : Math.ceil(this.pageSize / this.elementCount);
this.initialized = true;
}

this.refresh = function(){
if (this.initialized){
this.elementCount = this.divToPage.childNodes.length;
this.pageCount = this.pageSize == 0 ? 20 : Math.ceil(this.elementCount/this.pageSize);
if (this.elementCount < this.pageSize){
this.div.style.display = "none";
}
else {
this.div.style.display = "block";
clearChildren(this.div);
this.showPager();
}
}
}

this.showPager = function(){
var firstlink = new PagerLink("<<< first", this, function() { this.pageChanged(0); });
var nextlink = new PagerLink("next >>", this, function() { this.pageChanged(this.pager.currentPage+1); }) ;
var prevlink = new PagerLink("<< prev", this, function() { this.pageChanged(this.pager.currentPage-1); }) ;
var lastlink = new PagerLink("last >>>", this, function() { this.pageChanged(this.pager.pageCount); });

var pagelinks = Array();
for (var i = 0; i < this.pageCount; i++){
var pl = new PagerLink("" + (i+1), this, function(){ this.pageChanged(this.pageIndex); });
pl.setPageIndex(i);
pagelinks.push(pl);
}

if (this.pageCount > 10) this.div.appendChild(firstlink.link);

this.div.appendChild(prevlink.link);
for (var i = 0; i < pagelinks.length; i++){
this.div.appendChild(pagelinks[i].link);
}
this.div.appendChild(nextlink.link);

if (this.pageCount > 10) this.div.appendChild(lastlink.link);

this.pageChanged(this.currentPage);
}

this.pageChanged = function(pageNumber){
if (pageNumber >= this.pageCount) pageNumber = this.pageCount-1;
if (pageNumber < 0) pageNumber = 0;

var pageRange = [pageNumber*this.pageSize, (pageNumber+1)*this.pageSize];
for (var i = 0; i < this.elementCount; i++){
if (i >= pageRange[0] && i < pageRange[1]){
this.divToPage.childNodes[i].style.display = "block";
}
else this.divToPage.childNodes[i].style.display = "none";
}
this.currentPage = pageNumber;
}
}

function PagerLink(text, pager, clickEvent){
this.link = getLink(text, clickEvent);
this.pager = pager;
this.text = text;
this.link.pager = pager;
this.link.pageIndex = -1; // for page number links

this.link.pageChanged = function(pageNumber){
this.pager.pageChanged(pageNumber);
}

this.setPageIndex = function(i){
this.link.pageIndex = i;
}


}


It's used like this:

addEvent(window, "load", loaded);
var pager = new Pager();

function loaded(){
pager.init("pager");
}


You initialize the pager with the id of the element you want to hold the pager links.

<div id="pager" divtopage="existingNotes" pageSize="2">

</div>



Then when you add or remove elements from the element you are paging (I hard-coded a div), you refresh the pager, in case the number of pages has changed:

function saveNote(){
var note = getNote();
saveObject(note, noteSaved);
}

function noteSaved(note){
appendNote(note);
clearForm();

pager.refresh();
}
function deleteNote(note){
if (confirm("Are you sure you want to delete the note '" + note.Title + "'?")){
deleteObject(note, noteDeleted);
clearForm();
}
}
function noteDeleted(note){
removeNote(note.NoteId);

pager.refresh();
}


The code I'm writing uses AJAX, JSON and regular old javascript to talk to my ORM. So I can call stuff like "deleteObject" and it'll create the XML (parsing XML on the server is easier than parsing JSON) to make the call, call it, and get back a response. It's super simplistic right now, there's nothing returned except for some easy things.

The pager uses some common functions that have to be linked somewhere (which were either shamelessly stolen from quirksmode.org or I wrote them myself)

Array.prototype.clear = function(){
while (this.length >= 1){
this.shift();
}
}

function addEvent(obj, evType, fn, useCapture){
if (obj.addEventListener){
obj.addEventListener(evType, fn, useCapture);
return true;
} else if (obj.attachEvent){
var r = obj.attachEvent("on"+evType, fn);
return r;
} else {
alert("Handler could not be attached");
}
}

function clearChildren(node){
while ( node.childNodes.length >= 1 )
{
node.removeChild( node.firstChild );
}
}

function params(name){
var qs = document.location.search;
if (qs && qs.length > 1){
var start = qs.indexOf(name);
var end = start != -1 ? (qs.indexOf("&", start) != -1 ? qs.indexOf("&", start) : qs.length) : -1;
if (start != -1 && end != -1){
var value = unescape(qs.substring(start+1+name.length, end));
return value;
}
else return null;
}
else return null;

}

function getLink(text, clickEvent){
var jsl = document.createElement("a");
jsl.setAttribute("href", "javascript:void(0)");
if (text) jsl.appendChild(document.createTextNode(text));
if (clickEvent) addEvent(jsl, "click", clickEvent);
return jsl;
}

Subversion server up

If you want access, let me know, I'll create you an account and let you access all the code on all of my websites! There's lots of neat stuff up there.

Subversion is a code versioning system that is heavily used by developers on teams who want to keep their source code in a single place, let people edit or view it, and keep versions of it. Branches are often made when projects are going to be upgraded from, for example, 1.0 to 2.0. The 1.0 branch is kept so that any bugs that come up for 1.0 users can be fixed without them having to upgrade to 2.0. Patching is also very easy with a good versioning system. There are many reasons to use them, and hardly any not to.

But why am I using one? Frankly because I had to set up a Subversion server at work (svn for short), so I knew somewhat how to do it. Also, because it's a good backup system. Like, hmm, this code used to work, I wonder what I did. Then I can just look back at the history of a file and see what changed, and revert back to what worked. Also, for backup, if I ever want to work on it anywhere, I can, because it's on my server that's on the internet 24/7 with the same IP address. Also if something were to happen to my computer and I haven't backed up recently, I'm screwed.

I've set up SVN about 5 times now, so I'm pretty much an expert. One thing that I am not an expert at is the authz file. The other stuff is simple though. Here's a rundown:

yum install subversion (or apt-get install subversion or emerge subversion) (or download it and run the exe or dmg on Windows or Mac)

svnadmin create /var/data/svndata

edit the configuration
vi /var/data/svndata/conf/svnserve.conf

edit the passwd file (add your user)
echo "jason = jason123" > /var/data/svndata/conf/passwd

(I actually haven't tested that exact syntax... it may put it on the same line as a commented line, which wouldn't work)

svnserve -d -r /var/data/svndata

This will create the repository and start the server daemon.

Then you can test it out.

svn mkdir svn://localhost/dev

It might ask you for a username and password then hopefully spit out the message

Committed Revision 1.

Then you can use your favorite code editor plugin for svn and start sharing! Simple as that.

More dog sickness

Kodie had diarrhea so I took her to the vet. She seems fine now. I can hear her from here banging on her bowl for food and she didn't eat when she was sick. That's her way of telling me something's not right. And banging on her bowl is her way of telling me "I'm effing hungry you ignorant clod!"

She got a haircut while she was there too. They gave her the "lion cut". She's had it before, and I wanted to take a picture of her when she had it because it's F#@$#@ing hilarious! Not just how she looks, but because her hair is so short, she freaks out because she's not used to feeling her tail on her back. Her tail curls up. I have to remember to take a picture.

Today I figured out Logic Express

And to some degree, Mac OS X. I record with an audio interface (Yamaha GO46) through FireWire. This required no setup in a Mac at first. I upgraded to Leopard and probably got an update to Logic Express 8 that I just said, OK install it. This caused some problems.

One of the next times I went to record, I got no sound on monitoring. It would record, but I couldn't record another track with no feedback. So my next few recorded songs were single tracks. Until I really wanted to record more than one track, this was fine. I then had to check the internets for an answer.

Some forums were like "Create an aggregate device in the Audio MIDI Setup tool." I was like, yeah. I tried this but had no idea what the implications were. I found an Apple article that basically solved all of my problems. So I set up my aggregate device, set my audio interface as the first device and the 'clock', and set my built-in output as the second device. Worked like a champ... until I tried to "bounce" the songs I was recording.

The way I had it set up, inputs 1-4 and outputs 1-6 were the audio interface, and outputs 7-8 were built in output. So, I could hear everything as I was recording, but now I couldn't get any sound when I bounced to mp3. This is because the default bounce method bounces outputs 1-2. I had to bounce 7-8, my built-in outputs. Anyway, I have to go babysit. Here's the songs I recorded recently.

Jamaica, I'm excited for my trip.
Improva. I was calling this one "Improv in A" but shortened it.

The check is in the mail

I always feel like I accomplished something when I pay bills, so I have to write a post about it. But this time is extra special.

One check, which happened to be almost precisely covered by a combination of two checks I received recently, including my tax refund and a refund for homeowners insurance, with $8 remaining after the fact, will guarantee a great time for me and Zatko and a bunch of our friends, Zatko's fiancee Amanda, her friends, some family, and loads of unsuspecting resort occupants, as we embark on our trip to Jamaica!!! Zatko and Amanda are getting married down there.

It's at the end of June, we'll be departing Philadelphia on my Dad's birthday, June 25th, and heading back on July 2nd. I figure I'll take off the 3rd as well and be back in work that following Monday, since July 4th falls on a Friday. Woohoo. I'll use jet lag as an excuse even though Jamaica is in the same time zone. Not much to say about it now, though. I will have TONS of pictures and stories when we get back. I really can't wait.

I also mailed in some checks for things like mortgage and the oil bill, and mailed in my latest netflix movies, two John Grisham movies and a documentary. Good stuff. I have to get to mailing them in quicker so I can actually not waste all that money.

The postage price goes up tomorrow so I just put two $0.41 stamps on each envelope. The trip payment and the mortgage are close to due so I don't want them coming back to me.

Mother's Day was nice, even though the Flyers lost again. Not sure how the Phillies did but we watched for a while. It was 4-3 Giants last I saw. Then the golfer we were cheering for (Goydos) lost to Sergio Garcia in the playoff. I had to have some happy news to write about.

More Flyers Posts!

From the Playoffs in 2006 (I was just as excited this year but I haven't been making posts about it):

April 2006

It includes such classic posts like Philadelphia Fans Defined (which goes on to say I hate Buffalo natives and now I work with two of them... it's hockey, they forgave me already), and my Mom's birthday where I talk about how I told the lady at the jewelry store that perhaps she isn't a good mom! It's a classic. Back when I used to get comments on my website (not a blog)! NOAT where are you?!? And of course, NHL playoffs in general which happen "nearly every year" with an asterisk. The year previous was the lockout, so of course the asterisk read "Not last year". Man, I used to be pretty funny :) At least I make myself laugh.

On the eve of Philadelphia vs. Pittsburgh

I watch this movie:



It's a good one. It ends with "Flyers win the Stanley Cup!! Flyers win the Stanley Cup!!" But it has a lot of great Philly sports moments, like the 93 NL East Championship, Eagle's in '04 beating the Falcons to go to the Super Bowl, Dr. J's tomahawk dunk or whatever. It was made before the Phils won the NL East last year. Then it has a lot of bad moments... Lindros going down to Scott Stevens, Mitch Williams and the Phils losing the World Series in '93, shots of McNabb (although some good ones when he was athletic), and a bunch of other crap. But it ends on the best moments, and it gets me hyped up for the game. So much that it's 1am and I can't fall asleep.

The Flyers look great so far, and I hope they can keep it up.

GTA IV is soulless fun

GTA IV is all over the news because you can:

  • Drive Drunk
  • Shoot Cops
  • Score with Women
  • Go to strip clubs
  • Cause complete chaos and have the cops forget about you a few minutes later
  • Of course, steal cars
  • And, hit monstrous jumps

There are a bunch of groups that are going after the game, like MADD, who has turned from an anti drunk-driving group into a prohibitionist group trying to get alcohol banned again. Good luck with that.

There's also other people addressing the violence.

Any of those things I mentioned above, you would not be able to survive in real life. It's what makes it a game. In other games I've also ran through burning buildings and lived to tell about it, or have taken thousands of bullets and all I have to do is find cover and I'm fine. One time in GTA IV I drove my car off of a 80 foot drop straight down. The car flipped numerous times and wound up hitting a pole straight on. I didn't even lose any health.

People need to lighten up, but damn that game's fun. And I wasn't driving like a maniac after I played for a few hours. I just drive the way I normally do. In fact, I have a difficult time "escaping" reality in that I don't just go running over pedestrians or shooting people. I try to find one car and stick with it as long as I can. I don't even like to get into accidents where all I do is side swipe someone. Sometimes you can't help it though and it will turn out to be some hilarious death of some poor sucker who just happened to be between your car and some pole or wall at the most inopportune of times.

It is soulless fun and it takes some really screwed up minds to come away affected by it, more than just dreaming about it. I've played Railroads! for hours, which is the least violent game ever, and I've dreamed about it. If you have no imagination, then you obviously can't think this kind of stuff up to keep your idle mind entertained. If you have video games, you don't need an imagination to have fun (unless they're the really old games that expected you to still use your imagination). However, if you look at games as *practice*, then you're screwed up.