A while back, I wrote this blog series about how to build a Silverlight client for flickr. This seemed to be pretty popular among a bunch of the people who stumble across my blog. I don’t know if it was specifically because it was using flickr or if it was because it went through the entire application step by step or if it was something else. But since then, I have gone around thinking about other possible applications that I could dissect in the same way, and for some odd reason I stumbled across Twitter. I know…you don’t stumble across Twitter. It is all over the place, and anybody that hasn’t heard of it is probably dead or deaf and blind. I’m personally not that active on Twitter, even though I try on and off. For anyone interested, I’m available here.
Anyhow, after having looked at it for a while, I decided to create a Silverlight based Twitter application. Even though it’s not as fancy or useful as some of the other alternatives out there, it will show the basics behind how to build a client. And not a client that just allows you to read a feed, but actually interact with it and send tweets. If you are not interested in how to develop a Twitter client and just want a Silverlight based client, I would recommend Gadfly, which is a fantastic client compared to what I’m going to show. But the idea behind this blog series is not to get the coolest application, but have a look at how one could go about building a client.
The first step to getting started with a Twitter client is of course to get a Twitter account. This is easy, just run over to Twitter.com and sign-up if you haven’t already. After that, it is time to have a look at how you interact with Twitter. All of this information is readily available at Twitter’s developer wiki. Here you can find everything you need.
You will quickly find out three things about Twitter. First of all you will realize that the entire API is REST based. That means that all functionality is exposed using simple HTTP GET and POST requests to their server. The second thing you realize is that to be allowed to actually interact with a persons Twitter account, you need to get some form authorization going. And the third one is that there are a bunch of pre-built libraries that you can download and that will manage all communication with Twitter.
So…let’s start off by agreeing that I am not going to use a pre-built library. I’ve already seen a couple of blogs explaining how to create a Silverlight Twitter client using a pre-built library. That is probably the fastest and simplest way of doing it, but it is really boring. I want to take it from one end of the system to the other…a FULL application, not just a little shell that lives on top of somebody’s API library.
After I got that off my chest, it is time to take a look at authentication and authorization for Twitter. Twitter currently supports 2 forms of authentication, basic authentication and OAuth. The obvious way to build a client fast and simple would be to use basic authentication. That way, you just pass the username and password over the wire with each call. However, there are 3 downsides to this. First off, this is very insecure. The username and password will be passed back and forth between the client and Twitter in clear text… The next one is that Twitter stop supporting this in the future. It might be a long time until they do, but they will. OAuth on the other hand will live on, and is an open standard used not only by Twitter. So learning to use it is good. And finally, by having to pass username and password with the requests, means that the application must know these. Basically I need to tell the user of my client to hand over his or her credentials, which might be used in malicious ways.
So I have obviously opted for OAuth, which is a bit tedious and “interesting” in some ways, but still the best option. Once again, there are pre-built libraries…all of which I will ignore. I would however like to give shout out to Eran Sandler who created a basic C# class for performing OAuth signing. I haven’t used that as such, but I have borrowed pieces of that code in my implementation. But mostly, it explained how to do signing in a way that nobody else managed to do. Code says it so much better than words… :)
I started out with the idea that everything would be placed in my Silverlight application, which would perform all communication with Twitter. Unfortunately, this grinded to a complete stop quite quickly. Reading a feed (called Timeline on Twitter) is simple to do using Silverlight. That is just a HTTP GET request. However, as soon as you start looking at using OAuth and performing HTTP POST requests it all fails. Silverlight can’t do cross domain POST calls. A limitation that it shares with XMLHttpRequest. I found that out pretty quickly, since I decided that I might try using the JavaScript bridge to call out to the XMLHttpRequest object. Unfortunately this didn’t work. So I had to figure out a solution for this. And I guess there are two, which both include one sucky point…my server… I have to let the Silverlight client call back to the hosting server, which can then do one of two things. It can either work as a relay station and just forward my request as a proxy server, or expose webservices with the required functionality and let them talk to Twitter.
Since the server would have to be involved anyway, I decided for the latter. I might as well put the communication logic there and give the client a nice API to work against. This also makes it possible for me to create other clients for that functionality.
So, let’s get started with creating the application… Unfortunately there is a little bit more involved before we can go on. We need to have a look at how OAuth works. Since OAuth is all about security, it doesn’t at any point involve the client having access to the users username and password. Instead it works like this
- The client sends a request to Twitter (or whoever uses OAuth and you want to interact with) and requests an authorization token. This token is created based on some parameters sent to Twitter. In the response the client gets a token that can be used to generate a URL used in step 2
- The user is told to visit this URL, login and authorize the application to interact with the persons account.
- Twitter gives the user a PIN number and tells the user to return to the client
- The user feeds in the PIN code in the application
- The application contacts Twitter and tells it that it wants to exchange its authorization token for and access token, passing along the authorization token and the PIN number
- Twitter returns an access token.
This access token can then be used together with the PIN to access the users Twitter account until the user specifically tells Twitter to revoke that token. So the initial startup of the application will be a little cumbersome, but in the end it is worth it. Twitter supports a couple of other flows as well. You might especially be interested in the flow that redirects the user to a designated URL after having authorized the client. But I opted for this solution for a some reason…
So, how does Twitter know what application is trying to communicate with it? And how can this be secure when there is all of this information flying over the wire? Well, because it is all signed and includes a “consumer key” and a “consumer secret” that Twitter knows about. The key is sent back and forth with the requests, but the signature is generated using the secret. That way, Twitter can see who is calling by looking at the key, but also verify if the call is coming from the client and has not been modified. Pretty smart right…
But to be able to do what I have been talking about, you need a consumer key and secret. These can be generated by visiting http://twitter.com/oauth_clients. Here you can register your client and get your key and secret. This is by the way also a good reason to go via the server for the Silverlight communication. Otherwise, the secret would be compiled in the assembly in the Xap, and thus pretty easy to get hold of…
After having generated a key and a secret, it is time to get started. I started my Twitter application by handling the login methods. So I created a class that I called Twitter. Might have been smarter to call it something better, but I am not the most imaginative guy when it comes to names… Since I know that I can never communicate with Twitter without a key and secret, I added these as parameters to the constructor. I actually created 2 constructors. One that takes a key and a secret, and one that also takes an AccessToken. The second constructor will be used as soon as the user has gone through the registration procedure and the application has an AccessToken to use. It looks like this
public class Twitter
{
const string BASE_URL = "http://twitter.com/";
private AccessToken _accessToken;
private string _consumerKey;
private string _consumerSecret;
public Twitter(string consumerKey, string consumerSecret) : this(consumerKey, consumerSecret, null)
{
}
public Twitter(string consumerKey, string consumerSecret, AccessToken accessToken)
{
_consumerKey = consumerKey;
_consumerSecret = consumerSecret;
_accessToken = accessToken;
}
}
As you can see, I have also added a constant that holds the base address to the Twitter REST API. Why? Well…it’s nice having it in one place instead of spread out. And because I theoretically might be able to re-use this if some other service starts using OAuth.
If you look in the text above, you will see that step one in authenticating with Twitter is to request an authorization token. This is then used to create a URL and so on. To make the procedure simpler, I decided to wrap it up into one method called GetAuthorizationUrl. It returns a URL and has an out parameter for the actual authorization token.
public string GetAuthorizationUrl(out AuthToken authToken)
{
string resp = CallTwitterGetMethod("oauth/request_token", new List<QueryParameter>(), false);
authToken = AuthToken.Parse(resp);
return BASE_URL + "oauth/authorize?oauth_token=" + HttpUtility.UrlEncode(authToken.Token) + "&" + OAuthUtility.CallbackKey + "=oob";
}
The code above shows you exactly what is happening. Unfortunately most of the functionality is not visible since it is placed in other methods. So let’s dissect the involved code. But I will leave the CallTwitterGetMethod to the end, since it is the most complex.
The AuthToken class is not that complicated. It’s a class that holds 2 string properties, Token and TokenSecret. The AuthToken class implements a static Parse method to parse the response from Twitter. The response from Twitter will look something like this:
oauth_token=32844063-LcJ31sTP3RUVx8svgBkneFeuNgehmbmCLPOcDRGAp&oauth_token_secret=wnhwGIE8Qyh0l2V3uY9gT5mpuroENlrkN5TSu347BLU
So it needs to be parsed to get the useful pieces. The AuthToken class looks like this
[DataContract]
public class AuthToken
{
public AuthToken(string token, string tokenSecret)
{
Token = token;
TokenSecret = tokenSecret;
}
public static AuthToken Parse(string str)
{
string[] parts = str.Split('&');
string token = parts[0].Split('=')[1];
string tokenSecret = parts[1].Split('=')[1];
return new AuthToken(token, tokenSecret);
}
[DataMember]
public string Token { get; private set; }
[DataMember]
public string TokenSecret { get; private set; }
}
The only real functionality is the Parse method. I have also added DataContract and DataMember attributes to this class so that it can be used for webservices…more about this in later blog posts…
In the GetAuthorizationUrl I am then concatenating the base URL with the address of the authorization page, appending the token as well as a callback key. The OAuthUtility class is a utility class (duh…) containing helper methods as well as constants for the parameter name strings used when communicating with Twitter. So OAuthUtility.CallbackKey is just a const string with the value “oauth_callback”. I also make sure to UrlEncode the token.
So, what’s the magic in the CallTwitterGetMethod? Well…there is no magic at all. It is a method that helps out with the GET requests to Twitter. It has a sibling called CallTwitterPostMethod that helps with out with the POST requests.
The CallTwitterGetMethod takes 3 parameters. The name of the method to call, a list of QueryParamters to pass and a boolean indicating it is a call to a method that requires authentication. These parameters makes it possible to use this method to call any GET method on Twitter in a simple way. In the case of the CallTwitterGetMethod, I am passing in the method “oauth/request_token”, an empty list of parameters and false.
The QueryParameter class is a very simple. It basically a name/value class..
public class QueryParameter
{
public QueryParameter(string name, string value)
{
Name = name;
Value = value;
}
public string Name { get; private set; }
public string Value { get; private set; }
}
The first thing that the CallTwitterGetMethod does, is to verify if the call requires authentication. Depending on this, it calls one of two overloads for a method called GetSignedUrl. The GetSignedUrl is responsible for taking the different parts of the request and generate the URL to be used. This includes a few step. But lets first look at the rest of the CallTwitterGetMethod, just accepting that the GetSignedUrl method will give us a useful URL.
As soon as a URL has been created, the method instantiates a new HttpWebRequest, sets its Timeout a little higher configures it to use GET. After that, it makes the request and gets the response. It then returns the response as a string for further parsing. It looks like this
public string CallTwitterGetMethod(string methodName, List<QueryParameter> parameters, bool requiresAccessToken)
{
string url = null;
if (requiresAccessToken)
{
url = GetSignedUrl(BASE_URL + methodName, parameters, "GET", _accessToken.Token, _accessToken.TokenSecret);
}
else
{
url = GetSignedUrl(BASE_URL + methodName, parameters, "GET");
}
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.Timeout = 10000;
req.Method = "GET";
string response = null;
StreamReader sr = null;
try
{
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
sr = new StreamReader(resp.GetResponseStream());
response = sr.ReadToEnd();
}
finally
{
if (sr != null)
sr.Close();
}
return response;
}
So, lets go back to that mysterious GetSignedUrl method. That has to be magical…well…not really. But it does encapsulate some tedious work. First of all, it must gather all the parameters needed to make the call. Every single call to Twitter needs at least 5 parameters. So even if the call to GetSignedUrl passes an empty list of parameters, it will automatically add the necessary 5. The 5 required parameters are: oauth_version, oauth_nonce, oauth_timestamp, oauth_signature_method and oauth_consumer_key. The version is always 1.0. The timestamp is the current time represented as seconds since January 1 1970 (sweet!!!). The signature method used is HMAC-SHA1, which is the only one supported by Twitter. The consumer key is of course the key that Twitter has assigned our application. And finally, the nonce. The nonce is basically just a string that should be unique for the used timestamp. Only ASCII values are accepted by Twitter.
As you can see, there are two overloads. One with a token and token secret and one without. The one without just forwards the request to the other overload, passing String.Empty for those parameter. If a token is available, this is added as a parameter as well.
All parameters are then sorted alphabetically by name, before being concatenated into a querystring format, that is parameterName=value¶meterName2=value2. Finally, another string is created by concatenating the HTTP method being used (upper case) with the URL to the API method to call and finally with the querystring just created. The parts of the string are combined with an ampersand separating them. The end result would look something like this
GET&http://twitter.com/methodname¶meter1=value1¶meter2=value2
A hash is then generated from this string, using the consumer secret as the key. Finally, the signed URL is created by concatenating the URL, the querystring and adding the signature as a final querystring parameter.
protected string GetSignedUrl(string url, List<QueryParameter> parameters, string httpMethod, string token, string tokenSecret)
{
parameters.Add(new QueryParameter(OAuthUtility.VersionKey, "1.0"));
parameters.Add(new QueryParameter(OAuthUtility.NonceKey, OAuthUtility.GenerateNonce()));
parameters.Add(new QueryParameter(OAuthUtility.TimestampKey, OAuthUtility.GenerateTimeStamp()));
parameters.Add(new QueryParameter(OAuthUtility.SignatureMethodKey, "HMAC-SHA1"));
parameters.Add(new QueryParameter(OAuthUtility.ConsumerKeyKey, _consumerKey));
if (!string.IsNullOrEmpty(token))
{
parameters.Add(new QueryParameter(OAuthUtility.TokenKey, token));
}
OAuthUtility.SortParameters(parameters);
StringBuilder reqParams = new StringBuilder();
foreach (var param in parameters)
{
reqParams.AppendFormat("{0}={1}&", param.Name, param.Value.OAuthUrlEncode());
}
string normalizedRequestParameters = reqParams.ToString().TrimEnd('&');
StringBuilder signatureBase = new StringBuilder();
signatureBase.AppendFormat("{0}&", httpMethod.ToUpper());
signatureBase.AppendFormat("{0}&", url.OAuthUrlEncode());
signatureBase.AppendFormat("{0}", normalizedRequestParameters.OAuthUrlEncode());
string signature = OAuthUtility.HMACSHA1Encode(_consumerSecret, tokenSecret, signatureBase.ToString());
return url + "?" + normalizedRequestParameters + "&" + OAuthUtility.SignatureKey + "=" + HttpUtility.UrlEncode(signature);
}
There are a few interesting things to note in the previous code. First of all, I have some helpers in the OAuthUtility class for creating the Timestamp and the nonce. They are simple little things
public static string GenerateNonce()
{
return _random.Next(123400, 9999999).ToString();
}
public static string GenerateTimeStamp()
{
TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
return Convert.ToInt64(ts.TotalSeconds).ToString();
}
You might also have noticed that I am calling a method called OAuthUrlEncode on my strings. The reason for this is that before the generation of the hash, the strings must be URL encoded. Unfortunately, the HttpUtility.UrlEncode method in the framework doesn’t work. Why? Well, when UrlEncoding your parameters, any encoded character should be encoded using %xx. The xx is hex and the HttpUtility version uses the wrong casing for this. So I created an extension method to the String class to handle this for me. It looks like this
public static string OAuthUrlEncode(this string value)
{
StringBuilder result = new StringBuilder();
foreach (char symbol in value)
{
if (ALLOWED_CHARS.IndexOf(symbol) != -1)
{
result.Append(symbol);
}
else
{
result.Append('%' + String.Format("{0:X2}", (int)symbol));
}
}
return result.ToString();
}
So, after that huge sidestep looking at all sorts of helpers, I am done with the code needed to complete the GetAuthorizationUrl method. After the user has used this URL to authorize the application, it is time to use the acquired PIN code to exchange the authorization token for an access token. This is done in the GetAccessToken method. This method is a little special. It is the only method I have created that doesn’t use any of the request helper methods. Why? Well, it was simpler to do it manually for this one.
What makes that method so special? Well, nothing really, but I had a hard time to get my helpers to work nicely with 2 different kind of tokens without making them complicated. In this case, I need to pass both my authorization token as well as my access token. So this is how I implemented it.
First of all, the method needs two parameters. The PIN and the authorization token from the previous method. After that, it creates a list of QueryParameters. The list is populated with one single parameter, the oauth_verifier parameter. The value for it is the PIN. After that it calls the GetSignedUrl method. However, this time it passes in the method name “oauth/access_token” and POST as HttpMethod. It then simply uses a WebClient to make the request and download the response. It is kind of funky that this works. Twitter expects this to be a POST, but has no problems what so ever to handle a GET request with the parameters passed as querystring parameters… Nice! Finally, it creates a AccessToken class by calling its Parse method.
public AccessToken GetAccessToken(string pin, AuthToken authToken)
{
List<QueryParameter> parameters = new List<QueryParameter>();
parameters.Add(new QueryParameter(OAuthUtility.VerifierKey, pin));
string url = GetSignedUrl(BASE_URL + "/oauth/access_token", parameters, "POST", authToken.Token, authToken.TokenSecret);
WebClient client = new WebClient();
string resp = client.DownloadString(url);
return AccessToken.Parse(resp, pin);
}
The AccessToken class is more or less identical to the AuthToken, but holds 2 more properties, the PIN and the ScreenName for the user. So I won’t show it…
That was two methods down. Three to go. However, they are much simpler since we have already seen most of the helper methods…
Lets start by looking at the final “user account method”, the VerifyCredentials method. This method can be called to verify that the users haven’t revoked the access token since last use of the application. The REST API method name is “account/verify_credentials.xml”. The “.xml” tells the system to return the information as XML. It is also possible to get the result as Atom or RSS or JSON. But I like XML. It takes no parameters except the required ones. So the call looks like this
public User VerifyCredentials()
{
string response;
List<QueryParameter> parameters = new List<QueryParameter>();
try
{
response = CallTwitterGetMethod("account/verify_credentials.xml", parameters, true);
}
catch (Exception ex)
{
HandleException(ex);
return null;
}
XDocument doc = XDocument.Parse(response);
return User.Parse(doc.Root);
}
As you can see, it returns a User object. Once again, I have created a static Parse method to handle the extraction of information from the Xml document. The User object is just another simple object with properties corresponding to the values returned from Twitter in Xml form. The properties are ID, Name, ScreenName, Location, Description and ProfileImageUrl. The Location is still not really implemented, but I liked the idea of using it in future experiments. The class also has DataContract and DataMember attributes for passing over the wire.
The final two methods in the Twitter class is about getting the the users timeline (the feed) and updating the users status (tweeting). Lets start by looking at the users feed.
Once again, the code is pretty much the same as the previous methods. As soon as you got the “helper” methods down, the actual methods using them tend to be simple. This also makes it VERY easy to extend this class to support more of the Twitter API. The GetTimeline method takes two nullable parameters, sinceId and count. The sinceId parameter will tell Twitter only to get tweets tweeted after the tweet with ID=sinceId was tweeted. And the count is the amount of tweets to get back. If either of these aren’t null, they are added to the QueryParameter list. After that the CallTwitterGetMethod is used to call the “statuses/friends_timeline.xml” method. The response is then read into a XDocument, which is then traversed using a Linq expression pulling out Tweet objects.
public Tweet[] GetTimeline(long? sinceId, int? count)
{
string response;
List<QueryParameter> parameters = new List<QueryParameter>();
if (sinceId.HasValue)
{
parameters.Add(new QueryParameter("since_id", sinceId.Value.ToString()));
}
if (count.HasValue)
{
parameters.Add(new QueryParameter("count", count.Value.ToString()));
}
try
{
response = CallTwitterGetMethod("statuses/friends_timeline.xml", parameters, true);
}
catch (Exception ex)
{
HandleException(ex);
return null;
}
XDocument doc = XDocument.Parse(response);
var tweetQuery = from tweet in doc.Descendants(XName.Get("status"))
select Tweet.Parse(tweet);
return tweetQuery.ToArray();
}
The Tweet class is, just like the token classes and the User class, “instantiations” of the returned Xml and implements a Parse method. The only interesting part of that class is the way it parses the creation date property. Twitter returns the date in a somewhat useless format, e.g. Wed Sep 16 04:13:03 +0000 2009. So this needs to be manually parsed. I did it using the following method, but I have seen some other ways of doing it
static DateTime ParseDateTime(string date)
{
string dayOfWeek = date.Substring(0, 3).Trim();
string month = date.Substring(4, 3).Trim();
string dayInMonth = date.Substring(8, 2).Trim();
string time = date.Substring(11, 9).Trim();
string offset = date.Substring(20, 5).Trim();
string year = date.Substring(25, 5).Trim();
string dateTime = string.Format("{0}-{1}-{2} {3}", dayInMonth, month, year, time);
DateTime ret = DateTime.Parse(dateTime);
return ret;
}
The final method in the Twitter class is the one used to tweet, or as Twitter calls it, update the users status. Once again the method is quite simple. It passes along two QueryParameters to a helper method method, one with the new status and one with the PIN used to create the AccessToken. The main difference is that it calls a different helper than before. The previous methods have used HTTP GET and not POST. This uses POST and thus needs a different implementation. But lets first look at the boring code
public bool UpdateStatus(string status)
{
string response;
List<QueryParameter> parameters = new List<QueryParameter>();
parameters.Add(new QueryParameter(OAuthUtility.StatusKey, status));
parameters.Add(new QueryParameter(OAuthUtility.VerifierKey, _accessToken.PIN));
try
{
response = CallTwitterPostMethod("statuses/update.xml", parameters);
}
catch (Exception ex)
{
HandleException(ex);
return false;
}
return true;
}
Nothing impressive here… Let’s go on…
The CallTwitterPostMethod is a little different than the previous one. It still starts out by getting a signed URL by calling the GetSignedUrl method, but after that it changes… It starts by stripping out the querystring part of the URL. This will be posted instead of sent as querystring parameters. After that, it creates a new HttpWebRequest using the querystringless (is that even a word? I think not, but I guess you know what I mean…) URL. And this method also ups the Timeout a bit and sets the Method. In this case the Method is set to “POST”. It then proceeds with changing the content type. The post will be made using "application/x-www-form-urlencoded". The next line of code is a trick to get around a problem with the HttpWebRequest. For some reason it defaults to using a feature called Expect100Continue. This needs to be turned off. You can read more about it if you just Google the word Expect100Continue. Most or the returned sites will probably be about Twitter…
Next is sets the content length, gets the request stream and sends the querystring into the stream using a StreamWriter. It then gets the response and turns it into a string that is returned from the method.
private string CallTwitterPostMethod(string methodName, List<QueryParameter> parameters)
{
string url = GetSignedUrl(BASE_URL + methodName, parameters, "POST", _accessToken.Token, _accessToken.TokenSecret);
string queryString = new Uri(url).Query.Substring(1);
string baseUrl = url.Substring(0, url.IndexOf("?"));
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(baseUrl);
req.Timeout = 10000;
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ServicePoint.Expect100Continue = false;
req.ContentLength = queryString.Length;
StreamWriter sw = new StreamWriter(req.GetRequestStream());
sw.Write(queryString);
sw.Close();
string response;
StreamReader sr = null;
try
{
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
sr = new StreamReader(resp.GetResponseStream());
response = sr.ReadToEnd();
}
finally
{
if (sr != null)
sr.Close();
}
return response;
}
That’s it! That’s the Twitter class with all its helpers. In the downloadable code that will be posted at the end of the series you will actually see a few more classes. A base class to help with a little Xml stuff and some Twitter specific exceptions. But I didn’t feel that they were needed in this already way too long blog post.
I hope you have enjoyed this first part. As always it turned out to be longer than it was supposed to, but I felt that a good understanding of the topic might actually help out a bit.
The goal is to cover the webservices in the next post, which will probably go up early next week. After that it will be the view models and finally some ugly UI. This time I have actually created a nice looking UI as well, but that will be in the downloadable code only, as it adds unnecessary complexity to the project.
So, stay tuned for more Twitter client information. If you have any questions or comments just post them as usual! (Not that anyone ever does…or at least very few…).
Since I have a busy schedule at work at the moment, I’m not sure when the future posts will go up. I will try to get them online as soon as possible. But I would recommend subscribing to my RSS feed to get notified when they do go up…
Cheers!
PS: There is a serious lack of safety checks in the code…it is only demo. If you mean to use it, you should add checks making sure the correct values are passed to methods and so on.
PPS: You might also want to track the amount of requests being sent to Twitter since they have limited some of the calls to 150 per hour. That might seem like a lot, but when testing and developing, it is consumed fantastically fast…
[UPDATE]
Part 2 is now available
as well as Part 3 and Part 4 and Part 5