Home » Odeon Blogs »

Tudor, UI/UX Maestro

Google App Engine Update

Note to self: After updating the Google Appengine SDK for MacOS Snow Leopard, I must run GoogleAppEngineLauncher which creates some symlinks. Otherwise importing the SDK in Python doesn't work anymore.

Categories: GAE Python

Leave a Comment

jQuery Mobile Framework

Web apps or native apps built with PhoneGap and likings allow a lot of user interface freedom. Freedom always comes at a price. In these case the price is the balance between time spent and quality of the designed user interface elements.

jQuery Mobile Framework

The current state

Sencha Touch looks like a good combination between HTML5, CSS3 and JavaScript aimed at the mobile space. I’ve got only one issue with it, how many developers use Ext JS library?

jQTouch is another library good for mobile web page and it imitates pretty closely the iPhone interface. I’ve found it so neat and fun that I’ve even made a prototype for Grokking.it using jQTouch and wrote a simple extension for it to support multi-touch events. The only problem I had with jQTouch is that it requires a pretty strict mark-up, so most of the pages are pre-loaded and some hacks were needed for dynamic pages.

The new kid

The official jQuery Mobile Framework. First of all because jQuery rocks. The community is cool, the development time it saves is amazing and the results are limitless. One thing they tried before is to make a standard for interfaces around the web trough their jQuery UI. 

jQuery Mobile Framework does look promising. Here’s a preview of some user interface elements for mobiles and tablets: http://jquerymobile.com/designs/. This does look promising and I’m more than excited to experiment with jQuery Mobile Framework, maybe even in a real life application.

Categories: Android BlackBerry Javascript iphone mobile


Tagged as: javascrip jquery

Leave a Comment

Corey Haines Talks Software Craftsmanship

Robert Dempsey and Corey Haines talk about the growing software craftsmanship movement.

"We don’t do computer science, we built business software."
Corey Haines

Categories: talents tdd

Leave a Comment

Django Test Client [quick tip]

While using the Django Test Client, sometimes views need to access request.META['HTTP_HOST'].

Sometimes the views need to retrieve request.META['HTTP_HOST']. This key is not available by default in Django's Test Client. Here's an example on how to enable it:

  1. host = 'django.testserver'
  2. client_providing_host = Client(HTTP_HOST=host)
  3. response = client_providing_host.get('/test_client/my_view/')

The default Django TestCase already contains an instance of the Test Client. Here's how to overwrite it:

  1. def setUp(self):
  2. self.client = Client(HTTP_HOST = "django.testserver")

Categories: Django tdd

Leave a Comment

Geo-location Point Inside Area

I was curious to detect if a known point is inside a polygon. Turns out that the algorithm is far simpler than I thought. Now think of this point as a person inside a building. Is the guy really inside the building?

Here is the test which can be used as an example use case:

  1. import unittest

  2. from insidePolygon import Point, is_inside_polygon

  3. class insidePolyTest(unittest.TestCase):

  4. def test_defaults(self):
  5. p = Point()
  6. self.assertEquals(p.x, 0)
  7. self.assertEquals(p.y, 0)

  8. def test_defaults(self):
  9. p = Point(3, 4)
  10. self.assertEquals(p.x, 3)
  11. self.assertEquals(p.y, 4)

  12. def test_is_inside_poly(self):
  13. poly = [Point(1,5), Point(5,5), Point(3,2), Point(1,5)]
  14. outside_point = Point(1,2)
  15. self.assertFalse(is_inside_polygon(poly, outside_point))
  16. inside_point = Point(3,4)
  17. self.assertTrue(is_inside_polygon(poly, inside_point))

  18. def test_geo_data(self):
  19. london = Point(51.501249,-0.126271)
  20. berlin = Point(52.540227,13.420944)
  21. madrid = Point(40.427994,-3.70182)
  22. rome = Point(41.922444,12.48436)
  23. paris = Point(48.860589,2.350674)
  24. bucharest = Point(44.443945,26.101341)
  25. # triangle
  26. poly = [london, berlin, madrid, london]
  27. self.assertTrue(is_inside_polygon(poly, paris))
  28. self.assertFalse(is_inside_polygon(poly, bucharest))
  29. # rectangle
  30. poly = [london, berlin, rome, madrid, london]
  31. self.assertTrue(is_inside_polygon(poly, paris))
  32. self.assertFalse(is_inside_polygon(poly, bucharest))

  33. unittest.main()

