Archive for the 'Twitter' Category

How do I ‘like’ your course? The value of Facebook recommendation

For the JISC Winter Fayre I was asked to fill in for a last minute drop out. My only brief was that the title – though not necessarily the content - should be a reworking of that shown in the programme: ‘CREATE, Reach and Engage’. Following recent conversations/presentations with/from Tony Hirst and Pauline Randall, I already had some ideas floating around about ‘search’ and ‘recommendation’ and their potential effect on course discovery and enrolment. The crystalisaton of these ideas came together in my presentation: ‘Cost, Reach and Engagement’.

Here’s the slidecast:

If you prefer to read rather than listen, here’s an overview of what I said (incorporating some new material towards the end of this post, with a survey of RSC Scot N&E supported institution websites and … my recommendations for what you might want to do):

In the beginning

The tools for Internet search actually predate the web itself. Tools like Archie could extract information from file servers, generating searchable indexes of stuff. At around the same time, directories of websites also emerged. Some of these were curated lists, others automatically generated, or even a hybrid of both.

A big turning point in web search was the increasing use of algorithms to rank the relevancy of results. Google’s PageRank method has arguably received most of the recent attention, using a wide range of factors including the number of inbound links, click-throughs, even page-load speed to rank search results.

More details of the specifics of this can be found on the Wikipedia page on the history of search engines.

Recommendation: trusted and crowdsourced

Recommendation is an incredibly powerful way to influence action. It’s even more powerful when it comes from a trusted source. Personal recommendations are probably the most powerful, people being more likely to accept a recommendation from a friend than a stranger. Other forms of recommendation include advice from an independent source like the consumer protection site ‘Which?’, and more recently ‘crowdsourced’ reviews which are commonplace on sites like Amazon and are at the core of sites like laterooms.com, where trust is replaced by volume.

Another way to receive recommendations is through social networking sites like Facebook, Twitter and Linkedin. In some cases these recommendations are explicit- Linkedin allows an option to recommend directly to your colleagues - but they are also implied, ‘I liked this, so might you’.

Recommendation has always been and continues to be an important part of how businesses and institutions market themselves, but what is the value of recommendations made via social networks?

The value of Email, Share, Tweet and Like

I’m sure you’ve seen these four buttons appearing on various websites including this blog. These buttons send out notifications via your social networks (if you are enrolled) to your followers. Media sites like the BBC use them mainly to get you to share news stories around your networks. But it doesn’t end there, manufacturers and utility companies are also using these types of buttons to get you to do their marketing for them, for you to make a recommendation about their product or service to your network.

Is there any value in this type of recommendation? Fortunately online event promotion and administration site Eventbrite has revealed the value of those four little buttons. Eventbrite make money by charging a booking fee for paid for events (2.5% of ticket value + $0.99 per ticket with a maximum fee of $9.95), as Techcrunch revealed in October 2010: For Eventbrite, Each Facebook Share Is Worth $2.52. Update: Revised figures have been published by Mashable in Facebook “Likes” More Profitable Than Tweets [STUDY].

$2.52 is the average return to Eventbrite each time that someone clicks the Facebook ‘Like’ button! The second best return is on email which has an average return of $2.34 per click, followed by Linkedin ($0.90) and lastly Twitter ($0.43). So assuming that the majority of paid-for events hits the maximum booking fee ($10) then someone clicking the Facebook ‘Like’ button has a 1in 4 chance of getting someone else to buy a ticket.

Quickly looking at what I think might be happening here: email is a highly trusted recommendation source but is usually a one-to-one distribution. Facebook is a less trusted source as your network can be diluted to a degree, but clicking the ‘Like’ button makes it visible to your network (one-to-many). Networks like LinkedIn and Twitter probably have less social cohesion, Twitter in particular will have more accounts designed to market businesses and brands, so while they are potentially bigger networks they aren’t as trusted.

How do I ‘like’ your course?

So for Eventbrite there is a demonstrable value in incorporating these buttons into its service, providing a mechanism for people to easily recommend events to their friends, thereby generating sales. So are institutions missing a trick? If I went to your institution’s website is there an easy way for me to recommend courses to my friends?

 

I’ve carried out a quick survey of institutions supported by our RSC and below is a table of the results. As can be seen, whilst the majority of them have a social media presence, only a minority have implemented a share button within their course information - and these are generally pushed inconspicuously to the page footer or sidebar. In a number of cases, even if there was a share option, bad meta tagging of the page name (which is often used by these buttons to classify what is being shared) meant that what was being shared was often meaningless. (As shown in the table, AddToAny and AddThis are share/ bookmarking services which provide widgets for your website with a collection of social media sites for the user to choose from when clicked upon).

