Mostrando entradas con la etiqueta Twitter. Mostrar todas las entradas
Mostrando entradas con la etiqueta Twitter. Mostrar todas las entradas

miércoles, 5 de noviembre de 2014

Web scrapping with Go and PhatomJS

Some time ago I wrote a blog called Web scrapping with Julia and PhantomJS...then I wrote another blog called Web scrapping with Haskell and PhantomJS...

This time...it's Go's time -;)

The concept is the same...we create a PhantomJS script that will read a "user" Twitter page and get the hashtags of the first 5 pages...here's the PhantomJS script...

Hashtags.js
var system = require('system');

var webpage = require('webpage').create();
webpage.viewportSize = { width: 1280, height: 800 };
webpage.scrollPosition = { top: 0, left: 0 };

var userid = system.args[1];
var profileUrl = "http://www.twitter.com/" + userid;

webpage.open(profileUrl, function(status) {
 if (status === 'fail') {
  console.error('webpage did not open successfully');
  phantom.exit(1);
 }
 var i = 0,
 top,
 queryFn = function() {
  return document.body.scrollHeight;
 };
 setInterval(function() {
  top = webpage.evaluate(queryFn);
  i++;
   
  webpage.scrollPosition = { top: top + 1, left: 0 };

  if (i >= 5) {
   var twitter = webpage.evaluate(function () {
    var twitter = [];
    forEach = Array.prototype.forEach;
    var tweets = document.querySelectorAll('[data-query-source="hashtag_click"]');
    forEach.call(tweets, function(el) {
     twitter.push(el.innerText);
    });
    return twitter;
   });

   twitter.forEach(function(t) {
    console.log(t);
   });

   phantom.exit();
  }
}, 3000);
});

If we run the script we're going to see the following output...


Now...what I want to do with this information...is to send it to Go...and get the most used hashtags...so I will summarize them and then get rid of the ones that only appear less than 5 times...

Let's see the Go code...

TwitterHashtags.go
package main

import ( "os/exec"
  "strings" 
  "fmt" )

func main() {
 cmd := exec.Command("phantomjs","--ssl-protocol=any","Hashtags.js", "Blag")
 out, err := cmd.Output()
 if err != nil {
  println(err.Error())
  return
 }
 
 Tweets := strings.Split(string(out), "\n")
 charmap := make(map[string]int)
 for _, value := range Tweets {
  if value != "" {
   charmap[value] += 1
  }
 }
 
 for key, value := range charmap {
  if value >= 5 {
   fmt.Print("(", key, ", ")
   fmt.Println(value, ")")
  }
 }
}

The only problem with this script is that there's not an easy way to sort a map[string]int...so I will simply leave it like that -:)

Here's the result...


If someone knows an easy way to sort this...please let me know -:)

Greetings,

Blag.
Development Culture.

martes, 23 de septiembre de 2014

Web scrapping with Haskell and PhatomJS

Some time ago I wrote a blog called Web scrapping with Julia and PhantomJS...today...I wanted to do the same but using Haskell instead...

The concept is the same...we create a PhantomJS script that will read a "user" Twitter page and get the hashtags of the first 5 pages...here's the PhantomJS script...

Hashtags.js
var system = require('system');

var webpage = require('webpage').create();
webpage.viewportSize = { width: 1280, height: 800 };
webpage.scrollPosition = { top: 0, left: 0 };

var userid = system.args[1];
var profileUrl = "http://www.twitter.com/" + userid;

webpage.open(profileUrl, function(status) {
 if (status === 'fail') {
  console.error('webpage did not open successfully');
  phantom.exit(1);
 }
 var i = 0,
 top,
 queryFn = function() {
  return document.body.scrollHeight;
 };
 setInterval(function() {
  top = webpage.evaluate(queryFn);
  i++;
   
  webpage.scrollPosition = { top: top + 1, left: 0 };

  if (i >= 5) {
   var twitter = webpage.evaluate(function () {
    var twitter = [];
    forEach = Array.prototype.forEach;
    var tweets = document.querySelectorAll('[data-query-source="hashtag_click"]');
    forEach.call(tweets, function(el) {
     twitter.push(el.innerText);
    });
    return twitter;
   });

   twitter.forEach(function(t) {
    console.log(t);
   });

   phantom.exit();
  }
}, 3000);
});

If we run the script we're going to see the following output...


Now...what I want to do with this information...is to send it to Haskell...and get the most used hashtags...so I will summarize them and then get rid of the ones that only appear less than 5 times...

Let's see the Haskell code...

hashtags.hs
import System.Process
import Data.List

hashTags :: String -> IO()
hashTags(user) = do
 let x = readProcess "phantomjs" ["--ssl-protocol=any","Hashtags.js",user] []
 y <- x
 mapM_ print $ sortBy sortGT $ count y

count :: String -> [(String,Int)]
count xs = filter ((>=5).snd) $ 
     map(\ws -> (head ws, length ws)) $ 
           group $ sort $ words xs

sortGT :: (Ord a, Ord a1) => (a1, a) -> (a1, a) -> Ordering
sortGT (a1, b1) (a2, b2)
  | b1 < b2 = GT
  | b1 > b2 = LT
  | b1 == b2 = compare a1 a2

When we run this code...we're going to have this output...


The nice thing about this app is that we can pass any username as parameter and the result is going to nicely ordered and filtered...another reason to love Haskell -;)

Greetings,

Blag.
Development Culture.

jueves, 15 de mayo de 2014

Social Media Mining with R - Book review

I was really excited when my friend from Packt Publishing send me this book...as I haven't read any R book in a while...but don't get me wrong...the book is not bad...it's just that I expected a little bit more...let me explain a little bit...


