Thursday, June 17, 2010

Unemployed in Summertime – Programming

Emiliana Torrini - Love in the Time of Science - Album Cover 

I’ve always wanted to work in Unemployed in Summertime since I first heard this song by Emiliana Torrini (from her Love in the Time of Science release). Alas, it applies to my situation now – at least for a few more weeks. In the space before my next trick (the last trick a la Anja Garbaek?) I’m taking some time to see what’s the latest in programming languages – since I feel like a pre-dinosaur of sorts (see for example diictodon which plays a role in the interesting BBC series Walking with Monsters that we saw recently.) Anyways, I found the TIOBE index and the LangPop* index of languages which rate programming languages by popularity. What’s popular as a measure is problematic as pointed out elsewhere, however, it is not without interest as a measure of some kind of common currency of communication. I guess I felt a bit deflated since the top 5 languages of the TIOBE index and the top 4 of the LangPop index are not languages I use at all. So I grit my teeth and decided to take a look at Python (not the snake) because I overheard a teenager talking about how awesome Python is. Maybe it's not the best reason for picking up a new language, but I'm unemployed in summertime so I have the luxury of entertaining bad motivation - at least for a little while.

* This link "http://langpop.com/" used to work, but hey nothing lasts forever on the internet.

Monday, June 14, 2010

Nightblooming Cereus (E. oxypetalum)

Epiphyllum oxypetalum
A friend gave us an Epiphyllum oxypetalum plant a few months ago, one of the several species with the common name night-blooming cereus that are members of the Cactus family. I’m pretty sure ours is E. oxypetalum. The plant itself is honestly a bit gangly with an unruly growth habit, though not without its charm. E. oxypetalum’s special treat is its one-night, fragrant blooms. So far we haven’t experienced any blooms and it looks like we won’t this year. The friend shared some blooms from previous years so we know what we are in store for.

The first thing we did is cut it back (late spring) as it had one large stem that dwarfed the main plant. From what we’ve read, new blossoms come on new growth. From that cut stem we took several leaves and propagated them very easily. The method we used was to place the lower part of the dried-off leaf between two moist paper towels. In a week or so, roots develop. Then we cut the paper towel out (as the roots were stuck pretty well to it) and put it in soil. The photo with this post shows two potted plants, one sprouting new growth from the leaf and the other sending up new stems from the base. The photo also shows some other starts in paper towel.

Name origins: Epi = on or over and phyllum = leaf. The genus name refers to the fact that the blooms are on the margins of the leaves. Oxy = sharp, from the Greek “oyxs,” and petalum = petal. The species name refers to the bloom’s sharp-looking petals? (I don't remember them being much more than sharp-looking.) The common name cereus = Latin for “waxy” referring to the waxy nature of the plant leaves and stems.

Wednesday, June 9, 2010

Facebook Simple Integration



In a previous post we looked at the Graph API as resource for reading and writing Facebook data. In this post we look at a simple Facebook integration. A Facebook integration is about tapping into, extending, and enriching (with new experiences) a user’s social graph. If a Facebook user can sign on to a non-Facebook site using Facebook credentials, and the user authorizes the site to access some of his FB data, then any content on the site can be recommended or shared with the user’s friends – to illustrate a simple scenario. The user’s social graph in this scenario has been extended. Before you start an integration you should consider the following:

  • What’s your end result? Is your end result going to be web page that is external to Facebook like TripAdvisor (with FB login button e.g.) or is it going to be an application that runs within Facebook (i.e. has the Facebook chrome around it) like the TripAdvisor Travel Map (see the application directory for more applications)? Or will it be both external and internal to FB. In this post, I’m tackling the first scenario (external), though the code can be used for the second scenario as well.


  • How are you going to render your content? Are going to use IFrames or Facebook Markup Language (FBML) ? This topic discusses the choices. I started with FBML because without any prior experience with Facebook development the documentation (by my reading) seemed to suggest to go that way. As I got into it I found that not all the FBML features are, shall we say, well-baked and I ran into lots of little problems that took time to figure out. I also used the new JavaScript API as opposed to the old one, because the docs recommended it.
Before showing the code there are a couple of things to point out.

1) If you are using FBML like fb:login-button or fb:comments don’t forget to include a namespace declaration so that the prefix “fb” is understood. They rarely mention this in the docs.

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:fb="http://www.facebook.com/2008/fbml">


