Merge lp:~eduardo-mucelli/cairo-dock-plug-ins-extras/Twitter into lp:~cairo-dock-team/cairo-dock-plug-ins-extras/third-party

Proposed by Eduardo Mucelli Rezende Oliveira
Status: Merged
Merged at revision: 218
Proposed branch: lp:~eduardo-mucelli/cairo-dock-plug-ins-extras/Twitter
Merge into: lp:~cairo-dock-team/cairo-dock-plug-ins-extras/third-party
Diff against target: 512 lines (+240/-233)
2 files modified
Twitter/Twitter (+239/-232)
Twitter/auto-load.conf (+1/-1)
To merge this branch: bzr merge lp:~eduardo-mucelli/cairo-dock-plug-ins-extras/Twitter
Reviewer Review Type Date Requested Status
Cairo-Dock Devs Pending
Review via email: mp+86149@code.launchpad.net

Description of the change

Fixing the tabulation, updating instructions on the source, and on the conf file, changing a lil the auth flow.

To post a comment you must log in.
218. By Eduardo Mucelli Rezende Oliveira

Twitter: Updating the instructions on both conf file, and on the applet source header

Revision history for this message
Matthieu Baerts (matttbe) wrote :

Hello Eduardo,

Thank you for these new modifications ;)

PS: don't forget to sync this branch with the trunk because your branch has diverged ;) (by using this command: bzr pull lp:cairo-dock-plug-ins-extras)

Revision history for this message
Eduardo Mucelli Rezende Oliveira (eduardo-mucelli) wrote :