This book is not too big, which is something I appreciate...it's 122 pages...it comes with a short introduction to R which is good for newbies and then it goes straight to Social Media Mining using Twitter.


The problem I had with this book...and that's maybe not really a bad thing...it has more Social Media Mining explanation than actual code...so sure, it does a great job explaining how Social Media Mining works but for a die hard developer like me...the source code is more important...


To be honest with you...I would bought this book if I haven't got any Social Media Mining experience....but I have worked and made several applications using R and Twitter in the past...so...this book wasn't really for me...

Greetings,

Blag.
Development Culture.

lunes, 2 de diciembre de 2013

Twitter Battle

I love to have fun with R and Twitter...there are a lot of cool things that you can do with it...so I just thought of having a small Twitter Battle application...something that will grab the number of followers and lists from two users...apply some crappy algorithms and determine the Twitter importance between those users...using our .RData file that holds the Twitter OAuth info...

Twitter Battle
require("Rook")
library("ROAuth")
library("twitteR")

setwd("C:/Blag/R_Scripts/Important_Scripts")
load("credentials.RData")

Get_Percentages<-function(p_one,p_two,flag){
      if(p_one > p_two){
        if(flag == 0){
          OneFollowPercent<-100
          TwoFollowPercent<-round((p_two * 100) / p_one)
        }else{
          TwoFollowPercent<-100 - (round((p_two * 100) / p_one))
          if(TwoFollowPercent <= 49){
            OneFollowPercent<-50 + TwoFollowPercent
            TwoFollowPercent<-100 - OneFollowPercent
            flag<-0
          }else{
            OneFollowPercent<-50 + TwoFollowPercent
            TwoFollowPercent<-100 - TwoFollowPercent
            TwoFollowPercent<-100 - round((round(TwoFollowPercent * 100) / OneFollowPercent))
            OneFollowPercent<-TwoFollowPercent
            TwoFollowPercent<-100 - OneFollowPercent
            flag<-1
          }
        }
      }
      if(p_one < p_two){
        if(flag == 0){
          OneFollowPercent<-round((p_one * 100) / p_two)
          TwoFollowPercent<-100
        }else{
          OneFollowPercent<-100 - (round((p_one * 100) / p_two))
          if(OneFollowPercent <= 49){
            TwoFollowPercent<-50 + OneFollowPercent
            OneFollowPercent<-100 - TwoFollowPercent
            flag<-0
          }else{
            TwoFollowPercent<-50 + OneFollowPercent
            OneFollowPercent<-100 - OneFollowPercent
            OneFollowPercent<-100 - round((round(OneFollowPercent * 100) / TwoFollowPercent))
            TwoFollowPercent<-OneFollowPercent
            OneFollowPercent<-100 - TwoFollowPercent
            flag<-1
          }
        }
      }
      if(p_one == p_two){
        OneFollowPercent<- 50
        TwoFollowPercent<- 50
      }
      percents<-c(OneFollowPercent,TwoFollowPercent,flag)
      return(percents)
}

newapp<-function(env){
  req<-Rook::Request$new(env)
  res<-Rook::Response$new()
  res$write('<form method="POST">\n')
  res$write('Enter your Twitter username: <input type="text" name="YourUserName">')
  res$write('</BR>')
  res$write('Enter your his/her Twitter username: <input type="text" name="HisHerUserName">')
  res$write('</BR>')
  res$write('<input type="submit" name="Start the Battle!">')
  res$write('</form>')
    
  if (!is.null(req$POST())) {
    YourUserName = paste("@",req$POST()[["YourUserName"]],sep="")
    HisHerUserName = paste("@",req$POST()[["HisHerUserName"]],sep="")
    
    reg<-registerTwitterOAuth(credentials)
    
    GetYourUser<-getUser(YourUserName,cainfo="cacert.pem")
    GetHisHerUser<-getUser(HisHerUserName,cainfo="cacert.pem")
    
    GetYourFollowers<-GetYourUser$followersCount
    GetYourLists<-GetYourUser$listedCount
    GetHisHerFollowers<-GetHisHerUser$followersCount
    GetHisHerLists<-GetHisHerUser$listedCount

    FollowPercents<-Get_Percentages(GetYourFollowers,GetHisHerFollowers,0)
    ListPercents<-Get_Percentages(GetYourLists,GetHisHerLists,0)

    YourPercents<-FollowPercents[1] + ListPercents[1]
    HisHerPercents<-FollowPercents[2] + ListPercents[2]

    FinalPercents<-Get_Percentages(YourPercents,HisHerPercents,1)

    YourPercents<-FinalPercents[1]
    HisHerPercents<-FinalPercents[2]
    if(FinalPercents[3] == 0){
      DiffPercent<-abs(YourPercents - 50)
    }else{
      DiffPercent<-FinalPercents[1]
    }
    
    if(YourPercents > HisHerPercents){
      message<-paste(req$POST()[["YourUserName"]],"is",DiffPercent,
                     " % more important on Twitter than",req$POST()[["HisHerUserName"]],sep=" ")
      res$write(paste('<H1>',message,'</H1>'))   
    }
    if(YourPercents < HisHerPercents){
      message<-paste(req$POST()[["YourUserName"]],"is",DiffPercent,
                     " % less important on Twitter than",req$POST()[["HisHerUserName"]],sep=" ")
      res$write(paste('<H1>',message,'</H1>'))
    }
    if(YourPercents == HisHerPercents){
      message<-paste(req$POST()[["YourUserName"]],
                     "is equally important on Twitter as",req$POST()[["HisHerUserName"]],sep=" ")
      res$write(paste('<H1>',message,'</H1>'))
    }
    
    pieValues<-c(YourPercents,HisHerPercents)
    pieNames<-c(paste(req$POST()[["YourUserName"]],YourPercents,"%"),
                      paste(req$POST()[["HisHerUserName"]],HisHerPercents,"%"))
    
    png("Twitter_Battle.png",width=1000,height=700)
    pie(pieValues,labels=pieNames,main="Twitter Battle")
    dev.off()
    res$write("<div align='center'>")
    res$write(paste("<img src='", server$full_url("pic"), "/", 
                    "Twitter_Battle.png'", "/>", sep = ""))
    
    res$write("</div>")
}
  res$finish()
}

