Direct Links to Multiple Google Accounts



>> Tuesday, November 27, 2012


I have a few different Google accounts that I use regularly. For Gmail, I mostly have it set up to send email from one inbox. However, there are times when I want to open up a specific inbox without having to open up the main account, click my address, and then click my other account. The same thing applies for multiple calendars, drive/docs, etc.

I set up some bookmarks to directly link to the accounts and here are the formats.

In all cases, you need to be signed in to each of your accounts. And the order you signed in matters. The number (0, 1, 2) corresponds to the order in which you signed in (starting at 0)

Here is the format of the URLs:

Gmail:
https://mail.google.com/mail/u/0 (or just https://mail.google.com)
https://mail.google.com/mail/u/1
https://mail.google.com/mail/u/2

Google Calendar:
https://www.google.com/calendar?tab=mc&authuser=0
https://www.google.com/calendar?tab=mc&authuser=1
https://www.google.com/calendar?tab=mc&authuser=2

Google Drive:
https://drive.google.com/?tab=mo&authuser=0
https://drive.google.com/?tab=mo&authuser=1
https://drive.google.com/?tab=mo&authuser=2

Read more...

Other Blog Posts



>> Sunday, May 13, 2012

Here are some recent posts I wrote on a different blog:

Creating an in-memory cache in a Grails/Groovy application using Google's Guava cache library:
http://refactr.com/blog/2012/05/grails-in-memory-cache-using-googles-guava-library/

Using Google fusion tables and GPS data from my Garmin running watch to easily create a heat-map of most-visited locations:
http://refactr.com/blog/2012/04/create-a-heat-map-using-google-docs/

Using Eclipse/STS for Grails development. Why you should switch and some common errors/remedies:
http://refactr.com/blog/2012/04/switch-to-sts/

Read more...

Extract Audio from YouTube Videos



>> Tuesday, September 20, 2011

I wanted to get an mp3 of a video on YouTube. There are sites that will do it for you, but I wanted a little more control.


Turns out it was pretty easy with free software.

1) Download the flv video
I used the open-source YouTube Downloader from Sourceforge. With that Java application I just needed to drag the URL from my browser onto the application and it would start downloading. I could even download multiple videos at once.

2) Extract the audio
ffmpeg was all I needed in this case. The command I used was:
ffmpeg -i youtubevideo.flv output.mp3

Simple as that!

Read more...

Calibre and Kindle Collections



>> Thursday, August 4, 2011

I recently bought a Kindle. Even though I didn't think I would like it, I really do. Maybe it is the computer scientist in me, but I want to control how books are organized and displayed from my computer instead of from the Kindle. Enter Calibre (http://calibre-ebook.com/). If you don't know, Calibre is to ebooks as iTunes is to mp3s. It is great at organizing and converting books. However, out-of-the-box it doesn't support collections on the Kindle.


It was pretty easy to set up:
  1. Install the "Kindle Collections" plugin (instructions here)
  2. Create a custom column by going to Preferences > Change calibre behavior > Interface > Add your own columns. Click the "Add custom column" button
  3. Give it a lookup name (kindlecollections), Column heading (Kindle Collections), and choose the "Text, column shown in tag browser"
  4. Fill in that new column with whatever collections you want on your Kindle. You can also go to Edit metadata > Custom metadata to add the name of the collections
  5. Plug in your Kindle (if you haven't already) so you can use the Kindle Collections plugin
  6. Go to Kindle Collections > Customize collections to create from Calibre...
  7. Select "Create" in the Action dropdown for your new column
  8. Go to Kindle Collections > Create collections on the Kindle from Calibre
  9. Eject and Restart your Kindle
It sounds more complicated than it really is. I know there are other tips out there for using existing columns like Series for Kindle Collections, but that didn't make sense to me as much as creating a new column.

Also, I don't like that you have to restart your Kindle every time, but I think that is a Kindle limitation, not Calibre or the plugin.

Let me know if you have any other Kindle/Calibre/Collections tips!

Read more...

Convert 2-Column PDF to eBook



>> Thursday, June 30, 2011

I recently bought a Kindle and have started loading it with techy books/papers/etc. that I can find for free. I am using the free calibre (http://calibre-ebook.com) software to do the conversion since pretty much everything I find is in PDF format.


It works OK for 1-column PDFs, but for 2-column the conversion does not work at all. I can read PDFs on my Kindle, but it is not as nice as reading an actual ebook.

I found one way to convert them in case anyone else is interested:

1) Upload the PDF to Google Docs
2) Choose to "Make a Google Docs Copy" which will convert it into the Google Docs document format that you can edit
3) Tweak as needed
4) Download as HTML
5) Load into Calibre and convert to your book type (mobi, epub, etc)