2) Don’t forget to include a script reference to the FB SDK. (In this code sample below I did not load the SDK asynchronously as recommended, but that ‘s easy enough to do following the code sample here.)

<script src="https://connect.facebook.net/en_US/all.js" type="text/javascript"></script>



3) In this code sample, I use jQuery as well, so I load that too. It doesn’t matter where you load it from; the sample here loads it from the Microsoft CDN.

<script src="https://ajax.microsoft.com/ajax/jquery/jquery-1.4.2.min.js" type="text/javascript"></script>


4) The FBML tag for like functionality fb:like did not work. had to resort to using an iframe. Last I saw there was a bug open for it.

5) At first I used server-side handling of the FB cookie, that is checking for it and pulling out the necessary information, like tokens. I used the C# approach here. Then I would pass the cookie info from the server-side to the client-side for use in JavaScript. Then, I discovered by chance that you could get the cookie easily using FB.cookie.load() method by playing around with the FB Test Console page. I would have expected this to be called out in the JavaScript SDK page but it wasn’t. In the end, the code sample below examines the cookie but doesn’t really use its information. I guess to the credit of the JavaScript SDK they’ve designed it so you don’t have to work with the cookie for common scenarios.

6) The FB login button doesn’t have a counterpart, log out. I was expecting that. So you have to provide your own log out feature and manage the displaying and showing of it and the FB login button. When the user is logged in, don’t show the FB login but show logout.

7) The code sample below worked in Firefox 3.6.3 and Chrome 5.0.375. But alas, IE 8.0 presented several problems where the consent/authorization dialog would not go away and the page ½ functioned. I saw mentions of this behavior in the forums, but did not pursue. Hopefully it gets worked out.

8) The div with id=”fb-root” is required, but nowhere is there a hint as to why it’s needed. Looking at the all.js file it looks like it might be used for cross domain communication when dealing with older browsers. Debugging and looking at what was inside the fb-root div during various times in the page lifecyle, I never saw anything in the div but that’s probably because I’m using a “modern” browser. In fact, I looked at the FB.XD._transport variabel and confirmed I was using “postMessage” capabilities of HTML 5 – which is the latest and greatest.

Here’s the code sample, a simple HTML page. You must run this file in the context of a web site. For example, register an application and get an application ID at Facebook, host the page on a web site locally on your test server (the same domain you registered), and place this page in the web site and browse to it. I used HTTPS for all my tests.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:fb="http://www.facebook.com/2008/fbml">
<head runat="server">
<title>Facebook Integration - Test</title>
<script src="https://ajax.microsoft.com/ajax/jquery/jquery-1.4.2.min.js" type="text/javascript"></script>
<script src="https://connect.facebook.net/en_US/all.js" type="text/javascript"></script>
<script type="text/javascript">
var fbCookie = {
accessToken: null,
signature: null,
userId: null,
secret: null
};

$(document).ready(function () {
FB.init({
appId: '107702769253652', // Fill in your correct AppID
status: true, // check login status
cookie: true, // enable cookies to allow the server to access the session
xfbml: true
});
});

FB.Event.subscribe('auth.sessionChange', function (response) {
if (response.session) {
// A user has logged in, get cookie information.
fbCookie.accessToken = FB.Cookie.load().access_token;
fbCookie.signature = FB.Cookie.load().sig;
fbCookie.userId = FB.Cookie.load().uid;
fbCookie.secret = FB.Cookie.load().secret;
$('#Login').css('display', 'none');
$('#Logout').css('display', 'inline');
} else {
// No session. Take action if needed.
}
});


function DoLogout() {
FB.logout(function (response) {
// User is now logged out
$('#Login').css('display', 'inline');
$('#Logout').css('display', 'none');
});
}

function GetDataAboutMe() {
FB.api('/me', function (response) {
$('#UserData').html("Name: " + response.name + ", gender = " + response.gender +
", birdthday = " + response.birthday + ", email = " + response.email);
});
}

function GetDataAboutFriends() {
FB.api('/me/friends', function (response) {
var sb = "";
for (var i = 0; i < response.data.length; i++) {
sb += "Friend" + i + ": " + response.data[i].name + " (" + response.data[i].id + ")<br/>";
}
$('#FriendData').html(sb);
});
}