server = Rhttpd$new()
server$add(app = newapp, name = "Twitter_Battle")
server$add(app = File$new("C:/Blag/R_Scripts/Important_Scripts"), name = "pic")
server$start()
server$browse("Twitter_Battle")

When we execute it...we're going to have some interesting results...




Have fun with it -;)

Greetings,

Blag.

Twitter unfollowers with R and Rook - Revisited

Some time ago I wrote a post called Twitter unfollowers with R and Rook where I used R and Twitter to get a list of the people that we follow...but that doesn't follow us back...

Right now...that post is obsolete as Twitter changed its API to API 1.1 which means that OAuth authentication must be used...

So...of course...we're going to use that for our new version of Twitter Unfollowers -;)

Getting Twitter Auth
library("ROAuth")
library("twitteR")

setwd("C:/Blag/R_Scripts/Important_Scripts")

options(RCurlOptions = list( capath = system.file("CurlSSL", "cacert.pem", package = "RCurl"), ssl.verifypeer = FALSE))

reqURL<-"https://api.twitter.com/oauth/request_token"

accessURL<-"http://api.twitter.com/oauth/access_token"

authURL<-"http://api.twitter.com/oauth/authorize"

consumerKey<-"Your own Consumer Key"

consumerSecret<-"Your own Consumer Secret"

download.file(url="http://curl.haxx.se/ca/cacert.pem", destfile="cacert.pem")

credentials<-OAuthFactory$new(consumerKey=consumerKey,
                              consumerSecret=consumerSecret,
                              requestURL=reqURL,
                              accessURL=accessURL,
                              authURL=authURL)

credentials$handshake(cainfo = system.file("CurlSSL", "cacert.pem", package = "RCurl"))

save(credentials, file="credentials.RData")

What are we doing here is simply get Authorization from Twitter and save that information as an RData file that we can use later on. This script is needed to be executed only once...and will ask you to enter a PIN number to validate the connection...


After that...we're ready to go -;)

Twitter Unfollowers
require("Rook")
library("ROAuth")
library("twitteR")

setwd("C:/Blag/R_Scripts/Important_Scripts")
load("credentials.RData")
registerTwitterOAuth(credentials)
Get_Screen_Name<-function(p_userid){
  SomeUser<-getUser(p_userid,cainfo="cacert.pem")
  SomeUser<-SomeUser$screenName
  return(SomeUser)
}

newapp<-function(env){
  req<-Rook::Request$new(env)
  res<-Rook::Response$new()
  res$write('<form method="POST">\n')
  res$write('Enter your Twitter username: <input type="text" name="UserName">\n')
  res$write('<input type="submit" name="Get Bad People!">')
  res$write('</form>')
  
  People_Id<-""
  Bad_People<-c()
  Bad_Names<-c()
  j<-0  
  
  if (!is.null(req$POST())) {
    UserName = req$POST()[["UserName"]]
    
    User<-userFactory$new(screenName=UserName)
    followers<-User$getFollowerIDs(n=NULL,cainfo="cacert.pem")
    following<-User$getFriendIDs(n=NULL,cainfo="cacert.pem")

    for(i in 1:length(following)) {
      Match<-following[i] %in% followers
      if(Match == TRUE){
      }
      else{
        Bad_Person<-Get_Screen_Name(following[i])
        res$write(paste(' ',Bad_Person,sep=' '))
        res$write('</BR>')
      }
    }
}
  res$finish()
}

server = Rhttpd$new()
server$add(app = newapp, name = "Twitter_Rook")
server$start()
server$browse("Twitter_Rook")

Thanks to this...I was able to shrink the code from 85 lines of the previous version to only 51 lines of code...nice achievement if you ask me -;)

So...when we execute the code...we will have this...


Of course...I don't expect them all to follow me back as they are mostly companies...but for people...follow me back or get unfollowed -:P

Greetings,

Blag.

sábado, 9 de marzo de 2013

Getting flexible with SAP HANA


Most of you might not be aware of a feature introduced on SAP HANA SPS5. This new feature is called "Flexible Tables", which means that you can define a table that will grow depending on your needs. Let's see an example...

You define a table with ID, NAME and LAST_NAME. The table works fine, but you realize that you need to also add the PhoneNumber and Address...in a normal situation, you will need to open the definition and add those fields...but using Flexibles Tables, you will need to only add those fields as part of the INSERT query and let SAP HANA do it's magic...

Of course, that scenario is very unlikely to happen, because for a couple of fields, it doesn't make sense...so...where do we use this Flexible Tables? Enterprise Search, were we need to have all products on one table, and this table can have a really big amount of columns...as different products will have different characteristics...

So...for this blog...I really break my head trying to find a simple scenario that could cover Flexible Tables...what I came up with? SAP HANA, Flexible Tables, R and Twitter...

The code is very complex, so I'm not going to explain line by line how it works...but of course, I'm going to give a nice overview...

The Twitter API (I'm using version 1 even when it's deprecated, simply because version 1.1 deals with Authentication and didn't want to spend too much time on that...) allows us to fetch information from Twitter...so in this case I was interested in the Hashtags...the ones that starts with an "#" and are used to identify and organize certain tweets related to an event, technology or famous person. (I'm using only Tweets, not taking Retweets into account)...


