Freitag, 2. März 2012

VI Commands to remember

Sometimes you need to edit a file with VI. Because the file is too big for other editors. Or you just have no other editor. But if you know these basic commands, using VI is really a pleasure:

Open, save, quit

CommandDescription
vi filenameopen filename in VI
ZZ or :wq or :xwrite changes to file and quit VI

Switching between edit mode and command mode

CommandDescription
ichange to edit mode at cursor position
ESCchange to command mode

Moving the cursor

CommandDescription
1234Gmove cursor to line 1234
Gmove cursor to end of file
12|move cursor to column 12
/stringmove cursor to first occurence of string
nmove cursor to next occurence of string

Copy & paste, delete

CommandDescription
yycopy current line into buffer
3yycopy next 3 lines into buffer
ppaste the line(s) in the buffer into the text after the current line
Ddelete the remainder of the current line
dGdelete to end of file
dddelete the current line
3dddelete the next three lines

Search & replace

CommandDescription
s/string1/string2/ replace all occurencies of string1 with string2

Mittwoch, 4. Januar 2012

Testing Windows 8 Developer Preview

To be able to debug my web sites on IE and Safari I installed Windows 8 Developer Preview.
Seems Microsoft hired some Apple developers ;-)

Google Identity Toolkit with go Step 3

How many users has Facebook currently? Round about 800 Million? Of course I want to welcome them on my site:


 func verifyFacebookAccount(ctx *web.Context) string {  
      api_url := "https://graph.facebook.com/oauth/access_token?client_id=xxx&redirect_uri=http://kwiqly.com/fbcallback&client_secret=1cf9ee8ac30ba20c25f298b262aa17bd&code=" + ctx.Request.Params["code"]  
      response, _ := http.Get(api_url)  
      b, _ := ioutil.ReadAll(response.Body)  
      accessToken := string(b)  
      response, _ = http.Get("https://graph.facebook.com/me?" + accessToken)  
      b, _ = ioutil.ReadAll(response.Body)  
      var f map[string]string  
      json.Unmarshal(b, &f)  
      registerFBUser(&f)  
      return f["email"]  
 }  

The JSON response I receive for my own acount looks like this:
 {  
   "id": "xxx",  
   "name": "Andreas Mu00fcller",  
   "first_name": "Andreas",  
   "last_name": "Mu00fcller",  
   "link": "http://www.facebook.com/asmuelle",  
   "username": "asmuelle",  
   "bio": "My CV coming soon",  
   "work": [  
     {  
       "employer": {  
         "id": "261972930486746",  
         "name": "energiepraemisse GmbH"  
       },  
       "location": {  
         "id": "106561559378306",  
         "name": "Niederried, Bern, Switzerland"  
       },  
       "position": {  
         "id": "148305368513781",  
         "name": "CTO"  
       },  
       "start_date": "2011-01"  
     }  
   ],  
   "education": [  
     {  
       "school": {  
         "id": "102066659835464",  
         "name": "Kaspar Zeuu00df Gymnasium"  
       },  
       "year": {  
         "id": "135676686463386",  
         "name": "1994"  
       },  
       "type": "High School",  
       "classes": [  
         {  
           "id": "193949477289719",  
           "name": "Biologie"  
         },  
         {  
           "id": "113028568708566",  
           "name": "Mathematik"  
         }  
       ]  
     },  
     {  
       "school": {  
         "id": "111896025493840",  
         "name": "Friedrich-Alexander-Universitu00e4t Erlangen-Nu00fcrnberg"  
       },  
       "year": {  
         "id": "144503378895008",  
         "name": "1999"  
       },  
       "concentration": [  
         {  
           "id": "103112013061919",  
           "name": "Mustererkennung"  
         },  
         {  
           "id": "105972309433865",  
           "name": "Computergrafik"  
         },  
         {  
           "id": "153631238025207",  
           "name": "Datenbanken"  
         }  
       ],  
       "type": "College"  
     }  
   ],  
   "gender": "male",  
   "email": "a.muelleru0040herban.de",  
   "timezone": 1,  
   "locale": "de_DE",  
   "verified": true,  
   "updated_time": "2011-09-16T08:14:46+0000"  
 }  

Unfortunately, Facebook is currently not supported by GIT, but on www.openidsamplestore.com I learned how you can define custom IDPs:

 window.google.identitytoolkit.addCustomIdp({
      'providerId': 'Facebook',
      'imageUrl': 'http://www.dwmroofing.com/images/facebook.jpg',
      'label': 'www.facebook.com',
      'createAuthUriHandler': function(callbackUrl, callbackHandler) {
        callbackHandler({ 'authUri': 'http://www.facebook.com/dialog/oauth?client_id=xxx&display=popup&scope=email&redirect_uri=http://kwiqly.com/fbcallback' });
      }});