Ok. So Paris is inside the triangle made by London, Berlin and Madrid. Bucharest isn't.

Europe

Might not be a deal-breaker for some, but I'm really disappointed by "check-in" applications. First because just stating that I'm present at a certain point on the globe is not fun. Secondly, if the application associates that point to a venue, it should better check if the person checking-in is really at that venue, maybe with a small margin of error, like a 500m radius. Why am I allowed to check-in 15.000 km away and get points for that? Yes, I'm talking about Foursquare-ish apps.

Here's the Python code for calculating this:

  1. class Point:
  2. x = 0
  3. y = 0

  4. def __init__(self, x = 0, y = 0):
  5. self.x = x
  6. self.y = y

  7. def __str__(self):
  8. return "(%s, %s)" % (self.x, self.y)

  9. def max(a, b):
  10. if a > b:
  11. return a
  12. return b

  13. def min(a, b):
  14. if a < b:
  15. return a
  16. return b

  17. def is_inside_polygon(poly, point):
  18. n = len(poly) - 1
  19. counter = 0

  20. p1 = poly[0]
  21. for i in range(0, n + 1):
  22. p2 = poly[i % n]
  23. if point.y > min(p1.y, p2.y):
  24. if point.y <= max(p1.y, p2.y):
  25. if point.x <= max(p1.x, p2.x):
  26. if p1.y != p2.y:
  27. xinters = (point.y - p1.y) * (p2.x - p1.x)/(p2.y - p1.y) + p1.x
  28. if p1.x == p2.x or point.x < xinters:
  29. counter += 1
  30. p1 = p2
  31. if counter % 2 == 0:
  32. return False
  33. return True

If Elvis was using Foursquare or Koprol - the cool new Geolocation Social Network from Yahoo - we would have known when he left the building.

Categories: curiosity iphone mobile sparks

Leave a Comment

Facebook Photo Upload From Google App Engine

The Facebook Graph API can handle photo uploads. If no album ID has been specified, the photo is uploaded to a new album, which is named after your application. The following implementation is a Kay Framework deployment, but with a few changes can be done in other frameworks too.

The form

  1. <form enctype="multipart/form-data" action="/facebook/photo_upload/" method="POST">
  2. <input type="hidden" name="MAX_FILE_SIZE" value="100000" />
  3. <input type="hidden" name="access_token" value="{{ access_token }}" />
  4. Choose a file to upload: <input name="file" type="file" /><br />
  5. <input type="submit" value="Upload File" />
  6. </form>

Where:

access_token - OAuth2 token retrieved from Facebook. I've used the official Python SDK for Facebook Graph API. You can grab it from here, and the actual library is here..

action="/facebook/photo_upload/" - a url mapped inside my application to process the form post.

The view

This is where the form is processed. It retrieves the logged in Facebook user, then sends a multi-part post request to Facebook's API.

  1. def test_graph_api(request):
  2. import facebook, utils
  3. auth = facebook.get_user_from_cookie(request.cookies, FACEBOOK_APP_ID, FACEBOOK_SECRET)
  4. if not auth:
  5. return NotFound()
  6. access_token = auth['access_token']
  7. out = ''
  8. if request.method == "POST":
  9. out = utils.posturl('https://graph.facebook.com/me/photos', [('access_token', request.form['access_token'])],
  10. [('myfile', 'myimage.jpg', request.files['file'].stream.read())])
  11. return render_to_response('fb/index.html',
  12. {'access_token': access_token,
  13. 'out': out})

After posting to Facebook, it prints the response from Facebook which should contain the new photo's ID and should look like the code snippet bellow. Note: this is a string, not a dictionary, so you need to parse it.

  1. {"id":414686348004}

On line 9 utils.posturl() is a helper defined in the next section.

The helpers