Survey of social media presence and course recommendation buttons for institutions supported by JISC RSC Scotland North & East
InstitutionSocial Media PresenceCourse Like/Share ButtonsProspectus Like/Share Buttons
AberdeenNoneNoneNone
Adam SmithNoneNoneNone
Angus CollegeFacebook, TwitterEmailVia Scribd
Banff & BuchanFacebook, TwitterNoneNone
BordersFacebook, TwitterNoneNone
CarnegieFacebook, TwitterAddThis * **Via Issuu
DundeeNoneFacebook, Reddit, Digg, StumbleUpon, Delicious * ***Buttons in footer
Edinburgh’s TelfordFacebook, TwitterNoneNone
ElmwoodTwitterNoneNone
Forth ValleyFacebookAddThis ***None
Inverness CollegeNoneNoneNone
Jewel & EskFacebook, TwitterNoneNone
Lews Castle CollegeNoneNoneNone
Moray CollegeNoneNoneNone
Newbattle AbbeyNoneAddToAnyNone
North HighlandNoneNoneNone
OrkneyTwitterNoneNone
OatridgeFacebookNoneNone
Perth CollegeFacebookNoneZmags
Sabhal Mòr OstaigNoneAddThis ***None
ShetlandFacebook, TwitterNoneNone
StevensonFacebook, TwitterNoneNone
West LothianNoneNoneNone
Edinburgh College of ArtNoneAddThis ***AddThis ***
Queen Margaret UniversityFacebook, TwitterAddThis * **Yudu
Scottish Agricultural CollegeFacebook, TwitterDelicious, Digg, Facebook, Reddit, StumbleUpon ***None
University of the Highlands and IslandsFacebook, Twitter, LinkedInNoneNone
Notes
* Page <title> doesn’t reflect page content - remains static
** Buttons in sidebar
*** Buttons in the footer

Surveyed 14th March 2011 – Data available in this Google Doc

My Recommendations

  • Go for full buttons and make them prominent

For reference, I’m talking about the course/prospectus parts of your website. For other parts of your site you might prefer the more subtle AddToAny/AddThis et al. widgets, but for selling/promoting your courses I think you have to be more brazen about it. The institutions that did have social media share buttons on their sites had them hidden away in the footer or sidebar. To maximise the potential of them being clicked I would prominently place the buttons next to the course title or at the end of the entry. Because sites like Facebook and Twitter want you to share information around their network (its precious data for them to target their own marketing), they all provide easy ways to incorporate their buttons. Here’s the page for creating Facebook ‘Like’ buttons and here’s the page for Twitter’s Tweet button

  • Deuce Email/Facebook Like or trips Email, Tweet, Facebook Like

Right now I think there are two clear options for education in terms of button choices. The one you go for is probably dependent or your institution’s existing social media presence. For example if you don’t extensively use Twitter in your social media strategy you probably don’t want to use it as one of your share buttons as it’s harder for you to track comments. With regard to email, there are various options for sending via a webpage. The option I’ve gone for on this blog is to use the ShareThis Email chicklet, mainly because their popup window has the option to pull contact email addresses from Google and Yahoo. [You’ll notice I don’t use ShareThis for my other buttons. This is because their code requires an additional layer to get to the Facebook and Twitter pages]

At this point you might be asking why I include other share/bookmarking options in my blog. The decision to include other services is in part informed by CMO’s guide to the social media landscape which I picked up in Mashable’s article on Which Social Sites Are Best for Which Marketing Outcomes? [INFOGRAPHIC]

  • Get some insight – Facebook Insights, ShareThis

So you’ve invested a day or so implementing share/recommendation buttons into your course catalogue, how do you monitor their use before sending that memo to senior management to argue for more money for website development now that you’ve attracted students from around the world to study at your institution? I imagine most of you are already using some basic analytics to monitor page performance. Well similar tools exist for Facebook, Twitter, and, if you use it, the ShareThis email button.

Twitter’s official analytics service has been announced but isn’t available for general use yet, but fear not as there are a whole host of 3rd party Twitter analytics tools (Crowdbooster and TwitSprout are my current favs). More impressive is Facebook’s Insights for Websites which not only gives you an overview of how many clicks your Like buttons are getting, but also includes demographic information on age, gender, language and country (more information on this in Real-Time Analytics For Social Plugins)

So hopefully some Like buttons are going to start popping up at our supported colleges and universities (and if you’d like help or further advice on how to do this get in touch).

One final reflection is that this post began by looking at the history of Web search. That history continues to be written. Google’s recognition that recommendation through social networks is a very powerful way to leverage content is highly significant. Why rely on machine recommendation when your friends can do it for you? This is why Google recently announced that its search results will include data based on the indirect recommendations of friends (See An update to Google Social Search). Not only does this create an opportunity to improve search relevance, but it is another reason for including Like/Share buttons. If it is difficult for someone to share your course with their friends, potentially there is a negative secondary effect which means it might not be included in Google’s socially-enabled search results.

Final finally, would you recommend or share this post with your network ;)

JISC Winter Fayre: Festive Tweets Material

