Monday, October 3, 2011

Applying Theory to the Item Arrays

The high point, or perhaps end point of my theoretical thinking was 25 August 2009. It all went to shit after that. I was disappointed by the results of my further iterations, and by the imbecility of the contemporary local school teachers.

I don't know why I was obsessed with the idea of multiple iterations. A single adjustment of item difficulty to compensate for the ability of the students tackling them, and of student ability to compensate for the difficulty of the items they tackle seems, on reflection, more than adequate. So I shall now revisit the calculations I did 2 years ago and focus on the results of the first pass.

A couple of things occur to me as I run my eyes over the data again. The first is the size of the dataset, at around 15,000 records, it is much larger than I remember. The second is the depth of the item list, at around 380 items for addition alone. So there is room for many more than the five difficulty levels that I currently use.

I am not sure what got me into such a negative frame of mind. I dug myself into a catch 22 mindset. that I needed more data to make it better, and I needed to make it better to get more data. But in fact I was already sitting on enough data at least to make some improvement.

So now I am sorting the item list by numeric value of the left and right hand numbers, and observing the completeness of the set. The number 1 has been combined with the numbers 1 to 7. The number 2 combined with the numbers 1 to 6. The number 3 combined with the numbers 1 to 5. The number 4 was combined with the numbers 1 to 8. So there are some gaps, but they are quite narrow. Certainly I think the first step now is to use all the number combinations in the existing data, and then later the gaps can be filled. I shall also order the items exactly by the results in the data set, with no personal juggling.

One of the problems with never having documented what I did in the past, is that I have spent hours writing something to produce item arrays from sorted items, but I have now idea what it was or where is it.

My first thought was that the arrays would have been produced with a few lines of Java, but the folder, where I found text files populated with arrays, had no sign of any java code, and a hunt for source files containing the term array yielded nothing. I then found a spreadsheet, which had probably been used to produce the files, containing cuttings from an Access query. Eventually I found an Access database dated March 2009, six months prior to my attempts at systematic estimation of item difficulty. So the logical thing to do now is to cut and paste those queries into the September database.

The first problem is that the September database uses compound items, whereas the March one uses the individual terms. Note to self - why did I ever put the compound item into a database and thank goodness I've changed that. A second is that after spitting the dummy two years ago, I did no analysis of the operations other than addition.

But with a bit of juggling and a tiny bit of cheating, I produced four new item arrays. The cheating is not an issue, because this is just an opening array set. They will all be adjusted regularly as new data comes in.

Sunday, October 2, 2011

Reducing Transaction Frequency

My niece was using the Applet last night, and in a couple of hours she generated a thousand lines of data, each one requiring it's own transaction with the database. A quick forum post confirmed that I need to modify the code so as to send more data with each transaction.

My first instinct was to upload data at the end of every activity, and I coded for that.

So the addItem3 method, which previously posted data after every item, was reduced down to accumulate a multiline SQL insert command in a new string , and the guts of it were put into a new addItem4 method, which posted the now multiline command:

private void addItem3(String newWord) {
if(firstPass) {
firstPass = false;
sqlbuffer = sqlbuffer + newWord;
}
else {
sqlbuffer = sqlbuffer + ", ";
sqlbuffer = sqlbuffer + newWord;
}
}

private void addItem4(String newWord) {
if(LIVE) {
sqlbuffer = sqlbuffer + ", ";
sqlbuffer = sqlbuffer + newWord;
firstPass = true;
if(jso != null )
try {
jso.call("updateWebPage", new String[] {sqlbuffer});
sqlbuffer = "";
}
catch (Exception ex) {
addItem2("jso call failed... ");
ex.printStackTrace();
}
}
}

But problems arose with posting 15 and 20 line inserts. So I modified the code again such that on longer activities, addItem4 gets called after 10 items, as well as on completion of the activity:

if ((oldItem == 10) && (NoOfItems > 10)) {
addItem4(qTrack.datInsert());
} else {
addItem3(qTrack.datInsert());
}

Then there was a typhoon, which prevented anything happening for a few days.

Thursday, September 22, 2011

Fixing the PHP connection

I was so keen to minimize disruption to existing code that I forgot a couple of crucial steps. The first was to add the following line to public void init():

jso = JSObject.getWindow(this);

I also added the following diagnostic code to public void start():

if(jso != null )
{
addItem2("jso filled... ");
}

This enabled me to confirm that the jso object variable was filled as soon as the Applet opened.