Using R, I read the User Timeline to get the most recent 200 tweets from a particular account. This information will be send back to SAP HANA to be stored.



With the 200 tweets, I extract all the Hashtags, summarize them and then save the information both in the final table and in a intermediate table (to be used for the next user). In this intermediate table, I will store a long string with all the Hashtags separated by a comma.

When the next user arrives, all 200 tweets are read, Hashtags extracted, combine with the one saved in the intermediate table, summarized (This is very important because we want to keep track of the previous Hashtags, both the ones that are common to both users and the ones that only exist on the first or second user) and the information will be saved in the final table and the information from the next user will be save (replacing the previous one) as a long string in the intermediate table.

Why I need to this? Simple...let's say that the first user has 3 Hashtags...#SAPHANA, #R and #Python with values 3, 2 and 1. The next user will have 5 Hashtags...#SAPHANA, #SAP, #Ruby, #IPhone and #Android with the values 2, 5, 1, 4 and 3.

When we store the first user we will have:

UserNameSAPHANARPython
First_User321

When we store the second user, we will have...

UserNameSAPHANARPython SAPRubyAndroidIPhone
First_User321 ????
Second_User321 5143

Now...you may wonder...why R has "0" for the next user and SAP has "?" for the first user? Easy...as you can see...as we added more fields (at runtime) the table grow...the R field was already there for the first user so it got a "0" for the next user, however SAP wasn't there before, so we don't actually know what should the value for the first user...so a "?" will be in place...

I'm sure you will have a better picture when you see the images of the table after I show the source code...

First, we need to create a table called "TWITTER_USERS", that will hold the users that we want to work with...


Then, we need another table were we are going to store the Hashtags and its values as a long string. This table will be called "FIRST_HASH".


Now, things get interesting, as we're going to create our Flexible Table using a very simple command...this table will be called "TWITTER_HASHTAGS".

Twitter_Hashtags.sql
CREATE COLUMN TABLE TWITTER_HASHTAGS(
USERNAME NVARCHAR(10)
) WITH SCHEMA FLEXIBILITY;

This table will look pretty regular when watching its definition...but it's a Flexible Table...as you can see...we only defined one field...so this table can grow and grow and grow -;)


Next, we need to create a couple of type tables to allow to interact between SAP HANA and R...


Table_Types.sql
CREATE TYPE T_COL_NAMES AS TABLE(
COL_NAMES NVARCHAR(1000)
);
 
CREATE TYPE T_COL_VALUES AS TABLE(
COL_VALUES NVARCHAR(1000)
);

And now...we're ready to start with the code...one R procedure and two SQLScript procedures...

Get_Hashtags.sql
CREATE PROCEDURE GET_HASHTAGS(IN twittername TWITTER_USERS,IN first_hash FIRST_HASH,
                              OUT out_col_names T_COL_NAMES, OUT out_col_values T_COL_VALUES)
LANGUAGE RLANG AS
BEGIN
UserName = twittername$USERNAME
hashline = first_hash$HASH_LINE
hashvalues = first_hash$HASH_VALUES
 
Get_Twitter<-function(p_source,p_pattern){
  datalines = grep(p_pattern,web_page,value=TRUE)
  getexpr = function(s,g)substring(s,g,g+attr(g,'match.length')-1)
  g_list = gregexpr(p_pattern,datalines)
  matches = mapply(getexpr,datalines,g_list)
  result = gsub(p_pattern,'\\1',matches)
  names(result) = NULL
  return(result)
}
 
Get_Hashtags<-function(p_source){
  check<-!length(grep('\\"([^,\\"]+)\\"', as.character(p_source)))
  if(!check){
    mypattern = '\\"([^,\\"]+)\\"'
    datalines = grep(mypattern,p_source,value=TRUE)
    getexpr = function(s,g)substring(s,g,g+attr(g,'match.length')-1)
    g_list = gregexpr(mypattern,datalines)
    matches = mapply(getexpr,datalines,g_list)
    result = gsub(mypattern,'\\1',matches)
    names(result) = NULL
    return(result)
  }else{
    result<-p_source
    return(result)
  }
}
 
url<-paste("http://api.twitter.com/1/statuses/user_timeline.xml?count=200&screen_name=",UserName,sep="")
mypattern = '<text>([^<]*)</text>'
web_page<-readLines(url)
tweets<-Get_Twitter(web_page,mypattern)
mypattern = '[^\\&]#(\\.?\\w+)'
hash_list<-Get_Twitter(tweets,mypattern)
hashtags<-sapply(hash_list,Get_Hashtags)
hashtags<-as.vector(unlist(hashtags))
hashtags<-toupper(hashtags)
 
dt.hashtags<-data.frame(UserName,hashtags)
tab.hashtags<-table(dt.hashtags)
dt.hashtags<-as.data.frame.matrix(tab.hashtags)
hashtags_names<-names(dt.hashtags)
hashtags_names<-gsub("^\\.",'',hashtags_names)
 