A couple of weeks ago we held our postponed JISC Winter Fayre (regional showcase of the best of local practice and the JISCy goodness). Below are my slides and a recording of the Livestream accenttally deleted it - no undo, no backup :(

It was the first time I had used Livestream to broadcast what I was doing. I think it worked reasonably well apart from when I forgot to pause a video being played in the browser, hence the double audio. I also need to invest in a better mic. The cheap bluetooth headset I used wasn’t great


Export Twitter Followers and Friends using a Google Spreadsheet

Recently I’ve noticed a growing number of people arrive at this blog having searched for ‘export twitter followers’. Rather than them leaving disappointed here’s a Google Spreadsheet I threw together which allows you to grab a copy of your friends/followers:

*** Google Spreadsheet to Export Twitter Friends and Followers ***

Update: added the ability to download other peoples friends/followers

Benefits of using Google Spreadsheet

  • Control - You register for your own API key with Twitter so you have full control of the account
  • Automatic whitelisting – Twitter currently automatically whitelist applications built in Google Spreadsheets this means instead of 150 API request per hour you get 20,000 meaning you can export a lot
  • Playing with the data – as you are importing straight into a spreadsheet you can do all of your own data manipulation like sorting, filtering and creating your own formula for things like follow/follower ratios
  • Backup – Google Spreadsheets allow you to download copies of spreadsheets in different formats
  • Share – You can make your lists of friends/followers easily viewable

Where’s this all going?

Having already done other things with the Twitter API and Google Spreadsheets (See Populating a Twitter List via Google Spreadsheet … Automatically!, Collect/backup tweets in a Google Spreadsheet, Google Apps Script, Spreadsheets, Twitter and Gadgets) the Twitter/Google Spreadsheet back is well and truly broken. You’ll probably see fewer posts one this area with new stuff instead I’ll probably start properly documenting the little code snippets I use (but if you have any interesting ideas you want help with get in touch).

This doesn’t mean I’ll be walking away from Google Spreadsheets. As recent posts like Turning Google Spreadsheets into a personal or group bookmarking service, show there is huge scope in using Spreadsheets as a very flexible rapid development platform.

Below are some bits of the code used in my new spreadsheet (all the code is viewable via the Script Editor in the Spreadsheet):

function tw_request(method, api_request){
  // general purpose function to interact with twitter API
  // for method and api_request doc see http://dev.twitter.com/doc/
  // retuns object
  var oauthConfig = UrlFetchApp.addOAuthService("twitter");
  oauthConfig.setAccessTokenUrl(
      "https://api.twitter.com/oauth/access_token");
  oauthConfig.setRequestTokenUrl(
      "https://api.twitter.com/oauth/request_token");
  oauthConfig.setAuthorizationUrl(
      "https://api.twitter.com/oauth/authorize");
  oauthConfig.setConsumerKey(getConsumerKey());
  oauthConfig.setConsumerSecret(getConsumerSecret());
  var requestData = {
        "method": method,
        "oAuthServiceName": "twitter",
        "oAuthUseToken": "always"
      };
   try {
      var result = UrlFetchApp.fetch(
          "https://api.twitter.com/1/"+api_request,
          requestData);
      var o  = Utilities.jsonParse(result.getContentText());
    } catch (e) {
      Logger.log(e);
    }
   return o;
}
function getFriendAndFo(sheetName){
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName(sheetName);
  sheet.getRange(2, 1, sheet.getLastRow(), sheet.getMaxColumns()).clear({contentsOnly:true}); //clear sheet
  var cursor = "-1";
  while(cursor != "none"){ // while twitter returns data loop
    try {
      var o = tw_request("GET", "statuses/"+sheetName+".json?cursor="+cursor); // note using sheetname to build api request
      var data = o.users;
      for (i in data){ // extracting some subobjects to top level (makes it easier to setRowsData)
        if (data[i].status){
          for (j in data[i].status){
            data[i]["status_"+j] = data[i].status[j];
          }
        }
        if (data[i].screen_name){ // also build url to jump to profile page
          data[i]["profile_link"] = "http://twitter.com/"+data[i].screen_name;
        }
      }
      var headRange = sheet.getRange(1, 1, 1, sheet.getMaxColumns());
      var rowIndex = sheet.getLastRow()+1;
      setRowsData(sheet, data, headRange, rowIndex); // dump data for this loop to sheet
      if (o.next_cursor!="0"){
        cursor = o.next_cursor; // get next cursor
      } else {
        cursor = "none"; // break
      }
    }  catch (e) {
      Logger.log(e);
    }
  }
}

TwapperKeeper looses API access, iTitle turns to the cloud with Twitter Search from Google Spreadsheets

Empty Archive
Empty Archive
Originally uploaded by bRokEnCHaRacTer

Recently Twitter has been paying close attention to 3rd party developer use of their API. First they stopped whitelisting new applications, then UberSocial and Twitdroid were suspended for terms of service violations, now the popular tweet archiving service TwapperKeeper announced that they will be removing export and API access in response to a request from Twitter.

Fortunately TwapperKeeper has been given until the 20th March to comply, but this is still a blow for 4th party developers, like myself, who build applications around the TwapperKeeper archive/API and will no longer have an easy way to grab historic tweets. Part of the problem is Twitter provides no easy access to collections of tweets over 5 days old necessitating the need for services like TwapperKeeper, so it’s discontinuation is going to cause headaches for some.

Personally, when developing my Twitter Subtitling service iTitle I was keen to make sure data could be used from various sources starting with the official Twitter Search results and TwapperKeeper integration, later adding support for .CSV file upload. Most recently I added support for my Google Spreadsheet/Twitter Search collection mashup [BTW after feedback from @AJCann there is now a setup video for this on YouTube]. So hopefully iTitle will live for a little longer.

So what about other services like my other Twitter mashup uTitle and Andy Powell’s Summarizr, which rely on the TwapperKeeper service. There are obviously other Twitter archive services out there, TwapperKeeper even has the JISC funded open source version yourTwapperKeeper, but all the online services potentially face the same problem of being prevented from making archived tweets reusable. One solution might be to develop a distributed cloud based archive. For example, initially I thought of using Google Spreadsheet hack for capturing tweets, and then sharing these archives with the community as a searchable index. Anyone fancy building an interface for this?

Google Apps Script, Spreadsheets, Twitter and Gadgets #guug11

Yesterday was the inaugural Google Apps UK User Group (#guug11) event at Loughborough University. I was put to the test with 5 minutes in the open mic session talking about my work with Google Spreadsheets and Twitter. Fortunately before I took the stage Tony Hirst had a session on Mashing Up Google Apps, which did a great job of setting the scene highlighting how Google Apps is a great environment for quickly manipulating ‘stuff’.

Given the short time and the fact I was demoing stuff in Spreadsheet instead of flipping back and forth from a presentation I decided to embed my slides with the aid of a little gadget I wrote which plays back a flickr photoset. This enabled me also prepare cells of text I could tweet at a click of button. This required a bit of refactoring of my Populating a Twitter List via Google Spreadsheet creating this more general function:

function tw_request(method, api_request){
  var requestData = {
        "method": method,
        "oAuthServiceName": "twitter",
        "oAuthUseToken": "always"
      };
   try {
      var result = UrlFetchApp.fetch(
          "https://api.twitter.com/1/"+api_request,
          requestData);
      var o  = Utilities.jsonParse(result.getContentText());
      Logger.log(result.getHeaders());
    } catch (e) {
      Logger.log(e);
    }
   return o;
}

I could then attach the following script to a button on the sheet:

function tweetBut(){
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getActiveSheet(); // get active sheet
  var tweet = sheet.getActiveCell().getValue(); //grab the active cell as item to tweet
  var api_request = "statuses/update.json?status=" + encodeURIComponent(tweet); // build query for Twitter Api
  var data = tw_request("POST", api_request); // function to send tweet
  sheet.getRange("B34").setValue(tweet); // write tweet in specified cell < formated cell to large font for eveyone to see
  Logger.log(data); // debug stuff
  if (data["text"]!=""){ // if tweet sent make a notification
    ss.toast("Tweet sent", "Tweet");
  }
}

As this original spreadsheet already had a function to interact with Twitter Search to find people using a particular hashtag, I rewrote this slightly to also allow me to pull a named search into a sheet (as used in Twitteralytics v2).

With my new tw_request() function this opens up the entire Twitter API for endless mashineering (mentions, followers, following and more). There’s more tinkering to do but here’s my latest iteration of Spreadsheet/Twitter mashup (GoogTweetSheet) – there’s a bug with the custom twitter menu not appearing –to do

Using my search here’s an archive of all the #guug11 tweets (I’ve filtered it to show the tweets I made during my presentation)

Collect/backup tweets in a Google Spreadsheet [Twitteralytics v2]

Back in June I hastily threw together Using Google Spreadsheet to automatically monitor Twitter event hashtags and more. It kind of worked most of the time but there were a lot of rough edges. So here is:

*** the Twitteralytics v2 Google Spreadsheet ***
(you’ll need to make a copy of this from the file menu before you can use - if make a copy is not available make sure you’ve logged in to Google first)

Here is a short video showing setup:

The concept is the same, you setup a search and Google Spreadsheet updates the results using a time driven trigger. The main difference is where the old version just collected date, author and tweet text this version has the option of pulling everything back available from the Twitter GET Search API. Even better you define what a where information is pulled by matching your column heading name with the Twitter search result schema, so if Twitter adds more data it’s easy for you to pull (one small caveat is it can only pull top-level data, anything nested in the results is lost apart from geo-tagging, which I thought was too useful to loose).

This was easily achieved by modifying Mikael Thuneberg getTweets() function which I originally used in version 1. This function collects search results using XML/ATOM. To achieve more flexibility I converted this to use the JSON results from Twitter. Because Google App Scripts are written using a JavaScript syntax it makes it easy to through the JSON results around and given that there is already handy bits of code for writing spreadsheet data using JavaScript Objects I was able to achieve more flexibility easily.

As my focus this time around is to just harvest tweets I dropped some of the original functionality of summarising ‘top tweeter’ and emailing results, but it’s easy enough to drop you own functions or gadgets to help you process the data. For example you could use the Map Gadget to plot geo-located tweets. This spreadsheet has some examples of what you can do with the data.

The from:briankelly sheet includes a map gadget whilst the first 5 columns of #purposed contain functions for extracting top tweeters and a Google Spreadsheet readable timestamp.

With services like twapperkeeper.com and downloadable apps like ThinkUp why have a Google Spreadsheet version? Not entirely sure I’ve got a good answer to that one. The biggest advantage is maybe its a quick way to collect tweets, make publically available and collaborate exploring the data.

Mainly for SEO here is the code for the modified version of getTweets(), the rest of the script is available in the spreadsheet.

function getTweets(searchTerm, since, until, maxResults, languageCode) {
    //Based on Mikael Thuneberg getTweets - mod by mhawksey to convert to json
    // if you include setRowsData this can be used to output chosen entries
    try {
        var pagenum = 1;
      var data =[];
      var idx = 0;
        if (typeof maxResults == "undefined") {
            maxResults = 100;
        }
        if (maxResults > 1500) {
            maxResults = 1500;
        }
        if (maxResults > 100) {
            resultsPerPage = 100;
            maxPageNum = maxResults / 100;
        } else {
            resultsPerPage = maxResults;
            maxPageNum = 1;
        }
        Logger.log(twDate(since)+" "+twDate(until));
        searchTerm = encodeURIComponent(searchTerm);
        for (pagenum = 1; pagenum <= maxPageNum; pagenum++) {
            var URL = "http://search.twitter.com/search.json"
            URL = URL + "?q=" + searchTerm;
            URL = URL + "&since=" + twDate(since);
            URL = URL + "&until=" + twDate(until);
            URL = URL + "&rpp=" + resultsPerPage;
            URL = URL + "&page=" + pagenum;
            URL = URL + "&result_type=recent";
            if (typeof languageCode != "undefined") {
                if (languageCode.length > 0) {
                    URL = URL + "&lang=" + languageCode;
                }
            }
            var response = UrlFetchApp.fetch(URL, {method:'get', headers: { "User-Agent": REFERER}});
            if (response.getResponseCode() == 200) {
              var objects = Utilities.jsonParse(response.getContentText()).results;
              for (i in objects){ // not pretty but I wanted to extract geo data
                if (objects[i].geo != null){
                  objects[i]["geo_coordinates"] = "loc: "+objects[i].geo.coordinates[0]+","+objects[i].geo.coordinates[1];
                }
                objects[i]["status_url"] = "http://twitter.com/"+objects[i].from_user+"/statuses/"+objects[i].id_str;
                data[idx]=objects[i];
                idx ++;
              }
            }
          }
    return data;
    } catch (e) {
        return e.message;
    }
} 

Google Apps Script: Using a Google Spreadsheet to populate a Twitter list [Hashtag Communities]

Update: I’ve revised this idea in Populating a Twitter List via Google Spreadsheet … Automatically! [Hashtag Communities]

Having recently rediscovered the joys of Google Apps Script I was looking for something to do after my Event Manager Spreadsheet. A couple of ideas I had were: something to do with linked data (possibly a email subscription list); or having read the Google Apps Script Twitter Approval Manager Tutorial something around an automated timezone retweet system.

But while wandering through the Virtual coffee shop at Innovating e-Learning 2010 I noticed a post from my colleague at RSC Eastern, Shri Footring asking:

Does anyone know whether there an automated way to create a twitter list of everyone who has used the tag #jiscel10 in a tweet?

I’ve been closely following Tony Hirst’s work on visualising community and user networks using Gephi (partly to play ‘Where’s Wally’ as I vainly try and spot myself in the various network visualisation). I also new Tony had released his Twitter Community Grabbing Code – newt.py, which if I had ever coded in Python would let me solve Shri’s problem in a blink of an eye.

Instead I thought it would be completely insane interesting to see if I could replicate some of Tony’s newt.py functionality in Google Spreadsheets. And guess what you can! So here’s how. [You can shortcut some of the steps in 1, 3–5 by copying this Spreadsheet]

How-to create a Twitter list from Google Spreadsheet

  1. Follow the steps in the Google Apps Script Twitter Approval Manager Tutorial up to and including authorising your spreadsheet with Twitter (if you start Tweeting you’ve gone too far)
  2. Generate a list of twitter usernames you would like to add to a list. I did this by exporting the jiscel10 hashtag archive from the Twitter archiving service Twapper Keeper (I used the export and download button. If you use Excel Permalink (beta) option increase the View Limit)
  3. Import this data to a sheet of the Twitter Approval Manager Spreadsheet. You can edit this data the important thing is that there is a column with the heading from_user and preferably it’s in column C
  4. Insert a new sheet called ‘To add to Twitter List’ and in the first cell enter ‘=UNIQUE(Sheet1!C:C)’ (this strips out an duplicate twitter usernames)
  5. Open the Spreadsheets script editor by clickingTools > Scripts > Script Editor and copy the code at the end of this post at the end of the spreadsheet script. Click on Run > onOpen (this should save changes to the script), then close the Script Editor.

In the Twitter drop down menu on the main spreadsheet  you should have 2 options Add to a List and Purge a List.

Add to a List
When you select add to a list you’ll be prompted for a list name. This list must already existing on your Twitter account even if it has no follower. Once you enter the list name the spreadsheet should start adding usernames. This process can take some time depending on the size of your list (the maximum is 500) and you will be prompted when it is done. You can always open a separate browser window with the twitter list to check if names are being added.

Purge a List
I’ve included a purge option to allow you to rebuild the list without deleting it entirely. This means followers of a list won’t be lost. Again this process can take some time so be patient.

The code

Note: For this code to work you also need the code from the Twitter Approval Manager

// Add list of twitter usernames to a Twitter list
// coded by @mhawksey
// Available under Creative Commons Attribution-ShareAlike 2.5 UK: Scotland License
var SCREEN_NAME = "";
function onOpen() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var menuEntries = [ {name: "Add to a List", functionName: "addToList"},
                      {name: "Purge a List", functionName: "purgeList"},
                      {name: "Tweet", functionName: "tweet"},
                      {name: "Configure", functionName: "configure"} ];
  ss.addMenu("Twitter", menuEntries);
}
function getScreenName() {
  var oauthConfig = UrlFetchApp.addOAuthService("twitter");
  oauthConfig.setAccessTokenUrl(
      "https://api.twitter.com/oauth/access_token");
  oauthConfig.setRequestTokenUrl(
      "https://api.twitter.com/oauth/request_token");
  oauthConfig.setAuthorizationUrl(
      "https://api.twitter.com/oauth/authorize");
  oauthConfig.setConsumerKey(getConsumerKey());
  oauthConfig.setConsumerSecret(getConsumerSecret());
  var requestData = {
    "method": "GET",
    "oAuthServiceName": "twitter",
    "oAuthUseToken": "always"
  };
  var result = UrlFetchApp.fetch(
      "http://api.twitter.com/1/account/verify_credentials.json",
      requestData);
  var o  = Utilities.jsonParse(result.getContentText());
  SCREEN_NAME = o.screen_name;
}
function twitterList(method, list, query){
  if (SCREEN_NAME==""){
    getScreenName();
  }
  var requestData = {
        "method": method,
        "oAuthServiceName": "twitter",
        "oAuthUseToken": "always"
      };
   try {
      var result = UrlFetchApp.fetch(
          "http://api.twitter.com/1/"+SCREEN_NAME+"/"+list+"/members.json"+query,
          requestData);
      var o  = Utilities.jsonParse(result.getContentText());
    } catch (e) {
      Logger.log(e);
    }
   return o;
}
function purgeList(){
  var list_id=Browser.inputBox("Enter list name to purge:");
  while(twitterList("GET", list_id,"").users.length>0){
    var object = twitterList("GET", list_id,"");
    for (var i = 0; i < object.users.length; ++i) {
      twitterList("POST", list_id, "?_method=DELETE&id="+object.users[i].screen_name);
      Logger.log(object.users[i].screen_name);
    }
  }
  Browser.msgBox("List purged");
}
function addToList(){
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var dataSheet = ss.getSheetByName("To add to Twitter List");
  var dataRange = dataSheet.getRange(2, 1, dataSheet.getMaxRows(), 1);
  //get list name to add users to (must already exist)
  var list_id=Browser.inputBox("Enter list name to add users to:");
  objects = getRowsData(dataSheet,dataRange);
  for (var i = 0; i < objects.length; ++i) {
    var rowData = objects[i];
    if (rowData.fromuser!="" ){
      try {
        var o = twitterList("POST", list_id, "?id="+rowData.fromuser);
        dataSheet.getRange(i+2,2).setValue("Added");
      } catch (e) {
        Logger.log(e);
      }
    }
  }
  Browser.msgBox("The list now has :"+o.member_count+" members");
}
//////////////////////////////////////////////////////////////////////////////////////////
//
// The code below is reused from the 'Reading Spreadsheet data using JavaScript Objects'
// tutorial.
//
//////////////////////////////////////////////////////////////////////////////////////////
// getRowsData iterates row by row in the input range and returns an array of objects.
// Each object contains all the data for a given row, indexed by its normalized column name.
// Arguments:
//   - sheet: the sheet object that contains the data to be processed
//   - range: the exact range of cells where the data is stored
//   - columnHeadersRowIndex: specifies the row number where the column names are stored.
//       This argument is optional and it defaults to the row immediately above range;
// Returns an Array of objects.
function getRowsData(sheet, range, columnHeadersRowIndex) {
  columnHeadersRowIndex = columnHeadersRowIndex || range.getRowIndex() - 1;
  var numColumns = range.getEndColumn() - range.getColumn() + 1;
  var headersRange = sheet.getRange(columnHeadersRowIndex, range.getColumn(), 1, numColumns);
  var headers = headersRange.getValues()[0];
  return getObjects(range.getValues(), normalizeHeaders(headers));
}
// For every row of data in data, generates an object that contains the data. Names of
// object fields are defined in keys.
// Arguments:
//   - data: JavaScript 2d array
//   - keys: Array of Strings that define the property names for the objects to create
function getObjects(data, keys) {
  var objects = [];
  for (var i = 0; i < data.length; ++i) {
    var object = {};
    var hasData = false;
    for (var j = 0; j < data[i].length; ++j) {
      var cellData = data[i][j];
      if (isCellEmpty(cellData)) {
        continue;
      }
      object[keys[j]] = cellData;
      hasData = true;
    }
    if (hasData) {
      objects.push(object);
    }
  }
  return objects;
}
// Returns an Array of normalized Strings.
// Arguments:
//   - headers: Array of Strings to normalize
function normalizeHeaders(headers) {
  var keys = [];
  for (var i = 0; i < headers.length; ++i) {
    var key = normalizeHeader(headers[i]);
    if (key.length > 0) {
      keys.push(key);
    }
  }
  return keys;
}
// Normalizes a string, by removing all alphanumeric characters and using mixed case
// to separate words. The output will always start with a lower case letter.
// This function is designed to produce JavaScript object property names.
// Arguments:
//   - header: string to normalize
// Examples:
//   "First Name" -> "firstName"
//   "Market Cap (millions) -> "marketCapMillions
//   "1 number at the beginning is ignored" -> "numberAtTheBeginningIsIgnored"
function normalizeHeader(header) {
  var key = "";
  var upperCase = false;
  for (var i = 0; i < header.length; ++i) {
    var letter = header[i];
    if (letter == " " && key.length > 0) {
      upperCase = true;
      continue;
    }
    if (!isAlnum(letter)) {
      continue;
    }
    if (key.length == 0 && isDigit(letter)) {
      continue; // first character must be a letter
    }
    if (upperCase) {
      upperCase = false;
      key += letter.toUpperCase();
    } else {
      key += letter.toLowerCase();
    }
  }
  return key;
}
// Returns true if the cell where cellData was read from is empty.
// Arguments:
//   - cellData: string
function isCellEmpty(cellData) {
  return typeof(cellData) == "string" && cellData == "";
}
// Returns true if the character char is alphabetical, false otherwise.
function isAlnum(char) {
  return char >= 'A' && char <= 'Z' ||
    char >= 'a' && char <= 'z' ||
    isDigit(char);
}
// Returns true if the character char is a digit, false otherwise.
function isDigit(char) {
  return char >= '0' && char <= '9';
}
​

eAssessment Scotland 2010: Twitter workshop reflections

Last Friday I ran a Twitter workshop as part of ‘eAssessment Scotland 2010: Marking the decade’. In the programme I described the session as:

What’s happening? Twitter for Assessment, Feedback and Communication

Twitter is a social networking site which continues to divide personal opinion. Some believe that the micro-blogging service is just an opportunity celebrities to boost their ego with millions of followers or just full of people ‘tweeting’ what they had for lunch. Whilst some users do use Twitter for this purpose a number of academics are now discovering that Twitter has the potential to support teaching and learning, providing a means to enable students to discuss and share within their personal learning network. Before you dismiss Twitter there are some basics worth considering: the service is free to register, status updates can be made from the most basic mobile phone, and users can monitor conversations through multiple means including, for some users, sending free SMS updates.

This workshop uses some of the features of Twitter highlighted above to let participants experience and use this service as a free electronic voting system (EVS), for classroom administration (assessment notification/reminders) and to monitor real-time student evaluation. As this technology is relatively new the workshop will begin with an overview of basic Twitter interaction making it suitable for novice and expert users.

I was perhaps too ambitious to include ‘novice’ users and it would have been better if I either focused on beginners or intermediate/advance users. The workshop I delivered was probably more beneficial for the later, but hopefully novice users were tantalised by the utility of twitter.

During the workshop I really missed having Timo Elliott’s PowerPoint AutoTweet tool (which is broken because of authentication changes at Twitter). This would have been really useful to send out links during the presentation (this example shows how I used it for another presentation).

As a number of participants had only just created Twitter accounts the week before it looks like Twitter quarantines their tweets preventing them from appearing in search results (I guess they wait until you hit some threshold in terms of following/followers/tweets to make sure the account isn’t being used from spam).

In the sides you’ll noticed I’ve revived the Twitter voting tool (TwEVS). Previously this solution relied on using Yahoo Pipes to manipulate results from Twitter, which meant graphs didn’t always have the latest results because of caching. To get around this I’ve created a script which can be run from a webserver. Here is the new TwEVS interface (you can also download the code).

What’s happening? The ‘utility’ of Twitter in teaching and learning

In this post I want to put down a marker as to the role I think Twitter could have within education. When previously presenting on the use of Twitter in education I’ve always tried to emphasis its not just about a tool for discussion (in fact I try to avoid the word discussion because 140 characters can seriously hamper the depth you can go into), but instead Twitter which can be easily interacted with via its API and 3rd party services has the potential to be used as the building blocks for a service to support teaching and learning.

Some examples for you.

Does your institution use (or is about to cut) a SMS service to send administrative information to students? If so you could save yourself 4p per text by asking students to follow a Twitter account and receive free SMS updates if they are customers of one of the four big mobile network operators.       

Do you use or want to use electronic voting in the classroom but don’t have enough handsets or are frustrated when students don’t bring them in? If so Twitter can be used as a mechanism for collect votes even using the most basic mobile phones.

Making a strategic decision to use Twitter for different aspects of the educational experience I believe students are less likely to perceive it as a gimmick and consequently more likely to take more ownership of it as a tool to support their own education.

A nice diagram I came across recently which illustrates the ‘different aspects of Twitter’ this is Mark Sample’s Twitter Adoption Matrix which featured in his A Framework for Teaching with Twitter post.

Twitter Adoption Matrix  

(Mark has followed up his post with another expanding on Practical Advice for Teaching with Twitter, which is also worth a read)

The idea of building applications around social network sites to aid teaching and learning isn’t new. Examples like OU’s SocialLearn and Purdue’s Hotseat spring to mind. Perhaps the issue with these is they are designed around breadth instead of depth, trying to tap into the illusive Personal Learning Environment.

What if instead we ignore the personal and focus on the functional. That is building applications around Twitter to provide students and tutors with the tools to support learning, focusing on formal uses enabling opportunities for serendipitous informal learning. 

But why Twitter and not Facebook or FriendFeed et al.? For me it comes down to a couple of things. With Facebook there is the ever distraction of games, friends and family. Twitter stripes a lot of this away. FriendFeed is better in terms of simplicity but you are not restricted by 140 characters. Whilst this makes FriendFeed a better tool for deep discussion it makes it less mobile friendly (i.e. you can read notifications from Twitter on the most basic phone via SMS).

Finally flexibility. My favouring of Twitter’s flexibility is perhaps down to my own limitations as an educational mash-up artist. I find it a lot easier to extend Twitter’s functionality because of the simplicity of the core product and number of examples that can easily be adapted.

Hopefully you are getting my gist. Focus on adopting Twitter as a tool. Think of Twitter’s utility. The utility to collect comments. The utility to collect votes. The utility to send notifications. Through focusing on utility you are creating opportunities for other learning theories to come into play enabling the transition from formal to personal.

Twitter/YouTube commenting: Embeddable, open sourced and with its own WordPress plugin [uTitle]

Player embedPlayer embed with jump navigation

Having added embed options for the Twitter subtitling of live events (iTitle), it made sense to include these with the Twitter/YouTube commenting tool (uTitle). As both these tools have some code in common adding embed options for the player and player+navigation was relatively straight forward. So now you can embed Twitter commented YouTube videos in other sites.

But what about providing an interface to let people comment on videos from your own site? This is now also possible … kind of.

Using the same method for embedding the player with jump navigation <iframe>, it is possible to just make a bigger one which includes the whole of the screen. The issue I haven’t been able to resolve is that the user needs to authenticate via Twitter. This processes unfortunately breaks the user out of the <iframe>, before automatically redirecting back them back to the comment interface on http://www.rsc-ne-scotland.org.uk/mashe/utitle/. My preference would be if a users is making a comment via uTitle embedded on www.yourweb.com that you stay on that site.

A possible workaround would be for www.yourweb.com to host their own version of the uTitle interface. So here it is the uTitle source code on github.

That just leaves the WordPress plugin. This was suggested by Dries Bultynck
in response to the original uTitle post. As I plan on using commentable videos on this blog it seemed like a good idea to put something together on this. So here it is the WordPress uTitle Plugin. This turns a custom shortcode into an embed/iframe.

So

is turned into …


Comments powered by Twitter Click here to add yours ...

which is nice

About

This blog is authored by Martin Hawksey e-Learning Advisor (Higher Education) at the JISC RSC Scotland N&E.

mhawksey [at] rsc-ne-scotland.ac.uk | 0131 559 4112 | @mhawksey

JISC RSC Scotland North & East logo

If you would like to subscribe to my monthly digest please enter your email address in the box below (other ways are available to subscribe from the button below):

Subscribe to MASHe to monthly email updates

Loading...Loading...


The MASHezine (tabloid)

It's back! A tabloid edition of the latest posts in PDF format (complete with QR Codes). Click here to view the MASHezine

Preview powered by:
Bluga.net Webthumb

The MASHezine (eBook)

MASHe is also available in ebook and can be downloaded in the following formats:

Powered by NEWSTOEBOOK.COM

Archives

Opinions expressed in this blog are not necessarily those of the JISC RSC Scotland North & East.

JISC Advance Logo

JISC Advance is a new organisation that brings together the collective expertise of established JISC services:

For further information visit www.jiscadvance.ac.uk

Creative Commons Licence
Unless otherwise stated this work is licensed under a Creative Commons Attribution-ShareAlike 2.5 UK: Scotland License