This will only convert the first 10 pages though, so you might need to split the original PDF (with a site like http://foxyutils.com/splitpdf). However, if it gets too long this method will get pretty tedious.

If you have any questions or thoughts, let me know.

Read more...

Ext 3.3 MessageBox Issues Resolved



>> Wednesday, June 8, 2011

I was doing some work using a MessageBox in Ext and ran into a couple of issues. Mainly the problem was because I am working in an infrastructure that is on Ext 3.3 and not Ext 4 (yet). Because of that I had to do some new things to add an ID to the MessageBox and also to bring the MessageBox above other elements on the page, specifically the loading mask.

Here is the code:


Ext.MessageBox.showWithId = function(dialogId, config){
var dialog = this.getDialog();
dialog.el.dom.id=dialogId;
Ext.MessageBox.show(config);
}

Ext.MessageBox.showWithId('myID', {
title : 'Progress',
msg : 'Processing...'
progressText : 'Initializing',
width : 270,
progress : true,
closable : false,
});

//bring it above the loading mask
Ext.MessageBox.getDialog().getEl().setStyle('z-index', '50000');

//remove the showWithId function to clean up after myself
Ext.MessageBox.showWithId = undefined;


First, the ID. I needed an ID to do automated testing with Selenium, and because of that I needed a way to locate the MessageBox by an ID. In Ext 4 you can just add an ID in the show() initialization, but that is not in Ext 3.3. So basically I had to create a new function called showWithId(). This just sets an ID in the dialog and then turn around and call show().

Next, the z-index. This just brings the MessageBox to the front. 50000 might be higher than I needed, but it worked for this example.

Let me know if you have any questions

Read more...

Use Groovy to Find Database Size



>> Wednesday, March 16, 2011

Last week I found a SQL statement to find the size of rows in a database. That was helpful but I wanted to be able to run this from the command line. Sounds like a good job for the Groovy database features.

import groovy.sql.Sql

//connect to the database
def sql = Sql.newInstance('jdbc:oracle:thin:user/pass@host:1521:database')

//define the statement to run
def sizeStatement = """select table_name, num_rows, avg_row_len,
ROUND((num_rows * avg_row_len / 1048576),2) "mb_used"
from user_tables
where num_rows > 0"""

//create a date to output (not needed for SQL, just for reporting purposes
def formattedDate = String.format('%tD %
//output the results
sql.eachRow(sizeStatement) { row ->
println "${formattedDate},${row.table_name},${row.mb_used}"
}


A nice little script. The only catch is that my database is Oracle so I need to pass in the driver jar when I run the script from the command line like this

groovy -classpath OracleThinDrivers.jar CheckSize.groovy

Read more...

Getting the Size of a Database



>> Wednesday, March 9, 2011

I recently needed to get an estimated size of an Oracle database. It turns out to be not too hard.

--by table
select table_name, num_rows, avg_row_len,
ROUND((num_rows * avg_row_len / 1048576),2) "MB Used"
from user_tables
where num_rows > 0

--total
select SUM(ROUND((num_rows * avg_row_len / 1048576),2)) "Total MB Used"
from user_tables

Read more...

Return Statements in Closures



>> Tuesday, December 21, 2010

I found an interesting little "quirk" that I was not expecting with Groovy today having to do with return statements in a closure.

Let's say I have some code like this:

String someMethod(){
def myList = ["1", "a", "test", "z"]
myList.each{
println "in each loop for: " + it
if(it == "test"){
println "\tfound"
return it
}
println "\tafter if"
}
}

def value = someMethod()
println value;


The output is:
in each loop for: 1
after if
in each loop for: a
after if
in each loop for: test
found
in each loop for: z
after if
[1, a, test, z]


I was hoping for this:
in each loop for: 1
after if
in each loop for: a
after if
in each loop for: test
found
test

Where it would return from the method once the value is found. It turns out each{} doesn't work this way. I am sure there are good (complicated) reasons for this, but for now I'm just going to change my method to use a good old for loop.

String someMethod2(){
def myList = ["1", "a", "test", "z"]
for(int i = 0; i < myList.size; i++){
println "in each loop for: " + myList[i]
if(myList[i] == "test"){
println "\tfound"
return myList[i]
}
println "\tafter if"
}
}

Read more...

Groovy Stopwatch



>> Friday, December 17, 2010

Groovy Stopwatch

Before I started using Groovy, I had created a simple little stopwatch Swing application that basically had one button (Start/Stop) and displayed a time. If you are interested, that is here. I wanted to improve it a bit so I could put a countdown so it would give me a few seconds before it started to time. As a little background, I needed that "feature" so when I was timing this UI I was working on it would give me some time to click "start" on my stopwatch and then switch to the UI I was testing. Not the most advanced tool, but it works fine for my needs.

Instead of updating my Java class, which was already fairly complicated due to the nature of Swing programming, I decided to use Groovy's SwingBuilder.

Here is the final result
Stopwatch
Download the Groovy code here.

It was interesting to find that my original Java class for this simple app was 80 lines and my enhanced application in Groovy was only 61, even though I added new features. I probably could have made each of them a little shorter if I really cared about lines of code, but for comparison sake I thought it was interesting how much shorter Groovy was.

For the application itself, here is the code that sets up and displays the Swing UI:

import groovy.swing.SwingBuilder;
import java.awt.BorderLayout as BL
import javax.swing.JFrame

startTime = 0
started = false

swing = new SwingBuilder()
myFrame = swing.frame(title:'Stopwatch', show: true, size:[200,130], defaultCloseOperation: JFrame.EXIT_ON_CLOSE){
panel (layout: new BL()){
panel(constraints: BL.NORTH){
label 'Countdown time'
countdownField = textField (text:'5', columns:4)
}
panel(constraints: BL.CENTER){
startStopButton = button (text: 'Start/Stop', actionPerformed: {
if(!started){
countdownThenStart()
} else {
stopTimer()
}
})
}
panel(constraints: BL.SOUTH){
messages = label (text:'Click Start')
}
}
}


The countdownThenStart() and stopTimer() methods are explained below. One interesting thing I found out was that if I wanted to reference a button (like "startStopButton"), label (like "messages"), or text field (like "countdownField") again, all I had to do was assign it to a variable. If I didn't need it, then I didn't assign it.

I could have made this even simplier if I didn't use the BorderLayout (remove the "constraints: BL.NORTH") or explicitly set the size. I could have just used "pack: true" in place of size. However, since I was learning how to do this, I added them in.

Also, be sure to put the "defaultCloseOperation: JFrame.EXIT_ON_CLOSE" in the frame. I forgot and ended up with dozens of instances of Java running.

To do the countdown, here is the method I used:
def countdownThenStart(){
int secondsInt = Integer.parseInt(countdownField.text)
enableFields(false)

def th = Thread.start{
for(int i = secondsInt; i > 0; i--){
messages.text = i
sleep(1000);
}
messages.text = "Go..."
startTimer()
}
}


This was a little tricky. I had a problem displaying the countdown. It would just display "Go..." and no digits. It turns out I had to wrap those messages in a separate thread and then it worked like a charm.

Finally, the rest of the helper methods look like this:
def startTimer() {
started = true
startTime = new Date().getTime()
enableFields(true)
}

def stopTimer() {
stopTime = new Date().getTime()
started = false
messages.text = ((stopTime - startTime) / ((double)1000)) + " seconds"
}

def enableFields(def enable){
countdownField.enabled = enable
startStopButton.enabled = enable
}


Nothing surprising or confusing here I hope.

Overall, the SwingBuilder was very easy to use. I've written a number of little Swing apps in the past, and I doubt I will ever need to use anything other than Groovy's SwingBuilder for them again.

Read more...

Word Frequency for YouTube Videos



>> Wednesday, November 17, 2010

YouTube has a feature where you can browse the top viewed videos over a specific time-frame (today, this week, this month, or all time). I thought it would be interesting to see which words (if any) pop up more than others. By just glancing at the list I guessed that "justin" and "beiber" would top the list. I thought I'd write some quick Groovy code to see if I was right.

The Stats:

Here is what I found when I looked at the top 160 most viewed videos of all time (as of today):

Top 25 Words:

WordCountFreq
official193%
music121%
song71%
cyrus71%
miley71%
version60%
gaga60%
lady60%
bieber60%
justin60%
jason50%
feat50%
dance50%
love50%
baby50%
high40%
david40%
best40%
this40%
sean30%
nuki30%
iglesias30%
enrique30%
goes30%
like30%

Other Stats:
Total words: 619
Total unique words: 424

The Code:

All the source code is located here (box.net)

Here are the guts of the program:
def html = new XmlSlurper(new SAXParser()).parse(urlString)
html.'**'.findAll{ it.@class == 'video-title'}.each {nextVideo ->
//split the title using regex on non-word characters
nextVideo.text().split(/\W/).each{nextWord ->
def lowerCase = nextWord.toLowerCase()
//limit the results to "interesting" words
if(lowerCase.length() >= minWordLength && !(lowerCase in ignoreList)){
wordFreq[lowerCase] = wordFreq[lowerCase] == null ? 1 : wordFreq[lowerCase] + 1
}
}
}


Here is what it does:
1. Parse the YouTube URL using XmlSlurper
2. Find all the titles on the page
4. Split the title to get individual words
5. Convert it to lower case to make comparisons easier
7. Limit the words by a minimum length (to get rid of stuff like "of", "and", "the") and ignore other words (like "video")
8. Update the wordFreq map

I am not very comfortable with minimum length and ignoring words, but without that the top 10 words were: video, the, official, ft, music, i, t, you, in, on. That is much less interesting that the filtered list, in my opinion.

Read more...

Google Calendar - When Was That Event Created?



>> Thursday, October 21, 2010

Usually I don't care, but occasionally I need to know when I created an event on my Google Calendar. It is not the easiest piece of information to find, but it is out there and here is how you find it.


  1. Go to Settings (Calendar Settings) > Calendars tab
  2. Select (click on) the calendar with the event you want
  3. Under the Private Address, click on the ICAL icon
  4. The address will pop up, just save and open that file
  5. In your editor, just search for the name of the event.
  6. Look for the CREATED attribute. There is also a LAST-MODIFIED attribute if you are interested in that.

Read more...

Use ConfigSluper Instead Of Properites Files



>> Thursday, September 9, 2010

I often use Java property files as configuration for prototypes, proofs of concepts, utility applications, etc. Groovy has a more powerful way of doing this called a ConfigSlurper (JavaDoc).

A ConfigSlurper just uses a Groovy script as input instead of a .properties file. This lets you do better (in my opinion) configuration like having typed properties (instead of them all being Strings you have to convert) including lists and maps, tree-structures of properties, even deriving a property value based on some calculation or closure.

Here are some examples. All the code can be downloaded here (box.net)


//Config1.groovy
stringProperty="Some string"
numberProperty=42
booleanProperty=false
listProperty=["Monday", "Tuesday", "Wednesday"]

Here is a basic configuration file using some different types. Here is how to read and use it:

def config = new ConfigSlurper().parse(new File('src/Config1.groovy').toURL())

assert "Some string" == config.stringProperty
assert config.stringProperty.class == String

assert 42 == config.numberProperty
assert config.numberProperty.class == Integer

assert false == config.booleanProperty
assert config.booleanProperty.class == Boolean

assert ["Monday", "Tuesday", "Wednesday"] == config.listProperty
assert 3 == config.listProperty.size()
assert config.listProperty.class == ArrayList


Another powerful feature is being able to use trees of data like this:

//Config2.groovy
teams {
packers {
quarterback="Aaron Rodgers"
recievers=["Greg Jennings", "Donald Driver"]
}
vikings {
quarterback="Brett Favre"
}
}


And then reading them like this:

def config = new ConfigSlurper().parse(new File('src/Config2.groovy').toURL())

assert "Aaron Rodgers" == config.teams.packers.quarterback
assert ["Greg Jennings", "Donald Driver"] == config.teams.packers.recievers
assert "Brett Favre" == config.teams.vikings.quarterback


Along those lines, there is a special configuration called "environment." This allows you to use different configurations based on what "environment" you are in.

//Config3.groovy
website {
//default values
url = "http://default.mycompany.com"
port = 80
user = "test"
}

environments {
development {
website {
url = "http://dev.mycompany.com"
port = 8080
}
}
production {
website {
url = "http://www.mycompany.com"
user = "prodUser"
}
}
}

In this example, there are some default values for the website properties. Then, the different environments overwrite some of the defaults. Here is how you call the ConfigSlurper to use the different environments.


//defaults
def config = new ConfigSlurper().parse(new File('src/Config3.groovy').toURL())

assert config.website.url=="http://default.mycompany.com"
assert config.website.port==80
assert config.website.user=="test"

//development environment
config = new ConfigSlurper("development").parse(new File('src/Config3.groovy').toURL())

assert config.website.url=="http://dev.mycompany.com"
assert config.website.port==8080
assert config.website.user=="test"

//production environment
config = new ConfigSlurper("production").parse(new File('src/Config3.groovy').toURL())

assert config.website.url=="http://www.mycompany.com"
assert config.website.port==80
assert config.website.user=="prodUser"


Finally (for this article), here are a few fun things you can do with a ConfigSlurper including calculated values and merging configs.


//Config4.groovy

//set the value as some calculation
calculation = 2+2

//base the value off of some other property
calc2 = calculation * 2

//set the value using a closure
doubling = 1
5.times{ doubling = doubling * 2 }


And using those values:

def config = new ConfigSlurper().parse(new File('src/Config4.groovy').toURL())

assert 4 == config.calculation
assert 8 == config.calc2

assert 32 == config.doubling

//merge config files
def config1 = new ConfigSlurper().parse(new File('src/Config1.groovy').toURL())
def config2 = new ConfigSlurper().parse(new File('src/Config2.groovy').toURL())
config1 = config1.merge(config2)
assert 42 == config1.numberProperty
assert "Aaron Rodgers" == config1.teams.packers.quarterback


Leave a comment if you have any questions or suggestions!

Read more...

Running an Ant Script in Groovy



>> Wednesday, September 1, 2010

I recently wanted to test the execution of an Ant script and I wanted to use Groovy. There are a lot of blogs about using AntBuilder to run Ant tasks in Groovy, but that isn't what I needed. I actually needed to test the Ant script itself.

This was not to hard, but the concept is tricky. I used AntBuilder to execute an external process (using the exec task). In this case, the external process is ant. Lost yet? Here is the code, maybe that will make it easier:


File antExecutable = new File("C:/Ant/bin/ant.bat")
assert antExecutable.exists()

File antScript = new File("C:/antscripts/build.xml")
assert antScript.exists()

def ant = new AntBuilder()
ant.exec(executable: antExecutable.getAbsolutePath(),
outputproperty:"cmdOutput",
errorproperty:"cmdError"){
arg(value: "-f")
arg(path: antScript.getAbsolutePath())
}
assert ant.project.properties.cmdOutput.contains("BUILD SUCCESSFUL")
assert ant.project.properties.cmdError == ""


Hopefully this is pretty straight-forward. Basically this is equivalent to calling "ant -f C:\antscripts\build.xml" from a command line. If you want to know more about how to use AntBuilder, go here.

The output gets stored in a property called "cmdOutput" which can be tested using the "ant.project.properties.cmdOutput" variable. In a similiar way, the standard error gets stored in "cmdError." If you just want to display the output, remove the outputproperty and errorproperty from the exec task.

There are a couple other things you might need to do.

First, if you want to pass additional arguments to the script (for example, setting some ant properties), you can just add additional "arg" lines like this:


ant.exec(executable: antExecutable.getAbsolutePath(),
outputproperty:"cmdOutput",
errorproperty:"cmdError"){
arg(value: "-f")
arg(path: antScript.getAbsolutePath())
arg(value: "-DsomeProperty=someValue)
}


Second, if the ant script needs to know about some classpath variables, just add an "env" line like this:


ant.exec(executable: antExecutable.getAbsolutePath(),
outputproperty:"cmdOutput",
errorproperty:"cmdError"){
arg(value: "-f")
arg(path: antScript.getAbsolutePath())
env(key: "CLASSPATH", path: "C:/jars/;C:/project/files")
}


Leave a comment if you have any questions or suggestions

Read more...

Scrape Powerball Number Frequency



>> Monday, August 30, 2010

I know that buying lottery tickets is a total waste of money. I also know that there is nothing you can do to increase the odds of hitting a Powerball jackpot (1 in 195,249,054). However, just for fun, I thought I'd fire off a quick groovy script that will read the frequencies from the Powerball website.

Once I have all the numbers I could sort the lists to find out which numbers are most frequently picked (or least frequently picked). I'm sure there is other statistical analysis that you could do too if you wanted. You could also watch the frequency trends over time (though this historic list of numbers may be better at that)

Here's the simple script:

import org.cyberneko.html.parsers.SAXParser;

//initialize
def maxPowerBall = 39
def whiteBallFreq = [:]
def pbFreq = [:]

//read the numbers
def url = 'http://powerball.com/powerball/pb_frequency.asp'
def html = new XmlSlurper(new SAXParser()).parse(url)

//create the lists from the HTML
html.BODY.TABLE.TBODY.TR[3].TD[1].TABLE.TBODY.TR[4].TD[1].TABLE.TBODY.TR[2..-2].each{nextRow ->
def cols = nextRow.children()
def ball = Integer.parseInt(cols[0].text())

whiteBallFreq[ball] = parsePossiblyBlankNumber(cols[1].text())
if(ball <= maxPowerBall){
pbFreq[ball] = parsePossiblyBlankNumber(cols[2].text())
}
}

def int parsePossiblyBlankNumber(String value) {
if(value.trim().length() == 0){
return 0;
} else {
return Integer.parseInt(value)
}
}

The import is found here. The long "html.BODY.TABLE..." line is needed because of how the Powerball website is set up.

I put in the parsePossiblyBlankNumber method since the website uses blanks instead of 0s when there are no frequencies.

Leave a comment if you have any questions or suggestions!

Read more...

Code Formatting in Blogger Using SyntaxHighlighter



>> Friday, August 20, 2010

I wanted to use SyntaxHighlighter, but it turns out it takes a little tweaking on Blogger. I found a number of blogs that had instructions, but none of them seemed to work. Here is what I did to get the code formatting.

1. Upload files to Google Sites (Optional)
You need to link to a few javascript and css files. It looks like SyntaxHighlighter has a hosted version, but I decided to host the specific files I wanted. Here are the files you need:

  1. shCore.js
  2. shCore.css
  3. shCoreDefault.css (or your theme, I used shCoreEclipse.css)
  4. Brushes (for type of code). I used shBrushPlain.css, shBrushJava.css, and shBrushGroovy.css
2. Edit your Blogger template
Go to Design > Edit HTML. Add this code towards the bottom:





The "trick" for blogger is to set the "bloggerMode" to true.

3. Wrap your code in "pre"
For example, if I wanted to use blog about this code in Java, I would use class="brush: java" like this:


public static void main(String[] args){
System.out.println("Hello World!");
}


And it would look like this:

public static void main(String[] args){
System.out.println("Hello World!");
}

Read more...

Fantasy Football Cheat Sheet Scraper



>> Wednesday, August 18, 2010

With my fantasy football draft coming up, I thought I would create a quick Groovy script to scrape a couple Fantasy Football cheat sheets. If you don't know, a cheat sheet has a ranking of players that you can use to make your draft picks. There are a bunch available online, and they are updated frequently (like now that Brett Favre is back with the Vikings I assume he will move up and Tarvaris Jackson will move down in rank).

Since I wanted the most up-to-date ones on the day of my draft, I wrote a couple classes in Groovy to read the webpages and print out the results in a common format. This turned out the be pretty easy to do.

For example, here is one from http://www.fftoolbox.com:


import org.cyberneko.html.parsers.SAXParser;

class FFToolbox {
public List getPlayerList(){
def playerList = []

//read the XML
['http://www.fftoolbox.com/football/2010/overall.cfm?page=1',
'http://www.fftoolbox.com/football/2010/overall.cfm?page=2',
'http://www.fftoolbox.com/football/2010/overall.cfm?page=3',
'http://www.fftoolbox.com/football/2010/overall.cfm?page=4'].each{url ->
def html = new XmlSlurper(new SAXParser()).parse(url)
def table = html.BODY.'**'.findAll{ it.name() == 'TABLE'}[0]
def rows = table.TBODY.children()[1..-2]

//convert to my BO
rows.each{ nextRow ->
def columns = nextRow.children()
playerList.add(new CheatSheetEntry(
rank: columns[0],
name: columns[1],
position: columns[2],
team: columns[3],
byeWeek: columns[4])
)
}
}
return playerList
}
}


Note that the import is from here and provides an HTML parser

Here is another example from ESPN.com:

class ESPN {
public List getPlayerList(){
def playerList = []

def url = 'http://sports.espn.go.com/fantasy/football/ffl/story?page=NFLDK2K10rankstop200'
def html = new XmlSlurper(new SAXParser()).parse(url)

def table = html.BODY.'**'.findAll{ it.name() == 'TABLE'}[0]
def rows = table.TBODY.children()

rows.each{nextRow ->
def columns = nextRow.children()
def positionMatcher = columns[3].text() =~ /\D+/
playerList.add(new CheatSheetEntry(
rank: columns[0],
name: columns[1].text().substring(0, columns[1].text().indexOf(",")),
position: positionMatcher[0],
team: columns[1].text().substring(columns[1].text().indexOf(",") + 2),
byeWeek: columns[2])
)
}

return playerList
}
}


Basically they do the same things: Connect to and parse the url(s), find the table with the cheat sheet, and then go through the rows and columns assigning the correct values to a GroovyBean called CheatSheetEntry.

Now I just need to combine the lists somehow to get an average ranking of the players.

Read more...

My Facebook Privacy Settings



>> Tuesday, July 27, 2010

There has been a lot of talk in the news about Facebook and their privacy/security settings. Here is how I have set up my account to make sure only certain people can see certain parts of my Facebook profile.

Step 1 - Create Friend Lists

All of the privacy settings are based on which lists of people can see which parts of your profile, so the first step is to create those lists. The two lists we want to create now are:

  • Full Access: used for your friends that can see all of your profile.
  • No Access: used for the "friends" that you don't want to see anything on your page
Everyone who falls between these two lists will just get "default" access, and we don't need to create a list for them since they are part of your "all friends" list.

To create a list, click on "Friends" on the right side


Then click on "+ Create a List," give it a name and pick which people you want in the list.

Step 2 - Set Up Privacy

Go to the privacy settings. Then choose "Custom" and then "Customize Settings"

For each item that you want to restrict (I do all of them), select the drop down, and choose "Custom"



Then say "Specific People" and choose the "Full Access" list (or whatever you called it)

You can choose what you want each group to see. If you only want the "Full Access" people to see something, do what I mentioned above.

If you want all of your friends except the "No Access" group, do this:

Note: if you say "Everyone" that is everyone in the world, not just your friends.

Repeat this for all the items under "Things I share," "Things others share," and "Contact information."

Step 3 - Protect your pictures

Privacy for your photos is set up per album. Go to this link to change the privacy settings for each album.

Step 4 - Preview your changes

One useful tool Facebook provides is allowing you to see your profile as your friends see it. Go back to the privacy setting in step 2 and click the button at the top labeled "Preview My Profile." Click that and you will be able to type in a friend's name and see what they will see of your profile. Try it with people in your new lists.


If you see something that doesn't look right, go back and update your privacy settings.

Summary

This should be enough to get you started. If you want to be more specific, just create more than two friend lists. For example, I have a "Work People" list that can see my employers and education, but most of those people aren't in the "Full Access" list so they can't see all my pictures.

If you have any questions, let me know.

Read more...

Route Finding Code



I uploaded the full source-code for the Route Finding Problem and the Touring Problem.

Source Code (box.net)

Read more...

Extending to Traveling Salesman Problem



>> Monday, July 19, 2010

My next step in my A.I. investigation was to extend the route-finding problem to do a touring problem. This is basically a simplified traveling salesman problem where you pick a starting node and have to visit each node one time.

This turned out to be pretty easy with the code I already had. I first created a new interface called Goal with just one method:

public interface GoalInterface {
public boolean goalMet(State currentState);
}
For the existing route finding problem, I moved the goalTest method to an implementation of this interface:

@Override
public boolean goalMet(State currentState) {
return currentState.getCurrentNode().getNodeName()
.equalsIgnoreCase(goalNode.getNodeName());
}
Note that the constructor for this goal takes in the goalNode

Then I just updated the RouteFindingProblem to take a Goal (described below) instead of an goalNode.

The new signature for solve:
public Path solve(final Node initialNode, final GoalInterface goal) { }

And instead of calling the goalTest method, I just call goal.goalMet(). At this point the initial route-finiding problem produces the same results and all the tests still pass.

For the touring problem, I just had to create a new goal. The goalMet() method just checks if every node has been visited by calling this method:
private boolean isEveryNodeVisited(final State currentState) {
boolean tourComplete = true;
final List<Action> currentPathActions = currentState.getCurrentPath()
.getActions();
final Set<Node> currentlyVisitedNodes = new HashSet<Node>();
for (Action nextPathAction : currentPathActions) {
currentlyVisitedNodes.add(nextPathAction.resultOfAction(allNodes));
}

// make sure all nodes were visited
for (Node nextNode : allNodes) {
if (!currentlyVisitedNodes.contains(nextNode)
&& !nextNode.getNodeName().equalsIgnoreCase(
initialNode.getNodeName())) {
tourComplete = false;
break;
}
}
return tourComplete;
}

A couple things about this. First, it is not very efficient, but for my testing that is not a big deal. Next, I had to add an extra check for the initialNode since the path that is stored in currentState has a list of actions after the initialNode, but does not include the initialNode.

The last thing I had to do was simplify the map. Since my map of Romania had a few branches that had only one route, there was no way to visit each city only one time. I just "trimmed" the branches and ended up with these segments:

segments = [
new Segment(start:"Arad", end:"Zerind", cost:75),
new Segment(start:"Arad", end:"Sibiu", cost:140),
new Segment(start:"Arad", end:"Timisoara", cost:118),
new Segment(start:"Bucharest", end:"Fagaras", cost:211),
new Segment(start:"Bucharest", end:"Pitesti", cost:101),
new Segment(start:"Craiova", end:"Drobeta", cost:120),
new Segment(start:"Craiova", end:"Pitesti", cost:138),
new Segment(start:"Craiova", end:"Rimnieu Vilcea", cost:146),
new Segment(start:"Drobeta", end:"Mehadia", cost:75),
new Segment(start:"Fagaras", end:"Sibiu", cost:99),
new Segment(start:"Lugoj", end:"Mehadia", cost:70),
new Segment(start:"Lugoj", end:"Timisoara", cost:111),
new Segment(start:"Oradea", end:"Sibiu", cost:151),
new Segment(start:"Oradea", end:"Zerind", cost:71),
new Segment(start:"Pitesti", end:"Rimnieu Vilcea", cost:97),
new Segment(start:"Rimnieu Vilcea", end:"Sibiu", cost:80)
];

Then I ran these tests in Groovy:

//make sure each node results in a path
nodes.each {assert problem.solve(it, new TouringGoal(it, nodes)) != null}
//check a couple paths
assert 1327 == (problem.solve(findNode(nodes, "Arad"), new TouringGoal(findNode(nodes, "Arad"), nodes))).getPathCost();
assert 1294 == (problem.solve(findNode(nodes, "Sibiu"), new TouringGoal(findNode(nodes, "Sibiu"), nodes))).getPathCost();

And finally I did a test to display the results in Groovy:

Node testNode = findNode(nodes, "Bucharest");
Path resultPath = problem.solve(testNode, new TouringGoal(testNode, nodes));
//display the results
println("Shortest tour from " + testNode.toString());
if(resultPath == null){
println("No route found");
} else {
for (Action nextAction : resultPath.getActions()) {
println(nextAction.toString());
}
}

With the results:

Shortest tour from In(Bucharest)
Go(Pitesti)(101)
Go(Rimnieu Vilcea)(97)
Go(Craiova)(146)
Go(Drobeta)(120)
Go(Mehadia)(75)
Go(Lugoj)(70)
Go(Timisoara)(111)
Go(Arad)(118)
Go(Zerind)(75)
Go(Oradea)(71)
Go(Sibiu)(151)
Go(Fagaras)(99)

Let me know if you have any questions or suggestions on improvements!

Update 7/27/10: Uploaded the source code.

Read more...

  © Blogger template Webnolia by Ourblogtemplates.com 2009

Back to TOP