if(length(hashline>=1)){
          hash_line<-gsub("^(\\w)+\\,",'',hashline)
          hash_line<-unlist(strsplit(hash_line, split=","))
          hash_values<-gsub("^(\\'+\\w+\\')+\\,",'',hashvalues)
          hash_values<-as.numeric(unlist(strsplit(hash_values, split=",")))
          hash_frame<-data.frame(names=hash_line,values=hash_values)
          hash_frame["values"]<-0
 
          Col_Names<-""
          Col_Values<-""
 
          for(i in 1:length(hashtags_names)){
                      Col_Names<-paste(Col_Names,hashtags_names[i],sep=",")
                      Col_Values<-paste(Col_Values,dt.hashtags[,i],sep=",")
          }
 
           Col_Names<-gsub("^\\,|\\.",'',Col_Names)
          Col_Values<-gsub("^\\,|\\.",'',Col_Values)
          Col_Names<-unlist(strsplit(Col_Names, split=","))
          Col_Values<-as.numeric(unlist(strsplit(Col_Values, split=",")))
          new_hash_frame<-data.frame(names=Col_Names,values=Col_Values)
          new_hash_frame<-rbind(hash_frame,new_hash_frame)
          new_hash_frame<-aggregate(values ~ names, FUN = "sum", data = new_hash_frame)
          new_hash_names<-new_hash_frame$names
          new_hash_values<-new_hash_frame$values
 
          Col_Names<-"USERNAME"
          Col_Values<-paste("'",UserName,"'",sep="")
 
           for(i in 1:length(new_hash_names)){
                      Col_Names<-paste(Col_Names,new_hash_names[i],sep=",")
                      Col_Values<-paste(Col_Values,new_hash_values[i],sep=",")
          }
}else{
          Col_Names<-"USERNAME"
          Col_Values<-paste("'",UserName,"'",sep="")
 
          for(i in 1:length(hashtags_names)){
                      Col_Names<-paste(Col_Names,hashtags_names[i],sep=",")
                      Col_Values<-paste(Col_Values,dt.hashtags[,i],sep=",")
          }
}
 
col_names<-gsub("^\\,\\.?",'',Col_Names)
col_values<-gsub("^\\,",'',Col_Values)
 
out_col_names<-data.frame(COL_NAMES=col_names)
out_col_values<-data.frame(COL_VALUES=col_values)
END;

Save_Hashtags.sql
CREATE PROCEDURE SAVE_HASHTAGS(IN in_col_names T_COL_NAMES, IN in_col_values T_COL_VALUES)
LANGUAGE SQLSCRIPT AS
v_select VARCHAR(2000);
v_col_names_char NVARCHAR(1000);
v_col_values_char NVARCHAR(1000);
CURSOR c_cursor1 FOR
SELECT COL_NAMES FROM :in_col_names;
CURSOR c_cursor2 FOR
SELECT COL_VALUES FROM :in_col_values;
BEGIN
                    OPEN c_cursor1;
                    FETCH c_cursor1 into v_col_names_char;
                    CLOSE c_cursor1;
                    OPEN c_cursor2;
                    FETCH c_cursor2 into v_col_values_char;
                    CLOSE c_cursor2;
                    DELETE FROM FIRST_HASH;
                    INSERT INTO FIRST_HASH VALUES(:v_col_names_char,:v_col_values_char);
                    v_select := 'INSERT INTO TWITTER_HASHTAGS (' || v_col_names_char || ') 
                                VALUES (' || v_col_values_char || ')';
                    EXEC v_select;
END;

Get_Twitter_Users.sql
CREATE PROCEDURE GET_TWITTER_USERS(UserName NVARCHAR(10))
LANGUAGE SQLSCRIPT AS
BEGIN
          Twitter_Users = SELECT USERNAME FROM TWITTER_USERS WHERE USERNAME = :UserName;
          First_Hash = SELECT HASH_LINE, HASH_VALUES FROM FIRST_HASH;
          CALL GET_HASHTAGS(:Twitter_Users,:First_Hash,T_COL_NAMES,T_COL_VALUES);
          CALL SAVE_HASHTAGS(:T_COL_NAMES,:T_COL_VALUES);
END;

In order for this to work, we need to insert some values on our "TWITTER_USERS" table...


And then, simply call the "GET_TWITTER_USERS" procedure...

Call_Get_Twitter_Users.sql
CALL GET_TWITTER_USERS('Blag');
CALL GET_TWITTER_USERS('Schmerdy');
CALL GET_TWITTER_USERS('ggread');

When we execute the first call...that's it with user @Blag we will have the following on the "FIRST_HASH" table...


And this on our "TWITTER_HASHTAGS" Flexible Table...


As you can see...our table started only with USERNAME...but as we pass in the Hashtags and its values...the table grew to able to hold them...

When we call the next user...that's @Schmerdy we will have this on the Flexible Table...


As you can see...in all the Hashtags that belong to @Blag but doesn't belong to @Schmerdy we have a "0" value...so what will happen to the ones that belong to @Schmerdy but not to @Blag?


Those field will have a "?" value, as they didn't exits before we add them...and again...the table grew to hold all the new fields....

Now...something interesting is that @Schmerdy had more Hashtags than @Blag...so what will happen when we call the last user which is @ggread that by the way...has less Hashtags than @Schmerdy and @Blag...


@ggread will have a value "0" in all the Hashtags that doesn't belong to the user...but will have a value in the one that are similar to @Schmerdy...


So...what will happen with the Hashtags that belongs to @ggread but doesn't exist on @Schmerdy or @Blag? Easy...they will be added and some "?" value will be placed where those Hashtags didn't exist before...


I wish I could put the whole table...but it contains more than 50 columns...so better...I can export them to a .CSV file...and do some analysis using Visual Intelligence...


Here, we can see how often these three user have used the Hashtags #SAPHANA, #SAP and #SAPTECHED in their last 200 tweets...

So...that's it...a nice and simple way to demonstrate how the Flexible Tables work in SAP HANA by using my always beloved R -:)

Greetings,

Blag.


martes, 12 de junio de 2012

Twitter unfollowers with R and Rook

In my last blog I'm following you in Twitter...are you following me back? I show you how to use the Twitter APIs to get a list of the people that you follow but doesn't follow you back.

This time, I want to extend the tool as I installed the Rook library on my RStudio -:)

So..what is Rook? Nothing more that just a nice Web Server for R...something that I was really missing in R when compared to Ruby (Sinatra, Camping) or Python (Bottle, Flask).