function PostToNewsFeed() {
var body = $('#TextBox3').val();
FB.api('/me/feed/', 'post',
{
message: body,
name: "Test Post",
caption: "Test Post Caption",
description: "Test Description",
link: "http://travelmarx.blogspot.com"
}
, function (response) {
if (!response response.error) {
$('#PostResults').html("Error posting to news feed. Error: " + response.error.message);
}
else {
$('#PostResults').html("Posted to news feed successfully.");
}
});
}
</script>
<style type="text/css">
#Logout {display: none; }
</style>
</head>
<body>
<form id="form1" runat="server">
<div>
<div id="fb-root">
</div>
<h3>
Login Functionality</h3>
<fb:login-button perms="email,user_birthday,read_stream,publish_stream,read_friendlists"
id="Login">
</fb:login-button>
<input type="button" value="logout" id="Logout" onclick="DoLogout()" />
<hr />
<h3>
Like Functionality (using iframe because fb:like wasn't working)</h3>
<img src="Folder.jpg" width="100px" />
<iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Ftravelmarx.blogspot.com&amp;layout=standard&amp;show_faces=true&amp;width=450&amp;action=like&amp;colorscheme=light&amp;height=80
scrolling="no" frameborder="0" style="border: none; overflow: hidden; width: 450px;
height: 80px;" allowtransparency="true"></iframe>
<hr />
<h3>
Comments</h3>
Comments about this integration site? <br />
<fb:comments>
</fb:comments>
<hr />
<h3>
Getting Graph API Data</h3>
<input type="button" id="Button1" value="Get Data About Me" onclick="GetDataAboutMe()" />
<span id="UserData"></span>
<br />
<input type="button" id="Button2" value="Get Data About Friends" onclick="GetDataAboutFriends()" />
<span id="FriendData"></span>
<br />
<fb:prompt-permission perms="read_stream,publish_stream">Would you like our application to read from and post to your News Feed?</fb:prompt-permission>
<br />
<input type="button" id="Button3" value="Post to News Feed" onclick="PostToNewsFeed()" />
<input type="text" id="TextBox3" />
<span id="PostResults"></span>
<br />
<hr />
<h3>
Activity</h3>
<fb:activity recommendations="true">
</fb:activity>
</div>
</form>
</body>
</html>

Sunday, June 6, 2010

Facebook Graph API – A First Look

Trying the Facebook Graph API in a Browser
The Facebook Graph API is for developers who want to integrate with Facebook and read and write data from Facebook. (The docs are here – sometimes it makes me sign in to see the doc!?) What you need to know to start is that “graph” really means a “social graph”. For example, a user’s social graph includes all the things important to a user like people, photos, friends, and shared content. Data in a social graph falls into two categories: objects (like people, photos, and events) and connections between objects (like relationships, shared content, and tags). When you work with the Graph API you’ll be working with objects and connections.

The “normal” way to use the Graph API is to get an application ID (here) that represents your company or application. Then, on a page of your web site you set up the infrastructure using one of the APIs (e.g. the JavaScript API) so that when a user comes to your page, hits the Facebook login button, and authorizes your web site to access data, the Graph API would be used behind the scenes. In a future post I'll cover that.

You can start getting familiar with the Graph API without an application ID by just constructing Graph API requests directly in a URL. Note, that Chrome and Firefox browsers display the JSON results of these requests directly in the browser which is nice. If you put the URL above in the address bar of Internet Explorer it will ask you want to do. You can download it somewhere, name it .txt and view it. Just more work.

If you put this URL (https://graph.facebook.com/68310606562?metadata=1) for the founder of Facebook, Mark Zuckerberg, into the address bar of Chrome you get the publicly available data for his page (an object). The “?metadata=1” part of the URL requests that connection information for the object be shown. The results of the Graph request above will give additional Graph requests you can follow and drill down into the data. So for example, take Mark Zuckerberg’s photos link (https://graph.facebook.com/68310606562/photos) and put that in the browser address line and so on.

This is what I started doing at first for myself and friends - Graph requests in a browser - to see how it worked. Then, I wanted to automatically check all the links without doing so much cutting and pasting and that’s where the code shown below comes in play. I created a first version and then found this page (http://zesty.ca/facebook/) and created a second page with some of the good ideas I found there. I wanted to play around with jQuery and issuing Ajax requests from the page so that drove the design of my page. My page checks all the connection links and displays the results (what was found) in the page. The previously mentioned link (zesty.ca) is a simpler and slicker page in that it’s just based on navigating to URLs.
Using the Graph API to Look at a Page
Drill Down on Feed
Using the Graph API to Drill Down to Feed
Graph API Looking at a User's Info

A Javascript Program To Work With Facebook API
The code below uses the ajax method of jQuery to get data from the Facebook Graph API. No data is written back. A big gotcha is that I could only run this code successfully in Internet Explorer. In Chrome or Firefox, it was a no go. I didn’t troubleshoot enough to find out why, though I saw others had problems with the ajax method in these browsers. I’ll revisit the issue.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Using the Facebook Graph API</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
var baseUrl = "http://graph.facebook.com/";
var pageUrl = window.location.protocol + "//" + window.location.hostname + window.location.pathname;
var notDef = "Not Defined";
$(document).ready(function () {
$('#Go').click(function () {
window.location.href = pageUrl + "?check=" + $('#Input').val();
});
if (window.location.search.indexOf("check") > -1) {
var params = window.location.search.split("=");
$('#Input').val(params[1])
checkGraphAPI(params[1]);
}
});
function checkGraphAPI(itemToCheck) {
$.ajax({
url: baseUrl + itemToCheck + '?metadata=1',
async: false,
data: null,
dataType: 'json',
success: function (data) {
$('#Output').html("");
bShowOnlyVisible = $('#ShowFlag').attr('checked');
processObjectResults(data, 0, "object");
processConnectionResults(data);
},
error: function (xhr, ajaxOptions, thrownError) {
$('#Output').html("Can't load anything. Could be invalid Graph API request.");
}
});

}
function processObjectResults(data, level, idFrag) {
if (data !== null) {
var objKeys = [];
for (var objKey in data) {
objKeys.push(objKey);
}
// Get object properties.
for (var i = 0; i < objKeys.length; i++) {
var property = data[objKeys[i]];
if (property === undefined || property === null) {
createOutputElement(objKeys[i], notDef, "Good", "child", level, idFrag + objKeys[i]);
}
else {
if (property.constructor === Object || property.constructor === Array) {
createOutputElement(objKeys[i], "", "", "openparent", level, idFrag + objKeys[i]);
processObjectResults(property, 1, objKeys[i]);
createOutputElement("", "", "", "closeparent", level, idFrag + objKeys[i]);
}
else {
createOutputElement(objKeys[i], property, "Norm", "child", level, idFrag + objKeys[i]);
}
}
}
}
else {
$('#Output').append("Couldn't look up the object. Could be permissions related.");
}
}
function processConnectionResults(data) {
if (data !== null) {
// Get connection properties.
var connections = data.metadata.connections;
var connKeys = [];
for (var connKey in connections) {
connKeys.push(connKey);
}
for (var j = 0; j < connKeys.length; j++) {
var conn = connections[connKeys[j]];
doConnectionCheck(conn, "connections" + connKeys[j]);
}
}
else {
$('#Output').append("Couldn't look up the connections. Could be permissions related.");
}
}
function doConnectionCheck(url, elem) {
$.ajax({
url: url,
async: true,
context: $('#' + elem),
dataType: "json",
success: function (response) {
if (response !== null) {
if (response.data) {
if ((response.data).length === 0) {
$(this).append(" - No Data Found");
}
else {
$(this).append(" - Visible");
}
}
else {
$(this).append(" - Unknown");
}
}
},
error: function (xhr, ajaxOptions, thrownError) {
var errMsg = "Error Viewing." + " Found: " + xhr.status + ", " + xhr.statusText;
$(this).append(" - " + errMsg);
}
});
}
function createOutputElement(prop, text, style, type, level, id) {
var div1 = document.createElement("<div>");
var div2 = document.createElement("<div>");
div1.style.width = 120 + parseInt(level) * 30;
div2.id = id; // where the results go
div1.className = "Prop";
div2.className = style;
switch (type) {
case "child":
div1.innerHTML = prop + " = ";
var link = text;
if (text.toString().indexOf(baseUrl) > -1) {
link = text.split(baseUrl)[1];
}
if (text !== notDef) {
if (prop === "picture" || prop === "icon") {
var img = document.createElement("<img/>");
img.src = text;
div2.innerHTML = img.outerHTML;
}
else {
div2.innerHTML = createHyperlink(link) + " ";
}
}
else {
div2.innerHTML = text + " ";
}
break;
case "openparent":
div1.innerHTML = prop + " { ";
break;
case "closeparent":
div1.innerHTML = " } ";
break;
}
$('#Output').append(div1.outerHTML + div2.outerHTML);
}
function createHyperlink(link) {
var a = document.createElement("<a>");
a.href = pageUrl + "?check=" + link;
//a.target = "_blank";
a.innerHTML = link;
return a.outerHTML;
}
</script>
<style type="text/css">
body { font-family: Verdana;}
div { float: left;}
div.Prop { width:120px; text-align: right; clear: left;}
div.Bad {color: Red; font-weight: bold; }
div.Good {color: Green; font-weight: normal; }
div.Norm {color: Black; }
</style>
</head>
<body>
<div>
<h3>
Using the Facebook Graph API </h3>
Put in the ID or Friendly Name of a Facebook user in the text box below and then
hit go. For example you could enter "markzuckerberg" or his id "68310606562". To
find an ID of Friendly Name right click and view properties of the person/group/product
link in Facebook. This test does not require a Facebook account or to be logged into Facebook.
<br />
<input type="text" id="Input" value="" />
<input type="button" id="Go" value="Go" />
<br />
<span id="Output" ></span>
</div>
</body>
</html>

Saturday, June 5, 2010

The Getty Villa

Getty Villa - Outer Peristyle Garden

The design of the Getty Villa is based on the Villa dei Papyri, a private house in the ancient Roman city of Herculaneum (today Ercolano, near Naples) that was buried in AD 79 from the eruption of Vesuvius.

Villa dei Papyri was first discovered in the 1700s and got its name because of a library found inside the villa containing thousands of papyrus scrolls. Untangling and deciphering the badly burned and stuck together scrolls is ongoing as the Philodemus Project named after Philodemus (c. 100 – c. 40-35 BC), an Epicurean philosopher and poet whose work comprises the bulk of the library. Epicureanism in one compact sentence, that I’ll borrow, “taught that man is mortal, that the cosmos is the result of accident, that there is no providential god, and that the criterion of a good life is pleasure.”[*]

So what’s the Getty Villa like? We thought it was great. Sure it’s shiny and bright compared to what we saw in Pompeii – also subject to the same eruption, but less buried than Herculaneum. But who cares? It’s fun to experience an approximation of Roman villa in a form something close to what it must have been like. The collection of Greek, Roman, and Etruscan antiquities housed in the museum part of the villa is equally engaging. The collection is arranged around themes and one of the must-see artifacts is the statue of a Victorious Youth, but don’t let that be your only stop. I was awed by the Gold Wreath in the same room as the Victorious Youth.

The Getty Villa was first opened in 1974 adjacent to the ranch house owned by John Paul Getty (1892-1976) in Pacific Palisades (not Malibu!). The museum underwent extensive remodeling in 1997 and reopened in 2006. The newly added architecture surrounding the villa is designed to suggest an archaeological dig with many layers. Entrance to the Villa is free, but you must make a reservation ahead of time at time of writing. Parking is $15. One photo attached to this post is taken from the Outer Peristyle, the largest garden at the Getty Villa. We visited the villa back in April 2010. The picture was taken with the intent of saying something about the extensive use of Hedera helix (English Ivy) which surprised us but apparently was common in Roman gardens. I guess we’ve been reading the King County noxious weed warnings too much.

Getty Villa - Gold Wreath Getty Villa - Old Meets New

Wednesday, June 2, 2010

1/1000th

The Jousters - Getty Center
While in Los Angeles recently we really got a dose of what seemed like nanny state. There was not just one, but many incidents where rules and regulations seem a little bit much. Case in point is this display plaque for an outdoor sculptor at the Getty Center. Okay, the “Please do not enter” is in line with standard phrasing a museum would use. But below that is “Lead is a metal known to the State of California to cause reproductive harm.” After some research, I found out that this warning is the result of the controversial California Proposition 65. Is the warning useful here? What does it apply to, the plaque, the fencing, the border edging the lawn of dymondia? In what doses and exposures is there harm? On the Prop65 site they specify that “Businesses subject to Proposition 65 are required to provide a warning if they cause exposures to chemicals listed as causing birth defects or reproductive harm that exceed 1/1000th of the ‘no observable effect level’”. 1/1000th of no observable level!? Ponder that as you stand in the smog.