Beyond this the response handler must be changed:
  

  var widget = window.google.identitytoolkit.easyrp.util.getWidget_();
  widget.handleGetUserStatusResponse_ = jQuery.proxy(function(result) {
    if (result && 'registered' in result) {
      var account = {email: result.email, legacy: true};
      if (result.displayName) {
        account.displayName = result.displayName;
      }
      if (result.photoUrl) {
        account.photoUrl = result.photoUrl;
      }
      if (result.registered) {
        window.google.identitytoolkit.easyrp.util.accountstorage.
            refreshAccount(account);
      }
      if (result.legacy && result.registered) {
        this.showLegacySignInPage(account);
      } else if (result.legacy) {
        this.showSignUpPage(result.email, true);
      } else {
        if (result.providerId) {
          this.startFederatedLogin_(result.providerId, 'signin', result.email);
        } else {
          this.startFederatedLogin_(result.email, 'signin', result.email);
        }
      }
    } else {
      this.page_.setError(window.google.identitytoolkit.easyrp.messages.
          signUpTypePage.emailFormatError);
    }
  }, widget);


The showAccountChooserPage must be hacked to add support to only show the specified accounts.

  // Hack the showAccountChooserPage to add support to only show the specified accounts.
  widget.showAccountChooserPage = jQuery.proxy(function(opt_error, opt_accounts) {
    jQuery('#popin-box').empty().addClass('widget-panel-chooser');
    var self = this;
    this.page_ =
        new window.google.identitytoolkit.easyrp.page.AccountChooserPage();
    this.page_.onAccountClicked = function(account) {
      if (account.email == self.options.email) {
        self.closeAccountChooser();
      } else if (window.google.identitytoolkit.easyrp.config.
          tryFederatedFirst) {
        self.tryFederatedLoginInAC_(account.email, 'signin', account.email);
      } else if (window.google.identitytoolkit.easyrp.config.
          useCachedUserStatus) {
        if (account.legacy) {
          self.showLegacySignInPage(account);
        } else {
          self.startFederatedLogin_(account.email, 'signin', account.email);
        }
      } else {
        var request = self.getRequestFactory().newGetUserStatusRequest(
            account.email, false);
        request.execute(jQuery.proxy(self.handleGetUserStatusResponse_, self));
      }
    };
    this.page_.onAddAccountClicked = function() {
      self.showAddAccountPage();
    };
    this.page_.onRemoveAccountClicked = function(account) {
      window.google.identitytoolkit.easyrp.util.accountstorage.removeAccount(account);
      self.showAccountChooserPage();
    };
    this.page_.onCloseIconClicked = function() {
      self.closeAccountChooser();
    };
    var accounts = opt_accounts || window.google.identitytoolkit.easyrp.util.accountstorage.
        readAccounts();
    this.page_.render(jQuery('#popin-box'), accounts, undefined, true);
    if (opt_error) {
      this.page_.setError(opt_error);
    }
    window.google.identitytoolkit.easyrp.util.setPopinPosition_();
  }, widget);

Google Identity Toolkit with go Step 2

First I want to implement a callback for Google, Yahoo, AOL and MSN. That*s quite easy, these identity providers are supported by GIT.


func gitCallbackHandler(ctx *web.Context) string {

    ctx.SetHeader("Cache-Control", "max-age=0,private", true)
    userid := verifyByGoogle(ctx)
    user := getUserAccount(userid)
    registered := "false"
    if user.Active == "a" {
        registered = "true"
    }
    ctx.SetSecureCookie("l", userid, 60)
        return getAction(userid, registered)
}

func verifyByGoogle(ctx *web.Context) string {
 var reqbody = "{\"requestUri\":\"" + ctx.Request.Params["openid.return_to"] + "\",\"postBody\":\""
 for k, _ := range ctx.Request.Params {
  reqbody += k + "=" + url.QueryEscape(ctx.Request.Params[k]) + "&"
 }
 reqbody += "\"}"

 var api_url = "https://www.googleapis.com/identitytoolkit/v1/relyingparty/verifyAssertion?key=XXX"
 response, _ := http.Post(api_url, "application/json", strings.NewReader(reqbody))
 userid := ""
 if response.StatusCode == 200 {
  var f map[string]string
  b, _ := ioutil.ReadAll(response.Body)
  json.Unmarshal(b, &f)
  registerGoogleUser(ctx)
  userid = f["email"] + f["verifiedEmail"]
        }

 return userid
}

func getAction(userid,registered string) (action string) {
        if userid=="" {
         action="window.google.identitytoolkit.notifyFederatedError();"
        } else {
         action=`window.google.identitytoolkit.notifyFederatedSuccess({ "email": "` + userid + `", "registered": ` + registered + ` });`
        }
        return `
     
     `
     return
}


Yes, no error handling yet. You can try it on http://kwiqly.com

Google Identity Toolkit with go Step 1

I want to use Google Identity Toolkit with a web.go backend. GIT tutorial says I need some handlers, so here we go:

    web.Post("/gituserstatus", gitUserstatusHandler)
    web.Post("/gitlogin", gitLoginHandler)
    web.Post("/gitcallback", gitCallbackHandler)
    web.Get("/gitcallback", gitCallbackHandler)
    web.Get("/fbcallback", fbCallbackHandler)
    web.Get("/gitsignup", makeUserTemplateHandler("signup"))
    web.Get("/githome", makeUserTemplateHandler("home"))