The idea here is that we request a Twitter username and then provide the list with the "Bad People". Here's the source code...

require("Rook")

Get_Twitter_Info<-function(p_source){
  web_page<-readLines(p_source)
  mypattern = '<id>([^<]*)</id>'
  datalines = grep(mypattern,web_page,value=TRUE)
  getexpr = function(s,g)substring(s,g,g+attr(g,'match.length')-1)
  g_list = gregexpr(mypattern,datalines)
  matches = mapply(getexpr,datalines,g_list)
  result = gsub(mypattern,'\\1',matches) 
  names(result) = NULL
  return(result)
}

Get_Screen_Name<-function(p_userid){
  user_url<-paste("https://api.twitter.com/1/users/lookup.xml?user_id=",
                      p_userid,"&include_entities=false")
  web_page<-readLines(user_url)
  mypattern = '<screen_name>([^<]*)</screen_name>'
  datalines = grep(mypattern,web_page,value=TRUE)
  getexpr = function(s,g)substring(s,g,g+attr(g,'match.length')-1)
  g_list = gregexpr(mypattern,datalines)
  matches = mapply(getexpr,datalines,g_list)
  screen_name = gsub(mypattern,'\\1',matches)
  names(screen_name) = NULL
  return(screen_name)
}

trim <- function(x){
  x<-gsub(' ','',x)
  return(x)
} 

newapp<-function(env){
  req<-Rook::Request$new(env)
  res<-Rook::Response$new()
  res$write('<form method="POST">\n')
  res$write('Enter your Twitter username: <input type="text" name="UserName">\n')
  res$write('<input type="submit" name="Get Bad People!">')
  res$write('</form>')

  People_Id<-""
  Bad_People<-c()
  Bad_Names<-c()
  j<-0  
  
  if (!is.null(req$POST())) {
    UserName = req$POST()[["UserName"]]
    
    followers_link<-paste("https://api.twitter.com/1/followers/ids.xml?cursor=-1&screen_name=",UserName)
    following_link<-paste("https://api.twitter.com/1/friends/ids.xml?cursor=-1&screen_name=",UserName)
    followers_link<-trim(followers_link)
    following_link<-trim(following_link)    
    followers<-Get_Twitter_Info(followers_link)
    following<-Get_Twitter_Info(following_link)
        
    for(i in 1:length(following)) {
      j<-j+1
      if(j>=100){
        j<-0
        People_Id<-substring(People_Id,2)
        Bad_People<-Get_Screen_Name(People_Id)
        Bad_Names<-append(Bad_Names,Bad_People)
        People_Id<-""
      }
      Match<-following[i] %in% followers
      if(Match == TRUE){
      }
      else{
        following[i]<-trim(following[i])
        People_Id<-paste(People_Id,following[i],sep=",")
      }
    }    
  }
  for(i in 1:length(Bad_Names)) {
    res$write(paste(' ',Bad_Names[i],sep=' '))
    res$write('<BR>')
  }
  res$finish()
}

server = Rhttpd$new()
server$add(app = newapp, name = "Twitter_Rook")
server$start()
server$browse("Twitter_Rook")

When we run the code, the browser will open automatically showing us the application.



For my first use of Rook, I think the application looks pretty nice...and hope those that doesn't follow me back...start doing it -:P

Greetings,

Blag.


sábado, 9 de junio de 2012

I'm following you in Twitter...are you following me back?

If you spend some time on Twitter, you might have some followers and some people that you follow...the more time you spend, the more people you're going to interact with...

Sometimes, you just realized that you're following some many people that might or not follow you back...for some "accounts", it doesn't matter...I mean...if I follow @annafaris I don't expect her to follow me back...would love that of course, but I have some common sense -:) But...when it's a John Doe that I follow...and doesn't follow me back...things get personal...and it's time to clean up Twitter a little bit...

Twitter provides some useful APIs that are sadly restricted to only 150 calls per hours as you can verify by calling Rate_Limit_Status.

Anyway...I was thinking about doing something with Twitter and specially the people that I follow and doesn't follow me back...so of course...I choose #R as I have already done some interesting things with Python...

setwd("C:/Debug/R Source Codes")

Get_Twitter_Info<-function(p_source){
  web_page<-readLines(p_source)
  mypattern = '<id>([^<]*)</id>'
  datalines = grep(mypattern,web_page,value=TRUE)
  getexpr = function(s,g)substring(s,g,g+attr(g,'match.length')-1)
  g_list = gregexpr(mypattern,datalines)
  matches = mapply(getexpr,datalines,g_list)
  result = gsub(mypattern,'\\1',matches) 
  names(result) = NULL
  return(result)
}

Get_Screen_Name<-function(p_userid){
  user_url<-paste("https://api.twitter.com/1/users/lookup.xml?user_id=",
                      p_userid,"&include_entities=false")
  web_page<-readLines(user_url)
  mypattern = '<screen_name>([^<]*)</screen_name>'
  datalines = grep(mypattern,web_page,value=TRUE)
  getexpr = function(s,g)substring(s,g,g+attr(g,'match.length')-1)
  g_list = gregexpr(mypattern,datalines)
  matches = mapply(getexpr,datalines,g_list)
  screen_name = gsub(mypattern,'\\1',matches)
  names(screen_name) = NULL
  return(screen_name)
}

trim <- function(x){
  x<-gsub(' ','',x)
  return(x)
} 