This is the fun part, because here I post a multi-part form to Facebook.

  1. def posturl(url, fields, files):
  2. import urlparse
  3. urlparts = urlparse.urlsplit(url)
  4. return post_multipart(urlparts[1], urlparts[2], fields,files)
  1. def post_multipart(host, selector, fields, files):
  2. """
  3. Post fields and files to an http host as multipart/form-data.
  4. fields is a sequence of (name, value) elements for regular form fields.
  5. files is a sequence of (name, filename, value) elements for data to be uploaded as files
  6. Return the server's response page.
  7. """
  8. import httplib
  9. content_type, body = encode_multipart_formdata(fields, files)
  10. h = httplib.HTTPS(host)
  11. h.putrequest('POST', selector)
  12. h.putheader('content-type', content_type)
  13. h.putheader('content-length', str(len(body)))
  14. h.endheaders()
  15. h.send(body)
  16. errcode, errmsg, headers = h.getreply()
  17. return h.file.read()
  1. def encode_multipart_formdata(fields, files):
  2. """
  3. fields is a sequence of (name, value) elements for regular form fields.
  4. files is a sequence of (name, filename, value) elements for data to be uploaded as files
  5. Return (content_type, body) ready for httplib.HTTP instance
  6. """
  7. BOUNDARY = '----------ThIs_Is_tHe_bouNdaRY_
  8. CRLF = '\r\n'
  9. L = []
  10. for (key, value) in fields:
  11. L.append('--' + BOUNDARY)
  12. L.append('Content-Disposition: form-data; name="%s"' % key)
  13. L.append('')
  14. L.append(value)
  15. for (key, filename, value) in files:
  16. L.append('--' + BOUNDARY)
  17. L.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename))
  18. L.append('Content-Type: %s' % get_content_type(filename))
  19. L.append('')
  20. L.append(value)
  21. L.append('--' + BOUNDARY + '--')
  22. L.append('')
  23. listy = []
  24. for element in L:
  25. try:
  26. listy.append(element.decode('string_escape'))
  27. except:
  28. listy.append(element)
  29. body = CRLF.join(listy)
  30. content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
  31. return content_type, body
  1. def get_content_type(filename):
  2. import mimetypes
  3. return mimetypes.guess_type(filename)[0] or 'application/octet-stream'

This code snipped is heavily inspired by: http://code.activestate.com/recipes/146306-http-client-to-post-using-multipartform-data/, with one major change to handle binary data. From line 46 to line 52, binary data is converted in a plain string. This method is not perfect.

Who finds a better solution gets a cupcake. Leave a comment below to claim your cupcake.

Photo source: http://www.flickr.com/photos/emdot/95460346/

Categories: GAE facebook

Leave a Comment

Facebook Connect in Google App Engine. Making the cloud sociable

Socialble CloudGoogle App Engine is great for fast deploying and fast scaling applications. That’s a fact. The default authentication system uses Google accounts. Another option is deploying a custom user/password combination, which is the more traditional approach.

For one of our recent projects, we wanted to make the user authentication even simpler, so we integrated Facebook Connect and the Graph API. Now users can login with only one click, if they are already logged into Facebook. 

Another advantage of using this approach is avoiding boring registration forms. One click on the blue Facebook button and you’re done. User info is retrieved from Facebook, after granting the appropriate permission.

Integration

As in the past, we’ve used Kay Framework to help with some of the lower-level tasks on Google App Engine. Kay already comes with it’s own username/password authentication system, aside from the Google Accounts one. Mimicking the existing back-end, we wrote a simple one, based only on the Facebook User ID.

Facebook uses OAuth 2.0, which is token based. The token is obtained from a short “chat” between Google Appengine and the Facebook Server.

Graph API

After authenticating, using the token we can make any requests to the Graph API. Examples: retrieving user info, photo albums, uploading photos (which I’ll cover in another blog post), commenting. Head over to the Facebook Graph API docs for a full list of actions.
Since we’re developing in Python, we used Facebook’s official Python SDK, which turned out to save a lot of headaches.

Testing

In our Agile manner, tests play an important role. Kay Framework’s test client turned out to have a problem storing cookies (which we’re looking into fixing), so testing properly by doing server requests to Facebook was difficult.
One important story to test is when a user tries to access a non-public page. In that case, the user should be prompted to login with Facebook, then return to the original page.

  1. def test_fb_login_decorator(self):
  2. _create_fb_user(FACEBOOK_UID)
  3. resp = self.client.get('/projects/new/')
  4. # fb user is not logged in and attempts to access this url. redirection expected, hence 302.
  5. self.assertEquals(resp.status_code, 302)
  6. # fb user is logged in and now should be able to access the url.
  7. _facebook_login(self)
  8. resp = self.client.get('/projects/new/')
  9. self.assertEquals(resp.status_code, 200)

Source code

Here’s the link for the source code for the Kay Framework authentication back-end and some usage examples:

http://github.com/tudormunteanu/fb-auth-backend