Hahaha! Ive been messing up the things :)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'Twitter/Twitter'
2--- Twitter/Twitter 2011-12-17 03:28:23 +0000
3+++ Twitter/Twitter 2011-12-17 23:24:23 +0000
4@@ -6,20 +6,21 @@
5 # E-mail: edumucelli@gmail.com or eduardom@dcc.ufmg.br
6 #
7 # This program is free software: you can redistribute it and/or modify
8-# it under the terms of the GNU General Public License as published by
9-# the Free Software Foundation, either version 3 of the License, or
10-# (at your option) any later version.
11+# it under the terms of the GNU General Public License as published by
12+# the Free Software Foundation, either version 3 of the License, or
13+# (at your option) any later version.
14
15 # This program is distributed in the hope that it will be useful,
16-# but WITHOUT ANY WARRANTY; without even the implied warranty of
17-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18-# GNU General Public License for more details.
19+# but WITHOUT ANY WARRANTY; without even the implied warranty of
20+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21+# GNU General Public License for more details.
22
23 # This applet provides for Cairo-Dock an interface with Twitter
24
25-# On the first time, the applet is going to ask your screen name and later the authorization to connect with Twitter.
26-# Authorize opening the URL shown in the dialog box pressing Enter.
27-# Log in on the browser and copy the number that you will be presented. On the dock, paste this number on the next dialog box will be shown.
28+# On the first time, the applet is going to ask your nickname and authorization to connect with Twitter.
29+# The applet is going to open your browser with the authorization page
30+# As soon as you authorize it, a PIN number will be shown on the page, copy this number
31+# Paste this number on the next dialog box will be shown.
32 # The plugin is going to inform that you are successfully connected.
33
34 import urlparse, os, webbrowser, simplejson
35@@ -30,235 +31,241 @@
36 # TODO import ConfigParser later conver files to config syntax
37
38 class TwitterOauth:
39- def __init__(self):
40- self.request_token_url = 'https://twitter.com/oauth/request_token'
41- self.access_token_url = 'https://twitter.com/oauth/access_token'
42- self.authorize_url = 'http://twitter.com/oauth/authorize'
43-
44- consumer_key, consumer_secret = read_consumer_key_and_secret()
45- self.consumer = oauth.OAuthConsumer(consumer_key, consumer_secret)
46- self.signature_method = oauth.OAuthSignatureMethod_HMAC_SHA1()
47- self.request_token = None
48- self.access_token = None
49-
50- def get_authorization_url(self):
51- self.request_token = self.get_unauthorized_request_token()
52- oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer,
53- token = self.request_token,
54- http_url = self.authorize_url)
55- oauth_request.sign_request(self.signature_method, self.consumer, self.request_token)
56- return oauth_request.to_url()
57-
58- def get_unauthorized_request_token(self):
59- oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer, http_url = self.request_token_url)
60- oauth_request.sign_request(self.signature_method, self.consumer, None)
61- url = oauth_request.to_url()
62- response = get(url)
63- token = oauth.OAuthToken.from_string(response)
64- return token
65-
66- # Exchange request token for access token
67- def get_access_token_and_secret(self, pin):
68- oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer,
69- http_url = self.access_token_url,
70- verifier = pin,
71- token = self.request_token )
72- oauth_request.sign_request(self.signature_method, self.consumer, self.request_token)
73- url = oauth_request.to_url()
74- response = get(url)
75- self.access_token = oauth.OAuthToken.from_string(response)
76- access_token_data = dict((x, y) for x, y in urlparse.parse_qsl(response)) # tuple to dict
77- return access_token_data['oauth_token'], access_token_data['oauth_token_secret']
78+ def __init__(self):
79+ self.request_token_url = 'https://twitter.com/oauth/request_token'
80+ self.access_token_url = 'https://twitter.com/oauth/access_token'
81+ self.authorize_url = 'http://twitter.com/oauth/authorize'
82+
83+ consumer_key, consumer_secret = read_consumer_key_and_secret()
84+ self.consumer = oauth.OAuthConsumer(consumer_key, consumer_secret)
85+ self.signature_method = oauth.OAuthSignatureMethod_HMAC_SHA1()
86+ self.request_token = None
87+ self.access_token = None
88+
89+ def get_authorization_url(self):
90+ self.request_token = self.get_unauthorized_request_token()
91+ oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer,
92+ token = self.request_token,
93+ http_url = self.authorize_url)
94+ oauth_request.sign_request(self.signature_method, self.consumer, self.request_token)
95+ return oauth_request.to_url()
96+
97+ def get_unauthorized_request_token(self):
98+ oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer, http_url = self.request_token_url)
99+ oauth_request.sign_request(self.signature_method, self.consumer, None)
100+ url = oauth_request.to_url()
101+ response = get(url)
102+ token = oauth.OAuthToken.from_string(response)
103+ return token
104+
105+ # Exchange request token for access token
106+ def get_access_token_and_secret(self, pin):
107+ oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer,
108+ http_url = self.access_token_url,
109+ verifier = pin,
110+ token = self.request_token)
111+ oauth_request.sign_request(self.signature_method, self.consumer, self.request_token)
112+ url = oauth_request.to_url()
113+ response = get(url)
114+ self.access_token = oauth.OAuthToken.from_string(response)
115+ access_token_data = dict((x, y) for x, y in urlparse.parse_qsl(response)) # tuple to dict
116+ return access_token_data['oauth_token'], access_token_data['oauth_token_secret']
117
118 class TwitterAPI:
119- def __init__(self, access_key, access_secret):
120- self.update_url = 'http://twitter.com/statuses/update.json'
121- self.home_timeline_url = 'http://twitter.com/statuses/home_timeline.json'
122- self.tweety_streaming_url = 'https://userstream.twitter.com/2/user.json'
123-
124- self.signature_method = oauth.OAuthSignatureMethod_HMAC_SHA1()
125- consumer_key, consumer_secret = read_consumer_key_and_secret()
126- self.consumer = oauth.OAuthConsumer(consumer_key, consumer_secret)
127- self.access_token = oauth.OAuthToken(access_key, access_secret)
128-
129-# def tweety_streaming(self):
130-# oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer,
131-# token = self.access_token,
132-# http_url = self.tweety_streaming_url,
133-# parameters = {'track':'recipe', 'delimited':'length'},
134-# http_method = "GET")
135-# oauth_request.sign_request(self.signature_method, self.consumer, self.access_token)
136-# url = oauth_request.to_url()
137-# response = get(url)
138-# return simplejson.loads(response)
139-
140- def tweety(self, message): # popularly "send a tweety"
141- oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer,
142- token = self.access_token,
143- http_url = self.update_url,
144- parameters = {'status':message},
145- http_method = "POST")
146- oauth_request.sign_request(self.signature_method, self.consumer, self.access_token)
147- post_data = oauth_request.to_postdata()
148- return post(self.update_url, post_data)
149-
150- def home_timeline(self):
151- oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer,
152- token = self.access_token,
153- http_url = self.home_timeline_url,
154- http_method = "GET")
155- oauth_request.sign_request(self.signature_method, self.consumer, self.access_token)
156- url = oauth_request.to_url()
157- response = get(url)
158- return simplejson.loads(response)
159+ def __init__(self, access_key, access_secret):
160+ self.update_url = 'http://twitter.com/statuses/update.json'
161+ self.home_timeline_url = 'http://twitter.com/statuses/home_timeline.json'
162+ self.tweety_streaming_url = 'https://userstream.twitter.com/2/user.json'
163+
164+ self.signature_method = oauth.OAuthSignatureMethod_HMAC_SHA1()
165+ consumer_key, consumer_secret = read_consumer_key_and_secret()
166+ self.consumer = oauth.OAuthConsumer(consumer_key, consumer_secret)
167+ self.access_token = oauth.OAuthToken(access_key, access_secret)
168+
169+# def tweety_streaming(self):
170+# oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer,
171+# token = self.access_token,
172+# http_url = self.tweety_streaming_url,
173+# parameters = {'track':'recipe', 'delimited':'length'},
174+# http_method = "GET")
175+# oauth_request.sign_request(self.signature_method, self.consumer, self.access_token)
176+# url = oauth_request.to_url()
177+# response = get(url)
178+# return simplejson.loads(response)
179+
180+ def tweety(self, message): # popularly "send a tweety"
181+ oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer,
182+ token = self.access_token,
183+ http_url = self.update_url,
184+ parameters = {'status':message},
185+ http_method = "POST")
186+ oauth_request.sign_request(self.signature_method, self.consumer, self.access_token)
187+ post_data = oauth_request.to_postdata()
188+ return post(self.update_url, post_data)
189+
190+ def home_timeline(self):
191+ oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer,
192+ token = self.access_token,
193+ http_url = self.home_timeline_url,
194+ http_method = "GET")
195+ oauth_request.sign_request(self.signature_method, self.consumer, self.access_token)
196+ url = oauth_request.to_url()
197+ response = get(url)
198+ return simplejson.loads(response)
199
200 class User:
201- def __init__(self, screen_name="", access_key="", access_secret=""):
202- self.screen_name = screen_name
203- self.access_key = access_key
204- self.access_secret = access_secret
205+ def __init__(self, screen_name="", access_key="", access_secret=""):
206+ self.screen_name = screen_name
207+ self.access_key = access_key
208+ self.access_secret = access_secret
209
210 class Applet(CDApplet):
211
212- def inform_start_of_waiting_process(self):
213- self.icon.SetQuickInfo("...")
214-
215- def inform_end_of_waiting_process(self):
216- self.icon.SetQuickInfo("")
217-
218- # Twitter methods
219-
220- def show_home_timeline(self):
221- self.inform_start_of_waiting_process()
222-
223- timeline = self.api.home_timeline()
224- if len(timeline) > 0:
225- message = "".join (["[%s] %s\n" % (status['user']['name'], status['text']) for status in timeline])
226- else:
227- message = "Oh, dear, your timeline is empty :-("
228-
229- self.inform_end_of_waiting_process()
230- self.show_popup_message(message)
231-
232- def tweety(self, message): # popularly "send a tweety"
233- self.inform_start_of_waiting_process()
234- self.api.update_status(message)
235- self.inform_end_of_waiting_process()
236-
237- # Applet methods
238-
239- def ask_for_tweety(self):
240- dialog = {'buttons':'ok;cancel'}
241- widget = {'widget-type':'text-entry', 'nb-chars':140} # 140 characters max, a tweety :)
242- self.show_popup_message(("%s, send a tweety") % self.user.screen_name, dialog, widget)
243- self.dialog_type = self.responding_tweety
244-
245- # TODO: Handle multiple users inside the .users files
246- # TODO: Implement it as a config file using screen_name as section index
247- def read_user_data(self):
248- """Read the users file formated as Screen Name<space>Access Key<space>Access Secret"""
249- found = False
250- if os.path.exists(self.user_file):
251- if os.path.getsize(self.user_file) > 0:
252- f = open(self.user_file, "rb")
253- # for line in f:
254- data = f.read()
255- self.user.screen_name, self.user.access_key, self.user.access_secret = data.split() # split the line by space token
256- f.close()
257- found = True
258- return found
259-
260- def write_user_data(self):
261- f = open(self.user_file, 'w')
262- f.write("%s %s %s" % (self.user.screen_name, self.user.access_key, self.user.access_secret))
263- f.close()
264-
265- def ask_for_screen_name(self):
266- message = "What is your Twitter nickname?"
267- dialog = {'buttons':'ok'}
268- widget = {'widget-type':'text-entry'}
269- self.show_popup_message(message, dialog, widget)
270- # self.dialog_type = self.responding_screen_name
271-
272- def ask_for_authorization(self):
273- message = "Twitter applet needs you to give the authorization. Press Enter and your browser will be open with the URL shown bellow. Copy the PIN number that will be shown in the browser"
274- dialog = {'buttons':'ok'}
275- widget = {'widget-type':'text-entry', 'initial-value':self.twitter_auth.get_authorization_url()}
276- self.show_popup_message(message, dialog, widget)
277- self.dialog_type = self.responding_authorization
278-
279- def ask_for_pin_number(self):
280- message = "Enter the PIN number that appeared when you accessed the URL shown before"
281- dialog = {'buttons':'ok'}
282- widget = {'widget-type':'text-entry'}
283- self.show_popup_message(message, dialog, widget)
284- self.dialog_type = self.responding_pin
285-
286- def show_popup_successful_connection(self):
287- self.show_popup_message("Successfully connected with Twitter")
288-
289- def show_popup_message(self, message, dialog={}, widget={}):
290- dialog_attributes = {'message':message}
291- widget_attributes = {}
292- dialog_attributes.update(dialog)
293- widget_attributes.update(widget)
294- self.icon.PopupDialog (dialog_attributes, widget_attributes)
295-
296- def __init__(self):
297- self.user = User()
298- self.user_file = '.users'
299- self.twitter_auth = TwitterOauth()
300- self.api = None
301- self.responding_screen_name, self.responding_authorization, self.responding_pin, self.responding_success, self.responding_tweety = range(5)
302- self.dialog_type = self.responding_screen_name
303-
304- CDApplet.__init__(self) # call CDApplet interface init
305-
306- # Inherited methods from CDApplet
307- def begin(self):
308- logp("Looking for user ...")
309- if not self.read_user_data(): # first time for the user
310- logm("User not found")
311- self.ask_for_screen_name() # start asking for its screen name
312- else: # user not found
313- logp("User '%s' found" % self.user.screen_name)
314- self.api = TwitterAPI(self.user.access_key, self.user.access_secret) # getting control over the api
315-
316- # TODO: Fix it!
317- def reload(self):
318- self.read_user_data()
319-
320- # Callbacks
321- def on_answer_dialog(self, key, content):
322- if (key == 0 or key == -1) and content: # ... and pressed Ok or Enter
323- if self.dialog_type == self.responding_screen_name: # user typed screen name ...
324- logp("Receiving screen name '%s'" % content)
325- self.user.screen_name = content
326- self.ask_for_authorization()
327- elif self.dialog_type == self.responding_authorization:
328- logp("Authorizing ...")
329- webbrowser.open(content)
330- logp("Opening the auth URL '%s'" % content)
331- self.ask_for_pin_number() # ask for the PIN number received when acessed the auth URL
332- elif self.dialog_type == self.responding_pin: # user typed the PIN number
333- logp("Receiving PIN: %s" % content)
334- self.user.access_key, self.user.access_secret = self.twitter_auth.get_access_token_and_secret(content)
335- logp("Writing user data")
336- self.write_user_data() # writing the new users data
337- self.api = TwitterAPI(self.user.access_key, self.user.access_secret) # getting control over the api
338- if self.api:
339- self.show_popup_successful_connection()
340- else:
341- logm("A problem has occurred while getting access to the API")
342- elif self.dialog_type == self.responding_tweety:
343- logp("Sending a tweety '%s'" % content)
344- self.api.tweety(content)
345-
346- def on_click(self, key):
347- self.ask_for_tweety()
348-
349- def on_middle_click(self):
350- self.show_home_timeline()
351+ def inform_start_of_waiting_process(self):
352+ self.icon.SetQuickInfo("...")
353+
354+ def inform_end_of_waiting_process(self):
355+ self.icon.SetQuickInfo("")
356+
357+ # Twitter methods
358+
359+ def show_home_timeline(self):
360+ self.inform_start_of_waiting_process()
361+
362+ timeline = self.api.home_timeline()
363+ if len(timeline) > 0:
364+ message = "".join (["[%s] %s\n" % (status['user']['name'], status['text']) for status in timeline])
365+ else:
366+ message = "Oh, dear, your timeline is empty :-("
367+
368+ self.inform_end_of_waiting_process()
369+ self.show_popup_message(message)
370+
371+ def tweety(self, message): # popularly "send a tweety"
372+ self.inform_start_of_waiting_process()
373+ self.api.update_status(message)
374+ self.inform_end_of_waiting_process()
375+
376+ # Applet methods
377+
378+ def ask_for_tweety(self):
379+ dialog = {'buttons':'ok;cancel'}
380+ widget = {'widget-type':'text-entry', 'nb-chars':140} # 140 characters max, a tweety :)
381+ self.show_popup_message(("%s, send a tweety") % self.user.screen_name, dialog, widget)
382+ self.dialog_type = self.responding_tweety
383+
384+ # TODO: Handle multiple users inside the .users files
385+ # TODO: Implement it as a config file using screen_name as section index
386+ def read_user_data(self):
387+ """Read the users file formated as Screen Name<space>Access Key<space>Access Secret"""
388+ found = False
389+ if os.path.exists(self.user_file):
390+ if os.path.getsize(self.user_file) > 0:
391+ f = open(self.user_file, "rb")
392+ # for line in f:
393+ data = f.read()
394+ self.user.screen_name, self.user.access_key, self.user.access_secret = data.split() # split the line by space token
395+ f.close()
396+ found = True
397+ return found
398+
399+ def write_user_data(self):
400+ f = open(self.user_file, 'w')
401+ f.write("%s %s %s" % (self.user.screen_name, self.user.access_key, self.user.access_secret))
402+ f.close()
403+
404+ def ask_for_screen_name(self):
405+ message = "What is your Twitter nickname?"
406+ dialog = {'buttons':'ok'}
407+ widget = {'widget-type':'text-entry'}
408+ self.show_popup_message(message, dialog, widget)
409+ # self.dialog_type = self.responding_screen_name
410+
411+ def ask_for_authorization(self):
412+ authorization_url = self.twitter_auth.get_authorization_url()
413+ logp("Opening the auth URL '%s'" % authorization_url)
414+ try:
415+ webbrowser.open(authorization_url)
416+ message = "Twitter applet needs you to give the authorization. Authorization page was opened on your browser. As soon as you do, copy the PIN number that will be shown, and close this dialog"
417+ dialog = {'buttons':'ok'}
418+ self.show_popup_message(message, dialog)
419+ except webbrowser.Error:
420+ message = "Twitter applet needs you to give the authorization. Copy the address bellow and access it with your browser. Copy the PIN number that will be shown as soon as you authorize"
421+ dialog = {'buttons':'ok'}
422+ widget = {'widget-type':'text-entry', 'initial-value':authorization_url}
423+ self.show_popup_message(message, dialog, widget)
424+ self.dialog_type = self.responding_authorization
425+
426+ def ask_for_pin_number(self):
427+ message = "Enter the PIN number on the authorization page"
428+ dialog = {'buttons':'ok'}
429+ widget = {'widget-type':'text-entry'}
430+ self.show_popup_message(message, dialog, widget)
431+ self.dialog_type = self.responding_pin
432+
433+ def show_popup_successful_connection(self):
434+ self.show_popup_message("Successfully connected with Twitter")
435+
436+ def show_popup_message(self, message, dialog={}, widget={}):
437+ dialog_attributes = {'message':message}
438+ widget_attributes = {}
439+ dialog_attributes.update(dialog)
440+ widget_attributes.update(widget)
441+ self.icon.PopupDialog (dialog_attributes, widget_attributes)
442+
443+ def __init__(self):
444+ self.user = User()
445+ self.user_file = '.users'
446+ self.twitter_auth = TwitterOauth()
447+ self.api = None
448+ self.responding_screen_name, self.responding_authorization, self.responding_pin, self.responding_success, self.responding_tweety = range(5)
449+ self.dialog_type = self.responding_screen_name
450+
451+ CDApplet.__init__(self) # call CDApplet interface init
452+
453+ # Inherited methods from CDApplet
454+ def begin(self):
455+ logp("Looking for user ...")
456+ if not self.read_user_data(): # first time for the user
457+ logm("User not found")
458+ self.ask_for_screen_name() # start asking for its screen name
459+ else: # user not found
460+ logp("User '%s' found" % self.user.screen_name)
461+ self.api = TwitterAPI(self.user.access_key, self.user.access_secret) # getting control over the api
462+
463+ # TODO: Fix it!
464+ def reload(self):
465+ self.read_user_data()
466+
467+ # Callbacks
468+ def on_answer_dialog(self, key, content):
469+ if (key == 0 or key == -1): # ... and pressed Ok or Enter
470+ if self.dialog_type == self.responding_screen_name: # user typed screen name ...
471+ logp("Receiving screen name '%s'" % content)
472+ self.user.screen_name = content
473+ self.ask_for_authorization()
474+ elif self.dialog_type == self.responding_authorization:
475+ logp("Asking for PIN")
476+ self.ask_for_pin_number() # ask for the PIN number received when acessed the auth URL
477+ elif self.dialog_type == self.responding_pin: # user typed the PIN number
478+ logp("Receiving PIN: %s" % content)
479+ self.user.access_key, self.user.access_secret = self.twitter_auth.get_access_token_and_secret(content)
480+ logp("Writing user data")
481+ self.write_user_data() # writing the new users data
482+ self.api = TwitterAPI(self.user.access_key, self.user.access_secret) # getting control over the api
483+ if self.api:
484+ self.show_popup_successful_connection()
485+ else:
486+ logm("A problem has occurred while getting access to the API")
487+ elif self.dialog_type == self.responding_tweety:
488+ logp("Sending a tweety '%s'" % content)
489+ self.api.tweety(content)
490+
491+ def on_click(self, key):
492+ self.ask_for_tweety()
493+
494+ def on_middle_click(self):
495+ self.show_home_timeline()
496
497 if __name__ == '__main__':
498- Applet().run()
499+ Applet().run()
500
501=== modified file 'Twitter/auto-load.conf'
502--- Twitter/auto-load.conf 2011-12-17 03:28:23 +0000
503+++ Twitter/auto-load.conf 2011-12-17 23:24:23 +0000
504@@ -4,7 +4,7 @@
505 author = Eduardo Mucelli Rezende Oliveira
506
507 # A short description of the applet and how to use it.
508-description = This applet provides an interface with Twitter. On the first time, the applet is going to ask your screen name and later the authorization to connect with Twitter.\nAuthorize opening the URL shown in the dialog box pressing Enter.\nLog in on the browser and copy the number that you will be presented. On the dock, paste this number on the next dialog box will be shown.\nThe plugin is going to inform that you are successfully connected.
509+description = On the first time, the applet is going to ask your nickname and authorization to connect with Twitter.\nThe applet is going to open your browser with the authorization page\nAs soon as you authorize it, a PIN number will be shown on the page, copy this number\nPaste this number on the next dialog box will be shown.\nThe plugin is going to inform that you are successfully connected.
510
511 # Category of the applet : 2 = files, 3 = internet, 4 = Desktop, 5 = accessory, 6 = system, 7 = fun
512 category = 3

Subscribers

People subscribed via source and target branches