followers<-Get_Twitter_Info("https://api.twitter.com/1/followers/ids.xml?
                                cursor=-1&screen_name=Blag")
following<-Get_Twitter_Info("https://api.twitter.com/1/friends/ids.xml?
                                cursor=-1&screen_name=Blag")

People_Id<-""
Bad_People<-c()
Bad_Names<-c()
j<-0

for(i in 1:length(following)) {
  j<-j+1
  if(j>=100){
    j<-0
    People_Id<-substring(People_Id,2)
    Bad_People<-Get_Screen_Name(People_Id)
    Bad_Names<-append(Bad_Names,Bad_People)
    People_Id<-""
  }
  Match<-following[i] %in% followers
  if(Match == TRUE){
  }
  else{
    following[i]<-trim(following[i])
    People_Id<-paste(People_Id,following[i],sep=",")
  }
}

write.csv(Bad_Names,"Bad_Names.csv",row.names=FALSE)

This little program will take my followers (from my account @Blag), and the people I follow...a simple loop at the people I'm following allows me to determine who is following back or not. With that identified, I made groups of 100 User Id's (As the Lookup API only support 100 accounts) and grab their user names...

Finally, I generate a .CSV file with all the people who I follow but doesn't follow me back...time to clean up my Twitter -;)

P.S: Would love to show the generated file...but...don't want to expose the names of  the Bad People, who only but unforgivable crime is not to follow me back -:)

Greetings,

Blag.

martes, 13 de julio de 2010

TripIt.com listens...


Yesterday I was kinda angry...I'm supposed to make a trip to Bathurst, New Brunswick, Canada for work...so the first thing I did was to go to TripIt and tried to add a trip.

At first I got confused as I saw this...


Australia? Where my boss is sending me? That's pretty far from Montreal! So I checked my flight tickets...and of course...I wasn't going to Australia...so I tried again...


Unable to resolve? Where I was going? To a hidden place? So angry as I was I posted this on Twitter...


So...after a long day of hard work...I went home...when I was going to into the elevator, I got an email on my IPhone...from TripIt!!!


So they actually listen to me...even when I didn't tweet them directly...even when I didn't use a hashtag...even when I'm just a regular Geek trying to make a living...

This time, TripIt really surprise me as they use Twitter as a real tool for customer support...kudos for TripIt and kudos for Ruth who was kind enough to read my tweet and actually make something about it.

After this...and as soon as I can...I'm going Pro on TripIt -;)

Greetings,

Blag.

miércoles, 7 de octubre de 2009

My evil plans for SAP TechEd Phoenix 2009


We're only 4 days away from TechEd...and I was planning to inform about my evil plan this Saturday...but couldn't resist -;)

If you follow my blogs on SCN you might know that on my first TechEd (Las Vegas 2007) I wrote one blog per day...a very difficult task of course, so in my second TechEd (Las Vegas 2008) I wrote a "in a nutshell" blog, summarizing all that happened there...this year, it's going to be my third TechEd...so I want to do something different from last year...I want to share even more! -:D

So...my evil plans are this:

*"The Blag Show - Limited Edition Podcast" to be launched this Saturday...and one per day...

* A short blog per day on SCN.

* Video Blogging, mostly on RIA Hacker Night and Community Clubhouse.

* Blagbert comics about TechEd funny situations. Yes...Blagbert is going to TechEd too -;)

* Twitter stream for sure -;)

* Assist @jspath55 giving out @SCNotties awards.


A Gapinvoid comic strip kindly send to me by Mrinal Wadhwa (@mrinal)

Greetings,

Blag.

jueves, 6 de agosto de 2009

Twitter is down...but don't panic...


Believe it or not...Twitter is down again...so what can we do now?

Relax...there's always a nice and elegant solution to this kind of critic problems...just visit this site... When Twitter is down

Greetings,

Blag.

jueves, 22 de enero de 2009

SAP Mentors...On Twitter? Yes Sir!


Do you know about SAP Mentors? You should...I'm one myself -:)

Wanna know what we are up to? Follow us on SAP Mentors on Twitter.

Also you could check this nice list and follow all the guys/gals that didn't made it to my previous list...Otherwise they're going to go mad on me -:(

It's hard to keep everyone happy -:)

Greetings,

Blag.

Who you should be following on Twitter...


Twitter is a great service, no doubt about it...But sometimes is hard to choose who to follow and who not.

That's why I' want to drop a little list of interesting people...

@Blag --> Alvaro Tejada Galindo (That's me of course). Senior ABAP Consultant, Scripting Languages Geek, SAP Mentor, Blogger, Programming books author and Punk. I don't need no introduction -;)

@dahowlett --> Dennis Howlett. Full time blogger on innovation for professional accountants. This talks straight to the face, no jokes...Just the awful truth.

@monkchips --> James Governor. Co-founder of RedMonk, something like a firehose - tech and everything else in 140 char bursts. This is your reference for everything IT related.

@_why --> Why the Lucky Stiff. The ill-conceived freelance prof. If you're related to Ruby, Camping or Shoes...He's your guy -;)

@jonerp --> Jon Reed. Jon Reed of JonERP.com is an SAP Mentor who blogs and podcasts on SAP skills trends. No one knows more about SAP that this guy...Ok...Maybe SAP CEO's...

@TechCrunch --> Michael Arrington. Making The World A More Ajaxy Place. Come on...You know you love TechCruch!

@ChuckFacts --> Chuck Norris Facts. You better follow him...You're life depends on it...

@ryanstewart --> Ryan Stewart. I obsess over Rich Internet Applications and work at Adobe as a Platform Evangelist. Are you on RIA? Follow this guy then!

@Scobleizer --> Robert Scoble. Tech geek blogger @ http://scobleizer.com. I don't this guy, but all my friends follow him...He must be good stuff...

@Veronica --> Veronica Belmont. Host of Tekzilla on Revision3 and Qore on PSN. Also, a geek. She's a geek girl...What else can you ask for?

@timoreilly --> Tim O'Reilly. Founder and CEO, O'Reilly Media. If you don't know Tim...You shouldn't be on the web...

