Had a blast attending mscosconf. Met online only friends. Now real life friends.
Met noted speakers; @anthonybaxter, dibona, @benbalbo, mark rees aka @hexdump, bsd guys and learned quite a lot.
Hackathon day - went to security track with mahmud. Too many bodies with no notebook. Not good.
Went to mostly developer tracks. However, not all developer tracks are tech enough, methinks. Some are too introductory.
Liked the always full of energy azrul talk; friendly jab with low in the django track and more.
Attend a few community tracks; one with @gen, one with zonestraits (salute)
Skipped most of the executive tracks, except for the security track.
The food was so-so. Didn't eat that much.
Some things that could do better. Note that it's easy to complain and not do anything about it. Sorry that I can't do anything about it (i.e help)
I think it's ok to have closed source stuff at the conference, but as @yoonkit put it , it'd be better if the end result is for the better OSS.
In the spirit of OSS, I think all, if not most (99.999%) services should be using OSS, web servers, office suite, etc, etc. Otherwise, we really missed the point.
With that, although osdc.my runs joomla, I think opensocial (+1) would be a better choice, or the very least google friend connect (+1/2), to socialize a web site. Making use of Facebook connect: +-0
Maybe it's not too late yet? Since the site is meant for developers, maybe a sandbox to try and put opensocial/google friend connect?
Maybe organizer could arrange a number of tutorials (1-2 hrs) during the hackathon day for future conference.
All in all, looking forward to the next conference.
benbalbo + anthonybaxter lightning talk
p/s - Here's the link to the slides I use for the lightning talk: zope2 in 5 mins
For a first time lightning talk, I guessed I did so-so. :P
Trackback is http://myzope.kedai.com.my/blogs/kedai/239/tbping
It's confirmed. I'm going to mscosconf. I think. The company gave me an undertaking letter to present during registration since the company can't pay without an invoice :P
Anyways, I'm so looking forward to going and learning and meeting others.
I hope large tags will be given (a la foss.my) so that it can be an ice breaker.
However, there are some closed source stuff going on too that may be a dent in the experience.
Anywho, the right tools for the right jobs, eh.
I would try and record interesting talks/stuff during the event.
See it at my video page
Any pythonistas want to meet for a Bof session? or anything at all?
Trackback is http://myzope.kedai.com.my/blogs/kedai/238/tbping
Last Saturday, Jaring IDC asked us to come and power off all our servers. They said they need to do some PM.
We came and before powering off one of the server, I took a video:
And guess what the PM was for? TSo that they can install power meter to charge us of power over use.
Oh, and their Network Box went down and took about 3 hours to replace. Can I charge for the overtime?
Trackback is http://myzope.kedai.com.my/blogs/kedai/237/tbping
Facebook connect lets our users log in and interact with our site using their facebook accounts.
With facebook APIs, we can then do more stuff such as publishing their actions at our sites to facebook; be more social.
We've looked at opensocial, and thought that facebook connect is another option to tap.
Here's how we put together google app engine, python+pyfacebook and facebook connect together.
Get google app engine sdk and read the tutorial. We'll be using the guestbook sample.
Also, create a new facebook application (via facebook developer app), and get the api_key and secret.
Here's the main class:
# -*- coding: utf-8 -*-
import cgi, os
import datetime, Cookie, md5
import wsgiref.handlers
import facebook
from google.appengine.ext import db
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
api_key = 'fbook app code'
secret_key = 'fbook app secret'
class Greeting(db.Model):
author = db.StringProperty()
content = db.StringProperty(multiline=True)
date = db.DateTimeProperty(auto_now_add=True)
class MainHandler(webapp.RequestHandler):
def get(self):
greetings_q = Greeting.all().order('-date')
greetings = greetings_q.fetch(10)
template_values = {'greetings': greetings}
path = os.path.join(os.path.dirname(__file__), 'index.html')
self.response.out.write(template.render(path, template_values))
class MembersHandler(webapp.RequestHandler):
def get(self): #get requests
#instantiate our pyfacebook
self.facebookapi = facebook.Facebook(api_key, secret_key)
#check for md5 values (cookie & calculated value) for verification
fbcookies = self.facebookapi.validate_cookie_signature(self.request.cookies)
if fbcookies is not None:
#get fb user
user = self.facebookapi.users.getInfo( [fbcookies['user']], ['uid', 'name', 'profile_url', 'relationship_status'])[0]
greetings_q = Greeting.all().order('-date')
greetings = greetings_q.fetch(10)
template_values = {'greetings': greetings,
'user': user,
}
path = os.path.join(os.path.dirname(__file__), 'members.html')
self.response.out.write(template.render(path, template_values))
class Guestbook(webapp.RequestHandler):
def post(self):
self.facebookapi = facebook.Facebook(api_key, secret_key)
fbcookies = self.facebookapi.validate_cookie_signature(self.request.cookies)
if fbcookies is not None:
user = self.facebookapi.users.getInfo( [fbcookies['user']], ['uid', 'name', 'profile_url', 'relationship_status'])[0]
greeting = Greeting()
greeting.author = user['name']
greeting.content = self.request.get('content')
greeting.put()
else:
pass
self.redirect('/')
def main():
application = webapp.WSGIApplication([('/', MainHandler), ('/members.html', MembersHandler),
('/sign',Guestbook)
],
debug=True)
wsgiref.handlers.CGIHandler().run(application)
if __name__ == '__main__':
main()
Note the guestbook model where we will use user's facebook identity instead of google's.
Facebook sessions can be transferred from Javascript to server side codes via cookies. Look for cookies in the form of api_key_xxx, where xxx maybe user, ss, etc.
In the above code, the MembersHandler class is interesting since that's where much wrangling is done.
There's code duplication (when instantiating pyfacebook) in different classes. There should be a better way. Ideas?
We learned a lot (the session transfer, for one) during this experience and hope to try and do something similar with opensocial.
To work with facebook openapi stream, see the pyfacebook patch in gwibber.
Go see the demo. Leave some note behind!
Helpful resources:
http://wiki.developers.facebook.com/index.php/Facebook_Connect
http://bazaar.launchpad.net/~segphault/gwibber/template-facebook-stream/annotate/head%3A/gwibber/microblog/facebook.py
http://dollarmani-facebook.blogspot.com/2008/09/using-facebook-api-in-python.html
http://facebooktoolkit.codeplex.com/Thread/View.aspx?ThreadId=40599&ANCHOR
Trackback is http://myzope.kedai.com.my/blogs/kedai/236/tbping
Further research while trying reverend brought me to opencalais. opencalais.org is a service by Thomson Reuters that will try and categorize or find meaning to texts.
Here's what they say:
The Calais Web Service automatically creates rich semantic metadata for the content you submit – in well under a second. Using natural language processing, machine learning and other methods, Calais analyzes your document and finds the entities within it. But, Calais goes well beyond classic entity identification and returns the facts and events hidden within your text as well.
Here's how we can access opencalais with python.
- get python-calais
- get our opencalais api
- prepare some texts to examine
[]$ ipython
In [1]: import calais
In [2]: c=calais.Calais('yourapikey')
In [3]: txt="""Got myself a webcam, Logitech Go, or Logitech Express elsewhere.
...:
...: Initially, I hoped that everything work off the bat. But no dice. A bt oftwiddling was needed.
...:
...: lsusb shows:
...:
...: Bus 001 Device 002: ID 046d:092f Logitech, Inc.
...:
...: I initially compiled and installed qc-usb. That was the wrong one. After a few google search, spca5x was the one I needed.
...:
...: a yum search spca5x revealed that I should use gspcav1. After installation, plugged in my webcam, and all is peachy.
...:
...: with kopete, I started a webcam session with someone on yahoo, and all works to perfection!
...:
...: ain't that cool or ain't that cool!"""
In [4]: res=c.analyze(txt)
In [5]: res.entities
Out[5]:
[{'__reference': 'http://d.opencalais.com/genericHasher-1/635db363-c5af-38d1-8f03-b62868130722',
'_type': 'IndustryTerm',
'instances': [{'detection': '[google search, spca5x was the one I needed.\n\na ]yum search spca5x[ revealed that I should use gspcav1. After]',
'exact': 'yum search spca5x',
'length': 17,
'offset': 358,
'prefix': 'google search, spca5x was the one I needed.\n\na ',
'suffix': ' revealed that I should use gspcav1. After'}],
'name': 'yum search spca5x',
'relevance': 0.17699999999999999,
'resolutions': []},
{'__reference': 'http://d.opencalais.com/comphash-1/f9228e55-d2a2-383a-bc24-f76863586c46',
'_type': 'Company',
'instances': [{'detection': '[Got myself a webcam, ]Logitech[ Go, or Logitech Express elsewhere.\n\nInitially, I]',
'exact': 'Logitech',
'length': 8,
'offset': 21,
'prefix': 'Got myself a webcam, ',
'suffix': ' Go, or Logitech Express elsewhere.\n\nInitially, I'},
{'detection': '[myself a webcam, Logitech Go, or ]Logitech[ Express elsewhere.\n\nInitially, I hoped that]',
'exact': 'Logitech',
'length': 8,
'offset': 37,
'prefix': 'myself a webcam, Logitech Go, or ',
'suffix': ' Express elsewhere.\n\nInitially, I hoped that'},
{'detection': '[shows:\n \n Bus 001 Device 002: ID 046d:092f ]Logitech, Inc[.\n\nI initially compiled and installed qc-usb.]',
'exact': 'Logitech, Inc',
'length': 13,
'offset': 216,
'prefix': 'shows:\n \n Bus 001 Device 002: ID 046d:092f ',
'suffix': '.\n\nI initially compiled and installed qc-usb.'}],
'name': 'Logitech Inc',
'nationality': 'N/A',
'relevance': 0.59999999999999998,
'resolutions': [{'name': 'Logitech International S.A.',
'score': 1,
'ticker': 'LOGN'}]},
{'__reference': 'http://d.opencalais.com/genericHasher-1/297cba0d-593e-3ae0-ad38-554d3114b0a1',
'_type': 'IndustryTerm',
'instances': [{'detection': '[qc-usb. That was the wrong one. After a few ]google search[, spca5x was the one I needed.\n\na yum search]',
'exact': 'google search',
'length': 13,
'offset': 311,
'prefix': 'qc-usb. That was the wrong one. After a few ',
'suffix': ', spca5x was the one I needed.\n\na yum search'}],
'name': 'google search',
'relevance': 0.26000000000000001,
'resolutions': []}]
Look at other methods too, especially analyze_file() and analyze_url()
Next step? A zope 2 product, hopefuly.
Trackback is http://myzope.kedai.com.my/blogs/kedai/235/tbping
Getting python, zope2 and oauth to dance takes efforts. Understanding how OAuth works is essential.
However, the oauth draft is too long for eager developers to grok. But fret not, read the quick and dirty guide to oauth and we'd be on our way.
Here's what I did to get python, zope and twitter work together via oauth.
First, create your app key
Get oauth python client
Since this is a quick exercise, We will use External Method. Here's our file that should be put in Extensions directory:
# -*- coding: utf-8 -*-
import httplib, oauth
import simplejson as sj
REQUEST_TOKEN_URL='http://twitter.com/oauth/request_token'
ACCESS_TOKEN_URL='http://twitter.com/oauth/access_token'
AUTHORIZATION_URL='http://twitter.com/oauth/authorize'
RESOURCE_URL='http://myzope.kedai.com.my/blogs/kedai'
CONSUMER_KEY='your consumerkeyfrom your app'
CONSUMER_SECRET='your consumer secret frim your app'
consumer=oauth.OAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET)
signature_method_hmac_sha1 = oauth.OAuthSignatureMethod_HMAC_SHA1()
TWITTER_CHECK_AUTH = 'https://twitter.com/account/verify_credentials.json'
TWITTER_FRIENDS = 'http://twitter.com/statuses/friends.json'
TWITTER_STATUS = 'http://twitter.com/statuses/friends_timeline.json'
def obtainRequestToken(self):
oauth_req = oauth.OAuthRequest.from_consumer_and_token(consumer, http_url=REQUEST_TOKEN_URL)
oauth_req.sign_request(signature_method_hmac_sha1, consumer, None)
print "request via headers obtainRequestToken", oauth_req.parameters
conn=httplib.HTTPConnection('twitter.com',80)
resp=conn.request('GET',REQUEST_TOKEN_URL,headers=oauth_req.to_header())
resp=conn.getresponse()
token=oauth.OAuthToken.from_string(resp.read())
print "token keys", token.key, token
print "parameters", oauth_req.parameters
return token
def authorizeRequestToken(self, token):
print 'access token',token, type(token)
oauth_request = oauth.OAuthRequest.from_token_and_callback(token=token, http_url=AUTHORIZATION_URL)
print 'REQUEST (via url query string)authorizeRequestToke'
print 'parameters: %s' % str(oauth_request.parameters)
print 'token auth', token,'\n----'
url = oauth_request.to_url()
return self.REQUEST.RESPONSE.redirect(url)
def accessToken(self, token):
oauth_request = oauth.OAuthRequest.from_consumer_and_token(consumer, token=token, http_url=ACCESS_TOKEN_URL)
oauth_request.sign_request(signature_method_hmac_sha1, consumer, token)
print 'REQUEST (via headers) - access url\n'
print 'parameters: %s' % str(oauth_request.parameters)
conn=httplib.HTTPConnection('twitter.com',80)
conn.request('GET', ACCESS_TOKEN_URL, headers=oauth_request.to_header())
response = conn.getresponse()
token = oauth.OAuthToken.from_string(response.read())
print 'my real token',token,type(token),'\n----'
print 'access token', token.key, token.secret,'\n----'
self.REQUEST.SESSION['token'] = token #.key
return self.REQUEST.RESPONSE.redirect('twit')
def getStatus(self, token):
print 'the token from session in getstatus',token,'\n----'
print token,type(token),'\n----'
#token = oauth.OAuthToken.from_string(token)
oauth_request = oauth.OAuthRequest.from_consumer_and_token(
consumer, token=token, http_url=TWITTER_STATUS, parameters={'page': 1})
oauth_request.sign_request(signature_method_hmac_sha1, consumer, token)
url = oauth_request.to_url()
conn=httplib.HTTPConnection('twitter.com',80)
conn.request(oauth_request.http_method,url)
response = conn.getresponse()
res = sj.load(response)
return res
Ignore all the print statements. Following the quick and dirty guide, listed here are the necessary DTML Methods (yeah, yeah) and Script (Python) required to make things work:
#dtml method id: twit
#we check for session token and return the login page if not available
<dtml-var standard_html_header>
<h2><dtml-var title_or_id> <dtml-var document_title></h2>
<p>
<dtml-if expr="SESSION.has_key('token')">
<dtml-let token="SESSION['token']">
<b>status</b><br>
<dtml-in expr="getStatus(token)" prefix=seq>
<dtml-var expr="seq_item['user']['screen_name']">: <dtml-var expr="seq_item['text']"> at <dtml-var expr="seq_item['created_at']"><br>
</dtml-in>
</dtml-let>
<dtml-else>
<p>
<a href="getpage">login</a>
</p>
</dtml-if>
</p>
<dtml-var standard_html_footer>
#script python id: getpage
token = context.gettoken() #our first step. gettoken is an
#external method pointing to obtainRequestToken
session = context.REQUEST.SESSION
session['token'] = token
print context.getaccesspage(token)#2nd step, points to
#external method authorizeRequestToken,
#send to authorize page
#once users click allow, users will be redirected to Application Website as
#specified in our twitter app page, e.g http://host.domain/twitest
#script python id: twitest
token = context.REQUEST.SESSION['token']
context.accessUrl(token) #accessUrl is external method pointing to
#accessToken which will redirect to twit, our main page
#and to finish things off, we get status from twitter and iterate thru. see above
It's easy once we got the hang of it. Thanks to the quick and dirty guide, python oauth client (see the examples at their page), python oauth samples (is this tav who used to hang at #zope in the 90's?) and django example
Now that we got the basics done, we can turn this to a Zope 2 product! Are there any new zope2 users nowadays ? But that's for another day :P
Trackback is http://myzope.kedai.com.my/blogs/kedai/234/tbping
