Sunday, November 20, 2011

Twitter @Anywhere and PHP Symfony. Implementing login action

While playing with the Twitter @Anywhere and PHP Symfony I have implemented "Sign in with Twitter" method for RoundTeam app (http://roundteam.co).

How it was done:

Creating a placeholder to represent "Sign in with Twitter" button.
mainpageSuccess.php:
<span id="login" class="twit_login">Sign in with Twitter</span>
I am not going to describe CSS part here.

Enabling Twitter connection using @Anywhere
javascript (rt.js):
$(document).ready(function() {
    twttr.anywhere(function(T) {
        $("#login").bind('click', function () {
            T.signIn();
        });
    }
Now when user clicks on "Sign in with Twitter" button he will be prompted to login using Twitter credentials. On this step "twitter_anywhere_identity" cookie is created (more details about this cookie and how to interpret it on server side see here: https://dev.twitter.com/docs/anywhere/welcome).

Okay, now we need to notify server that login has happened.
Here is one of the ways to implement this using PHP Symfony:

routing.yml
rt_get_user:
  url: /rt/user
  param: {module: connect, action: user}

action.class.php (for module "connect"):
public function executeUser(sfWebRequest $request) {
$cookie = $request->getCookie('twitter_anywhere_identity');
$this->logMessage('got auth request');
if ($cookie) {
$twitter_data = explode(':', $cookie);
$userId = $twitter_data[0];
$secret = $twitter_data[1];
$calculatedSecret = sha1($userId.RoundTeam_auth::SECRET);

if ($secret === $calculatedSecret) {
$this->logMessage('secret verified');
$userJson = $request->getParameter('user');
if ($userJson) {
$this->logMessage('user found!');
$user = json_decode($userJson);

$this->data = $user;

$this->logMessage($userJson);

$screenName = $this->data->screenName;
if (TeamTable::getInstance()->exists($screenName) == false) {
$this->logMessage('authenticated: '.$screenName);
$this->getUser()->signIn($this->data);
} else {
$this->logMessage('Failed to login using team: '.$this->$screenName, 'err');
}
} else {
$this->logMessage('user not found');
}
}
}
$this->redirect('@rt');
}

The last step is to post user data to server and reload page:

T.bind("authComplete", function (e, user) {
        post('rt/user', {user: JSON.stringify(user)}, function(response) {
        location.reload();
    });
});

That's it. Now user may login using his twitter credentials without leaving the round-team.com page. User data is passed to server and server authenticates user to enter.

It means that user stays logged in on both client side and server side. That said when you implement logout don't forget to log out user from server side:
$this->getUser()->setAuthenticated(false);
and client side:
twttr.anywhere.signOut();

Complete js code listing may be found on http://round-team.com

Saturday, April 2, 2011

Mozilla Firefox -- getting Social

Let me share my experience of how to make Mozilla Firefox more "social" browser. So it will keep you up-to-date with your communication channels, like social networks, mail accounts, news feeders etc.

Twitter, Facebook, LinkedIn

Yonoo plug-in for Firefox keeps me connected. Some features:
  • All updates in one line -- no more different tabs of several lines of updates. Twitter, Facebook, YouTube, LinkedIn and many other instant messengers/social networks feeds are listed in one place (being still distinguishable)
  • Minimum extra space -- when collapsed it costs me one small column to the left of the browser window. I use 11'inch laptop for my daily work, so, being concerned about every pixel, I am totally fine with this size
  • Simple yet flexible user interface
  • Amount of new items is shown even if main view is collapsed
  • Pop-up notifications in bottom-right corner of browser (may be turned off)

Google reader

I use Google Reader Watcher to stay updated with the latest news. Be careful not to install this plug-in instead.

What I don't like about this plug-in is that it is located in status bar thus not visible in full-screen mode. Well, it's still better than open a new tab.

Gmail

Have a look at Gmail Watcher. The only Gmail Firefox add-on which is installed into navigation bar (not status bar). Also, it doesn't require to enter login/password.

These add-ons all together provide me constant connectivity to the community.

If you have other cool socializing Firefox add-on to share -- please comment on this post!

Thursday, March 31, 2011

Yet another "Like" button

Google has introduced own Facebook-"Like" button named "+1".
Yet another "+1" button...

Have a look at the article on CNN.com announcing it:
http://money.cnn.com/2011/03/30/technology/google_button/index.htm

It has 9(!) links with partially duplicated functionality to share this article.
With Google's it will be 10. Too many, as for me. How do you think?

Also considering various integrations supported by many social applications like
Facebook <-to-> Twitter <-to-> LiveJournal <-to-> LinkedIn <-to-> Facebook -- for more and more people that becomes irrelevant to make this choice. Because any choice will produce the same result. I do not see any reason for this number of "like and share it" links. That amount produces minimum value for end-user (read contributors) and noises web-pages.

However that's a political move, that's clear. That's pity that companies like Google always being thinking about the end-user first start to produce things which are good for Google, less for googlers.

Tuesday, March 29, 2011

Java 7 support in IDE's

Eclipse versions up to 3.6 (Helios) do not support Java SE 7 features completely.
I have installed JDK 7 on Ubuntu laptop, however this is not possible now programming using it within Eclipse.

Java 7 support is expected in the next Eclipse release which 3.7 aka Indigo planned for June 2011.

IDEA update 10.5 planned for Spring 2011 will include Java 7 support.

And of course, Java 7 is already supported in NetBeans. Are you surprised?..

Monday, March 28, 2011

Mergesort in Java

A simple implementation of Mergesort in Java.
Mergesort algorithm is used in Java SE Collections.sort() method.
Provided implementation has an optimization which prevents already ordered arrays to be merged thus guarantees O(n*log n) time performance.

Mergesort is particularly useful for "online" sorting which means that all amount of data is not known in advance and is becoming available to sorting mechanism chunk-by-chunk.
In this case algorithm can sort each new chunk and then effectively merge it into existing sorted structure. For such cases mergesort is much more effective than quicksort.

One of the "cons" for mergesort is that it uses O(n) auxiliary memory in distinct of quicksort which operates in constant O(1) memory.

It is possible to implement merge sort to be in-place (use constant auxiliary memory) and stay stable, however these algorithms are overcomplicated and their complexity usually is not balanced by their benefit.

public class Mergesort {
 public static int[] sort(int... array) {
  return new Mergesort().sort(array, 0, array.length - 1);  
 }
 
 private int[] sort(int[] array, int start, int end) {
  if (start >= end) {
   return array;   
  }
  int pivot = start + (end - start) / 2 + 1;
//  At this point end may become bigger than start because of integer
//  division. If pivot == start => pivot - 1 < start
  sort(array, start, pivot - 1);
  sort(array, pivot, end);
  merge(array, start, pivot, end);
  return array;
 }

 public int[] merge(int[] array, int start, int pivot, int end) {
  if (start == end) {
//   array of one element is already sorted
   return array;
  }
  
  if (array[pivot - 1] <= array[pivot]) {
//   Handling the case when array is already properly sorted. This optimization
//   guarantees O(n*log n) sorting time 
   return array;
  }
  
  int length = end - start + 1;
  int[] merged = new int[length];
  for (int i = start, j = pivot, storeIndex = 0; i < pivot || j <= end; storeIndex++) {
   if (i == pivot) {
    merged[storeIndex] = array[j++];
   } else if (j > end) {
    merged[storeIndex] = array[i++];
   } else {
    merged[storeIndex] = array[i] <= array[j] ? array[i++] : array[j++];
   }
  }
  System.arraycopy(merged, 0, array, start, length);
  return array;
 }
}

Don't trust Wiki blindly

Sometimes Wiki contains inconsistencies even for basic computer science articles. Wiki page for merge sort states that Java SE 7 uses merge sort as a default implementation for Arrays.sort() method. However that's not true.


Oracle Java SE 7 documentation for Arrays.sort() clearly states that the default implementation is based on tuned Double-Pivot version of Quicksort.

This is important if some applications depend on stable sorting algorithms.
Merge sort is stable, quicksort is not (in most implementations).

Quicksort in Java

Java implementation of Quicksort

Best case O(n*log n)
Worst case O(n^2) -- the worst case is appeared when the worst pivot is taken for every iteration. In this case Quicksort acts very similar to bubble-sort.

public class Quicksort {
 public static int[] sort(int... array) {
  Quicksort quicksort = new Quicksort();
  return quicksort.sort(array, 0, array.length - 1);
 }

 private int[] sort(int[] array, int start, int end) {
  if (end - start <= 0) {
//   TODO: Consider other sorting for short arrays
   return array;
  }
  int pivotIndex = selectPivotIndex(array, start, end);
  pivotIndex = partition(array, start, end, pivotIndex);
  sort(array, start, pivotIndex - start);
  sort(array, pivotIndex + 1, end);
  return array;
 }

 private int partition(int[] array, int start, int end, int pivotIndex) {
  int pivotValue = array[pivotIndex];
  int storeIndex = start;
  swap(array, pivotIndex, end);
  
  for (int i = start; i < end; i++) {
   if (array[i] < pivotValue) {
    swap(array, i, storeIndex++);
   }
  }
  swap(array, storeIndex, end);
  return storeIndex;
 }

 private void swap(int[] array, int index1, int index2) {
  int temp = array[index1];
  array[index1] = array[index2];
  array[index2] = temp;
 }

 private int selectPivotIndex(int[] array, int start, int end) {
//  TODO: Consider better pivot selection
  return start + (end - start) / 2;
 }
}