@jwales --> Jimbo Wales. You know, the Wikipedia and Wikia guy. Believe or not...I got a picture with this guy!!!

Please keep in mind, that not only because you start following them, they're going to follow you back...If you think that, you really need to read this...

Do you follow me on Twitter? Coz I'm not following you...

P.S: To all my dear and beloved Geek friends (Yes...SAP Mentors and SCN related), if you're not on my list, it's not because you're not interesting to follow...It's because this is a short list...And wanted to put the most representative guys/gals that I'm following...If I'm on the list...It's because this is my blog and I can do what I want here...Don't like it...Do your own list on your own blogs!

P.S.S: I'm joking of course -;)

P.S.S.S: Thanks to my good friend @luislanz --> Luis Felipe Lanz. NetWeaver Visual Composer Expert at SAP AG. This is a direct link to all the people I'm following...

Who's Blag following.

Greetings,

Blag.

miércoles, 17 de diciembre de 2008

Do you follow me on Twitter? Coz I'm not following you...


I have using Twitter for a long time...And I can't deny that I totally love the service (Even with the whales)...

But there's something that I still don't get...Why people try so hard to be the Promo Queens? Sometimes I see profiles following thousands of people and being followed by another thousand of people...I really don't see a point on this...

Guy Kawasaki
posted on his blog a nice essay called How to Use Twitter as a Twool, while I like it, I don't follow his idea of using Twitter as a marketing tool. Why? Simple answer...I use Twitter to keep in touch with my friends or to know people who share my interests...Why on earth would I follow someone who doesn't nothing related to my own interests?


You can see that 368 individuals follow me, but I only follow 235...There are 133 individual that I don't follow...

I simply don't want my Twitter flooding with Tweets that I don't want to read or are in any way interesting to me...

Pretty sure, I'm going to loose some followers after this post...I don't care...I just my Twitter to be plain and simple -;)

Greetings,

Blag.

viernes, 31 de octubre de 2008

Tweeting like the pros...With Twitwall


If you're a Twitter addict, like me -;) You should be aware of Tinypaste and TwitPic, two wonderful Twitter companions...But are you aware of Twitwall?

This free service created by Michael E. Carluen provides the same functionality as Tinypaste and TwitPic with some more cool features...Let's see some pictures...



You first notice that the interface is very similar to Twitter, but you can change font size and color -:)


You got a very nice RichText editor with the change to include pictures on the same post...


The pictures gets embed in your post...And yes...I attached the same picture as above -:) Have you noticed that you can actually add a title and description to your post?


On Twitter you see the title, and a link send you to Twitwall to see both the picture and the description on your post.

After seeing this...Why you haven't create you account yet? You even got Twitter Grader inside you account -:D

Greetings,

Blag.

jueves, 28 de agosto de 2008

The Twitter phenomena


No one can deny that Twitter is a huge success...Thanks to it many Microblogging sites appeared, by say, Indenti.ca, Plurk, Pownce. Those sites are good, but most of the people who left Twitter slowly back to it...

Of course...Twitter is far from perfection...We must take a look at this nice pictures at least twice a day...


A lot have been already talked about the scalability problems of Twitter, they are using Rails, and planning to migrate to PHP...Meanwhile, we must suffer the consequences of a too rapidly grow system...

Many people just can't stop Tweeting...I'm one of them -;) I really feel bad if I can't post at least once a day...Or at least read what my friends are saying...

Another example, that it's not tightly related with Twitter but shows how can a website can be degrated is Hi5. It started as a good site, a good choice for Social Networking...But let's face it...It really sux right now...I got millions of users doing whatever they want with the system...I don't any Geek is using it anymore...In the same path is Facebook which is recently starting to take control over it's app's.

It's great to give user control over Social Networking sites, but when you give them enough rope...You take the risk of loosing everything...

I know that Twitter is not facing the same problems as those websites, but SPAM accounts
and people following millions of users (And those millions of users following millions of users), are slowly killing it...

Everyday I get notifications of people following me...99% of the times...I don't even know them, or the don't speak Spanish neither English, or they are not related to SAP, Programming or anything interesting. People follow people just to get millions of friends...Or to be the Promo Queens...Anyway, that's not a good thing...

I really love Twitter and I don't want it to die...But...Only time knows...

Taken from http://ephemerist.files.wordpress.com

Greetings,

Blag.

martes, 22 de julio de 2008

Even Google is afraid of Chuck Norris...


By following ChuckNorris_ on Twitter I discovered this interesting fact...

Go to Google...Type find chuck norris...Press I'm feeling lucky...


Get amazed -:)


Another reason to fear Chuck...

Greetings,

Blag.

sábado, 28 de junio de 2008

Chinposin...Show you authority


Ok...Let's pretend were on Twitter and it's Friday...What does it means? Yeah! It's Chinposin Day!!!

So...What does means? Ok...Let's review some history...

Basically James Governor and Chris Dalby thought that it could be funny to make everyone update their Twitter profiles with Chinposin pics...Lame idea you might think...And maybe your right...But now, Chinposin got millions of followers...Ok, maybe not so much, but sure they had a lot of people working hard all week to post the best chinpose picture on Fridays...I'm one of those of course -;)


Ok...I know you guys are hard to get...You might be thinking..."Sure...nice thing...but a Chinpose picture every Friday it's kind of boring"...I agree...Really....But the Chinposin master is aware of that too -;) So every Friday we got a new and fresh them...Superheros...Younger you...Grooming...So the fun never ends -:D

So now...I'm pretty sure I got your interest right? You wanna know how to join the club...Piece of cake...

Follow the Chinposin Master on Twitter...


Change the picture in your profile and send an update...


You can review your status on the Chinposin main page.



Enough said...Chinposin is not a pose...It's a way of life!

Greetings,

Blag.