diff --git a/configure.ac b/configure.ac
index fe6b11e..69d70c9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -403,6 +403,31 @@ if test "$enable_kerberos" != "no"; then
 fi
 AM_CONDITIONAL(BUILD_KERBEROS, [test x$enable_kerberos != xno])
 
+#Github
+AC_DEFINE(GOA_GITHUB_NAME, ["github"], [ProviderType and extension point name])
+AC_ARG_ENABLE([github],	[AS_HELP_STRING([--enable-github], [Enable Github provider])], [], [enable_github=yes])
+AC_ARG_WITH([github-client-id],
+	[AS_HELP_STRING([--with-github-client-id],
+		[Github OAuth 2.0 client id])],
+	[],
+	[with_github_client_id=dbe233184a6a2c226771])
+AC_ARG_WITH([github-client-secret],
+	[AS_HELP_STRING([--with-github-client-secret],
+		[Github OAuth 2.0 client secret])],
+	[],
+	[with_github_client_secret=9b24f392a755ebd12e95a931efbfc384786ce3a2])
+AC_ARG_WITH([github-redirect-uri],
+	[AS_HELP_STRING([--with-github-redirect-uri],
+		[Github OAuth 2.0 client redirect uri])],
+	[],
+	[with_github_redirect_uri="https://wiki.gnome.org/Projects/GnomeOnlineAccounts"])
+AC_DEFINE_UNQUOTED(GOA_GITHUB_CLIENT_ID, ["$with_github_client_id"], [Github OAuth 2.0 client id])
+AC_DEFINE_UNQUOTED(GOA_GITHUB_CLIENT_SECRET, ["$with_github_client_secret"], [Github OAuth 2.0 client secret])
+AC_DEFINE_UNQUOTED(GOA_GITHUB_REDIRECT_URI, ["$with_github_redirect_uri"], [Github OAuth 2.0 redirect uri])
+if test "$enable_github" != "no"; then
+   AC_DEFINE(GOA_GITHUB_ENABLED, 1, [Enable Pocket data provider])
+fi
+
 # Optional timerfd support
 AC_MSG_CHECKING([for timerfd support])
 AC_COMPILE_IFELSE([AC_LANG_PROGRAM([
@@ -526,6 +551,7 @@ src/goabackend/goa-backend-1.0.pc
 src/goaidentity/Makefile
 src/daemon/Makefile
 src/examples/Makefile
+src/js/Makefile
 po/Makefile.in
 doc/Makefile
 doc/version.xml
@@ -564,6 +590,7 @@ echo "
 	Windows Live provider:          ${enable_windows_live} (OAuth 2.0, id:${with_windows_live_client_id})
         Telepathy provider:             ${enable_telepathy}
         Pocket provider:                ${enable_pocket} (id:${with_pocket_client_id})
+        Github provider:                ${enable_github} (id:${with_github_client_id} secret:${with_github_client_secret} redirect-uri:${with_github_redirect_uri})
 
 	Maintainer mode:                ${USE_MAINTAINER_MODE}
 	Building api docs:              ${enable_gtk_doc}
diff --git a/data/icons/16x16/Makefile.am b/data/icons/16x16/Makefile.am
index 889664f..1b23c79 100644
--- a/data/icons/16x16/Makefile.am
+++ b/data/icons/16x16/Makefile.am
@@ -10,6 +10,7 @@ icon_DATA =				\
 	goa-account-pocket.png		\
 	goa-account-foursquare.png	\
 	goa-account-yahoo.png		\
+	goa-account-github.png		\
 	$(NULL)
 
 EXTRA_DIST = \
diff --git a/data/icons/16x16/goa-account-github.png b/data/icons/16x16/goa-account-github.png
new file mode 100644
index 0000000..5b4b824
Binary files /dev/null and b/data/icons/16x16/goa-account-github.png differ
diff --git a/data/icons/22x22/Makefile.am b/data/icons/22x22/Makefile.am
index 710f3cc..a3bd830 100644
--- a/data/icons/22x22/Makefile.am
+++ b/data/icons/22x22/Makefile.am
@@ -10,6 +10,7 @@ icon_DATA = 				\
 	goa-account-pocket.png		\
 	goa-account-foursquare.png	\
 	goa-account-yahoo.png		\
+	goa-account-github.png		\
 	$(NULL)
 
 EXTRA_DIST = \
diff --git a/data/icons/22x22/goa-account-github.png b/data/icons/22x22/goa-account-github.png
new file mode 100644
index 0000000..b38b8c4
Binary files /dev/null and b/data/icons/22x22/goa-account-github.png differ
diff --git a/data/icons/24x24/Makefile.am b/data/icons/24x24/Makefile.am
index 9863d8c..7bcf9ae 100644
--- a/data/icons/24x24/Makefile.am
+++ b/data/icons/24x24/Makefile.am
@@ -10,6 +10,7 @@ icon_DATA = 				\
 	goa-account-foursquare.png	\
 	goa-account-flickr.png		\
 	goa-account-yahoo.png		\
+	goa-account-github.png		\
 	$(NULL)
 
 EXTRA_DIST = \
diff --git a/data/icons/24x24/goa-account-github.png b/data/icons/24x24/goa-account-github.png
new file mode 100644
index 0000000..5e44441
Binary files /dev/null and b/data/icons/24x24/goa-account-github.png differ
diff --git a/data/icons/32x32/Makefile.am b/data/icons/32x32/Makefile.am
index 9bf6ce9..46f2264 100644
--- a/data/icons/32x32/Makefile.am
+++ b/data/icons/32x32/Makefile.am
@@ -10,6 +10,7 @@ icon_DATA = 				\
 	goa-account-pocket.png		\
 	goa-account-foursquare.png	\
 	goa-account-yahoo.png		\
+	goa-account-github.png		\
 	$(NULL)
 
 EXTRA_DIST = \
diff --git a/data/icons/32x32/goa-account-github.png b/data/icons/32x32/goa-account-github.png
new file mode 100644
index 0000000..e15d8ab
Binary files /dev/null and b/data/icons/32x32/goa-account-github.png differ
diff --git a/data/icons/48x48/Makefile.am b/data/icons/48x48/Makefile.am
index 1f794a4..1f7544a 100644
--- a/data/icons/48x48/Makefile.am
+++ b/data/icons/48x48/Makefile.am
@@ -10,6 +10,7 @@ icon_DATA = 				\
 	goa-account-flickr.png		\
 	goa-account-foursquare.png	\
 	goa-account-yahoo.png		\
+	goa-account-github.png		\
 	$(NULL)
 
 EXTRA_DIST = \
diff --git a/data/icons/48x48/goa-account-github.png b/data/icons/48x48/goa-account-github.png
new file mode 100644
index 0000000..04c5f99
Binary files /dev/null and b/data/icons/48x48/goa-account-github.png differ
diff --git a/src/Makefile.am b/src/Makefile.am
index 63a20e5..13ca7a8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,6 +1,6 @@
 
 NULL =
 
-SUBDIRS = goa goaidentity goabackend daemon examples
+SUBDIRS = goa goaidentity goabackend daemon examples js
 
 -include $(top_srcdir)/git.mk
diff --git a/src/goabackend/Makefile.am b/src/goabackend/Makefile.am
index 59ed25a..c58562f 100644
--- a/src/goabackend/Makefile.am
+++ b/src/goabackend/Makefile.am
@@ -93,6 +93,7 @@ libgoa_backend_1_0_la_SOURCES =						\
 	goatelepathyfactory.h		goatelepathyfactory.c		\
 	goatelepathyprovider.h		goatelepathyprovider.c		\
 	goapocketprovider.h		goapocketprovider.c		\
+	goagithubprovider.h		goagithubprovider.c		\
 	goautils.h			goautils.c			\
 	goawebview.h			goawebview.c			\
 	nautilus-floating-bar.h		nautilus-floating-bar.c		\
diff --git a/src/goabackend/goagithubprovider.c b/src/goabackend/goagithubprovider.c
new file mode 100644
index 0000000..b8a5121
--- /dev/null
+++ b/src/goabackend/goagithubprovider.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2014 Gnome Foundation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+#include <glib-unix.h>
+#include "goaprovider.h"
+#include "goaoauth2provider.h"
+#include "goagithubprovider.h"
+#include <rest/oauth2-proxy.h>
+#include <rest/rest-proxy-call.h>
+#include <json-glib/json-glib.h>
+
+#define API_ROOT "https://api.github.com"
+
+/* S => stringify */
+#define S(X) #X
+
+/* D => g_debug */
+#define D g_debug
+
+/* F => function name */
+#define F __PRETTY_FUNCTION__
+
+/* GGE => Goa Github Error */
+#define GGE(c,m) g_error_new(g_quark_from_static_string("goa-github-provider-error"), c, m)
+
+/* RE => Return if Error */
+#define RE(ee, e, r) do{                        \
+    if(e){                                      \
+      D("%s:%d:%s: %s",                         \
+        F,                                      \
+        e->code,                                \
+        g_quark_to_string(e->domain),           \
+        e->message);                            \
+      g_propagate_error(ee, e);                 \
+      return r;                                 \
+    }                                           \
+  }while(0)
+
+/* RN => Return if NULL */
+#define RN(e, i, r) do{                                 \
+    if(!i){                                             \
+      D("%s: " S(i) " is null", F);                     \
+      g_propagate_error(e, GGE(1, S(i) " is null"));    \
+      return r;                                         \
+    }							\
+  }while(0)
+
+struct _GoaGithubProvider
+{
+  GoaOAuth2Provider parent_instance;
+};
+
+typedef struct _GoaGithubProviderClass GoaGithubProviderClass;
+
+struct _GoaGithubProviderClass
+{
+  GoaOAuth2ProviderClass parent_class;
+};
+
+G_DEFINE_TYPE_WITH_CODE(GoaGithubProvider,
+			goa_github_provider,
+			GOA_TYPE_OAUTH2_PROVIDER,
+			goa_provider_ensure_extension_points_registered();
+			g_io_extension_point_implement(GOA_PROVIDER_EXTENSION_POINT_NAME,
+						       g_define_type_id,
+						       GOA_GITHUB_NAME,
+						       0));
+
+static const gchar* get_provider_type(GoaProvider *provider)
+{
+  return GOA_GITHUB_NAME;
+}
+
+static gchar* get_provider_name(GoaProvider *provider,
+				GoaObject *object)
+{
+  return g_strdup(_("Github"));
+}
+
+static GoaProviderGroup get_provider_group(GoaProvider *provider)
+{
+  return GOA_PROVIDER_GROUP_BRANDED;
+}
+
+static GoaProviderFeatures get_provider_features(GoaProvider *provider)
+{
+  return GOA_PROVIDER_FEATURE_BRANDED;
+}
+
+static gboolean build_object(GoaProvider *provider,
+			     GoaObjectSkeleton *object,
+			     GKeyFile *keyfile,
+			     const gchar *group,
+			     GDBusConnection *connection,
+			     gboolean just_added,
+			     GError **error)
+{
+  return GOA_PROVIDER_CLASS(goa_github_provider_parent_class)->build_object(provider,
+									    object,
+									    keyfile,
+									    group,
+									    connection,
+									    just_added,
+									    error);
+}
+
+static void show_account(GoaProvider *provider,
+			 GoaClient *client,
+			 GoaObject *object,
+			 GtkBox *vbox,
+			 GtkGrid *grid,
+			 G_GNUC_UNUSED GtkGrid *dummy)
+{
+  goa_util_add_account_info(grid, 0, object);
+}
+
+static const gchar* get_authorization_uri(GoaOAuth2Provider *provider)
+{
+  return "https://github.com/login/oauth/authorize";
+}
+
+static const gchar* get_token_uri(GoaOAuth2Provider *provider)
+{
+  return "https://github.com/login/oauth/access_token";
+}
+
+static const gchar* get_redirect_uri(GoaOAuth2Provider *provider)
+{
+  return GOA_GITHUB_REDIRECT_URI;
+}
+
+static const gchar* get_scope(GoaOAuth2Provider *provider)
+{
+  return
+    "user"
+    ",repo"
+    ",delete_repo"
+    ",gist"
+    ",admin:org_hook"
+    ",admin:org"
+    ",admin:public_key";
+}
+
+static const gchar* get_client_id(GoaOAuth2Provider *provider)
+{
+  return GOA_GITHUB_CLIENT_ID;
+}
+
+static const gchar* get_client_secret(GoaOAuth2Provider *provider)
+{
+  return GOA_GITHUB_CLIENT_SECRET;
+}
+
+static gboolean get_use_mobile_browser(GoaOAuth2Provider *provider)
+{
+  return TRUE;
+}
+
+static gchar* get_identity_sync(GoaOAuth2Provider *provider,
+				const gchar *access_token,
+				gchar **out_presentation_identity,
+				GCancellable *cancellable,
+				GError **error)
+{
+  GError *lerror = NULL;
+  RestProxy *apiconn = NULL;
+  RestProxyCall *apicall = NULL;
+  const gchar *client_id = NULL;
+  gchar *function = "/user";
+  gchar *payload = NULL;
+  JsonParser *parser = NULL;
+  JsonNode *root = NULL;
+  gchar *login = NULL;
+  gchar *id = NULL;
+
+  client_id = goa_oauth2_provider_get_client_id(provider);
+  RN(error, client_id, NULL);
+  apiconn = oauth2_proxy_new_with_token(client_id,
+					access_token,
+					NULL,
+					API_ROOT,
+					FALSE);
+  RN(error, apiconn, NULL);
+  rest_proxy_set_user_agent(apiconn, "goa-github-provider");
+  apicall = rest_proxy_new_call(apiconn);
+  RN(error, apicall, NULL);
+  rest_proxy_call_set_method(apicall, "GET");
+  rest_proxy_call_set_function(apicall, function);
+  rest_proxy_call_sync(apicall, &lerror);
+  RE(error, lerror, NULL);
+
+  payload = g_strdup(rest_proxy_call_get_payload(apicall));
+  RN(error, payload, NULL);
+  g_object_unref(apicall);
+  g_object_unref(apiconn);
+
+  parser =  json_parser_new();
+  RN(error, parser, NULL);
+  json_parser_load_from_data(parser, payload, -1, &lerror);
+  RE(error, lerror, NULL);
+  root = json_parser_get_root(parser);
+  RN(error, root, NULL);
+
+  login = g_strdup(json_array_get_string_element(json_node_get_array(json_path_query("$.login",
+										     root,
+										     &lerror)),
+						 0));
+  RE(error, lerror, NULL);
+  id = g_strdup_printf("%lu",
+		       json_array_get_int_element(json_node_get_array(json_path_query("$.id",
+										      root,
+										      &lerror)),
+						  0));
+  RE(error, lerror, NULL);
+  g_object_unref(parser);
+
+  D("%s: login: %s, id: %s", F, login, id);
+  *out_presentation_identity = login;
+  return id;
+}
+
+static gboolean is_deny_node(GoaOAuth2Provider *provider,
+			     WebKitDOMNode *node)
+{
+  return FALSE;
+}
+
+static gboolean is_identity_node(GoaOAuth2Provider *provider,
+				 WebKitDOMHTMLInputElement *element)
+{
+  return FALSE;
+}
+
+static void goa_github_provider_init(GoaGithubProvider *instance)
+{
+}
+
+static void goa_github_provider_class_init(GoaGithubProviderClass *klass)
+{
+  GoaProviderClass *providerclass;
+  GoaOAuth2ProviderClass *oauth2providerclass;
+
+  providerclass = GOA_PROVIDER_CLASS (klass);
+  providerclass->get_provider_type = get_provider_type;
+  providerclass->get_provider_name = get_provider_name;
+  providerclass->get_provider_group = get_provider_group;
+  providerclass->get_provider_features = get_provider_features;
+  providerclass->build_object = build_object;
+  providerclass->show_account = show_account;
+
+  oauth2providerclass = GOA_OAUTH2_PROVIDER_CLASS (klass);
+  oauth2providerclass->get_authorization_uri = get_authorization_uri;
+  oauth2providerclass->get_redirect_uri = get_redirect_uri;
+  oauth2providerclass->get_token_uri = get_token_uri;
+  oauth2providerclass->get_scope = get_scope;
+  oauth2providerclass->get_client_id = get_client_id;
+  oauth2providerclass->get_client_secret = get_client_secret;
+  oauth2providerclass->get_use_mobile_browser = get_use_mobile_browser;
+  oauth2providerclass->get_identity_sync = get_identity_sync;
+  oauth2providerclass->is_deny_node = is_deny_node;
+  oauth2providerclass->is_identity_node = is_identity_node;
+}
diff --git a/src/goabackend/goagithubprovider.h b/src/goabackend/goagithubprovider.h
new file mode 100644
index 0000000..31001e2
--- /dev/null
+++ b/src/goabackend/goagithubprovider.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2014 Gnome Foundation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if !defined (__GOA_BACKEND_INSIDE_GOA_BACKEND_H__) && !defined (GOA_BACKEND_COMPILATION)
+#error "Only <goabackend/goabackend.h> can be included directly."
+#endif
+
+#ifndef __GOA_GITHUB_PROVIDER_H__
+#define __GOA_GITHUB_PROVIDER_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GOA_TYPE_GITHUB_PROVIDER   (goa_github_provider_get_type ())
+#define GOA_GITHUB_PROVIDER(o)     (G_TYPE_CHECK_INSTANCE_CAST ((o), GOA_TYPE_GITHUB_PROVIDER, GoaGithubProvider))
+#define GOA_IS_GITHUB_PROVIDER(o)  (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOA_TYPE_GITHUB_PROVIDER))
+
+typedef struct _GoaGithubProvider GoaGithubProvider;
+
+GType goa_github_provider_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __GOA_GITHUB_PROVIDER_H__ */
diff --git a/src/goabackend/goaprovider.c b/src/goabackend/goaprovider.c
index 9d99296..4a6cbdb 100644
--- a/src/goabackend/goaprovider.c
+++ b/src/goabackend/goaprovider.c
@@ -35,6 +35,7 @@
 #include "goatelepathyfactory.h"
 #include "goapocketprovider.h"
 #include "goamediaserverprovider.h"
+#include "goagithubprovider.h"
 
 #ifdef GOA_KERBEROS_ENABLED
 #include "goakerberosprovider.h"
@@ -803,6 +804,9 @@ static struct
 #ifdef GOA_TELEPATHY_ENABLED
   { GOA_TELEPATHY_NAME, goa_telepathy_factory_get_type },
 #endif
+#ifdef GOA_GITHUB_ENABLED
+  { GOA_GITHUB_NAME, goa_github_provider_get_type },
+#endif
   { NULL, NULL }
 };
 
diff --git a/src/js/Makefile.am b/src/js/Makefile.am
new file mode 100644
index 0000000..a6e1914
--- /dev/null
+++ b/src/js/Makefile.am
@@ -0,0 +1,16 @@
+NULL =
+
+gjsdir = $(datadir)/gjs-1.0
+gjs_DATA =				\
+	introspectable.js		\
+	simplesoup.js			\
+	github.js			\
+	$(NULL)
+
+EXTRA_DIST = \
+	$(gjs_DATA)
+
+clean-local :
+	rm -f *~
+
+-include $(top_srcdir)/git.mk
diff --git a/src/js/github.js b/src/js/github.js
new file mode 100644
index 0000000..7e15974
--- /dev/null
+++ b/src/js/github.js
@@ -0,0 +1,199 @@
+/*
+ * github.js - github api using goa-github-provider
+ */
+
+const Lang = imports.lang;
+const Signals = imports.signals;
+const Introspectable = imports.introspectable;
+const SimpleSoup = imports.simplesoup;
+const Format = imports.format;
+String.prototype.format = Format.format;
+
+const GLib = imports.gi.GLib;
+const Gio = imports.gi.Gio;
+const GObject = imports.gi.GObject;
+const Goa = imports.gi.Goa;
+const Soup = imports.gi.Soup;
+
+const CHUNK_SIZE = 4098;
+const USER_AGENT = 'goa-github-provider';
+const GOA_ONLINE_ACCOUNTS = "org.gnome.OnlineAccounts";
+const GITHUB = {
+    'root': "https://api.github.com",
+    'gists': {
+	'user_gists': '/users/%s/gists',
+	'user_public_gists': '/gists',
+	'user_starred_gists': '/gists/starred',
+	'public_gists': '/gists/public',
+	'id': '/gists/%s',
+	'create': '/gists'
+    }
+};
+
+const GithubError = function(errormsg) {
+    this.message = errormsg;
+}
+GithubError.prototype = new Error();
+
+const Github = new Lang.Class({
+    Name: "GitHub",
+    Signals: {
+	"got-access-token": {}
+    },
+    _init: function(props) {
+	String.format = Format.format;
+	this.props = props;
+	this.user_id = props.user_id || '';
+	if(!this.user_id) throw new GithubError("no user_id provided");
+	this.introspect = props.introspect || new Introspectable.Introspect();
+	this._get_account();
+	if(!this.account) throw new GithubError("No Github Account configured in Goa");
+	this.account['Account'].EnsureCredentialsRemote(Lang.bind(this, function(expires){
+	    if(expires){log(expires);};
+	}));
+	this.account['OAuth2Based'].GetAccessTokenRemote(Lang.bind(this, function(res){
+	    this.access_token = res[0];
+	    this.expires_in = res[1];
+	    this.soup = this.props.soup || new SimpleSoup.SimpleSoup({"user_agent": USER_AGENT,
+								      "chunk_size": CHUNK_SIZE});
+	    this.emit("got-access-token");
+	}));
+    },
+    _get_account: function() {
+	let goaclient = Goa.Client.new_sync(null);
+	for(let account of goaclient.get_accounts()) {
+	    let node = this.introspect.get_node(account['g-connection'],
+						GOA_ONLINE_ACCOUNTS,
+						account['g-object-path'])
+	    let ifaces = {};
+	    for(let iface of node.interfaces) {
+		let ifacename = iface.name.substring(iface.name.lastIndexOf('.') + 1);
+		ifaces[ifacename] = this.introspect.get_proxy(account['g-connection'],
+							      GOA_ONLINE_ACCOUNTS,
+							      iface.name,
+							      account['g-object-path']);
+	    }
+	    if(ifaces['Account'].ProviderName == 'Github'
+	       && ifaces['Account'].PresentationIdentity == this.user_id) {
+		this.account = ifaces;
+	    }
+	};
+    },
+    _url: function(path, params) {
+	let u = "%s%s?access_token=%s".format(GITHUB['root'], path, this.access_token);
+	let p = null;
+	for(let k in params){
+	    let s="%s=%s".format(k,params[k]);
+	    (!p ? p = s : p += "&%s".format(s));
+	}
+	u = (p ? "%s&%s".format(u, p) : u);
+	return u;
+    },
+    gists_list: function(type,
+			 pageparams,
+			 cancellable,
+			 callback) {
+	return this.soup.call('GET',
+			      this._url(GITHUB['gists'][type].format(this.user_id), pageparams),
+			      null,
+			      cancellable,
+			      callback);
+    },
+    gists_id: function(id,
+		       cancellable,
+		       callback) {
+	return this.soup.call('GET',
+			      this._url(GITHUB['gists']['id'].format(id)),
+			      null,
+			      cancellable,
+			      callback);
+    },
+    gists_create: function(file,
+			   description,
+			   ispublic,
+			   cancellable,
+			   callback) {
+	cancellable = cancellable || null;
+	let post = {
+	    "description": description,
+	    "public": ispublic,
+	    "files": {}
+	};
+	if(file.path) {
+	    let giofile = Gio.File.new_for_path(file.path);
+	    if(callback) {
+		giofile.load_contents_async(null, Lang.bind(this, function(giofile,
+									   asyncresult,
+									   post,
+									   cancellable,
+									   callback) {
+		    let content = giofile.load_contents_finish(asyncresult)[1];
+		    post["files"][giofile.get_basename()] = {"content": content.toString()};
+		    let request = {'headers': {'Content-Type': 'application/json'}, 'body': JSON.stringify(post)};
+		    return this.soup.call('POST',
+					  this._url(GITHUB['gists']['create']),
+					  request,
+					  cancellable,
+					  callback);
+		}, post, cancellable, callback));
+		return true;
+	    }
+	    else {
+		let stream = giofile.read(cancellable);
+		stream.result = '';
+		stream.chunksize = CHUNK_SIZE;
+		while(true) {
+		    let result = stream.read_bytes(stream.chunksize, cancellable);
+		    if(result.get_size() <= 0) break;
+		    stream.result += result.get_data().toString();
+		}
+		post["files"][giofile.get_basename()] = {"content": stream.result};
+		let request = {'headers': {'Content-Type': 'application/json'}, 'body': JSON.stringify(post)};
+		return this.soup.call('POST',
+				      this._url(GITHUB['gists']['create']),
+				      request);
+	    }
+	}
+	else {
+	    post["files"][file.name] = {"content": file.content};
+	    let request = {'headers': {'Content-Type': 'application/json'}, 'body': JSON.stringify(post)};
+	    let url = this._url(GITHUB['gists']['create']);
+	    return this.soup.call('POST',
+				  url,
+				  request,
+				  cancellable,
+				  callback);
+	}
+    },
+    gists_delete: function(id,
+			   cancellable,
+			   callback) {
+	return this.soup.call('DELETE',
+			      this._url(GITHUB['gists']['id'].format(id)),
+			      null,
+			      cancellable,
+			      callback);
+    }
+});
+Signals.addSignalMethods(Github.prototype);
+
+/*
+let mainloop = imports.mainloop;
+let github = new Github({'user_id': 'mohan43u'});
+github.connect('got-access-token', function(self){
+    let content = '[n00b-in-youtube] whats the name of this song at 01:40-00:20?? [everyones-reply] darude sandstorm..!!!';
+    let file = {'name': 'screwed-world.txt', 'content': content};
+    let response = self.gists_create(file,
+				     'test file',
+				     true,
+				     null,
+				     function(response) {
+					 print(response.statuscode);
+					 for(let header in response.headers) {
+					     print("%s: %s".format(header, response.headers[header]));
+					 }
+					 print(response.body);
+				     });
+});
+mainloop.run();
+*/
diff --git a/src/js/introspectable.js b/src/js/introspectable.js
new file mode 100644
index 0000000..498fa9d
--- /dev/null
+++ b/src/js/introspectable.js
@@ -0,0 +1,37 @@
+/*
+ * introspectable.js - introspect dbus objects
+ */
+
+const Lang = imports.lang;
+const Format = imports.format;
+String.prototype.format = Format.format;
+
+const Gio = imports.gi.Gio;
+
+const Introspect = new Lang.Class({
+    Name: "Introspect",
+    _introspect: function(conn, dest, path) {
+	let Proxy = Gio.DBusProxy.makeProxyWrapper('<node>'
+						   + '<interface name="org.freedesktop.DBus.Introspectable">'
+						   + '<method name="Introspect">'
+						   + '<arg direction="out" type="s"/>'
+						   + '</method>'
+						   + '</interface>'
+						   + '</node>');
+	let proxy = new Proxy(conn, dest, path);
+	return proxy.IntrospectSync()[0];
+    },
+    get_node: function(conn, dest, path) {
+	return Gio.DBusNodeInfo.new_for_xml(this._introspect(conn, dest, path));
+    },
+    _get_interface_xml: function(conn, dest, iface, path) {
+	return this.get_node(conn, dest, path).lookup_interface(iface).generate_xml(0).str;
+    },
+    get_proxy: function(conn, dest, iface, path) {
+	let Proxy = Gio.DBusProxy.makeProxyWrapper('<node>'
+						   + this._get_interface_xml(conn, dest, iface, path)
+						   + '</node>');
+	let proxy = new Proxy(conn, dest, path);
+	return proxy;
+    }
+});
diff --git a/src/js/simplesoup.js b/src/js/simplesoup.js
new file mode 100644
index 0000000..a5202ff
--- /dev/null
+++ b/src/js/simplesoup.js
@@ -0,0 +1,104 @@
+/*
+ * simplesoup.js - simple libsoup wrapper
+ */
+
+const Lang = imports.lang;
+const Format = imports.format;
+String.prototype.format = Format.format;
+
+const GLib = imports.gi.GLib;
+const Gio = imports.gi.Gio;
+const Soup = imports.gi.Soup;
+
+const SimpleSoupError = function(errormsg) {
+    this.message = errormsg;
+}
+SimpleSoupError.prototype = new Error();
+
+const SimpleSoup = new Lang.Class({
+    Name: "SimpleSoup",
+    _init: function(props) {
+	this.soup = props.soup || new Soup.Session();
+	this.user_agent = props.user_agent || 'simplesoup.js';
+	this.chunk_size = props.chunk_size || 4098;
+	this.debug = props.debug || GLib.getenv("SOUP_DEBUG");
+	if(this.debug) {
+	    let debuglevel = {"minimal": Soup.LoggerLogLevel.MINIMAL,
+			      "headers": Soup.LoggerLogLevel.HEADERS,
+			      "body": Soup.LoggerLogLevel.BODY};
+	    let debug = debuglevel[this.debug] || debuglevel['body'];
+	    this.soup['add-feature'] = Soup.Logger.new(debug, -1);
+	}
+    },
+    call: function(method, url, request, cancellable, callback) {
+	cancellable = cancellable || null;
+	let message = Soup.Message.new(method, url);
+	let headers = message['request-headers'];
+	this.response = {"headers": {}};
+	headers.append("User-Agent", this.user_agent);
+	message.connect("got-headers", Lang.bind(this, function(message) {
+	    this.response.statuscode = message['status-code'];
+	    message['response-headers'].foreach(Lang.bind(this, function(name, value) {
+		this.response.headers[name] = value;
+	    }));
+	}));
+	if(request) {
+	    if(request.headers) {
+		for(let header in request.headers) {
+		    headers.append(header, request.headers[header]);
+		}
+	    }
+	    if(request.body) {
+		message.set_request(headers.get('Content-Type') || 'text/plain',
+				    Soup.MemoryUse.COPY,
+				    request.body);
+	    }
+	}
+	if(callback) {
+	    this.soup.send_async(message,
+				 cancellable,
+				 Lang.bind(this, function(soup,
+							  asyncresult,
+							  cancellable,
+							  callback) {
+				     let stream = soup.send_finish(asyncresult);
+				     stream.result = '';
+				     stream.chunk_size = this.chunk_size;
+				     stream.callback = Lang.bind(this, function(stream,
+										asyncresult,
+										cancellable,
+										callback) {
+					 let result = stream.read_bytes_finish(asyncresult);
+					 if(result.get_size() > 0) {
+					     stream.result += result.get_data().toString();
+					     stream.read_bytes_async(stream.chunk_size,
+								     GLib.PRIORITY_DEFAULT,
+								     cancellable,
+								     stream.callback);
+					 }
+					 else {
+					     this.response.body = stream.result;
+					     callback(this.response);
+					 }
+				     }, cancellable, callback);
+				     stream.read_bytes_async(stream.chunk_size,
+							     GLib.PRIORITY_DEFAULT,
+							     cancellable,
+							     stream.callback);
+				 }, cancellable, callback));
+	    return true;
+	}
+	else {
+	    let stream = this.soup.send(message, cancellable);
+	    stream.result = '';
+	    stream.chunk_size = this.chunk_size;
+	    while(true) {
+		let result = stream.read_bytes(stream.chunk_size, cancellable);
+		if(result.get_size() <= 0) break;
+		stream.result += result.get_data().toString();
+	    }
+	    this.response.body = stream.result;
+	    return this.response;
+	}
+    }
+});
