Uploaded on Mar. 30, 2008 |
Uploaded on Mar. 20, 2008 |
Uploaded on Dec. 25, 2007 |
Uploaded on Dec. 25, 2007 |
Uploaded on Dec. 25, 2007 |
Uploaded on Dec. 25, 2007 |
Uploaded on Dec. 25, 2007 |
Uploaded on Dec. 25, 2007 |
Uploaded on Sep. 11, 2007 |
Uploaded on Sep. 07, 2007 |
|
|
|
| Thankfully, I was able to find the answer to my problem in German! Here is the forum I read. I found a lot of English speaking topics with the error message I was getting, but they were having slightly different problems. Basically, I renamed the file in the ".safetable" folder, reimported my project, and everything's fine. Weird. Good thing, too, I've been getting tons of comment spam on my pictures because I haven't implemented my anti-spam mechanism on there. I will employ the same method I use here. |
|
|
|
|
|
|
|
|
This new server is about 4 times more powerful than my previous server, but for the same price. I will now definitely be putting lots of new stuff up on here to get the full use out of it. I have my subversion server running off of it, and again, an open invitation to anyone who wants all the free awesome code they can handle :P
Be wary of hosting companies installing MySQL for you. They might install the latest version of it (5.x), but in my.cnf specify that it should use the old password hashing method, the insecure one used before MySQL 4.1. This old method only generates a hash 16 bytes long, whereas the new one is 41 bytes (with a leading *). I did notice it but didn't think anything of it until I tried to login to my website here to post a new item. I had just finished getting all of my passwords for my websites input too. This required looking in the config file that I read to connect to the database to get the current password out, then running "grant all privileges on database.* to 'user'@'localhost' identified by 'password'" for each one. Ridiculous. I think I got them all right on the second go, I didn't feel like reading in the config files again. This site works, and so does Jim and Kate's site (which is awful and is long overdue for an upgrade). Vacre Tei works too. Stringed.org might work but not all of the name servers are pointed correctly yet, so I can't see it. It might work for you, it worked at the office.
Also, if you get "Can't connect to MySQL" and it's running, chances are it isn't allowing networking. I just commented out those two lines (old-passwords and skip-networking) and if I got all the passwords right, everything should work fine. Overall, the transition from the old server went without a hitch, but was a pain in the ass. Here's the breakdown:
- Zip up the websites on May 24 and promise not to upload any new files because then they'd also have to be pushed over.
- Zip up the databases and promise not to make any new posts or anything.
- Zip up tomcat since I don't want to have to reconfigure it
- Download them (the size of jasontconnell.com gzipped up is currently over 600 MB)
- Upload everything to the new server.
- Extract everything where it belongs.
- Update the MySQL passwords
- Set JAVA_HOME
- Hope it works
There were some other steps in there and perhaps at a later date I will be willing to tell them, but that's the gist of it. Enjoy! |
|
|
|
|
|
|
|
|
Here's the updated code which should work all the time.
var EventList = new Array();
var g_eventIndex = 0;
function Event(obj, type){
if (obj._eventIndex){
if (EventList[obj._eventIndex][type]) return;
}
else
obj._eventIndex = g_eventIndex++;
if (typeof(EventList[obj._eventIndex]) == "undefined")
EventList[obj._eventIndex] = new Array();
EventList[obj._eventIndex][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 (typeof(obj._eventIndex) == "number" && EventList[obj._eventIndex][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");
}
}
Now it will handle events of the same name in different objects. I just didn't want to have to come up with different names for events in different objects that did nearly the exact same thing.
I was reading a bit on the internets about how people do this type of thing. I read a post on Yahoo! that said the YUI event handling mechanism is "only 2KB". This is 55 lines with liberal white spacing. The thing about computer science is that sure, there might be something out there that does what you need it to do, and you can get it for free, but it's gonna do tons of other stuff that you really don't need. Not yet anyway. Same goes for software in general. If you need a simple photo editor, you're not gonna pay $600 for Photoshop when iPhoto will do (part of a $79 package with tons of other neat software, which also is overkill if you don't need that other stuff). So, if I need something very specialized, small, and easy to use, I'll write it. If you need this as well, feel free to use mine directly or for knowledge. It's not big or special, but will be used as part of a big and special project :) That will come soon. |
|
|
|
|
|
|
|
|
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. |
|
|
|
|
|
|
|
|
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;
}
|
|
|
|
|
|
|
|
|
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. |
|
|
|
|
|
|
|
|
I am a software developer, but I will not buy most of the software that I use. Don't worry, I don't steal it. But I find that there's tons of software out there that's "free" but also good. I'm not talking about "Lite" versions of software, or "Shareware" trial versions that you can hack to never have to register / buy... I'm talking about FREE SOFTWARE that the authors wrote out of the kindness of their heart (and a huge curiosity and desperate search for knowledge) that they put on websites somewhere, put the code out there, and said "Here. Enjoy."
I know I couldn't have a job right now if all software was free. But custom development is another story. If someone needs an online scheduling system, then I (we) will write them one. I'm sure they could find one online and tweak it, but that's usually a shot in the dark. There's also somewhat of a difference between working out of curiosity and working to put food on the table. I've done an online scheduling system, it wouldn't be fun or illuminating since I've already done it.
The thing with software is that if you're making it for fun or out of curiosity, the cost of reproducing it today is so cheap. The same thing everyone's figuring out about music and movies. You produce it once, and everyone in the world can have a copy if you can get it to them. It's kind of crappy that we all still have to pay $0.99 per song at most places we can get digital music. Some software, however, can cost millions of dollars to produce, and these should charge hefty sums. But if you're just doing it out of curiosity and to learn something new, putting it on the web, even just code in html or something, gives that knowledge to everyone who happens to come across it. Then they can be inspired to try something new with it, and if they learn something out of it, they would share it with you since you sparked their interest and gave them that initial knowledge to light that fire under their bums.
Software today is generally in good shape this way. There are sites dedicated to sharing code (sourceforge.net to name one). There are sites set up to provide legal assistance to those looking to open source their code in a way that if someone uses it, they can't sue them if it goes bad. These licenses generally also state that if the next person makes changes, (s)he's free to either send the changes back to the original author to improve that software, or put his or her changes up on their own website and pass it on to people under the same license (free and open source). You don't see this type of stuff in business, only in SCIENCE. Science is the pursuit of knowledge. That's what it's all about baby. |
|
|
|
|
|
|
|
|
There's probably two subscribers to my feed, and one of them yelled at me :p But Google Reader should be back to business now, shortly after showing 400+ new items from this website. Atom has an ID that it uses, and Google Reader apparently keeps track of your read items by that ID and doesn't care about the date at all, evidently. So, new items showed up back to the beginning of this website.
So, will there be 400+ new items every time I post? No. It has all those IDs now, which are new and changed, and unless I change them, they won't show up again.
I can't just write a post apologizing though. I have to talk about the new cool thing that I'm working on here at home. I've talked about it before but apparently, wasn't able to carry through with it. Reasons were mainly that my laptop proved to be way to slow after the initial "wow" factor of installing Ubuntu. (My reaction now would be more "Wow, FreeBSD on a ThinkPad RULES!") The thing I'm talking about is my seamless integration between front end Javascript and backend Java. I wrote about it here. But I've made a few changes.
First, instead of the backend generating XML, it'll just read XML and spit out results in JSON. I'm kind of partial to that technology because of the name... it just kicks ass. I got my first foray into JSON last week at work. Initially, our backend PHP was just returning a few things, like 3, for the front end Javascript to parse and spit into HTML on the website. What the final requirements called for was way more complex, and I didn't want to have to come up with some naming scheme, because it would just get so ugly. Some things were related to each other but not to everything. It would be something like this:
"What is my name?:Jason,Steve,Albert:Jason:True: Jason,80%:Steve,5%,Albert:15%,2000,Elite"
This is like a quiz or trivia, where the question was "What is my name?", the possible answers "Jason,Steve,Albert" comma separated, the correct answer "Jason", whether that person got it write "True", and finally the percentages that other people guessed, the total points for that user "2000", and their ranking "Elite". And that's not even all of it. It has to include the next question, and all of those possible answers. Painful. So instead, this is what it looks like:
{
"LastQuestion" : {
"Text" : "What is my name?",
etc
},
"User" : {
"Points" : "2000",
etc
},
"AnswerPercentages" : {
"Jason" : "80",
etc
}
}
Much easier to maintain, much easier to read, much MUCH easier for the front end to parse! This can be parsed like this... assume your callback function is called "callback" and is passed whatever is returned from the server, e.g. the JSON code above:
function callback(data){
var obj = eval(data);
alert(obj.LastQuestion.Text); // will alert "What is my name?"
}
Yup, it's that easy.
Next affair... I'll need, and will build over time, a large Javascript library for building out websites with the data returned from the server. Tables, forms, etc. This will generally be a pain in the ass and is attributed to me delaying this project for as long as possible. Ugh.
If I get tired of that, then something's gotta give, and I'll either stop this crazy experiment or go crazy writing Javascript for hours and hours. Thank God for FireBug. |
|
|
|
|
|
|
|
|
I had this log file from my server that's just been sitting there collecting errors for about 2 years. It got pretty big, upwards of 60 MB. So, I wrote this program to break it into chunks. I looked over the FreeBSD documentation to see if there's a program that just reads the last few KB or so. I was getting no output on my new "Browse By Month" code, and when I wrote this program, I was able to split the file into chunks of about 976 KB each (1,000,000 bytes).
package filebreaker;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class FileBreaker {
public static void main(String []args){
String dir = "/usr/home/jason/Downloads/";
String filename = dir + "catalina.out";
int chunk = 1000000;
try {
BufferedInputStream fs = new BufferedInputStream( new FileInputStream(filename) );
BufferedOutputStream os = null;
int itr = 0;
byte []buf = new byte[chunk];
int status = 0;
while (status != -1){
status = fs.read(buf, 0, chunk);
String chunkFilename = dir + "/out/catalina-" + itr + ".txt";
os = new BufferedOutputStream(new FileOutputStream(chunkFilename));
os.write(buf);
os.flush();
os.close();
itr++;
}
fs.close();
}
catch (Exception e){
e.printStackTrace();
}
}
}
I found out the error. I'm using Java 1.6.0 on my local machine, and have yet to install it on my server. I used a method (Calendar.getDisplayName(int, int, Locale)) that wasn't part of Java 1.5.0, which is running on my server. DOH!
I also now like putting code on my website since I have new css for handling <code /> tags. It looks like this:
code {
display: block;
overflow: auto;
width: 600px;
white-space: pre;
}
code br {
display: none;
}
:D My text formatter takes line breaks and replaces them with "<br />", and I wanted code to be preformatted so I don't have to replace tabs with spaces, and also I didn't have to check if I was inside a "code" tag and not insert <br /> for line breaks. It's just a very convenient way to handle it that might look like crap in another browser that's not FireFox. I'll add lots more code now :) |
|
|
|
|
|
|
|
|
After about an hour of programming, I have my URLs in a search engine friendly format! This has many other benefits as well:
For instance, I don't have to know the ID of the news I want to link to, just the title. So, I can make a link to a news item I have previously written by typing in the title in a format that it expects. For the news item titled "The Guitar Player", the link will be "the-guitar-player". Click here to test.
Also, if I want, I can modify my "text writer" component in JSF, to search for strings like "[[The Guitar Player]]", and to write out the url, namely "/news/the-guitar-player". Or I'd have to make it "[[News|The Guitar Player]]" if I want to add more dynamic linking, say for photos, downloads, comments, etc. This is much like a Wiki works. It can be a "news wiki" or a "wiki blog" or something ridiculous like that.
Also, after I save this, it will probably write out all of the news in my atom.xml file... it might take a while, there'll be 454 news items! That's ok though. I'll probably have to delegate that task to a new thread, so I can get to adding more news right away.
Categories are changed for rewriting purposes. "Labels" have not been updated yet. I have to make a new page because a "Label" object can pertain to Downloads and Pictures, so I have to list results for each, or modify the URL rewrite filter to accept "/picture/label/me" and "/download/label/music" to list pictures of me and my music downloads, respectively.
I don't run Apache HTTPD, so I had to write the URL rewriter all in Java for Tomcat. It wasn't too bad. Regular Expressions are neat.
The meat:
String url = ((HttpServletRequest)req).getRequestURL().toString().replace(HttpUtil.getBaseUrl((HttpServletRequest)req), "");
if (rewriteConfig.ignoreUrl(url)){
chain.doFilter(req, resp);
}
else {
String location = rewriteConfig.getLocation(url);
String rewriteUrl = rewriteConfig.getUrl(location, url.replaceAll("/" + location + "/", ""));
if (rewriteUrl != null){
RequestDispatcher dispatcher = req.getRequestDispatcher(rewriteUrl);
dispatcher.forward(req, resp); // forward the request
}
else {
chain.doFilter(req, resp);
}
}
url is the requestUrl stripped of the host. This is so I can make it work on dev (http://localhost:8080/jtccom) and production (http://www.jasontconnell.com/).
This filter is called for every request, so I have an "ignore" map set up. This tests if the URL contains a ".", since every rewritten url will only contain numbers, letters, and the occasional "/" or "-". This is a HashMap for quick lookups. So, it won't attempt to rewrite calls to "/js/someFile.js".
The "location" part of the request is "/x/", so for news it will be "/news/". The location is "news". This is so I only have to loop through rewrite patterns for news, not for everything.
The pattern is written as "([0-9a-z-]+)/?" so if I pass in the whole URL (without the host), "/news/my-news-title", it won't match, so that's what the next line does, removes "/news/" so it's just "my-news-title". The getURL function returns the rewritten URL, so like "/news.jsf?title=my-news-title". I created a new unique column for News, and my "DaoWeb" interface has a "ChangeListener" property, so if I create a news or change it's title, it updates the "TitleKey" in this case. Pictures are just forwarded by their picture id for now, so
"/picture/23" as an example.
Coming soon: News by date span! /news/2008 for all news in 2008. /news/2008/03 for all news in March 2008! /news/2008/03/23 for all news on my birthday this year!!
Tune in for more updates. I'm cranking now, and Java is like riding a bike. I also fixed a few bugs. |
|
|
|
|
|
|
|
|
Blows monkey snot (or insert your own, more vulgar version of "sucks" here). When you're going to look at a store instead of online, of course you have to deal with salespeople who know less about laptops than you do. You can't tell them exactly what you're going to be using it for, because it won't help them decide what model you need, and you already have in mind that you want a "business" laptop. Not something for games, or something with eighteen card readers on it. Definitely not something that comes preinstalled with Windows Vista.
I'm trying to tell the guy, "I don't need HDMI, card readers, Bluetooth, photo album software, MS Office, built in web cam... I have a Mac" :D I just need a good CPU, a fast hard drive, and decent amount of RAM. Wireless is optional. Before I let him in on the little secret that I know a slow mother f@#%@$ing hard drive when I see it, he was trying to push 4800 RPM drives on me.
When he was trying to sell me anti-virus software and MS Office, I sorta just smiled at him and said "I won't be running Windows", in a smart ass type of way that only a true geek can do.
What I ended up with was a Lenovo ThinkPad T61 (as "business" as it gets, and what I have been eyeing online for weeks), with a 14.1" screen (which is running at 1280x800 on Gnome on my FreeBSD, so I'm fine with it), 2.1 GHz Core 2 Duo, 1 GB RAM (but I put in another GB when I got it home), a 100GB 7200 RPM hard drive, and an NVidia basic video card, and tons of ThinkPad goodness (which means nothing!). Minimal but is absolutely awesome. It's 5.3 lbs. It kicks the f%#@ out of my previous laptop's ass. So fast.
Compare to my other laptop (which I'm fuzzy on now):
1.5 GHz single core Centrino, I upped it to 1GB ram, 4800 RPM 60GB hard drive, ATI video card.
A hard drive's speed will make or break productivity in programming. I also just needed an upgrade in CPU speed, and RAM never hurts :)
There's just one thing though that I wish I had noticed about this laptop before I bought it, but I think I can deal with it. Most laptops today have a touch version of a mouse's "scroll wheel" on their pads. My previous laptop has it. This one doesn't :( I can use page up / down, or go old school and use the scroll bar. I'm used to it though, since I had Gentoo Linux on my other laptop for so long, nothing f%@#$ing worked anyway :)
So, I'm installing FreeBSD, getting my development environment set up, and will be creating features for this website, and new websites and software in the near future. |
|
|
|
|
|
|
|
|
Keeping with my 'money' theme from the last few posts, here we have something on the complete opposite side of the spectrum. Not including donations, I've paid $0 for all of the software on my other laptop, and it does everything.
Now, I've been thinking about doing something drastic. Since I installed Ubuntu Linux, my development time on that laptop has actually diminished about 100%. I haven't done any development on it. This is because it's so f@#$@#ing slow. I do a lot of ANT builds and they just take forever. The drastic thing I've been thinking of is upgrading my laptop to a new one. Preferably a Lenovo ThinkPad or something. Customizing one of those for a Linux installation (everything except picking Linux, since they only offer Vista Home Basic) is a lot cheaper than configuring it for even Vista Home Basic. All I need is 2GHz Core 2 Duo (the minimum CPU option), 1GB RAM (although I've been bumping it up to 2GB in the "Customize" section), 1Gbps LAN, and integrated graphics. I could opt to have Wireless, but that's extra. It's not that expensive, although I can't afford it now.
So, instead of getting a beefier laptop to run a slow operating system (Gentoo ran super fast on the same exact old crappy laptop), I was looking into some other operating system that's just as powerful and fast as Gentoo, but not the hardest thing to set up. In my search, I decided to go with something that I've been eyeing ever since I got into free software. FreeBSD.
Having this Mac, and having nothing to work on when I got a side job doing .NET with SQL Server for one of the local schools (Episcopal Academy, which isn't exactly 'one of the local schools'), and the Mac being Intel, I found out about that program called "Parallels", which can run virtual machines of multiple operating systems. I have a Windows one installed for all of that development I did for EA, and I have an Ubuntu Linux one for when I tried it out (much like now) before I installed it on my laptop. So, I did the same thing with FreeBSD. I think I'm going to give it a shot on the laptop.
It's a lot easier than Gentoo, that's a plus. It's as well documented as Gentoo (just visit freebsd.org and see for yourself), it's *almost* as fast as Gentoo, and it runs Gnome. The only thing that I was wondering was "Will it run everything?" Yes it will.
FreeBSD is Unix, not Linux. While they are similar in some areas, there's others where they are just very very different. Like, FreeBSD and Linux use different threading models, which Sun depends on in its Linux implementation of Java and Sun does not provide a native implementation of Java for FreeBSD, yet. However, you can get "Linux compatibility mode" running on FreeBSD which will make the Linux implementation work on FreeBSD. The down side of that is that FreeBSD has to build the source for Java to install it, and the source is released under an incompatible license. So, when you install it, it fails, and asks you to download certain files before it can continue. And still, after you do that, you're contractually obligated (through the license) to NOT distribute the resulting built Java binaries. It's weird. There is hope, though, as most believe that Java 7 (it's at 6 right now) will be released under the GPL, since Sun completely open sourced Java recently.
So, I'll give FreeBSD a shot, and if it doesn't work out, then I'll download and try out another one!
Interesting side story. FreeBSD offers its ISOs in "torrent" format. I've known what BitTorrent was since about 7 years ago, but never got into it. It's a giant legal mess since it's also used to distribute "pirated" material. But there are very legal, morally good ways of using BitTorrent. Anyway, I downloaded it through that (a BitTorrent client called "Transmission" for Mac, also free open source software), and it's just neat seeing all the people you're downloading the same file from simultaneously. It's really brilliant software, BitTorrent is. |
|
|
|
|
|
|
|
|
I've added a new feature this weekend. It would have only taken me about a half hour, but I encountered some major problems on the way. In my ORM system which I call "Dumb", table aliases were previously generated a stupid way. If a table referenced another table, and the two tables were possibly at the long end of a list of joins, it would generate table aliases something like this:
User_UserId_Bio_BioId.BioId
which would be joined from a table with an alias something like this:
User_UserId
This seemed to have worked well for a while amazingly. However, when I tried to build my latest addition, I ran into problems because my User table was being referenced towards the tail end of two different branches in the so-called "join hierarchy". Through much trials and tribulations, I eventually ended up creating a class called "JoinHierarchy" so I could get consistent and unique table aliases. I created a thing called "NewsPicture" which basically links a News item (what you're reading) to a Picture. There's also a "NewsDownload" so I can list downloads as well. Here's what NewsPicture and its join hierarchy looks like:
NewsPicture [PictureId, NewsId, Sequence (for ordering)]
PictureId -> Picture -> PictureAlbum -> User -> Bio
NewsId -> News -> User -> Bio
So as you can see, User and Bio were being joined twice but under the same alias, so MySQL has a problem with that, as well as any database management system out there. Now, each object that can potentially be saved to the database has its own join hierarchy that you can just call up whenever you need a table alias or to get all the joined fields or join statements (including left joins if something could potentially allow null). Take a look at the images and downloads below!! I'll just throw in some random ones this time. |
Related Pictures |
 |
|
Related Downloads |
| Should Be Sleeping [Size: 4.54 MB] | Piano [Size: 3.34 MB] | Latest Resume [Size: 0.08 MB] | Thinkers [Size: 0.01 MB] |
|
|
|
|
|
|
|
|
|
It's funny to me, I've always downloaded the latest ISO of Ubuntu Linux, but have never installed it. Frankly because I don't have any blank CDs lying around. So, last night, I fired up Parallels and installed an ISO I had on my Mac, gave it a quick run through, and made the decision to install it on my other laptop which was currently running Gentoo Linux. Jared recently said he was digging Linux working alongside his Mac. He installed Ubuntu, so I figured I'd finally give it a shot. I was just afraid of losing work, but really I didn't get back into it, so it wasn't necessary that I switched operating systems.
Chances are you might not even have heard of Linux (a free open source operating system which competes with Windows, just in case you haven't heard of it), let alone Gentoo Linux, but if you were to install Gentoo Linux, it's like the super user's version of Linux. Say if you were buying a house, Gentoo would be a real fixer upper, and you could even use the analogy of it being all the raw materials and you have to put it together. Basically, I installed it on this laptop and the laptop was crippled for about 3 years (ever since I got the blasted Windows off of it). No sound, no wireless networking, my mouse pad wouldn't work right, and it took about a month to get a screen resolution that I was happy with. Ubuntu on the other hand is like a fully furnished, beautiful, modern house. You just move in and you can start living.
I installed it and fired up a game of Company of Heroes (against only 2 experts and a hard this time on Seine River). It was done before I finished the game in 41 minutes, which I would have hoped anyway. I whomped some ass in the game by the way.
When I backed up my Gentoo stuff, I have this script that I use that sets up a mount to my shared backup drive on my gaming PC with Windows XP SP 2. To do that, you have to use the smbmount command which, once you learn it, is very easy. Then you can browse to the folder that you mounted the Windows share on the gaming PC to, and just start copying files. The thing about Linux, though, is that it is easy once you learn it. But there is that learning curve, and lots of "man" pages that are pretty cryptic, and you have to figure out which options you need, how to format them, and all that other stuff. I don't mind it because I like a challenge.
Getting the files back after I installed Ubuntu, though, was as easy as going to "Places", selecting "Network", going through "Windows Network", opening up my work group, and opening up my Windows PC, "Voodoo2k7". I can then just copy files from there. If I want, which I probably will, I can use the smbmount command to set up a mount point, mount it to /mnt/voodoo, and go into the command line so I can copy stuff using "sudo" into protected directories, like "/usr/local/", since I haven't found a visual "sudo" program on it yet.
The other thing I noticed a short while ago... There's sort of a network button in the top right. I click on it, and it shows me all of the local wireless access points available! Wireless works with no setup on Ubuntu!! That's marvelous. I could have 5 wireless devices running now. In case you missed it, they are : MacBookPro, this Ubuntu laptop, PSP, PS3 (yup, I got one), and the Wii. It's a 802.11n router, so it can handle it. Ubuntu shows the signal strength of it as a sliver away from 100%, but definitely over 90%.
As soon as I restarted it from Gentoo with the Ubuntu disk in, I noticed that it instantly recognized the onboard sound and speakers. It played that nice little Ubuntu, African style introduction chime. I was like "F@#%@ YES!! UBUNTU ROCKS!!!" As soon as I got to a website that expanded beyond the visible bounds of the screen, I tried my mouse pad. It worked. I had spent MONTHS... maybe a couple of hours... trying to get this thing to work on Gentoo. I definitely spent a weekend, actually. Google "set up synaptics mouse pad on Gentoo Linux", and hit up any of the articles returned. You will see it's not easy. The "horizontal scroll" thing was what I couldn't get to work. The mouse pad worked fine otherwise.
I should have installed Ubuntu a long time ago. It wouldn't have ruled out getting a MacBook Pro, though (which is almost paid off, coincidentally), but I would have had a much better experience using Linux, and I might not have stopped using it hardcore in September. Gentoo was way beyond my capacity. I will miss "emerge" though :) Portage was nice, but Ubuntu has a whole graphical software update service. I say, if you're not using Windows for games, throw a Ubuntu disk in the drive and reboot. You won't be disappointed.
My favorite thing about having devices (weird side note... Firefox has a built in spell checker, and it underlined in dotted red, "favorite"... I switched it to "favourite" and it doesn't show any red line. I might have installed the wrong language! Although Ubuntu is maintained in South Africa or something).. oh yeah, so my favoUrite thing about having multiple devices is naming them. My PS3 is named "VoodooPS3", my PSP is similarly named "VoodooPSP", my Windows PC is named "Voodoo2k7" which was mentioned previously. My Mac doesn't have that naming appeal, and shows up on the network as "jasontconnell_s" or something. When I had Gentoo installed on this computer, I named it "gentoovoodoo". I bet you can probably guess what this computer is named... but I'll tell you anyway. "Voodoobuntu"!! Unfortunately, I've retired two computers, the original "Voodoo" computer, and my liquid cooled "LCVoodoo". Oh well. |
|
|
|
|
|
|
|
|
So, at work, we're working on this site for this company, and it's built on this software called "CommunityServer", which can be found at communityserver.org . The thing that pisses me off isn't necessarily to do with that software package, but in software in general, but it's most relevant with that software right now, because it's what I'm using.
Anyway, so many factors end up determining if something is "visible" or not. For instance, in Community Server, it might be a certain "forum". So, a forum might not be visible if the user isn't logged in, if the user isn't in a certain role, if the forum is the private messages forum. Or, it could be an email address, and it's shown to users logged in who also show their email address, or not shown if no user is logged in, or shown to admin. Et Cetera. There's tons of different variables that might determine if something is shown or not. Which is not my problem. It becomes a problem when you inherit this huge software application, and you have to make something behave just like other stuff that's already on the site.
This can also determine other states of an object, like is it editable? Does it get this certain process applied to it, like if certain versions of it X months old should be deleted, can it be printed, does it have a history, can it be part of an RSS or Atom feed, does it have an image with it? Etc, etc, etc. Tons of other things that could all be generalized, and shouldn't have to be figured out in every single instance.
Alright, maybe their software is poorly designed. I never said it wasn't :) But what I'd love to be able to do is, basically, not have to do anything, as a developer, and have it act like other things like it, whatever it is. I don't want to have to specify that, when selecting it from the database, that the "IsPrivate" bit must be set to 0, and that the "IsDeleted" bit must be set to 0. These aren't necessarily the fields, but examples. Also, I don't want to have to specify that the user has to be in the group that the forum belongs to in order to see it.
When I write software, I make it as easy as I can to write later on down the road. There's two ways to go about software development. #1, get the job done, which is how 99% of software is designed / developed. #2 is then, get it done but make it easier to add / change / remove stuff later on down the road. Software is, in fact, never done. It is a fact, a truth, a tautology. There is always something to add that can make it better. But 99% of the software written out there is so finalized when version 1.0 is out the door. Making changes is, for all intents and purposes, a f@%@#$ing pain in the ass.
Forget that it's never documented. That I can deal with. I can read code like a PhD can read a children's book. Although, it's a lot harder to tell what something *is* versus what something *does*. If you were looking at an engine for a blender, but you know you might find the same type of engine in, say, an electrical drill. You can tell that it probably turns something very fast, but you don't know what it is from the high level. Until you see it in motion. So, the code, along with the running version of the application, I can figure it out. Although, I can still read code like a pro. I am a pro after all :P
Anyway, if there was a way to define behavior in an object, without having to specify and filter and code for every possible variation, my life would be a lot easier. The sad thing is, I can think of hundreds of ways, because my mind has been conditioned, through years of hating to write code, to come up with the simplest, most developer friendly solution possible. I'd create interfaces! Object Oriented Programming is the best. An interface for "this might be private", or "this should be filtered for a role", and "this could only pertain to certain users", and "this could be deleted", etc. You just tag your objects with these interfaces and voila! No code!! Your filter logic would be in your data access layer... "if (obj instanceof IDeletable) then don't get deleted ones." Of course, this application doesn't even make it possible for me to modify this without having to put in hundreds of hours of work into it, and that's simply not an option. Stupid software.
Anyway, time for bed. Got some errands to run before the game tomorrow! |
|
|
|
|
|
|
|
|
Or, at least it should. It will reveal a serious flaw in international standards if that thing succeeds. The basis for my argument is that everyone who opposes it are smart people with no other reason to do so other than the specification is an atrocity. I've literally spent the whole night reading objections to it (simply because advocates for it are few and far between, and also sound like complete morons to me). Here are some links.
Groklaw (which I'm reading more and more every day, written by someone who claims no knowledge of the technical side of the debate, and who seems to side only with the law [not a particular company... a non-biased view])
Rob Weir (an IBM guy who just seems really smart to me)
Miguel de Icaza (who makes no argument at all for OOXML based on how ridiculous the whole thing is)
John Carroll (a Microsoftie who is just blowing his employer... err... his employer's horn.)
This is where it gets interesting. Carroll, in a "blog" post , ignoring all the technical diarrhea that is the OOXML spec (ECMA 367), posts a link to an article by Miguel de Icaza (an open source guy working for Novell which recently inked a deal with Microsoft), about why the OOXML spec should become a standard. Carroll thinks he'll win over MS-haters / Open Source (OSS) advocates because he's posting an OSS person's view on the subject which happens to coincide with his view. So, I start commenting on that post about logical inconsistencies inside of that document, as well as technical concerns I have about OOXML in general, to discredit anything anybody has to say in support of OOXML. On a quest that began after I started posting, I continued reading (I started earlier in work, but had to go home) a document on Groklaw.net that contained all of the objections to OOXML becoming an ISO standard.
When I finished that document, I still needed more ammo. I searched the web, as I had promised to do in a comment on Carroll's post, for pro-OOXML arguments. I couldn't find any on a technical basis besides that it supports old .doc formats all the way back to Word 5 (for which a simple converter could be written to upgrade all docs to the new standard...). So I gave up searching. I did come across a few non-MS employee articles that were pro OOXML, but they well... read for yourself (which, like all Microsoft articles I've read, miss the point ENTIRELY on "CHOICE"). After that waste of time, I somehow wound up on Slashdot.org, reading the comments by those readers (largely anti-OOXML) the same MS letter to IBM that James O'Neill's thing mentions. One of them posted a link to a funny article by Rob Weir. So I immediately liked him. After reading that, I decided to read more of what he had to say. Which is when I came across THIS!! As you can tell, it completely rips Miguel de Icaza's argument a new %@#$hole!! Read the comments on that one too. Miguel is the first to comment, asking Rob if he had ever written any software for OpenOffice.org (the frontrunner on the implementation side of ODF (there are many), the competing standard (yes, already an ISO standard) to MS' OOXML), or if he's just an Armchair General. Later down the page, Rob responds with this comment, which basically says "I am qualified to make that statement, dumbass."
Here's where advocates for OOXML miss the point on CHOICE. When ODF people speak of choice, they speak about different applications being able to operate with each other (interoperate). Meaning, if I save a file using this program on this operating system, I can later open it with this other program on this other operating system. Right now there are a lot (OpenOffice, KOffice, StarOffice, Corel, Google Docs and Spreadsheets, and a few independent apps) that can read and write ODF. Alternative, right now, there is one program that can read and write OOXML, and it was released 1/30/07 (Microsoft Office 2007). Funny timing, by the way, as OOXML went into ISO "fast track" approval on 1/05/07. So they didn't even have a working application to display it. I digress. So there's a difference in opinion of what "choice" actually is. However, when the average user wants to save an image file from their digital camera, should their camera care what operating system they're using, or what photo editing application they have installed? Likewise, there are a few "standards" for image formats. JPEG is highly used for photos because it can contain more colors to the less-lossy (pixel quality wise) but less colors overall GIF format. It has been argued though that OOXML is duplicating much of the same functionality as ODF, whereas JPEG and GIF are very different in their purposes (GIF is much better for small images and transparency, and JPG for high quality compression of larger images... however, both might soon be deemed obsolete by PNG which covers transparency and a good, near-lossless compression algorithm). In the objections document posted earlier, the final note offers an alternative solution. That Microsoft extend the ODF format with any of their functionality that isn't covered in ODF. This is clearly a good solution, since the base functionality is in ODF, is implemented in many standards, and is a good building block. This is what anti-OOXML people would welcome with open arms. Not a year through standardization on a spec that took 12+ years to fully develop!! ODF took 4 years to ISO standardization. 1 year would be ridiculous.
Quality night of reading overall :) Next, there are these gems...
Here are some letters to INCITS (International Committee for Information Technology Standards)...
Some of these letters from the opposition are the same, but all of the letters FOR OOXML are sent as a "joint letter signed by these 20 members of this committee that has 'Microsoft' in the title". To get a joint letter signed, I'd walk around an office and say "Yo, sign this... it's to get free pizza every Friday." There are three letters attached (in the one from "George LaVenture - International Association of Microsoft Certified Partners (IAMCP)"), each from different offices, each signed by 15+ people (but I can't see the signatures for some reason). All of those letters are the same exact thing, and they make no merits on the technical side. Which is fine, I guess. There are many arguments that either would stand up on technical merits. Although, developing an application that uses OOXML would be an absolute nightmare. The spec is 6000+ pages long. The only argument on the Microsoft side that ODF can't claim (not legally anyway :P ) is that there are billions of documents in old formats that this "document format" can support. As I said, write a CONVERTER.
John Hardin's letter makes the claim that if OOXML were to pass as an ISO standard, the reputations of ISO and ANSI standards organizations would be severely damaged. And that "they will be seen as open to manipulation by sufficiently large companies." In no way do we want that to happen. That would be like the US Patent Office! We don't want that situation repeated in standards organizations.
Another post I read somewhere says that if OOXML passes through ISO standardization, it could be the most costly mistake EVER. (Ahh, found the link here)
It's funny that the only people pushing for it are MS people, MS advocates, and some politicians who are paid by Microsoft, whereas the ODF crowd is many many good companies and lots of brilliant people. It leads one (not me certainly) to the conclusion that people who support Microsoft in this area are complete morons, will never be writing the software to support OOXML, or that they're on MS' payroll (either as an employee or accepting donations through politics). Every Microsoft post I've read is a last ditch effort that practically concedes victory to ODF. Not to mention the lies that they tell themselves (e.g. For ISO adoption, 103 companies vote, only 19 opposed on the first round, so they tell themselves and their employees that "We're almost there!!", when, in fact, 16 of those 19 countries that opposed make up HALF of the vote that MATTERS in the final vote, 5 months away!! SUCKERS!!). Just keep telling yourselves that.
Anyway, this was kind of a review of all the reading I did tonight, with no real guiding purpose or goal. Ok, I had a guiding purpose, basically to vent about how bad OOXML is technically, and that's confirmed by no technical merits from anyone that supports it. And, likewise, to convince anyone who reads this to read all the articles and documents I link to, and to convince them of my opinion... like all opinion writers :P The whole thing's probably way too long and filled with typos, but luckily I can only see the last 8 lines I wrote :P I'm going to bed. It's the Wiikend!!! |
|
|
|
|
|
|
|
|
In writing a web application, I've always found it a pain that no matter how advanced of an interface you try to make, the file upload mechanism is so archaic. This functionality is built into every web browser. It's a text box with a "browse..." button next to it. Upgrading this functionality is the last step, probably, in getting to Web 2.0.
When writing a news post or anything of the sort, where you can include images inline, personally, with my software, I'd have to upload the images before I even attempt to write the news. One way around this is to be able to drag an image from a folder on your computer inline to the document. This works but not as expected. The image shows for you because the URL of that image is pointing to the file on YOUR computer. If you were to save that news and review it, it would look great to anyone who viewed it from your computer, but to anyone else, they'd see the big X placeholders for missing images.
I've read a technical article on including the actual content of the image inside the "src" attribute of the "img" tag. It's the bytes encoded in base64. That makes download times pretty big for an HTML website. This behavior isn't available in the previous example, because javascript can't read the contents of a file on the computer, an that would be the only way you could achieve it in real time. Another downside is that images encoded this way only work in Mozilla and possibly a few other browser, definitely not anything Microsoft based.
Another option would be to upgrade the standard. The W3 standard about how files are uploaded to a website. If I could drag an image, like my example of editing a news post, from a folder on my computer into the text of the news, and have a way that it automatically, and asynchronously, uploads that file to the website, and instead displaying the one on my computer, it displays, after a short delay, the one that's physically located on the server... for lack of a better term, that'd be @#%#@$ sweet. Technically, that would take some pretty complex changes.
Technically, I imagine the only way to accomplish this feat is allowing access to the contents of that file in Javascript. Not to say that when you download a website, Javascript in the website can just access any file on your computer, but when you drag a file onto the web page, a Javascript event is called with the contents (and other specs) of that file. This is a client feature, it would have to be implemented in Javascript. So that cuts out any browsers that a) don't support Javascript, and b) don't have an asynchronous way to make requests to a server (the 'AJ' in "Ajax").
For all I know, the W3 is working on something like this. Right now, there's no way to get this functionality, aside from writing a client app wholly separated from your website code. This is a pain because what do you write it in? With the heterogeneous environment of client computers... there's Java, but still, the whole idea of having to write an app to achieve this functionality is a bad idea, and the way websites do it right now is flawed.
There's nothing Web 2.0 about file uploads today. Any app where you have to upload files to achieve any kind of goal for content will never feel like a desktop application until files can be dragged/dropped in real time. Or pasted for that matter. I'll take anything. |
|
|
|
|
|
|
|
|
But I never tried installing Windows on my Mac before. I bought Parallels and entered the name of the VM, my name, and my Windows product key. Clicked "OK" or something, and moments later, I had Windows installed. Parallels is a neat program, I didn't have to do anything after that to install it, it probably got all my settings from the Mac and used that for certain Windows settings (Timezone, etc). It was sweet. So now I can use it to make money :)
I have a project to do with a local school. I needed Windows, SQL Server, and Visual Studio .NET 2003. Luckily, I bought no new software for this. I own 2 copies of Windows (one is still installed on a computer that I haven't turned on in about 8 months, and one on my gaming computer which is running all the time...), I borrowed SQL Server 2000 Developer Edition, and I am using ICSharpCode's SharpDevelop, which is pretty neat. And Open Source. e.g. Free.
I did all the original work while working for a company about 3 years ago now. I tried to instill some better programming practices in them while I was there, but alas, it's been a pain to relearn how to use all the code. It's coming along though. |
|
|
|
|
|
|
|
|
Working on something exciting. Everything I wrote in Java, I'm going to convert it to Javascript! That's right. They will communicate to each other through XML/HTTP calls. It will be done in a few steps.
1) Get them talking.
---This involves having objects in JS that correspond to all my objects in Java. Also, a communication protocol, through XML, including updates, deletes, gets, and custom methods.
2) Automate it.
---This involves wrapping each thing in JS functions, like "update(myObj, callback);" which will generate all the XML and make the call, calling the callback function when it returns. Callback will have to have a few parameters, like error message, if it succeeded, etc.
3) Develop custom controls in JS / HTML (Dynamic HTML) for common types (labels, files, to be determined).
4) ???
5) Profit!!
All in all, it shouldn't be too difficult. The Java part was hard. I've been hacking javascript for about a year straight now. I have to say it's my favorite.
There are a few problems with this method that will hopefully be addressed...
1) Security: People who know my XML scheme and the place that accepts it could just write something that posts to the method with the right format of XML and do disastrous things. I have an idea for this, and it will be done before any site that uses this goes up.
2) Search engines won't see it: With everything being dynamic, there's no content on the page when a search engine browses to the site. There's some placeholder html where everything will go, but no content. Unless I have the atom feeds or some meta data in the html.
3) State saving: I will need a system for generating query string parameters based on the values on the page, and also, when someone goes to that page with those values in the query string, it'll load the page how they remember it. This might be tough, or it could be easy.
I think that's about it. Wish me luck, it should be done before Web 3.0 comes out :D |
|
|
|
|
|
|
|
|
Today, I'm going to make it even more of my routine to not use Office software that needs to be installed on my computer. To kick this off, today I created an online spreadsheet at Google Docs. I find it to be very convenient for my purpose, which is updating a client on the hours that I've worked on the current project. I added them as a "viewer" of the spreadsheet, and it's golden. Only problem was that it doesn't currently support Safari, the default browser on the Mac, so I had to install Firefox. Which is fine by me, except that I have two browsers installed. Oh well.
Also, I'll be using the word processor found at that site. That can be convenient for getting my ideas into English format, which could then be shared with anyone, but more importantly, I don't have to use the excuse "Oh, that document is on my computer at home... sorry." It also happens to be a great place to keep my resume.
Only thing is "Lock-In". We all hate it. Buy a song on iTunes and you can only play it on Apple stuff and with your account (lest you strip DRM from it). Buy a PS3 game and you can only play it on PS3s. Buy a car and you can only drive it on the road and within the limits of the law. That kind of stuff. It sucks. But oh well. As long as I can export it. That would be a good idea for Apple too. To be able to "export" purchased songs into another form of DRM, if you were to switch. It goes the other way as well. Buy songs on xyz, export to Apple format. Just recently, the cell phone companies allowed you to carry over your phone number to another provider, this wouldn't be much different (not technically, of course). Freedom is great. |
|
|
|
|
|
|
|
|
Have to help pay for certain recent purchases (see previous post...) I can't wait til that thing gets here.
Basically what I plan on using it for was everything that I used my Mac Mini for (until it blew up), which is like watching my X-Files DVDs at night to fall asleep to (as well as any movie I have), recording music on there using Garage Band, keeping my photo collection, editing movies from my digital camera (I have a Quick Time Pro 7 license that's currently not being used), browsing the internet, chatting, and getting started with Ruby and Rails.
So basically my other two computers currently in commission will only be tasked with one responsibility each. Actually, the Linux Laptop will be my primary Java programming machine as it is now, and the gaming PC will no longer have any software installed on it other than games, but that's also my large capacity storage machine, since it's the only one I can actually add hard drives to, seeing as the other ones are laptops. It's got about 330 GB of HDD space. Right now it holds my music collection, all the backups of everything I've ever done with computers (including my original websites, both in ASP and Perl! They're a blast from the past), and tons of other random stuff like images and screenshots from college. The new Mac will have 160 GB of HDD space, so I might have to get a dedicated backup drive to put in the gaming PC.
It's funny too, because most people are all about having multiple monitors for a PC, as it leads to higher productivity since you can read a spec on one screen and program on another. Everybody at work has multiple monitors. I fear that I'll need to do that at home if I get used to it, so I'm the only one in work that has a lone monitor. That and my current video card setup can't support more than one. It could get expensive, since right now I'm using a 19" Sony that I bought for 350 bucks a few years ago, and it works marvelous for my purposes. I'd much rather have multiple PCs than multiple monitors. A network leads me to be very productive. A KVM switch is wonderful. It's all about how quick you are on the computer. I can switch between computers in a bat of an eyelash, depending on the KVM switch.
Although nowadays with multiple cores in CPUs (my first multi-core CPU will be the Mac), you can easily run two computation-intensive apps at the same time. But still I'd much rather have two multi-core computers, and KVM between them in order to get shit done :D |
|
|
|
|
|
|
|
|
MBPRO 15/2.16 CTO
2.16GHz Intel Core 2 Duo
2GB 667 DDR2 SDRAM-2x1GB
160GB Serial ATA Drive@5400rpm
SuperDrive 6X
15" Widescreen Display
BkLit Keyboard/Mac OS
Country Kit
That is one fine piece of machinery, right there. |
|
|
|
|
|
|
|
|
And I mean, RIGHT after midnight.
Here's what the last few items of news look like if I select just NewsDate from mysql...
| 2006-08-29 00:00:19 |
| 2006-08-30 00:00:11 |
| 2006-09-05 00:00:41 |
| 2006-09-07 00:00:43 |
| 2006-09-08 00:00:13 |
| 2006-09-08 00:00:46 |
| 2006-09-10 00:00:03 |
| 2006-09-23 00:00:22 |
| 2006-10-05 00:00:53 |
| 2006-10-07 00:00:07 |
| 2006-10-10 00:00:40 |
| 2006-10-11 00:00:29 |
| 2006-10-16 00:00:19 |
| 2006-10-16 00:00:19 |
| 2006-10-17 00:00:22 |
| 2006-10-17 00:00:27 |
| 2006-10-19 00:00:11 |
| 2006-10-20 00:00:33 |
Don't ask me, I just write the sh@#%.
Actually, I know exactly why. Time didn't matter before I had the feed, but now all my items are showing up as "12 AM" and I hadn't the foggiest. Well, I had an idea, but it needs to be fixed, that's all. Time is of the essense. |
|
|
|
|
|
|
|
|
I plan on using just "Atom" as it is the W3 standard. As you can see here:
public class AtomSource {
private AtomCategory category;
private AtomPerson contributor;
private AtomGenerator generator;
private AtomUri icon;
private AtomUri id;
private AtomLink link;
private AtomUri logo;
private AtomDefaultText rights;
private AtomDefaultText subtitle;
private AtomDefaultText title;
private AtomDate updated;
}
Implementation to follow, and I'll have a link up of the feed and some readers, although I highly suggest Google Reader. I'm just implementing the bare minimum to be valid and readable by Atom readers because I have more important crap to do. |
|
|
|
|
|
|
|
|
World world = WorldFactory.getWorld("Earth");
I have the world... now all I need to do is save it. Is the world capable of saving itself? Can it be as simple as
world.Save();
??
I don't think so. I need a World Saver.
WorldSaver savior = new WorldSaver();
savior.setNeedsSaving("Everything");
savior.setPriority(10);
Now I have the world saver. We just need to save our world.
savior.save(world);
Phew!! Just in time too, the s@#$ was about to hit the fan. |
|
|
|
|
|
|
|
|
The last two days I jumped into Ruby. It's a programming language. It's pretty easy to use, although I have to get used to it since I went like 3 hours yesterday without being able to do anything! But it's just different.
I wrote a solution to the dining philosophers problem (it shows threading and synchronizing access to data using mutual exclusion in Ruby), which you can find if you go to my downloads and search for the label "ruby". Its output looks like this:
Socrates is thinking...
>>>p=Socrates:s=thinking:lh=None:rh=None:to_l=Utensil:to_r=Utensil
Plato is dining...
>>>p=Plato:s=dining:lh=Utensil:rh=Utensil:to_l=None:to_r=None
CC is thinking...
>>>p=CC:s=wants:thinking:lh=None:rh=None:to_l=None:to_r=Utensil
DD is thinking...
>>>p=DD:s=thinking:lh=None:rh=None:to_l=Utensil:to_r=Utensil
EE is thinking...
>>>p=EE:s=wants:thinking:lh=None:rh=None:to_l=Utensil:to_r=Utensil
It'll loop indefinitely. The philosophers will decide whether they want to think or dine, and then they'll do it if they can! See, there's 5 philosophers at the table, and only 5 utensils, one between each of them. So, only two can be eating at the same time, but two will only be eating at the same time if they're not right next to each other, and two want to eat at the same time.
Here's another loop. It shows what happens when a philosopher wants to eat but can't:
Socrates is dining...
>>>p=Socrates:s=dining:lh=Utensil:rh=Utensil:to_l=None:to_r=None
Plato is thinking...
>>>p=Plato:s=thinking:lh=None:rh=None:to_l=None:to_r=Utensil
CC is dining...
>>>p=CC:s=dining:lh=Utensil:rh=Utensil:to_l=None:to_r=None
DD wants to eat but can't (CC has Utensil <--> EE has None)
>>>p=DD:s=wants:dining:lh=None:rh=None:to_l=None:to_r=Utensil
EE wants to eat but can't (DD has None <--> Socrates has Utensil)
>>>p=EE:s=wants:dining:lh=None:rh=None:to_l=Utensil:to_r=None
Download ruby at ruby-lang and a whole bunch of other places if you want to play with it. It's a pretty decent language so far. |
|
|
|
|
|
|
|
|
Don't ask me what that means, I have no idea. I just came up with it. Proxy seemed like a good term, but I'll explain how it works, and why they were necessary.
I wanted to have filters on "dumbweb" (Read about dumbweb here). You know, the software running over at stringed.org... Well, filters are a configurable item. Just read this to learn all about them. "dumbweb" is a completely separate project, and you can't go writing very specific filter configuration parsing code in there. But, you would want dumbweb to be able to use filters in such a way that it's easy to configure, in the same config file where you define dumbweb. Hence the need for "configuration proxies".
Basically, now, in my dumbweb configuration xml, I can just write what would be in the filter configuration file but into the dumbweb configuration for the data item (i.e. "Picture") and a filter will show up for that item on the list page. Here's the xml
<form className="jtccom.domain.data.pictures.Picture" name="Picture" listed="true">
<filter helpIcon="/images/helpicon.jpg">
<fields>
<field label="Album" name="PictureAlbumId" helpText="This is LONG overdue!!" />
<field label="Labels" name="Labels" helpText="Search Labels" />
<field label="# of Labels" name="Count(PictureId):PictureLabel" helpText="Find pictures with or without labels." />
</fields>
</filter>
<operations>
<operation name="edit" />
<operation name="delete" />
<operation name="add" />
<operation name="view" />
</operations>
</form>
And basically what you see is the same as the filters on the Pictures, News and Downloads pages, only as a part of dumbweb. And those are configuration proxies. Configuration specifications that are used in the system but not in the current system, but the current system can... not load, but support or use the system that the proxy defines. So, dumb web configurations don't read the filter xml at all! It's read by the dumb filter system! It's neat. We can call this Configuration version 3. Read more about Configuration version 2 here, and that article links to version 1 if you're that interested. |
|
|
|
|
|
|
|
|
First, here's the problem:
When you "subfilter" labels, all of them are returned and there's like a thousand of them.
Second, here's the solution:
And check out all this DOM scripting to accomplish that! |
|
|
|
|
|
|
|
|
This is different from the last one. I went through, for about 4 hours, painstakingly labeling each and every picture. It led me to a few conclusions:
1.) I take too many damn pictures of the same thing. I guess taking them isn't bad, but I don't have to upload 40 pictures of the Phillies game I went to a year ago. Then every picture gets the same labels "philadelphia, sports, phillies". It was very boring doing that.
2.) There has to be an easier way to label stuff.
3.) Labeling stuff sucks. I'm glad I'm done.
Also, I went ahead and got rid of download categories and replaced them with labels.
Labels are a centralized thing. If I create a label called "ducks" for example (there are pictures under that label!), then that label will show up as a choice for downloads and for pictures (and later news), whether or not there are downloads labeled "ducks" or pictures labeled "ducks". When you search the filter in downloads for labels like "duck" then "ducks" will show up. This will lead me to develop something cool in the future. Like, search a label and list anything that has that label, whether it's a download or a picture or an X or a Y. It will be pluggable.
If you want to see how I input labels, search pictures for the label "labels". Also you can search for "java" and "dev". Those two will give you a bunch, whereas "labels" will give you the four screens I took of "dumb web" and how it handles labels. |
|
|
|
|
|
|
|
|
I decided to make everything have labels, and pictures are the first to be converted. There's more work to be done, but use the filter for most of your label needs. In fact, with the filter, there's really no more work to be done... I don't know, I'll probably think of something. So, now I have to go and add labels to all of my pictures... 226 of them.
But it took about a day to get the labels up, only because my data list that shows the pictures always goes back to the first record after I save a picture. It's pageable, and the first page was easy :) But after that, it goes back to the first page, so I have to keep track of what page the picture was on that I just added labels to. So I had to fix that. Now it'll keep go back to the last page you were on. That makes life easier. But isn't that what software development is supposed to do?
I've been hacking away at this site and my shared stuff (dumb, dumbweb, filter, etc, etc, etc) that I use on all my websites ever since I told my work that I won't be coming in anymore. Well, I actually just turned down the position offered to me, which was to do with VBScript, which I can't do. Not because I don't know it... it would just be a huge change in how I think when I program. If a language doesn't support standard object oriented features, then I'm f@#%@ed. I have a hammer and everything looks like a nail.
The other day I went to a User group meeting for Philly on Rails. I don't use rails or ruby, but I might start soon. Zatko said he'll play Dawn of War with me if I learn ruby and rails, so I have to since that's the best game ever, and I haven't played multiplayer yet. Actually, we have to play first then I'll learn Ruby. Jared went too. We were the bomb. |
|
|
|
|
|
|
|
|
First, notice the "Possible count" on the bottom right.
Then filter by this text exactly : Cigarettes and Carrot Juice
Then notice what it says. Cool huh?
Then, notice the help icon! I know they don't look great, I'm a n00b when it comes to CSS and DHTML. Plus, I hate Internet Explorer because I use the w3.org specs and they never work on IE. So, if you use IE, there's no support. Download a real browser.
But you're not a real programmer if you don't support IE!!
I'm a lazy programmer, as I've said many, many times. It might work... I did some standard checks, but haven't tested it. I'm on Linux and a Mac. No IE.
So that's it. I could go on explaining what I did but I'm not terribly proud of the count stuff. I did it and couldn't help but think I hacked it together. It's just not beautiful yet. |
|
|
|
|
|
|
|
|
All fixed.
First, it's common to want to do this...
Select * from Table1 join Table2 on Table1.ID = Table2.Table1ID where Table2.Something = whatever.
That now works in dumb by doing simply the following:
Table1 t = new Table1();
Table2 t2 = new Table2();
t2.setSomething(whatever);
t.setTable2(t2);
engine.load(t);
So it'll select everything from Table1 where a certain condition on Table2 is true. Like, selecting polls where a poll answer contains 'The'. Of course, this works in filters because the filter is actually generating its own SQL. Saving that object was never a problem, that's been a part of dumb since the old days, over a year ago.
Another problem I had... it's very common to have a table like this:
table UserFriend {
userId int not null,
friendId int not null,
constraint foreign key userId references (User) userId,
constraint foreign key friendId references (User) userId
}
Two fields are references to the same table. Before, my generated sql code would pretty much only work if no table was joined more than once, either from the same initial table, or later on down the joined road. Now, I can have any number of references to the same table either in the initial table or down the road. It all works now. It's beautiful.
Anyway, I'm still chugging away at the... oh wait, that last game update was the last one. |
|
|
|
|
|
|
|
|
Because I don't feel like doing them anymore. If you want to know, just ask me. Or subscribe to the newsletter...
The thing's almost done. When you have a document called "CWG_Status.odt", it of course means you're using the OpenDocument format, but also means that you are reminding yourself of what you still have to add. And when that file goes from 10.4 KB to 8.3 KB, it means your almost done! So, I poke a little fun at ODF for its size... so what? The price is just right ($0.00). It's fast enough for me. Anyways. Right now I have 9 lines of stuff that still needs to be added. One will be addressed after the initial version goes live. I know, it can't be considered "Finished" until it's actually "Finished" but, name one piece of software where the creator had no more ideas for new stuff to add after it was "finished". It's the great thing about my job, I just work and work and work, and my boss will ask "Are you finished?!" and I'll reply "Software is never finished..." And it's like eternal job security with no ship date.
That's funny though, because you can finish a work of art. Like, a song, or a painting, or a photograph. With art, though, it's like, you reach a point where you consider it done, and then you take stuff away. Especially in sculpting. They haul in a huge chunk of marble for Michaelangelo and he says "I'm done! I just have to cut some marble away now."
At some point in the last 3 years, I've learned to see computer science as more art than science, though. A program can be beautiful. It can be elegant. You can show it to other people and they may or may not (usually not) see the beauty in it. It's a messy process. I'm not talking about the user interface either. I'm talking about the code. The design. The implementation. The very little code that does a lot. The abstraction. The sweet, sweet pleasure of everything running correctly.
So the game is almost done. It's looking beautiful... not in the sense of how you probably think of beauty, but in the sense described above. The code is beautiful. The interface is not beautiful, at all. Well, it kinda looks like this site, only less gray, and more non-colorish. Here's my motto:
Function, then beauty
It makes life easier. Get it to work, then make it aesthetically appealing. That's down the road though, since this isn't like a 3D game or something. It's a web game. With an incredibly lazy creator.
There's more logic in this game than anything I've programmed in the last 3 years. Well, I guess that's an exaggerated statement. There's certainly a lot of logic in dumb and it's web counterpart. I guess I can say, there's more logic in this application than any other application I've ever done. Meaning, something specific, like this website, or other websites I've done, even in work. Underlying systems aren't applications, they're tools to help make application development easier, and that includes dumb and dumb web. And the security system, and my menu system which still holds its own. So this adds a level of complexity that I wouldn't normally find in an application, but not one that I'm not capable of handling. Basically, here's what goes on with my other applications...
select data from the database
show it
or
show a form
input data to the database
With dumb and JSF, there was literally no work do be done here. I can't say what's going on now, only because it's too complex and it would give away my great ideas.
I look forward to releasing this game on the web for the 4 people in the world that will enjoy it. Should be within the next week or so. w00t! |
|
|
|
|
|
|
|
|
Also, you've probably noticed the news categories on the left of the main page are gone
(<---- psst... over there)
This is due to the filter destroying this page and taking up all the landscape, and no need to list categories anymore since you can just filter by them, and Todd wanted to know when I replied to his comment in "The end of the world".
So, now my website seems VERY busy. I want to add more crap...
I started to reply to Todd, then had to go to work, saved the text in a file on my MacMini, went to work, came home a few hours later, then the Phillies were playing the Yankees and our fearless genius leader, Charlie Manuel, had set the lineup so Abreu and Howard were sitting and Chase Utley was playing first... it was something I had to see... they won!! Amazing. I was being sarcastic about Charlie being a genius. Oh, and I watched game seven of the Stanley Cup Finals, and was cheering for Edmonton so that probably doomed them, since Carolina won the Stanley Cup, those b@#tards. So, I had to work on that stuff after those games. Now it's like 2am and I have to go to bed. So, probably tomorrow Todd :)
Out of curiosity, due to the fact that when my web game comes out, it will require probably tons of disk space, I checked the amount of space left on my hard drive on this server. It's an 80 GB drive. There are a few websites on it, and one with lots of images, and this one has lots of images, and there is a lot of data in my databases, and of course Linux and software like Java, Tomcat, GNU tools, etc, etc, etc. Lots of stuff. There are three partitions, and one's not a file system (maybe it's a backup?). Here's what the "df" command in Linux returns. I was like "SWEET!"
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/hda2 75790304 4175216 67765112 6% /
/dev/hda1 101089 9324 86546 10% /boot
none 252864 0 252864 0% /dev/shm
Basically, I'm using 4 Gigabytes for all this junk. Well, you can add it up. The boot partition has a 101 MB partition, which is nothing compared to the 67 GBs I have left on hda2 (Linux doesn't use C: or D: like Windows. HDA is the first hard drive, and 1 or 2 [3,4,5, etc] refer to the partition). In other words, I have plenty of f@#%ing room. |
|
|
|
|
|
|
|
|
You can thank Zatko for this one. Since I only test this on my laptop so far, my mouse pad is directly accessible from my keyboard without much effort. So, on my laptop I am much quicker. You can refer to the post entitled "Hell" (use the filter, silly!) to see how much I hate how people go between their keyboard and mouse, when they can just use the keyboard all the time. So, generally, on a laptop, I don't have a problem with using the mouse moreso than on a desktop, since it's so close. And naturally, I totally forgot about keyboard accessibility when designing the filter.
So Zatko says "I would recommend using a form post instead of that link. i kept typing stuff and pushing enter and nothing was happening."
Touche. As this implies, great programmers think alike and hate using the mouse when they've already got two hands on the keyboard.
So, I've scripted up some script-y JavaScript. It now checks if you press enter on the form. Due to incredible programming ( ... in onkeypress, return false in a child control ... ), it will process the subfilter, where you search for News Categories on this site, and not process the filter, when pressing enter on a subfilter's text box. But, when you check an item in the result and press enter, it'll process the filter. It's quick and responsive like that.
However, I'm not sure it's 100% valid. I've noticed in the html reference for the FORM element, that s@#% doesn't have an "onkeypress" attribute. So, instead I used the good old fashioned "document.forms['formId'].onkeypress = funcKeypress;" method of doing it, instead of "<form onkeypress='(some javascript code)'>". Function pointers are always an excellent way of doing things. I searched for the second one, and the only sites I could find are *SHOCK* Microsoft web development sites like ASP and ASP.NET forums. I'm just not sure if Mozilla is allowing it in Quirks Mode or if it's an actual event on the form object. Who knows. It works, but that just doesn't seem good enough for me. Oh, and I have no idea if it works in any Microsoft related technology, since I've only tested it on my Linux and Mac computers... The gaming computer is the only Windows one up, and I'm not sure it's fit to be browsing in IE, and I don't install any software on it besides games :)
So, it's a lot simpler to use, thanks to me being down to 3/4ths of the number of computers I'm used to having, and the one being the one I spend most of my time browsing the internet on, and of course, to Zatko. |
|
|
|
|
|
|
|
|
I'm heading out to watch the Phillies today, so real quick I decided to put up a filter on the news. It's like being a proud father, you just want everyone to see your kid hit home runs. I just want to be able to have everyone search for news. You can always find quality stuff when you enter "drinking" (or "beer") into the "Text" search. I know it doesn't make sense to have a filter AND have the categories listed on the left, but I literally have to go get ready for this game and buy some beer to bring along, which of course means I have to hit up WaWa, get money, and buy smokes and something to keep me occupied while the Phillies are getting slaughtered by whoever they play today. They're the only sport right now in Philly, so when they suck, your whole summer sucks.
I'll be putting one up for pictures and downloads soon. Pictures especially needs some help. Plus, there's a major bug on the page that I notice every time I go there, like 3 times a week, and I haven't devoted any time to fixing it yet. Plus, I'll be adding more cool filter types so you can say "List news that has comments". Or like, "List news with comments between 5/1/2006 and 6/17/2006... 0 results returned!!" Oh well. |
|
|
|
|
|
|
|
|
Man, this thing's cool. Dynamically rendering, populating, and filtering.. filter.
(Forgive the colors... the Linux Gnome screenshot utility kinda cut out some colors, but it looks good on it)
In this screenshot, I search for all "Works" where the title contains "My" (or "my" or "MY" or "mY"...) within the last 9 days, and that costs at least 0 "gold". This is kinda giving away some secrets of my game, but there's more fun parts to it.
In this one, the filter doesn't change, but I am actually searching for "Labels" that I would want to filter by. Labels are like "Tags", where a user can enter any number of comma separated labels, and they get parsed and put into a table if they don't already exist. Basically, that table contains a LabelId and a LabelText field. When I search for Works with a Label, I am actually searching neither the Work table nor the Label table (rhyme!!). I'm searching a link table called "WorkLabel" which has WorkId and LabelId. It's neat, but necessary.
Here, I actually search for Works labeled "jtccom". None came up, because I created that work 10 days ago, so I had to change the Date filter to be within the last 10 days.
And that's all created with a simple JSP tag, as shown here:
Filter name comes from the following config file, which is where all most of the magic happens is defined.
So, there you have it. Automatic filters, based on "Dumb". My life doesn't get much easier.
It's not done yet of course. But I made it so I could easily add more "modes" for controls. For example, the Date filter right now only has one mode, "within". That searches for a date after the value computed from the filter. I could add a "withinof" mode, which will basically have a second input area for a Date, and you could specify "within 3 days of March 23, 2007". So, filters can be extended. Also, I have two other objects that work behind the scenes pretty heftily. There's a FilterProcessor object, which takes a FilterInput object and, using SQLDOM (another home made thingy), crafts a where clause. That where clause is appended to any other where clauses already in the select statement. A "Work" will only be listed if it is Active, however, that's not in the "autoFilters" section of the filter-config.xml file (although it could be). It's specified in my application.
Just take my word on it, it's sweet. :) |
|
|
|
|
|
|
|
|
I do this every time. I get so close to finishing something, then I decide that I must add something that I find to be a common thing, so that I never have to do it again, for any project in the future. And of course, it must be flexible, customizable, etc, and above all, it must work.
The latest thing is a filter, or an automated filter system. For instance, I have news on this site. News has a date, the title, the text, and some categories. So basically, I want to create a filter system that will have some control for each of these fields, a user can type "I am hot" in the description field, and it'll find all the news with that in the description. It's a search, basically, but a search only has a text field, therefore it's more of a filter. One thing is they'll be able to say "Find all the news in this category with this in the description"... or "Find the news within 5 days of this day and in this category".
So, I have to finish that now before I'll be able to work further on the game. |
|
|
|
|
|
|
|
|
I have a shirt from ThinkGeek that has a regular expression on it. I wear it to work sometimes.
I'm making my web game, and one of the requirements that I came up with is to allow formatting HTML but not all HTML. This is a pretty reasonable request.
It's easy to get rid of all HTML tags using a simple regular expression in Java. It's
<[/]?.*?>
Just do this:
String regex = "<[/]?.*?>";
myHtmlFilledString.replaceAll(regex,"");
This is elaborate. I actually wrote an app so I could upload screenshots. The Java source code is here.
What I needed to do, for now, is replace all HTML except those basic HTML tags that do formatting... essentially to bold, italicize and underline. You can think of it methodically, easily. "Go through, if it's an HTML tag but it's not bold, italic, or underline, erase it." But I'm lazy. Here's the shot of my test application replacing all HTML in an input string. The input string is on top, the result is in the middle, and the regular expression used is on the bottom. The button simply performs that replacement.
Here is the regex I found to replace "not allowed" HTML tags... those that aren't bold, underline and italics (for now).
<[/]?[^/uUbBiI].*?>
I basically went through hell to get that though. It's fun but man it's a mind bender to think in terms of regular expressions. Here's the screenshot of that regex.
That is all. |
|
|
|
|
|
|
|
|
So far I am 0% done my web game. This is as of Friday night at 10:20 (or as my Linux box shows the time, 22:20). So far, I have two documents written on it though. One is a functional specification. The other is a technical specification. Working in the software world, you learn to depend on these two documents. Here is what they are:
Functional Spec: (Sometimes refered to as the f@#%ing spec... by me only apparently. Commonly refered to as the Design Document) This document gives an overview of the various use cases of the software. During the functional spec, you lay out that this is indeed a software solution to an otherwise real world problem. Say you are designing an email program. You will say that the user will be able to send and receive emails, using at least one server. They will be able to view the entire contents of emails, and have a hierarchy of folders to hold archived emails. They will be able to flag emails by importance. The solution should filter spam automatically, determined by a number of factors, some of them user specified.
Now, a technical spec, on the other hand, takes the functional spec and builds out, in detail (as much detail as you can before you start writing actual code in an [in this case] OpenDocument text document), each high level feature of the functional spec, and defines exactly how each feature will interact with other features. This makes it simple to write software. If you hand me a functional spec and a tech spec, and say "Get to work, you lazy bearded b@#%^@", I will reply with "Yes, Sir, may I have another?!?" As you can see, these are highly desireable in the field of software design and development.
Note also, that when "speccing" (actual word in IT) out a set of "Design Documents" (you can also refer to the whole set as "Design Documents", as well as just the functional spec... Software is flexible like that, and everyone knows what you mean by the singular form, and that you mean the group in the plural form)... where the f*@#! was I? Too many parentheses. Oh right. When speccing out design documents for your own, home brewed project, it is a much more enjoyable scenario. Like, I can be going through and say "You know what... f@%! that feature, no one will use it and they'll all probably send hate mail to me if I include it", whereas in work, you have to do it because it was predetermined that we don't care about customers enough to make them happy, therefore the feature must stay. Also what makes home project docs more enjoyable is that it's your s@#%. You get full credit, people worship you, girls send you pictures of themselves in bikinis, guys question their sexuality, etc. It's just cool.
Anyway, I have to get back to work. It's speccing out to be much more complex and detailed than what I first imagined, however, I'm speccin' I won't go past my two week estimate. (O Brother, Where Art Thou shout-out : "I'm speccin' you'll be wantin' them chains knocked off". Great movie). |
|
|
|
|
|
|
|
|
My web game. I'm becoming increasingly sick of the internet and it's "nothing fun to do for a 5 minute window of time to waste". I was looking for something to easily scan images in that I create on paper, but the only thing I can find got bad reviews. It was a "pen scanner", literally 8.5 inches wide and about 1/2 inch thick, and you roll it on paper to scan it, but people were saying how the quality was diminished. I do have a flatbed scanner, but it's a POS. Basically, I wanted to make the site look professional, since I can't draw with a mouse. I used to draw as a kid, and was pretty good at copying images from, say, a Teenage Mutant Ninja Turtles trading card, and scaling it up to fit onto a standard art pad (10x14 i think). I would color it in and show it off. One time I drew a picture of Homer Simpson and said to my oldest brother, "Want to see a picture I drew of Homer?" He said sure, so I showed him, and he was like "Man, I was expecting something pretty bad but that looks just like him!" I also did pictures from Marvel comics like Wolverine and the Fantastic Four. They were fun. Point is, I used to be able to draw, and remember enjoying it a bit, and think I can still do it with the right equipment. Like this picture I drew in work at my last job:
Pretty f@#%@ing sweet, huh?!? Anyway, I'm going to just program the site this weekend during times of soberness (Three day weekend!!!), see how far I get, then do some art for it later. It'll be fun, and like the original post says, there's nothing like it out there. |
|
|
|
|
|
|
|
|
I just found this site, The Daily WTF. Your average computer user won't find much use in it, but programmers love it! They post pieces of code like this:
if (errMsg.indexOf("Violation of UNIQUE KEY constraint 'UQ__mbrs_pwd'") != -1)
return "The password entered is already in use. Please enter another.";
And there's always some terrible thing wrong with it. The post with that code is called "Uniquely Secure".
I notice users on there that have trouble grasping what's wrong with the code sometimes, and it's good that they visit this site every day or whatever, since it's not only funny, it's a brain teaser every day.
Here's another quick sample:
function executeQuery($string)
{
GetDatabaseConnection();
$result = mysql_query($sqlText) or die(
"Query failed " . writeErrorToLog(
$_SESSION['USERNAME'],
"Query Failed: " .$sqlText . " " . mysql_error()
,$scriptName
));
return $result;
}
function writeErrorToLog($owner,$description,$script)
{
$script = str_replace($_SERVER['DOCUMENT_ROOT'], "", $script);
$sqlText =
"INSERT INTO errorLog (ownerID,time,description,script) " .
"VALUES ('" . $owner . ",Now(),'" . $description . "','" . $script . "')";
executeQuery($sqlText, $_SERVER['PHP_SELF']);
return "";
}
At first glance (I think it's PHP) it doesn't seem like much is wrong, other then they do the cardinal sin of writing to the database to report an error when there's a database error! But anyway, you will notice that if a piece of code fails to write to the database, it will always infinite loop! The reason for this is that, for one, there could be a database connection problem, and it would never succeed, but more interestingly, there seems to be a missing apostrophe (') in one of the values in the sql statement when writing an error! So no matter what, if it fails once, it's doomed for infinite loopage.
And the site has one of these per day, and I love reading stuff like this. I recently bought a book called Java Puzzlers: Traps, Pitfalls and Corner Cases. They're fun brain teasers, and most of the time, in the Java one, you can't tell what's wrong (having 10 years programming under my belt, that's odd!) and then you go read the solution and it's like some bit can't be set when calling a certain function. Java's a pesky language :) I still love it though. |
|
|
|
|
|
|
|
|
I'm extremely disappointed to inform everyone that stringed.org has been treated to a significant upgrade... a security system. Well, I simply use the same security system as I had for this site, made no modifications to the inner code (since it's perfect), and now I have a per item per operation security system in place for stringed.org.
That "per item per operation" bit might be confusing. Basically, say I want to allow someone to edit News but not be able to delete it. Or to have full permission for News, Photo Albums and Polls but not for Downloads. I can do all that and I didn't have to change the old security system that I built. Why? Well, I would start out by saying I've seen quite a few hand built security systems in my 4-5 years in the professional business of software development to know what works and what doesn't. Or to pick the pieces that work from other security systems that might not be that great overall. As Picasso says, "Good artists copy, Great artists steal."
So what else is new with it, you ask with desperate anxiety... Hmm. I have listeners in there for when objects are saved and deleted. This is more for editing the security system, since it's kept, for quick lookup, in the application map. If I don't reload the registry after making a change, that change never takes place, as far as the security system is concerned. Also, it will be an important piece behind "Attachments". Although, I might just write a new engine for that.
Also, since you're dying to know, there was a bug on the form when I had two dual-select lists. Fortunately, this bug never made it off of my computer, as my wicked javascripting skills extinguished it when I found it. I have two dual-select lists on a "SecurityGroup" object, since Groups have a list of Privileges and also a list of Users. I've said too much :p
I had debated trying to create a new security system. This would be so I wouldn't have to create a new menu system, as the menu system relies heavily on the current security system. So, since I didn't want to write a new menu system, and a new security system, I was forced to think brilliantly into the current solution that doesn't change anything and does not restrict anything either. The menu will work, the forms will work, and the rest of the site will work just as it's supposed to, as you can see by going to this page. You will see "You are unauthorized to see this page." or something.
One other helpful change is for the lists that list an object that might have the same name as another object in the list, but have a foreign key "parent" that will be different. On the old version of the site, if you go to add a library, it lists books with just their title. But, you can't tell who wrote those books without first going to the book list and seeing. Now, they are listed with their "parent", in a book's case, Author. So, my book shows up as "Jason Connell - Orientation of Objects". You can see this illustrated here, along with the two dual select lists on Group. Basically imagine the list being "view add delete edit view add delete edit view add delete edit". That's why I added that :) But also, you can see it in my User list... A User for stringed.org has a foreign key to Author, making Author it's "parent", so now, the User will display "Author Name - Username".
It's pretty sweet. I am trying to think of other stuff that I did for it. I didn't have that much time this weekend with my neice Megan's Christening, hanging out with Kira, Caden, Ethan and Danny, and my brothers, watching lots of college basketball, etc. This week should be a big time of productivity, since I can finally start on Attachments!! They'll be neat. |
|
|
|
|
|
|
|
|
I took out the "Book" form for now, otherwise it would be a gigantic cluster@#%@@#, and I limit the file size to 1000 bytes (less than 1KB). Other pictures here and here.
And with that, stringed.org's underlying software is ready for some major overhauls!! There's this whole huge thing I want to do to it yet. |
|
|
|
|
|
|
|
|
Check out stringed.org NOW!! Updates include:
Customizeable actions - specify what a user can do with an object (add, edit, delete, view). You can see this in the book list, it shows a "view" link. If I don't specify "edit" for an object, the whole site has been updated to account for this, so you won't be able to trick the site into being able to edit something that isn't editable (or edible :-p )... or deleteable for that matter.
Lists are perfect - As well as the below mentioned "many to many problem" (which you can see at work on the "Library" form), all lists that are sequenceable can be sorted (See Chapters on a book and Books in a library). You can add a list to an object that hasn't been saved yet. (This was more of an "uncomfortable with the greatness of 'dumb'" situation, as I just had a line of code that said "if the object hasn't yet been stored into the database, don't process lists". You would have seen those repercussions yesterday if you logged on, but not anymore). Obviously, also, the subforms work perfectly.
Bitmasked int field - This can be seen at work on the "Library" form also. Right now it takes parameters for the values, but I will write plugins for it that it gets it from the database and shows them as checkboxes like they are now. There's also a corresponding output component for bitmasked integers.
Still a lot to do... I have to have it so you can specify something's a file field, and make a cool control for that, and there's probably other types of fields that I haven't accounted for yet.
Also, I registered the domain name that Salzburg will be found at later, but I can't tell you it. Secrets rock even more than progress. |
|
|
|
|
|
|
|
|
Some things you are so used to thinking about one way, that to think about it another way IS considered to be "thinking outside the box". Even if you were thinking about it wrongly before, and now are thinking about it correctly.
This happened to me sorta. It was more of a case of not making the obvious conclusion about something. All the facts were presented, sugar coated, with arrows pointing to a conclusion, but I only came to it through trial and error last night.
Databases are merely containers for data, and we have to use the tools that they provide (foreign keys, primary keys, indexes, unique constraints, SQL statements, etc) to really find out the meaning of the universe. Well, I didn't get to that point yet, but it was something close. The dreaded "many to many relationship" problem. I'll explain.
The simplest way to put it is that a many to many relationship is when one single object (we'll call it Object A) has many of some other object (Object B), but one of Object B can "be in" many of Object A. The best real world example I can give, using my "Library" model on stringed.org, is Book (Object A) and Word (Object B). A book will have many words in it, and a single word can "be in" many books (and in the case of Words, it can be in a book many times).
The simplest way to portray this in a database is having a Book table and a Word table, and then you have a "link" table (probably called BookWord) that has foreign keys to both a Book and a Word.
The way "dumb" was originally created, I had no functionality to handle "many to many" relationships. I had thrown in some XML to be able to handle it in the future, but never did anything with it. (Originally, I'd get lists of the "link table" object, with the references loaded, and then populate the list that was part of "Object A" with the list populated full of "Object B" objects, all manually, everytime I needed it. My News object has many categories, and a category has many News, so I'd get a list of the link table "NewsCategoryNews", and then grab the "Category" part of that object, and my News object actually had a list of "NewsCategoryNews" objects, instead of simply a list of "Categories", which it should).
Then last night, as I was creating a control and adding functionality to potentially handle "many to many" relationships, it dawned on me. With previously created tools in "dumb" (namely a MappedListProperty which says a certain object has a list of objects, as an Author can have many books [a one to many relationship unless you include functionality to have many authors write a book, which the model doesn't include]), the conclusion was obvious. A book has a list of Words!! I know, it doesn't seem brilliant, but now it all works. See, even if they are many to many, a book still just has a list of words, and a word has a list of books that it is in. All I had to do was simply add functionality to handle this, which basically meant to add some attributes to a MappedListProperty XML node, and override some functionality used when saving and loading a ListProperty. It was easy.
Now, a News object can have a list of "Categories", instead of a list of "NewsCategoryNews" (the link object). "NewsCategoryNews", the table and the object, still have to exist, however, because "dumb" still uses it to populate the "Categories" list for a News object.
I don't have that latest uploaded yet, but I will tonight. It works beautifully. Right now I have the model set as "Books can have many Genres" (a genre is like "Suspense", "Horror", etc), and "A Genre can have many books". All I do is specify, in books, and actually in the "Genres" list property, is that a book can have many Genres, but also a Genre can "be in" many books. I specify the "link table" to use for the many to many relationship, and it's smooth sailing after that.
So to review: Many to many relationships cannot be handled with just 2 tables. You need 3. The two tables to be linked, and the link table. So to represent it in software, you just need to specify that there's a link table, and handle it accordingly. Side effect: Never write unnecessary code again :) |
|
|
|
|
|
|
|
|
stringed.org has been updated again. What's up there is the result of my latest efforts, where I started it over, wrote some new controls for it, fell asleep and drueled all over it, etc. The "Remove" functionality doesn't work, I've yet to find the best way to do it. There are some kludges in the software, but none that were avoidable. So that sucks. I can offer a huge explanation about that but I have other things to attend to.
As you can tell from the site, there are a few very confusing things going on. First off, this might be the most confusing form ever. But that's ok. It'll really be used mostly for this sort of thing. And it won't be too confusing with only one child form (just a book form for author) as opposed to any number (books have chapters, so that's a form, and there could be an infinite amount of inputs on the screen... this won't ever happen for me).
It's not done though. I still have a few things planned for it, but it's really close. I can't see the rest of the site taking much more than a few weeks. I have to get to work on my "Salzburg" game so I'm the first to market. Not that I'm making money on it, but it just shows originality to employers if you're the first to market an original and creative idea. Then I can get jobs anywhere :)
Word. |
|
|
|
|
|
|
|
|
Woohoo.
In other news, I have the latest version of stringed.org up there. Actually, the official name of the software is "dumb web" since it's written on top of "dumb". At home I'm testing with the following data architecture: Authors have books, books have chapters. So when you add or edit an author, you'll be able to add books for that author and add chapters for each book, while on the author form. It is 100% dynamic. It's working except for some quirky validation issues, however, what's on the site works 100% (with just books and authors). As soon as I get subforms inside subforms inside subforms working, I'll post that version up :) Please note that I recreate the database each time, so your additions / changes will only remain intact until the next update.
I still have a lot of work to do, but I should be pretty close by the end of this weekend.
I played "The Movies" but only for a few hours, and didn't get a chance to take any screens. There's no easy way to do it. But here are screens at GameSpot. It's a fun game, but more like "The Sims" with it's "Keep your stars happy" theme. But, there are a lot of neat things going on... writing your own scripts to movies, directing movies, post production of movies, buying sets, researching technology, etc. I recommend it if you find that kind of stuff interesting.
Kodie was out in the snow the other day, and what happens when a furry little dog runs around in 16-22 inches of snow for an hour?! I'll post that picture tonight :) It's HILARIOUS. And Cute.
That's what happens to furry little dogs in the snow :)
Today I was tired, so I went to Dunkin Donuts and got a medium for the ride into work, and an extra large for at work!! To make it look like I was ordering for 2 people, I got a few donuts. I should just shamelessly admit that I can drink like a gallon of coffee without it having any effect on me, that way I don't have to get donuts to go along with them. I could do without them :) |
|
|
|
|
|
|
|
|
It's very, very young. Basically, last night, I went from being able to only add a new "Author" to being able to edit and delete them, as well as detect that a book has an "Author", and when editing a book, to show a list of authors to choose who wrote that book. Feel free to try it out. There will be bugs for a long, long time, and I've noticed quite a few on those two simple objects, so just bare with me.
There are quite a few object types that I need to support in order to be able to convert this website over to the new system. First thing's first, though. Naming the software! Considering the fact that it's using the same exact version of "dumb" as this website, and the whole front end is built using information collected from "dumb", it's only right that it be called "dumb web" (read about it here).
So far, the development is progressing nicely. I hit a few speed bumps last night, but just glided over them and now it's just a matter of supporting more object types. Right now, you can see that "Foreign Keys" are supported (if you know your database talk), as well as strings (like Author name and Book title), and another type of string that I'll just call a "long string" (or "text" to the db folk), which is tested with a biography on the Author object. Other object types to support would be dates, files, many to many lists (like news can be in many categories), one to many lists (a poll's answers are entered in a list), and a potentially long list of others. It should be fun, and will probably never be done.
Check out the site here. I prefer that everyone access it without the "www." in front, because it just looks cooler, but the non-cool way is still supported... for now :-P |
|
|
|
|
|
|
|
|
This is basically a personal post to Todd, but anyone is allowed to join in. Feel privileged. Or you can use this time to listen to my latest song, "Should Be Sleeping", at the bottom of this page.
I did some research on amicable numbers, and tried and succeeded to write a program that calculates an amicable number given a number. Then I tried to write it so it loops for a while, listing any amicables it finds. The problem is it's slower than death. The key, obviously, is finding the right function to calculate a sum of divisors of a number. It's brutal. This is what I have so far.
private int sumOfDivisors(int n){
int sum = 1;
int max = (n/2)-1;
for (int i = 2; i < max; i++){
int x = (n/i);
if (n % i == 0 && i < x){
sum += i + x;
max = x-1;
}
}
return sum;
}
I adjust "max" based on the last divisor, so, knowing that (for instance) 3 divides into the number 81 times, it should now only loop up to 80. Then, later on if it finds that 9 divides into it 27 times, then it will only loop up to 26. This is just knowing that basically, since we're counting up, there will be no number above 27 that divides into the number that hasn't already been accounted for. Try it out. Then, to take care of that number, I add it to the sum and just adjust the max loop amount, significantly dropping the iterations needed to get the sum of the divisors, improving overall performance by a factor of around .00000001 :) Here are some results.
(NOTE: It takes 50 seconds because I'm looping from 10,000 to 11,000, checking each number for an amicable twin. To find out if a single number has an amicable twin isn't *that* bad :p )
10744 has an amicable number of 10856
from 10000 to 11000 took 50178 milliseconds.
Then from running it without adjusting the max loop
10744 has an amicable number of 10856
from 10000 to 11000 took 50228 milliseconds.
So, that's the key. If there's a formula out there for getting the sum of the divisors, it would greatly help, but I searched for a while and couldn't find it.
The general function body looks like this
int amicable = 0;
int sum = sumOfDivisors(n);
amicable = sumOfDivisors(sum);
if (n == amicable) {
// We have an amicable number stored in "sum" (not "amicable", since it will be the same as "n" if they are amicable)
}
50 seconds sucks. There should be something better out there. I even tried to save the trouble of searching numbers later on in the sequence that have already been determined to have or not have an "amicable twin". Anywho. It was fun.
[Update] I just remembered that division on a computer is like painting. It doesn't like to do it at all, but is asked to do it because the person who usually has to do it doesn't feel like it either, but the person asked is pretty good at it. Anyway, I changed the function so that it's faster. It doesn't divide as much. I just ran it on my laptop (1.5 GHz, 1GB ram, Linux), and it did the loop (10,000 - 11,000) in 125 milliseconds. I'd say that's a bit improved... unless it's just Linux :)
Found amicable (28,28)
28 is also a perfect number
Found amicable (220,284)
Found amicable (284,220)
Found amicable (496,496)
496 is also a perfect number
Found amicable (1184,1210)
Found amicable (1210,1184)
Found amicable (2620,2924)
Found amicable (2924,2620)
Found amicable (5020,5564)
Found amicable (5564,5020)
Found amicable (6232,6368)
Found amicable (6368,6232)
Found amicable (8128,8128)
8128 is also a perfect number
Found amicable (10744,10856)
Found amicable (10856,10744)
Found amicable (12285,14595)
Found amicable (14595,12285)
Found amicable (17296,18416)
Found amicable (18416,17296)
time took was 3266 milliseconds
(NOTE again... Description of Perfect Numbers)
That can't be Linux. 3.2 seconds?!? That's a loop from 2 to 25,000!! The other function took 50+ seconds to go from 10,000 - 11,000. The machine at work is a 1.7 GHz (faster than this laptop) with a GB RAM running Windows XP SP2 and the same version of Java. 4 divisions cut to 2 doesn't normally shave off 50 seconds... now I'm curious.
[Update] Forget it. I forgot I was throwing in a sleep everytime it looped... idiot. Anyway, Windows is still slower on a faster machine. 171 ms for 10k - 11k, vs 125 on Linux. |
|
|
|
|
|
|
|
|
Because I'd be famous to programmers everywhere! SSN of course is Social Security Number. Whenever we programmers write a program that takes an SSN for input, the most highly used test data for the field would have to be "123-45-6789". Just because the counting style of the number lets you know when to stop. "Stop at 9", I always say to myself. Whereas if you were to put in "111-11-11111", you might enter too many numbers (as I just did, which, of course, is a good test of your software).
Similarly if you live at "123 Main Street, Anytown USA". Your address, probably only second to Santa Clause's, is one of the most written in the world :) Of course, this is all speculation.
But out of those two examples, there has to be someone with the SSN of "123-45-6789". There'd have to be! Well, no there wouldn't. That sequence of numbers allows for 1 Billion permutations (10^9), and there's *only* ~280 Million in the SSN using world. I hope in my next life I get that SSN. |
|
|
|
|
|
|
|
|
Yesterday, I wrote a function for Todd to show him some Java since he's learning it. It was a Fibonacci sequence calculator. Basically, you pass in the index of the sequence that you want, and it'll calculate it for you. So, today, I'm killing some time, and I wanted to figure out how much time it took to figure out some high up numbers of the sequence. Well, the function that I wrote originally pretty much sucks, but it works and it conveys some pretty fun stuff in computer science. First, an explanation.
The Nth number in the Fibonacci sequence is defined as the (N-1)th number plus the (N-2)th number. Or, the Sum of the previous two fibonacci numbers in the sequence. The sequence starts as 1,1,2,3,5,8,13,21,34, ... ending with F(N-1)+F(N-2), or F(Infinity-1)+F(Infinity-2). So it doesn't end. Anyway, there's some good documentation on it out there. Here's the first function I wrote:
public long fibo(int n){
if (n <= 0) return 0;
if (n <= 2) return 1;
long ret = fibo(n-1) + fibo(n-2);
return ret;
}
Here's the new, much faster function :
public BigInteger fibo2(int n){
if (n < 3) return BigInteger.ONE;
BigInteger fn = BigInteger.ONE;
BigInteger last = BigInteger.ONE;
BigInteger last2 = BigInteger.ONE;
for (int i = 0; i < n-2; i++){ // n-2 because first 2 are 1
last = fn.add(BigInteger.ZERO);
fn = fn.add(last2);
last2 = last.add(BigInteger.ZERO);
}
return fn;
}
I had to use BigInteger (in the java.math package) because after about 100, "long" couldn't fit the result anymore! That's a big F@#%$!$#!ing number that a long could hold!! But not big enough.
For mathematical clarity, there is a formula out there, called Binet's formula, that calculates the Nth fibonacci number.
F(n) = (a^n - b^n)/(a - b)
I'm having problems with types, I can't get it working.
But for the fun of it, here's some output:
For #40:
102334155
Fibo2 for fibonacci #40 took 0 milliseconds.
102334155
Fibo for fibonacci #40 took 4811 milliseconds.
For #42:
267914296
Fibo2 for fibonacci #42 took 10 milliseconds.
267914296
Fibo for fibonacci #42 took 12955 milliseconds.
As you can imagine, the second one in the results (the function simply named "fibo") will be an unbearable burden to the rest of my experiment. So, I'm getting rid of it and will show you some major f@#%R@#ing numbers produced by "Fibo2". Check it out.
176023680645013966468226945392411250770384383304492191886725992896575345044216019675
Fibo2 for fibonacci #400 took 10 milliseconds.
WHAT IN THE WORLD IS THAT NUMBER?!?!?!?!!! Holy crap!! And 10 milliseconds. Let's see 500!! I wonder when BigInteger overflows... maybe never.
13942322456169788013972438287040728395007025658769 7307264108962948325571622863290691557658876222521294125
Fibo2 for fibonacci #500 took 10 milliseconds.
(I had to put a space in or else my website would be all f'ed up... but that's one number continuous)
That's incredible. "For my next job, I'll take a salary of $Fibo(150)." That's huge :) Anyway, I had fun. I want to see how far it will go before blowing the hell out of my computer, but that will be an experiment reserved for tomorrow at work :) It's not my computer then. |
|
|
|
|
|
|
|
|
I don't ever wish to win the lottery or be rich or anything like that, but if I did (if you don't play, you can't win...), I thought about what I'd do with it. Obviously, the smart thing to do would be to invest it somehow. Somewhere. I'm not too smart financially, so I wouldn't go with stocks or bonds or other financial things that I have absolutely no idea about. The obvious thing for me would be to go back to school. I am always buying books and learning stuff, so it's obviously obvious :)
Where I would go to school would be two places. Some kind of video game school (like Full Sail), and an elite institution for technology, namely, MIT. I think I'd go to MIT first, though. I'm all about getting a PHd from MIT. Besides the fact that it rhymes, that pretty much says "I know what the f@#%@# I'm talking about." I would make complete use of my time there. I'd be lost for the first year (it's been a while since I've done ANY math), but if I had money, I could just hire tutors for $100 an hour, and they could teach me math. It would be easy. I have a math mind, but it's not like riding a bike.
MIT first, also, because I'm more interested in Computer Science than I am in any one field of it. Creating video games uses multiple fields in CS, but it's not the whole of Computer Science. It's math, 3D graphics, artificial intelligence, and algorithms for other things like physics. You see physics in games today, but it would be neat to see other sciences, like Chemistry :) But that's going down another road.
Anyway, if you have an extra bazillion dollars lying around, I wouldn't mind having it :) I must be a geek, because I can't even think of anything else that I'd use it for. |
|
|
|
|
|
|
|
|
When it comes to Integrated Development Environments (IDEs), I am a knowledgeable critic. Having used quite a few (Borland C++ 5x, Visual Studio 6, Eclipse, NetBeans, Visual Studio .NET, 2003, 2005, etc), I know what features I like and expect. My day job consists of me primarily using a Visual Studio of some sort, and lately it's 2005 (Whidbey). So, the statement that I am about to make is absolutely true. It sucks.
When I first heard about it, I heard that it would have features like "Refactoring", a cool debugger, "smart" IntelliSense (I know, it's called IntelliSense, yet it's incredibly unreliable), and... you know, I really don't know all the features. Having used 2003 for so long, and now using 2005, it doesn't seem to be that different. However, hearing some cool tech terms like "refactoring", I became excited that, finally, work might go faster, I could get more done in shorter amounts of time, finish projects early by factors of weeks, get 15% annual pay increases, and retire by the time I'm 30. However, none of this will be happening. It sucks.
In my free time, I primarily use Eclipse. I must say, a bazillion times, that it's the best IDE out there.
Let me define refactoring. Refactoring is taking existing code and doing stuff with it, whether it be renaming a class, variable or a function (and automatically updating all references to it), generating properties for member variables, and stuff that generally has to do with renaming, but it can also be quite advanced. Say you have a class with a few public functions in it. Refactoring could mean taking that class and extracting an interface out of it. Refactoring could also entail creating a variable out of a "String" constant in your class, and externalizing it to a file, so that you could then change it without having to recompile each time. You can have a bunch of lines of code that you could foresee yourself using over and over, so you would want to extract those lines and put them into a function, and the function signature would include any variables (and their types) that the code is using to be passed in as parameters. This is also refactoring.
VS 2005 simply fails in what I need it to do most. At the top of that list is generating properties from private member variables. Most, particularly good, object oriented programmers who like to save time in the long run will follow "patterns". Google "Gang of Four" for examples of what I mean. Three patterns that save a lot of time are the following:
Business Object Pattern.
Data Object Pattern.
Data Access Object Pattern.
Business Objects perform business logic on a data object (which holds data) and these are stored and retrieved to/from a database through the data access object. Simple. The one of these patterns that will have a lot of properties is the Data Object. These hold the data, and as such, you should be able to find out what the data is that it's holding, and you should be able to set those fields to different values.
If you have access to these two IDEs, try the following experiment. Copy these two classes into your IDE as new classes, do a refactor, and get it to generate all of the properties (in Java, getters and setters) for the variables in the class, and see which one is quicker.
Java code:
import java.util.Date;
public class DataObject {
private Integer id;
private String name;
private String description;
private Date modified;
private DataObject parent;
private DataObject[] children;
}
C# code:
public class DataObject {
private Int32 id;
private String name;
private String description;
private DateTime modified;
private DataObject parent;
private DataObject[] children;
}
You'll find that Eclipse's goes faster, simply because you can right click, then click "Source -> Generate Getters and Setters", click the "Select All" (or Select "getters" or "setters" [giving the option of making every property read only or write only]) button, and click "OK". Done.
You'll find that VS 2005 is F@$^%ING RETARDED!!! You have to highlight a certain field, one field at a time, click "Encapsulate Field", then you get no option to only generate the get or set parts of the property, and it comes with the option to "Update References" of either just the external references or all of them. You know where I'm going with this. If it's a PRIVATE FIELD, THERE ARE NO EXTERNAL REFERENCES!! Not one. You can just see the lack of care put into this aspect of the product. Why even include it? I just type them now, because the project I'm working on has 37 (THIRTY SEVEN!!) projects that it would have to search to encapsulate ONE lousy field to update references to A PRIVATE VARIABLE. And it takes forever on my machine, AND you can't F@#%%&@ turn OFF the "Update References" option?!!?!!
It's really retarded.
Some other gripes. Intellisense isn't any smarter. At first, I thought it was, but it's not. Say I have a class like this:
public class Mulder { // x-files rules
public Mulder(){
this. /* <---- at this point, it drops down a list of accessible variables, which would include "memberVariable", but it doesn't! This is because it's defined *BELOW* the point at which you are typing (the constructor in this case), and VS 2005 has no idea that it's even there!! Try it yourself. */
}
private String memberVariable;
}
I have other smaller gripes on Intellisense, like it not selecting a String or a function that returns String when you are assigning something to a String variable.
String scully = this. /* <-- doesn't go to the first string */
This is somewhat understandable though, as every object in .NET has a "ToString()" function on it, which is really just used for debugging. It doesn't perform any better with other object types though.
Anyway, I love Eclipse and open source, but knowing of these great features just spoils every "feature" that Microsoft comes out with. |
|
|
|
|
|
|
|
|
This is a quick one before I head out to the Great American Pub tonight with some friends. I was writing a way to make simple input screens based off of the information in Dumb, when I realized that when I got that information, I had access to the whole class, and didn't like it. Basically, something that's using the information doesn't necessarily need to manipulate it. So, I abstracted out those classes into interfaces with selected properties that are readonly. The problem was this: I had to update all the references to the class to be references to the interface. It took forever, but I eventually got it, and after touching practically every class in Dumb, it's now almost up to date. I still have to create an "information getter" interface so that I don't have to have direct access to every method in my engine class (I only need to be able to select, insert, update and delete, for now), whereas the engine class has methods in it to create tables and generally access a lot of different stuff that a simple inquiry class doesn't need access to. Also, the engine already implements an interface, but it's a 1 to 1 implementation (meaning, it is just an abstract API interface so you don't have to know which implementation of the engine you are using... I can have multiple engine implementations and just swap one in [like a CachingEngine that doesn't hit the database everytime if it already loaded an object]). So, I'll have to add another interface on top of the engine interface
e.g.
public interface DaoEngine extends InformationGetter
that has just methods to get that info out. Names not final.
After that whole thing's done (including making the automated data input screens), I can work on Attachments. That's gonna be awesome. |
|
|
|
|
|
|
|
|
This post can also be subtitled "The Philosophy of Computer Science, Part 1.1". It's a new idea I'm playing with. It's not a new idea, really, it's derivative of a very cool concept in Computer Science called Aspect Oriented Programming. It's a pretty abstract concept. Basically, the typical example used is logging transactions on an object (I know, that description is very abstract also). So, say I have a bank account and I want to log my transactions, I can just flip a switch, sorta, and now my bank account is emailing me whenever I deposit or withdrawal money. But, what if now I want to deposit half of the money in a savings account when it's deposited in my checking account WITHOUT modifying ANY banking code?! Impossible, you say? They key here is that I don't want to go into the "deposit" function on my bank account object and enter stuff to deposit half of it into my savings. If you designed the system using an AOP container, this would be simple. What if I wanted to log AND deposit half into savings on a deposit into my checking account? I would just write a class that "intercepts" a call to deposit money into my checking account and takes half and puts it into my savings account, then continues the call to deposit the money into my checking account with half of the original value. Of course, if I was dishonest, I'd just deposit half into savings and then the original amount into checking!! But, that's not honest :)
So, AOP is very flexible. What I'm developing is a twist, though. It's for objects on my website, and it's mostly to do with data, rather than "processes" (like, before I deposit my check, take half, put it in savings, then put the other half into checking). So, to be more in line with data, and to be sorta AOP, what would it have to do?
Pretend I have a News object (I do, you're reading it), and that news object, right now, has a title, a date, text, the user who wrote it, and the categories it belongs in. What if I wanted to add a file to correspond with the news that I could upload and it would automatically show itself with a little paperclip (signifying an "file" attachment), and the filename next to it, with a link to download it. I don't want to program the news so that every news item could potentially have a file attached to it. You'll see later that by attachment, I don't only mean "File" attachment, like you send with an email. What if I want to allow other objects to have that same type of attachment, i.e. a file uploaded and shown under that item? I'm not about to change my whole, very well designed, table and object structure. I'm way too lazy for that.
Another attachment possibility for News would be a "History" attachment, so that whenever I update a news post, it puts an entry into a history table, and I can view that news' history. Another one would be a "View Count" attachment, so that whenever that news item is viewed, I increment a field for that news item, and that value shows under the news in a label that reads "Read 4 times". What if I wanted to put security on a certain news item? I could make a "Security" attachment that ties into my current security system and checks to see if the person viewing the website should be allowed to see that news.
The main thing here is that I don't know all of the possibilities for the future. That's where Object Oriented programming and Aspect Oriented Programming form a perfect marriage. I can program a new attachment and add it into the system, then any object can use that attachment. One downside of this design right now is that for every news item I enter, I will have to select, each time, what attachments I want. For some things, it just makes sense. Like, I could turn "Comments" into an attachment, but for most news items I will want to allow comments, so I would be adding that to every news item. The upside, in contrast, is that some objects were not designed to be commentable. I could make Content commentable this way (click "Your Site Rules!" for a Content example).
One thing I could do is have a global attachment for objects. News could have a global attachment of Comments, then a local attachment could be a file attachment for a certain news item.
One pretty big downside of this system is this... it's website rewrite time!! Yup, the whole website will have to be redesigned. The data, however, can pretty much stay how it is. That's good, because I decided on this design because I didn't want to change the data structure! I'd hate to lose anything I wrote, I love reading my own stuff ;-)
I can hardly stay awake right now though. Til tomorrow. |
|
|
|
|
|
|
|
|
This one goes back to my Configuration entry. Well, it turned out, 128 lines wasn't enough. See, when I write an XML document, I like to reuse tag names (see Element over at The W3), so, my old XML document of one line per object wouldn't cut it. The system would look up an object, but it will be a different type. For instance, I would use the "attribute" tag numerous times, but each time it means something else. One time it would mean the definition of an attribute, and another time it would mean "this attribute is the one that I want to use", or essentially, in as highly a technical way as I can describe it, something would reference an attribute that was previously created. Now, that one class that was 128 lines or whatever, is now 206. Still not a ton, and I wake up and thank God for letting me wake up one more day, and I also thank Him for recursion and reflection. Those are two of God's greatest gifts to any Computer Scientist. Each a gift in their own right, but get them together and that's how babies are born. It's SEXY.
Overall, here are the files and their line numbers in the Configuration Version 2 project:
Package voodoo.xmlconfig.domain :
ObjectMap.java : 7 lines
Package voodoo.xmlconfig.loader :
ConfigLoader.java : 104 lines
ConfigParser.java : 206 lines
Package voodoo.xmlconfig.nodes :
KeyNode.java : 12 lines
LookupNode.java : 45 lines
NodeMap.java : 47 lines
ObjNode.java : 125 lines
Package voodoo.xmlconfig :
Configuration.java : 39 lines
So there you have it. Sacrifices were made. Ideas were thrown around. XML parsing was ritually slaughtered. Never again. Woohoo.
There are some major features in this though, despite its brevity. When loading and looking up objects in a map at the same time, sometimes what you are looking up will not have been loaded into the map yet. I wrote my copy function to take care of this after the objects have been initialized and put into the map as basically blank objects. Copy then takes the actual values and loads them in. This is important because other objects already have a reference to the blank object, as opposed to the fully loaded object of the same type. This could cause problems in the future, but for my needs, it will serve the purpose. Another awesome feature is the ability to look up objects in a map in the first place! "I want to add a reference to this attribute to this object, but find it in this map under this key and this key." Sometimes, a map indexed with a key will reveal another map, so you can specify multiple keys. For my attribute, first, you look up the type, where many attributes can have the same type, then you look up the name in the resulting map of attributes with that type. This can be done infinitely.
Tune in next week. I just took my laptop out of its case for the first time in 2 weeks! I should be addicted to programming Java again in no time. |
|
|
|
|
|
|
|
|
Here's a function I just wrote that basically copies one object's data to another...
private void copy(Object src, Object dest) throws Exception {
if (src.getClass().equals(dest.getClass())){
Method []methods = src.getClass().getMethods();
for (int i = 0; i < methods.length; i++){
if (methods[i].getName().startsWith("get")){
String setname = methods[i].getName().replaceFirst("get","set");
Method setmethod = dest.getClass().getMethod(setname, new Class[]{methods[i].getReturnType()});
Object value = methods[i].invoke(src,new Object[]{});
Method clone = value.getClass().getDeclaredMethod("clone",new Class[]{});
if (clone != null && clone.isAccessible()){
value = clone.invoke(value,new Object[]{});
}
setmethod.invoke(dest,new Object[]{value});
}
}
}
}
It's in Java, and it imports the java.lang.reflect package. It's wicked. Obviously not the most complete function. It could be in a BeanUtils class as a public static function. I could also specify whether or not I want "clone" to be used, instead of just checking if it's implemented and using it. One last thing, if the destination class is a subclass of the source class, it should still work, because the destination is guaranteed to have the same functions as the source in that case. This, of course, assumes that the objects are "beans". |
|
|
|
|
|
|
|
|
Now that I have a job and haven't started yet (won't until November 7th), I feel I can comment on the current interview process in the information technology industry. This is the same with all interviews I have been on. Maybe it's just my age, and that I'm still considered a "junior" developer, considering there are people that work at the places I've interviewed at that have 10+ years experience in the field of technology. I can give them respect for that, for being older, for being around more things, but I still really can't consider myself a "junior" developer. Experience-wise, yes, I have 4 years experience. But, knowledge-wise, I rank up there with at least an eight to ten year developer, just because I live and breath this stuff, and I'm writing software on my TIME OFF. Jeez :)
The interview process for every interview I've been on is the same. The interviewer mentions something in technology, perhaps a term used in Object Oriented Programming, or they ask you something about the language that you are being interviewed to program in, or whatever, and you are supposed to answer it in the best way you know how. Well, let me let those interviewers in on a little secret: Everyone asks the same questions. If you interview at one place and get something wrong, you're going to look it up and have an answer for the next place. Not that I ever mess up on any of their questions. I've always known the answer to "What's the difference between public, private, protected and internal?", but now it's more like I'm spitting it out from memory just from all the times I've been asked it. There are numerous other ones.
I agree, this is a quick way to weed out the people who have never done object oriented programming, and the other questions may weed out people inexperienced in other aspects of technology which are related to the question at hand, but how about this. Try to weed out people who haven't used those things and people who haven't developed anything even remotely difficult in their lives, on ONE question! My one professor in college said that most Computer Scientists, after working in the field for a number of years, couldn't write a working "Queue". Sure, it's no easy task, but we did it, learned the ins and outs, things to watch out for, etc. I have that extremely good memory, detailed in The Philosophy, Part I, so I'll never forget. Although, I did it in C++, now with fully object oriented languages, it should be a bit easier :) Not that you would ask someone to write a queue in an interview, but perhaps you would ask "You want to write a queue... which data structure would be easiest to use when writing a queue?" Somewhat open ended, yet extremely difficult, and you're really tapping the knowledge of your interviewee. You can use an array, keep the current positions as integers (beginning and end). A linked list would be simpler coding, as long as you have the linked list code already, although it's not an extremely difficult challenge to write a linked list (just give me a pad and a pencil, I'll code you a linked list!). Maybe you can ask "What can't you use?" on top of it. Surely, a tree based structure is useless. Easiest thing would be a linear list of some sort. That's a good question, and when I'm interviewing people in a few years, as long as writing code is still a profession, I'll remember that one. Other questions could be more pointed to the type of programming the interviewee might be undertaking if he or she were to be hired, like web programming, databases, web services, UI programming, etc.
I'm not here to tell interviewers how to do their jobs, but us interviewees who know what we're doing with the technology typically snicker under our breaths when asked "What is a dataset and how is it different from a data reader?" For those who don't know what they're doing, they can look up this answer and have it ready for their next interview. Even if their resume says they're the bomb but they're really not...
Another reason that I don't like this process is because I might not know everything that they ask at an interview (SHOCK!!). I might not know every single function that a "DataSet" has on it, every single type of constructor it has, or things of this nature. However, there is no need to ask a question like "You want to create a dataset from XML, how do you do this?" This also points back to The Philosophy, Part I. I explicitly point out that it doesn't matter if you know how to do something, it only matters if you know what something does. Or, in this case, if you know what something is capable of. Yes, you can create a DataSet from an XML document, but when have I ever needed to do this?! If I did ever need to do this, how in the world would I learn in the first place? By looking at a reference. If, for some reason, I never used that again, would it matter now that I don't remember the specific function to call, or would it matter more that I know that you can create a DataSet from an XML document, somehow? I certainly wouldn't think that I can create a Hashtable, or a bottle of beer, from an XML document.
I look forward to not going on any interviews again for a long time (crosses fingers after only having last job for 5 months). |
|
|
|
|
|
|
|
|
This is a filler post. It's a play on the old riddle, "Which came first, the chicken or the egg?" It's computer science related, of course.
Which came first, the program or the compiler? It just baffles me, that before the first compiler, people had to type in machine code directly. The first compiler was made this way... it had to have been, right? It sort of has philosophical meaning behind it. The chicken would have had to have come first, but something made it, possibly building it up by hand. Because you can't have an egg without a chicken, how else would it get there? An egg doesn't just appear out of nowhere, but neither does a chicken... Theories point to some form of evolution or "intelligent design". It's a topic worth mentioning. One that I have no clear conclusion on. I tried to post on it a few weeks ago, did some research, and was unable to discount either. The more interesting argument is that of intelligent design. A compiler would have been made with intelligent design :) A supreme being, a computer scientist like me, designed the first compiler so other supreme beings could write software. Imagine a supreme being designing DNA, which is like machine code, and from a living creature comes the ability to make other living creatures. Is it science? Yes, that's what we call it. It's just whatever you happen to believe. I have come to no conclusion, though. The one site I visited, very much biased towards the God part, has a compelling argument. The chance that the Big Bang would have ended up with a part of it perfectly capable of allowing life is so small that believing that a supreme being started it all is actually the better bet. Imagine that. Those gullible scientists :) |
|
|
|
|
|
|
|
|
On Friday, I decided I was going to extend dumb to be able to read or write XML documents as data. Instead, I figured, with configuration, I should be able to write any document as I see fit, without worrying about whether or not dumb can read it. I decided to start a new project, and soon after, I finished it! It's along the lines of Jakarta Commons Configuration, although definitely not nearly as complex. It's just for XML configuration files following any scheme. Basically, I tell what a bunch of XML tags mean, and what class to load them as, and it reads my config files and loads objects from the xml, and makes them available by the xml tag name that are in my config files. This takes typically one line of XML for each type of object. It's simple.
I never read Jakarta Commons' Configuration code, so I didn't have a place to start. I only knew that I didn't want to read and parse XML using DOM. That type of processing, rather, the code for each type of XML document I can have, can be rather long. I had stuff written to read my latest XML documents, but I deleted it after I determined that my little configuration reader tool would do everything I need it to.
This falls under the laziness of a computer scientist, fully documented in The Philosophy, Part I. If I can write something to do something for me automatically, then by God I'm gonna do it. This one is particularly big, since I hate writing XML code every time. Really. I hate it, even in Java! This was the last time I have to do it for static configuration files. And when I update dumb to read and write XML databases, then I won't have to ever do it again. I can't wait, but that's a huge undertaking. I won't be doing it for at least a few months, or as need dictates.
Here's some sample xml (it reads an xml file to configure itself!! I know, it's ironic):
<obj type="map" spec="attributes" class="aproject.domain.attribute.AttributeMap" key="name" />
This says "When you come across the <attributes> tag, create a new AttributeMap and load that S$#@% in it". However, the "attributes" tag will have tags below it that also define objects or lists. So, each tag is defined in my config file, with a class, and can be loaded in, have properties set on it, and everything else. An object can have lists or properties, those objects can have lists or properties, so it's capable of some pretty complex stuff. My "ConfigParser" class, the one that reads all of the configuration files for your project, is only 128 lines though! A line in computer science is really nothing. It's one instruction. This is four of them:
public ConfigParser(NodeMap objs){
this.objs = objs;
map = new ObjectMap();
}
That's the constructor. Figure in blank lines, "import" declarations, and short lines like that, 128 lines is really nothing at all. And it WORKS!! Many thanks to recursion.
P.S. First game coming soon! Well, a LOT sooner than before I wrote this! |
|
|
|
|
|
|
|
|
Todd and I recently had a discussion where I described to him everything that I was working on currently, and my "dumb" system mentioned in the "Your Site Rules!" section. I had brought up my Philosophy of Computer Science. I couldn't explain it in such a good way though, so I will attempt to now.
I am a learner. When I'm done learning something, I go and learn more. I am not exceptionally brilliant, but apparently (or seemingly) I'm capable of absorbing huge amounts of data though. I take as long as the next person to learn something, but it sticks. My brain tends to tie things together logically, instead of memorizing something outright. So that I can remember small amounts of facts and deduce the outcome using them. I'm sure a lot of people do this. There are some that will memorize everything, but us lucky ones who can remember less but seem to memorize more, make more room in our brains for other small tidbits of information, making us seem exceptionally brilliant.
However, calculating an outcome each time you have to recall it is somewhat inefficient. It's very inefficient. When someone asks you how old you are, you don't calculate "well, I was born in 1979 and it's 2005, that makes me 26" every time... You just know that you're 26 or whatever age you happen to be. Or you lie to get into a bar or because you look younger than you are :)
Someone recently asked me "Why do you learn so many technologies, when you can be an absolute expert at one?" To me, this is an invalid perception of what I do. I don't learn any specific language. I spend a lot of time using Java instead of what I use for work, C# and .NET. When I was in college, the classes that I had made me realize the answer to this question. Not the "Programming Language Paradigms" class, or the "Organization of Programming Languages" class... these were Computer Science classes. I learned the answer to this question in my Philosophy classes. I took quite a few. My favorite one was "Logic". It made everything clear to me.
Computer science isn't "using computers to achieve a task". It's a connection of objects. Either different computers, different technologies, different objects in an Object Oriented Programming Language... different ideas with their own logic, connected together in a way that they all work as one beautiful system. Why I don't learn one specific language or technology is because you are then stuck in that technology. I happened to take jobs in only .NET in the past, so now I'm only able to get .NET jobs, which is part of why I don't learn one technology, but not the only or even most significant one. It's pretty insignificant, actually.
With many technologies in Computer Science, and by technology I mean anything in Computer Science, I find it more important to know what they do, rather than how they do it. Ok, here's an analogy. You learn how to use chainsaws, you don't learn how to use one specific chainsaw. By learning how to use chainsaws, as opposed to one specific chainsaw, you can use any chainsaw. Why should technologies be any different. Writing a website, or using sockets to connect to the internet, or zipping up files, or using a printer, or writing graphics libraries, or using rule engines, or a scripting language, etc. Knowing what something does is much more important than knowing how to use one of those things. Memorizing one language is bad, unlike my "I'm 26" analogy. Being able to deduct this information, based off of that little fact that you store (it's a programming language), is huge. So, when someone says "This is a programming language", I immediately know that it will contain features like input and output (I/O), ways to connect to the internet, something for printing, ways to create objects and inherit from them, interfaces, basic objects like ints, longs, floats, Strings, etc, a mechanism for threading and synchronizing data access, etc. It's a programming language, it's gotta have this stuff, and logically, I can deduce that. So, now all I have to do is sit down with a reference and a text editor, and I can write a program using that language that was introduced to me 3 minutes ago. As I said though, this isn't only to do with programming languages. Tell me what a technology does, I'll show you how to use it in a programming language. I will need a reference, but it just makes sense to me that you call certain functions in a certain order with certain parameters, and it works. Nothing more, nothing less.
So, this is my philosophy of Computer Science, Part I. I'll have more soon. |
|
|
|
|
|
|
|
|
I came across an article in my favorite tech news site, ZDNet, that said Microsoft had predicted 10 years ago that the Internet is the next platform. But, Microsoft still spent bazillions of dollars making Windows XP and the new Windows Vista. Meanwhile, under Microsoft's radar, 2 Stanford students develop something in their dorm room, a search engine, and in 2005, they are big. HUGE. Google. With Google's way of innovation, and their ideas and having the top minds in the field (except they don't have me yet :p ), they are developing a lot of things, and they are not platform specific, but they are for the internet. Gmail, Maps, etc. They have more, and you'll see them by visiting their beta section. So, now Microsoft is feeling the heat. Without having a specific operating system, you can use any of Google's Internet products. Microsoft just wants to take over the world, so they will fight this, and start doing their own, or they just don't want Google to get too big, because then they can go stealing all their smart employees, paying them the big bucks, giving them the Presidential Suites, etc, and using them to develop products specifically targeting Microsoft products, instead of Microsoft doing it to them. The playing field is leveled a bit.
It's an interesting concept, the Internet as a platform. How I picture it, the possibilities are endless. Before I had that vision though, and before I read that article, I had pictured something a little different, something like Google's platform, the latest desktop search. Plug in components into a base platform, and the base provides a lot of the functionality that the components need, providing quicker development. Think of Mac's Widgets. There's a widget container that can provide lots of functionality to the widgets, and then there are widgets that you can plug in. I always imagined something like an application container. I could have small apps that plug in, and you can open any of them from this container. I had thought of this before Mac's widgets, but instead turned towards internet applications. My main reason for this thought process was because of how Java works. I didn't know if you could make a Java program automatically run by double clicking it, you always have to open them with another program. Of course, have everything run under one program. (I later found out about JNLP, Java Network Launch Protocol, which launches 'JAR' files containing a Java program)
Sometimes solutions are so obvious for one problem and they aren't even considered for another problem.
What wasn't obvious to me is that this idea had already been done! In fact, everyone is doing it! When you visit a website, you are typically using an application written for the web. An application. Written for the web. My container application, the platform for running every program I write, is in fact your web browser. This seems like a great platform. Some obvious aspects that you have to watch out for are backing up data, security, limitations of certain web browsers, certain web browsers not following web standards, downtime, scalability, application flow, user experience, and users. Some great benefits to web applications are deploying, updating everyone's version instantaneously, data stored in a central location, and if you secure the server, it's virtually unhackable... if you develop it to be that way. Having a client application obviously has its benefits. You can access local resources (disk drives) and do stuff that you can't do in a web application, like video games and accessing hardware, and stuff that would kill the resources on a web server if too many people did it at once... intense applications. Basically, it depends on the application, whether you should make it a client application or a web application, and whether you can make it a web application.
There aren't too many downsides to writing a web application, but they are pretty big downsides. There is another one. HTTP. HTTP is pretty primordial. HTTP is the protocol in which web servers communicate with the world. It consists of numbered codes and data separated by line breaks. It was developed before XML. However, XML has its obvious downsides. It's heavy, lots of text. Depending on your data, XML can double the size. It's mainly used for text, so you wouldn't normally go storing your images in there. I only bring this up because of client/server applications, or server to server communication, which still falls under client/server. This is why SOAP was invented. SOAP is an XML format that was developed for multiple applications, infinite applications, to send XML data over HTTP. A standardized format is a good start. HTTP can stay as it is, as long as everyone uses SOAP. This was the advent of web services; small applications written to run on the server and communicate with the client. Usually just a function or two. There's a huge history there (search the internet for RPC or "Remote Procedure Call", you'll see what I mean), and the idea was to make a standard way, rather than hundreds of developers fending for themselves, all writing a different way to call functions over the internet.
One of the important downsides I mentioned with writing web applications is user experience. This isn't about making users laugh or showing help or different messages. This is about "perceived speed" of an application. Who wants to watch a progress bar at the bottom of the screen? Or watch as the whole website goes white and takes a few seconds for something to pop up. In client side programming, you typically develop a multithreaded application to improve user experience. Things appear to happen simultaneously. However, these applications run on a web server, and the only protocol for speaking between the web browser and the server is HTTP, which makes requests only at the user's request (hence the name) and provides responses, how in the world do you expect to make an HTML web page seem "multithreaded"?!? AJAX. You may have heard of it. It's "asynchronous" using JavaScript and XML. That's pretty much what the acronym stands for. This way, I can have JavaScript make requests back to the server without the user's interaction, typically on a schedule (every 5 seconds, every minute, etc), and get that ever-so-desired perception of multi-threading in a web application, significantly improving a user's experience.
Google has realized this. Maps and Gmail use AJAX extensively. It is the way of the future, and it is important enough that soon every browser will have it. But this isn't just about writing a web application that appears friendly to the user. It's about writing many applications that are all friendly with each other, and that all appear friendly to the user.
Imagine an internet portal, a website that you go to as the first page you visit on the web. It has everything. News, stocks, your email, messages sent to your IM client that you missed, emails from other accounts you have, voice mails from work and from your cell phone, reminders about events in your calendar, and anything else you can think of. This is Google's vision... probably. Imagine having all this personal data on one website, collected from many different web applications, each using SOAP to communicate with each other, sending XML to the user's browser on each AJAX request, and reading all this personal data on the fly, determining which advertisements to show that user. Advertising is Google's main source of income still, besides selling stock.
"But Google's also buying up loads and loads of dark fiber and buying wireless internet technologies and WAPs" you say... Yes, they have invested in a company that can triangulate exactly where you are when you connect to a wireless network. So you can search for the closest guitar shop to the exact point on which you are standing. This on a portal full of all of that other information I mentioned would just be showing off.
This is where I think Google is heading. As with its search technology, I think the Internet can do better. I must emphasize this. I've mentioned this before, here. I think all of Google's web applications will supply their data this way. I quote myself:
"Imagine, if Google, instead of just reading all of the HTML through a website url, can just ask a website "Yo, what's your deal?!" and the website can respond back "Dude, I am a guitar shop, here are my wares.""
RDF is this for news. Somehow Google is able to extract prices of goods on websites as well, and build a shopping cart around them. But instead of Google just being able to search these results for items you may be looking for, what if there was no website that actually sold this stuff, but Google just read data from a server, through another protocol, and did everything: shopping cart, credit card processing, etc. Google would be the only online shop. Or, what if someone else did this. Like me! No, there's an "end of the world" scenario in there somewhere. No more online shops, just Google, and less jobs, and less money, and more Google. It could be bad, let's hope that they're only doing the portal mentioned above :) |
|
|
|
|
|
|
|
|
Today, I have ceased development on this website. I will still be making news posts, uploading music, adding photos, etc, but I won't be making new features or even fixing bugs. I won't be able to! Actually, I will be able to, but just pretend I won't. I'll be "branching" the code used in this site, sort of backing it up if you will, rewriting all of it, hence breaking this website on my local machine. I will have backups though. There are a few things wrong with it.
First and foremost, I have ideas. Lots of ideas. I will be building a new site, called stringed.org which will just be a showcase of technology. This was explained before. If there is news on there, you might see posts like "Jason is t3h l33t" and just utter garbage like that. Come here for the real news :) It will just be test data, and it'll probably be open to the public, so you will also be able to log in, or just click an admin link, and edit things and input crap, just like I can! It'll be fun for everyone.
Second, I have ideas :) Ok, so that's the same as the first, but I have to reiterate the fact that these ideas could be life changing. You might be working for me or for one of the companies I will own in a few years, so you might want to respect these ideas. The future is easiest achieved in a non-persistent world. That's a cool quote that I just made up. You know all the movies about the future (most fresh in my mind is Minority Report) where everything is different. Buildings are futuristic, cars, houses, everything. We won't ever get there because it will just be too expensive to tear down a building and make it "futuristic". However, in software, it's very easy to tear something down and re-do it. Not for gigantic companies, but for us "hobbyist" software developers. True, I do it for a living too, but I do the hobby stuff more passionately :) That's because I only work on the cool stuff at home. I am doing cool stuff at work though that I haven't done anywhere. I'm rambling. Anyway, if I can just get a good idea in my head, like I have now, I can throw away most of what I have done and start fresh and build my idea. It might not be life-changing for everyone, but I'll get a kick out of it... :)
Third. I just always think things should have three points to them. Three is the magic number. But really, I'm someone who quickly bores of programming. If you've written one input screen, you've written a thousand. If you've updated one table in a database, you've updated a billion. Same thing with most tasks in programming. However, if you have written something to automatically generate SQL for you and update a database, then you don't have to write that thing again, and you never have to write SQL or anything to update the table AGAIN. I wondered when I got done writing "dumb", and still was doing repetitive tasks, like scheming a database out, building input pages, building output pages, building backing beans, etc, if it could all be automatically done for me. That is what I plan on figuring out with this new design. I will find an answer, and that answer will be the future :) For me anyway. I'll buy you a hoverboard when I'm there. |
|
|
|
|
|
|
|
|
So, I'm trying to get my laptop ready for more development. As you may have read, I've installed Gentoo Linux on my laptop recently. This has turned out to be quite a learning experience. Gentoo is no self-installer. You end up learning a TON about Linux, boot loaders, file system, device drivers, configuring a kernel, compiling a kernel, setting up partitions for boot, swap, and system, mounting the system, and just about everything you can imagine. There is one thing I can't figure out though. Laptops have a touchpad for a mouse. Most of these touchpads are one brand, and that's Synaptics. Gentoo has drivers for these devices, and there are other drivers out there. I can't get it to work. The mouse part of it works, like basic movement and clicking, but mine also has a scroll "wheel", which is actually a touch scroller, and I can't get it to work. The thing is, when my system boots up, I can see that Linux has found the Synaptics touchpad, however, the drivers don't recognize it. It sucks because the reason I was so fast at working on that computer is because of the mouse setup. So that's keeping me from working on my website. I can work as it is, but I want my mouse damnit.
Another thing that's keeping me from working on my website is that my website isn't working on my computer. I set up MySQL and configured it, so that's not the problem. I can compile it in Eclipse, so that's not the problem. And Tomcat works fine. The problem is, Tomcat stopped development on the 5.0.x version and is only working on 5.5.x. The new version of Tomcat only works with the new version of Java, Java 5. I got all that to work fine. The thing is a software problem. When I run my website, the thing tells me it can't find this one function in this one Apache class. I know the problem, the new version of Tomcat uses new versions of Apache classes, and JavaServer Faces apparently uses an old, deprecated version. Or they're just completely different. For a new version of software to not support the old version is practically a bad enough crime to seek the death penalty. Apache knows this, so it leads me to believe that they are just different. I have the old version that JSF used to reference, and references for compiling, but I'm not about to overwrite the newer Tomcat's version with it. That screams bad news.
One last reason that I can't work on my website is because of video games. They're too fun. |
|
|
|
|
|
|
|
|
I ran across an article that called Google's new "Desktop Search" for Windows a "Mini Operating System". I posted a reply. When I think "Mini-OS", I certainly don't think of a program written to run on an operating system. When I think "Mini-OS", I'll tell you what I think: Embedded Linux. That's "mini" and that's an "OS".
So what does an operating system do exactly? The first and foremost job of an OS is to interface with the hardware; let you save files on disk, use your monitor, your modem, your attached peripherals like printers, digital cameras, webcams, and anything else. This includes interfacing with your network card and implementing the TCP/IP stack so you can connect to the internet. Also, it includes a "platform" for writing software, an Application Programming Interface (API). Lately, operating systems have included all types of goodies, like integrated search (Mac OS X) and widgets (Mac OS X). This is simply "value added" stuff. Since an operating system might come with these things built into them, it does not change the definition of an operating system. Even if adding "Mini" to the front of it makes your observations less serious, you still have "OS" at the end, invalidating your generalization. How about call it a "program". That's what I call it. A program that happens to search your files and have plugins for stuff like weather. I don't even use it and I know that it's not an operating system.
One comment came from Google.
--- "We're really trying to make this into a platform"
---- Nikhil Bhatla, product manager for Google Desktop.
That can be confusing. I'll have you know that Eclipse is called a platform. I don't boot my computer into the "Eclipse" OS, though. It's a Java editor. A very great one. What this person means is that they will be developing programs on top of it. Which is why Eclipse is called a platform, you can write PLUG-INS. Technology is so misunderstood.
I'm a stickler for technological phrases used in the right way. I'm sure doctors, architects, lawyers, and every other profession will get just as upset if you butcher their terminology. Like, if a man finds a person murdered in the alley, and calls the police and says "We have a grand theft auto here." I'm not the only one :)
Here's another thing about it. That site, "paidcontent.org", is apparently a pretty highly visited site, and one that is as qualified to interpret that Google quote as I am to interpret Shakespeare. They call Google Desktop a mini-OS. People who read that are going to just go ahead and agree, usually. Unless they study. And they'll make posts on their websites, and it's like that game we would play in 2nd grade. One person starts the chain by thinking of something to whisper, and it goes around til the last person, and the last person says what the message is. I don't care if it starts out as "An apple a day keeps the doctor away", it'll turn into something like "A quick brown fox jumped over the lazy dog." Somehow. Let's just call into question every term that every past computer scientist has defined. I've run across at least 3 sites that refer to that post, and also call it a "Mini-OS".
This is another problem with the internet. If the facts are right, it's a beautiful filtering process, eventually making its way to everyone. But if it's wrong, it's like cancer. |
|
|
|
|
|
|
|
|
I'm going to clean my room today. It's not like there's food and wrappers and dirty plates all over the place, but there is a lot of computer stuff lying around, and soda cans. But, I look around and I'm like "F#@%#$@!!!" That's all I can mutter. But, then I just remember the definition of recursion
an expression such that each term is generated by repeating a particular mathematical operation
So, WTF in the WORLD does that have to do with cleaning my room? Simple. Well, let me break it down into a function.
int removeItem(Item[] items){
if (items.size() == 0) return 0;
items[items.size()-1].remove();
return removeItem(items);
}
As you can see, it's all about performing the same action, over and over again, but with a twist. Recursive functions call themselves. It's a very neat way to think when you're writing a program, and once you start to "think recursively", which I have to admit took me a few months in school, then you start to always think recursively, which is why I post this entry. So let's look at the program.
public void cleanRoom(){
Item[] items = ;/// get items from "Room" database
removeItem(items);
}
So, calling removeItem once will clean your entire room. Of course you could just have a "for loop":
for (int i = 0; i < items.size(); i++){
items[i].remove();
}
This gets into asynchronous access issues, array indexing issues, and everything that I just don't want to have to deal with when cleaning my room. You would have to reverse the loop, from items.size() to 0, and it's just too much thinking for something that shouldn't take much thinking at all. Grab item, throw it in trash bag. That's it. I'm not thinking any more than that. Thinking's stupid.
Thinking this way helps me to not feel overwhelmed. It's just one action, repeated over and over again, until the room is clean. And, the room will be clean when I cannot repeat the action any further, when there are no more items. Or when I'm passed out on my bed under a pile of computer game and parts boxes, and shoeboxes, coincidentally. That helps me as well as putting on my favorite tunes from Jimi Hendrix and Cracker. This is going to rule.
Hopefully you've learned a bit about recursion and computer programming, and how someone can think about this stuff all the time, except when they're trashed. Get it, trashed?! I kill me. |
|
|
|
|
|
|
|
|
For the last day and a half, I put some pretty major work into this website. However, the only parts you'll see are in the comments section, and now a News post can have multiple categories associated with it. The thing about the last one is it's not easy at all. You need a few things.
#1 Table structure
#2 Change all your code that uses just a Subject in the news table
#3 Create a dual select box (which I needed anyway)
#4 Create a data list control to list each subject associated with that news post underneath it.
Numbers 1 and 2 were simple, but time consuming. However, numbers 3 and 4, with a new technology and very little documentation out there to go on, can be particularly daunting tasks. In the end, the amount of code written was not at all proportional to the amount of time spent on it, but that's usually the case in Computer Science and programming. You think and think and think, then the easy work begins, unless of course you're using a technology that you aren't too familiar with, like JavaServer Faces. I've written web controls in the technology before. The menu control, for instance, and the calendar control. However, unlike the menu and calendar controls, the Dual Select list is an input control, and the Data List control is an interation control, neither of which I had developed in JSF, up until this weekend.
Here is what the dual select list looks like:
And here is the short amount of JSP code that writes out all of the categories under a news post.
Now the code to "plop" a dual select list onto a page
Simple.
Now I just have to go through all of my news posts and properly categorize them. I'd rather drink gravel. |
|
|
|
|
|
|
|
|
Recently, I had two very contradicting ideas. Keeping in the moment and thoughts of wanting to create a very good website with as little programming as possible, I had one idea. But then, looking at every website out there, I had another idea. Judging by these very short preludes, the second idea would be more of a revolution. So let's start with the first one.
Going back to the second class I had in college on Computer Science, we learned about "templates" in C++. "Template" is an overused word. In C++ it was probably misused. The basic idea then was to be able to write a container class, like a linked list, and use the same code to hold any type of object, be it integers, characters, built in objects, or your own objects. Anything. Converting this idea to a website could prove to be interesting. But it would add confusion for explanation, because I will use the word "template" in a completely different meaning, perhaps its designed meaning. So imagine having a list, and being able to add calendar events, downloads, news posts, links, pictures, etc to it. The web adds a need for "forms". Input forms, output forms, perhaps list forms (when shown in a list, which columns to show), among any other imaginary forms. These just define how the object translates from a piece of data to a viewable form, and vice versa. You would potentially have mounds of data, all in a list, and any of those objects could be placed onto a web page, modified, searched, linked, etc. You would just define the templates, the forms for viewing, inputting, and listing these items.
I never heavily considered this idea, simply because that's not the best way to store data. Searching would be a nightmare, the list could potentially become gigantic, and it would just be really difficult to do anything special with it. It would need tons of programming, something I'm not up to do :) Then came my very contradicting idea that says data should not be in a list.
Thinking about my first idea, it seems very hard to manage. Imagine giving someone permission to edit one record. Imagine, if everything is in one list, showing just downloads, or downloads under "Home Movies". You would have to search all of the data inside each record. What a pain in the butt. This other idea, then, doesn't have to do with making the best web page with as little code as possible. It is completely unrelated, except for the fact that an actual list is a bad way of showing information. Everything is a list. When you read the newspaper, articles, whether you realize it or not, are sorted in an order, in this case, an order of categories, and then an order of what's most important, and what should show up on the front page. On my website, news posts are only sorted by date, and I only show the first 5 on the front page. Some of these posts are really just thoughts, and they should all be read, not just the first five. So, there must be some way of keeping everything in context. I've had a hard time describing this idea, even to myself, and have had an even harder time thinking about how to represent this idea in what would eventually become a web page.
Obviously, a list on a web page is meant for sequential ordering, which means sequential viewing, which translates to most of my posts not getting read. Taking these items out of a list and showing them in another way is the key. But how? |
|
|
|
|
|
|
|
|
Here's a neat function I wrote as part of the photo album part of the site. It takes an image, a width and height, and an output image and creates a thumbnail with size "width by height". I will add that no part of this was with aid :-) Except for the Java 1.4.2 API Specification and a little brain power and some memory about how to scale geometric objects...
public void writeThumbnail(ImageInputStream iis,int w, int h, ImageOutputStream ios) throws Exception {
BufferedImage img = ImageIO.read(iis);
BufferedImage tnail = null;
double sx,sy;
sx = ((double)w)/img.getWidth();
sy = ((double)h)/img.getHeight();
AffineTransform at = new AffineTransform();
at.setToScale(sx,sy);
AffineTransformOp xop = new AffineTransformOp(at,AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
tnail = xop.createCompatibleDestImage(img,null);
tnail = xop.filter(img,tnail);
ImageIO.write(tnail,"JPEG",ios);
ios.close();
}
I should add that there is another function that takes two strings instead of Image streams, both full filenames. I could add one that takes just an input stream and output stream for both, not image input and output streams. That way you could potentially write a thumbnail over the internet :-P A practical example (I like practical) would be to enter a URL of an image on the internet and save a thumbnail of it on your computer.
[Update] Check out the much quicker load times on my album Trip to Lewes. If you've seen it before you'll know. The next step, per Doug's very angry suggestion, is to have some sort of easy image navigation system... We'll see if I want to do it.
[Final Update] I made the photo albums a little easier to navigate. I'm still stumped as to a good way to do it for this site. It goes along pretty well with how the rest of the site is laid out, so, I guess we'll hear from Doug about how I did :) |
|
|
|
|
|
|
|
|
Today, I was trying to make a simple content management system, and one part of a CMS is to be able to put that content onto a menu so you can have it easily show up and look like it's part of your website. Well, I have a menu system that seems to work. So, do I build capability into the content management system to be able to use my menuing system or do I build the menu system to be able to add content to itself???
Well, keeping to my philosophy as of late (besides just reading Plato), I like the second option. Sure, why not have a way for a menu to add a content page to itself? Of course you ask, isn't that stupid? Well, yeah, unless you make it completely reusable. In other words, the menu system can add anything to itself, as long as it's a menu-able something or other. And to define something as menu-able, you basically have to say, ok, what things are needed in order to add something to a menu. Well, in my system, all you need are a page, some text to display, and maybe you want to be able to supply parameters, which are built into the menu system. Ok great.
So, in a file called menu-objects.xml, I can define menu-able objects and supply parameters for them.
There are a few more things needed for the database. You want to have a list of things that are menu-able that you already have in the database. So, the screen can popup and say "what do you want to add a menu item for?" and you pick, say "content", and then a list of the content will show up and you can select it, type in a menu title, pick the menu, pick where on the menu you want to put it, and it's done. These are all simple mouse clicks.
Why can't content add itself to a menu, you might ask? Well, what if I want to add a ton more stuff that can be menu-able. What if I want to make news menu-able? I don't want to have to rebuild news... content isn't the only thing that's potentially menu-able. Also, I built the menu to be swappable later if I wanted to make another one, or add new features, I can just inherit the previous menu, add new features if I want, and without too much work, there's a new menu up there. Plus, I just don't like things depending on other things. Why have content depend on a menu system? Why have news depend on a calendar? Just have each thing be self contained, that's what I always say.
This philosophy I realized when I built the calendar. Do I want to add code to each object that is "calendar-able"? Code that, as it is, already works for the most part? No way. The only thing is, should the calendar be able to exist without this notion of calendar-able objects? Absolutely. And besides just not having any objects listed. This calls for the notion of a very advanced mechanism. One that brings joy to my once joyless heart. Interfaces and abstraction.
So, I want a calendar to be just a calendar at one time, but later transform into this amazing thing that can get events from your database, plot them onto itself, and have it clickable so you can see those events. Well, the fact is that it can't. At compile time, it should know that it might have to deal with calendar-able objects. That's pretty much the nature of programming. The best solution though, is to have an interface for something called a CalendarableObject and another interface to supply these items, called CalendarEventSupplier. The beautiful thing is, you can create a NullCalendarEventSupplier, set it as the supplier in an xml file somewhere, and your calendar is now just a plain old calendar with no mapped events. However, create a DatabaseCalendarEventSupplier, and it's now transformed into something that makes calls to your database, gets events, and plots them onto the calendar.
I love programming. |
|
|
|
|
|
|
|
| July 2010 |
|---|
| Sun | Mon | Tues | Wed | Thu | Fri | Sat | | | | | | 1 | 2 | 3 | | 4 | 5 | 6 | 7 | 8 | 9 | 10 | | 11 | 12 | 13 | 14 | 15 | 16 | 17 | | 18 | 19 | 20 | 21 | 22 | 23 | 24 | | 25 | 26 | 27 | 28 | 29 | 30 | 31 |
| June 2010 |
|---|
| Sun | Mon | Tues | Wed | Thu | Fri | Sat | | | | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 10 | 11 | 12 | | 13 | 14 | 15 | 16 | 17 | 18 | 19 | | 20 | 21 | 22 | 23 | 24 | 25 | 26 | | 27 | 28 | 29 | 30 | | | |
 |