The next necessary step was to tidy up the datInsert() function, which creates the SQL insert string, so that the string became:

ItemEntry = "INSERT INTO Items " +
"(Partid, OpCode, ItemLeft, ItemRight, Raw, Rate) " +
"VALUES (" +
sessTime + ", " +
OpCode + ", " +
ItemLeft + ", " +
ItemRight + ", " +
Raw + ", " +
SRate + ")";

The new variables ItemLeft and ItemRight were declared, but the old Itemdet was not removed, because it is still needed to populate a field. After that, with a few more comments thrown in here and there, the Applet ran.

Wednesday, September 21, 2011

Coding for a new database connection

When I worked for Mellon Bank, a favourite expression of my boss there was "If it ain't broke, don't fix it". I love that expression, and it really applies to what I am doing now.

Now I know you can work in the Collabnet working folder, but I prefer to copy files from there into another working folder, so I can just drag and drop from the original folder into another clean working folder when I stuff up. And because I am a little paranoid, the first thing I do is compile the code, just to make sure nothing strange has happened to prevent it doing so.

In the current version, the main class, AMJApp, makes a call to a function/method in my workhorse class QTrack.

The function call, which actually produces an argument for another local function is as follows:

addItem2(qTrack.datInsert());

And the function is:

public String datInsert() {
try {
ItemEntry = "INSERT INTO Items " +
"(Partid, OpCode, Itemdet, Raw, Rate) " +
"VALUES (" +
sessTime + ", " +
OpCode + ", '" +
Itemdet + "', " +
Raw + ", " +
SRate + ")";
smt.executeUpdate(ItemEntry);
buffer = "insert succeeds... ";
} catch(Exception ex) {
buffer = "SQLException: " + ex.getMessage();
}
return buffer;
}

Now, I want to minimize disruption, so the first thing I'll do is add another local function, which I shall call addItem3(String newWord). It is initially identical to addItem3(String newWord):

private void addItem3(String newWord) {
if(dbDEBUG) {
System.out.println(newWord);
jTADiagnosics.append(newWord);
}
}

I quickly recompile to see if this has destroyed the delicate balance. It hasn't yet, so I make another small change, making the function call:

addItem3(qTrack.datInsert());

I have to do this three times in different places in the code. And I recompile again, just to be safe. All OK so far.

My next change is a very subtle one, changing the value returned by the function in QTrack from buffer to ItemEntry. I recompile both classes again, and so far all is OK.

Now comes the crunchy part. I've been putting it off for a long time because I know it will stuff everything up. I have to make the addItem3(String newWord) function do some work. This is the function which will pass the data line to PHP.

I shall borrow the code from a previous post in my Learning Java blog. This code includes a JSObject, and that is why it gets messy. The JSObject requires the import of netscape.javascript.JSObject, which in turn calls on a collection of classes which can be found in a java archive called plugin.jar, while my main class also calls on other classes. So the compile command is no longer a simple javac but rather:

javac -classpath "C:\Users\MJHIPP\Documents\Current\Java\CodeLocal\AMJ110920\plugin.jar";"." AMJApp.java

I recompile again just to be safe, and then to be ultra safe I simply add the import line before recompiling with the new command. There was a bit of fiddling around, because that class path is a bit of a fiddle, but that is why I like to recompile after every small step. I can cope with one error, but not a whole screen full.

The next small step is to add the JSObject, and I put it right at the beginning, with my other supporting class declarations. Another recompile and all is still OK. Finally I have to add code to the addItem3(String newWord) function:

private void addItem3(String newWord) {
if(LIVE) {
if(jso != null )
try {
jso.call("updateWebPage", new String[] {newWord});
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}

The modified class compiles just fine, but I now realise a fatal flaw in my methodology. I complied at every step but I did not check to see that the modified Applet actually ran. I was therefore very disappointed when it did not.

After some discussion on the Java Applet development forum it seemed to have something to do with JDK versions. And after fiddling for a while with cross-compilation options, I removed everything to do with Java from my computer, installed JDK 6.27, and recompiled, and now the new Applet runs.

It's not posting data yet, but hopefully that is a small diagnostic problem, to be fixed another day.

Tuesday, September 20, 2011

Database modifications

I need to modify the structure of my database, because I noticed in my practice AJAX call to PHP, the "+" sign was getting lost. I'm sure I could fiddle around to get it back, but I'd lose generality and I don't need it. I already store an operation code in the database, so I simply need to record the numbers being operated on in their own fields.

Rather than changing the fields in an old table, I'll just create a new one. As this is an open source project, for future reference and replication, it seems cleaner to record a single create command, than to recall a dud one and a series of changes. The SQL command was:

CREATE TABLE Items(
Itemid INT NOT NULL AUTO_INCREMENT ,
Partid BIGINT,
OpCode SMALLINT,
ItemLeft SMALLINT,
ItemRight SMALLINT,
Raw SMALLINT,
Rate DOUBLE,
PRIMARY KEY ( Itemid )
)

I ran this with phpMyAdmin, because my ISP offers it, and it was quick and easy to do so.

I am now ready to make the coding changes in the Applet.

Monday, September 19, 2011

Review of current data insertion methods

Before changing the database and attempting to write new data insertion code, I need to refresh my memory of what the Applet currently does.

So in the second of four statutory Applet methods, public void start(), the Applet includes the following code:

if(LIVE) {
addItem(qTrack.dataDriv());
addItem(qTrack.dataConn());
}

I like this construct, and I shall be sorry to lose it. The theory behind the code is described in a post entitled Functions in my Learning Java blog.

Essentially the explicit purpose of the method is to return a string for display in the Applet, but the database connection code is written into the code of the method, and the string returned is either connection succeeds or connection fails, depending on the outcome.

Anyway sadly, it has to go, because under the new rules, the connection code has to be contained in a PHP file.

In the third statutory Applet method, public void stop(), is the following code:

if(LIVE) {
qTrack.dataClose();
}

This is just a void method, I guess because if the Applet is closing, there is nowhere to display any returned message.

Then in the core of the Applet code is the following:

addItem2(qTrack.datInsert());

This is another diagnostic display function, with data insertion code written into it, and it is run every time an item is completed. This is the code, which needs to be modified carefully to send a query to PHP, without disrupting too badly the functionality of the Applet.

Sunday, September 18, 2011

CollabNet Subversion

CollabNet Subversion can be downloaded from the CollabNet Subversion Downloads page. The manual can be read or downloaded from here, although the manual should come with the product download, and in Windows is even accessible from the Program menu.

To access code from an externally hosted project, such as my Rasch Itembank Project, only the client software needs to be installed.

And although they are kind enough to put the manual in the Windows GUI menu, the program itself has to be run from the command line. There is no need to set a binaries path, and if you navigate to the folder where you want to store your working copies of the code files, there is no need to set a target path either.

I had logged into my project from a browser before running the checkout command, and I was not asked for authentication when I ran it. The command for me was:

C:\Users\MJHIPP\Documents\Current\Java\Code\110918>svn checkout https://svn.java.net/svn/rasch-itembank~svn

This put a complete copy of my working files, including subfolders, into my working folder, as shown below. A quick glance at the screenshot will also reveal a batch file, which I used to run the svn command, to save typing.

On this occasion I simply added a stable working copy to the tags folder and reuploaded. To add the copy I had to use the svn copy command:

C:\Users\MJHIPP\Documents\Current\Java\Code\110918\rasch-itembank~svn\trunk>svn copy client C:\Users\MJHIPP\Documents\Current\Java\Code\110918\rasch-itembank~svn\tags\Client110918

The basic syntax of the command is similar to DOS copy, except that you simply have to name a folder and all contents will be copied.

I then wanted to add a text file explaining the significance of the copy. Here I had to create the file first and then use svn add. So this command does not create files, but adds them to some sort of a list.

C:\Users\MJHIPP\Documents\Current\Java\Code\110918\rasch-itembank~svn\tags>svn add Client110918.txt

Before committing the changes I wanted to run svn status. Initially I tried to run the from the parent directory into which I had downloaded my working copy, but it actually had to be done from the root directory of the working copy:

C:\Users\MJHIPP\Documents\Current\Java\Code\110918\rasch-itembank~svn>svn status

and the report came back:

A tags\Client110918.txt
A + tags\Client110918

The svn update command confirmed that nothing had changed on the server while I was working. I then added a comment to the svn commit command:

C:\Users\MJHIPP\Documents\Current\Java\Code\110918\rasch-itembank~svn>svn commit -m "Added working copy to tags folder."

My web log in had timed out by the time I did this, so I was prompted to log in again on the command screen.

Authentication realm: Subversion Repository
Username: jhipp117
Password for 'jhipp117': ******
Adding tags\Client110918
Adding tags\Client110918.txt
Transmitting file data .
Committed revision 12.

Having done this, I am now free to start hacking away at the main code.