Category: Python

Leave a Comment

iPhone SDK: Learning About Touch Events & Basic Game Animation

iPhone SDK: Learning About Touch Events & Basic Game Animation

One of most common actions used for an iPhone or iPad application is the
touch event. An event is not useful if it doesn’t trigger a meaningful
action. This tutorial covers how to attach a touch event to a custom
button and how to trigger the animation of an object. In the end, the
result is a simple on-screen game controller, which can be extended to
the limits of your imagination.

Read the full tutorial here.

Thanks to the great guys at MobileTuts+ for publicizing this tutorial.

Category: iphone

Leave a Comment

We Were At PyCon APAC 2010 – 9th – 11th June

PyCon Asia Pacific 2010 represents a conference dedicated to the Python programming language in Asia-Pacific and hosted for the first time in Singapore.

We couldn’t miss this opportunity to talk with like-minded people, so we were actively involved with the organizers and the whole community.

The first day was tutorial day. Calvin showcased some of the awesome features in Django, a very versatile web framework for perfectionists with deadlines.

The 2nd and 3rd day were dedicated to talks about some of the best tools and techniques for using Python. 

Early in the 2nd day I gave a talk on Test Driven Development in Django. Slides can be found here. Oh, you’re not sure how to apply TDD in Django? Don’t hesitate to ask here, because the benefits are priceless.

Wesley Chun’s keynote on Python 3, showed everyone why Python 3 is under development and what to expect from this backwards incompatible update as well as promoting the usefulness of deploying highly scalable applications in the cloud, Google App Engine to be more precise.

Steve Holden, chairman of The Python Software Foundation, had a keynote about the hurdles and the benefits of building a international Python community. His second talk was about dealing with the meta-class madness in Python.

From NoSQL, to web frameworks, language processing, bio-science and Python in education, all of the important subjects in a healthy coding community were taken care of.

The Python Coder’s Tournament brought together the best coders, to have fun while solving as fast as possible some witty coding problems. The platform used was SingPath, a cloud application for learning Python. The mythical cloud took the load of >50 participants surprisingly well. In typical Odeon manner, we had a remote participant, Stefan. Congrats to all the guys who won, they deserved it. Some of them are strong Python coders since more than 10 years.

More pictures can be found here: http://picasaweb.google.com/110465643935555027803/PyConAP2010#5481703086242237810

What have I learned from PyCon?

  • Python 3 is ready to be used, but only if you're starting a project without legacy code
  • Never make dark slides for a talk
  • Test Driven Development can save you even when changing some fundamentals in your software. E.g. switching from multi-thread to single-thread

Category: sparks

Leave a Comment

Odeon Scrums - How We Roll

In general

Scrum is an iterative, incremental framework for project management and agile software development. The main purpose of the scrum is to see the progress of a project, in terms of issues solved and issues to be solved. Scrums allow quick adapting to changes and review of progress, which is a main topic of the Agile Manifesto.

Scrum time!

Our methodology

Because we’re a distributed team, communication is very sensitive. Actually, communication is one of the most important ingredients to the success of a team, no matter the model.

In Odeon, our structure is flat, so everybody takes responsibility for his actions. To keep ourselves focused on the reason why we’re coding, we all take part in the communication with clients. We have scrums with our full team + clients in a range between 2 times a week to everyday. Each of these scrums has a Scrum Master, which has the role of ensuring a good communication flow, that everybody sticks to the subjects and scrums don’t drag over-time.

Aside from scrums with clients, each day at 5pm Singapore time (12pm Romania, 11am Italy) we have an internal scrum when we go over the current progress. To be more precise, we evaluate issues in Uberkode, our issue tracker. Uberkode can be accessed by anyone of our team or by the clients at any time, to get a full report of what's going on. 

The tricky part

Because communication is important and the client is always aware how his project is evolving, we need to have discipline when updating progress on issues. To ensure issues are updated and time is tracked properly, we came up with an original approach. Instead of a developer presenting what he has worked on, he presents what his colleague worked on, based on time tracked and issues updated. As a result of the scrum all the issues are fully updated with DONEs and TODOs and time is accurately tracked. 

This has helped us find quickly the pressure points in projects and allows for fast feature-creep detection. Now you know what we're up to at 5pm :)

Give us a sign so we can use our experience to help you.

Category: Communication

Leave a Comment
Page generated in: 0.50s