Dienstag, 31. Dezember 2013

Playing with ranges and functions in Swift

Looking for a generic way to map ranges to objects, and retrieve the object using values in the range.

For example, given a mapping of range 0..<2 to a string "first range" and 2..<4 to a string "second range", we want to get the string for the value 3.4.

I started with this because in my work I had to map rating ranges to certain background colors. If e.g. a user gives something a 5.9 rating (very good!) this would be in the range 4.5 - 6.0 which has to be displayed with a dark green background, etc. Sadly I had to do it using objc. I wondered how I would do it with Swift.

To start, the most primitive approach:

let n = 3.4
let found1:String? = {if n < 2 {
    return "first"
} else if n < 4 {
    return "second"
} else {
    return nil
}}()

println("found: \(found1)")


It's also possible to use a switch case. Rather weird (like in "don't do it"), but we are only playing.

let found2:String? = {switch n {
    case _ where (0..<2) ~= n: return "first"
    case _ where (2..<4) ~= n: return "second"
    default: return nil
    }
}()

println("found: \(found2)")


These approaches are a bit unflexible. And the worst: NOT FANCY! We explore further.

Little intro: get (first) containing range for a value

let result:HalfOpenInterval<Float>? = {
    for r:HalfOpenInterval<Float> in [(0..<1), (1..<2), (2..<3)] {
        if r ~= 2 {
            return r
        }
    }
    return nil
}()


Good! Now, we will make a helper class that holds the range and the object:

struct RangedEntry<T> {
    let interval:HalfOpenInterval<Float>
    let obj:T
    
    init(_ interval:HalfOpenInterval<Float>, _ obj:T) {
        self.interval = interval
        self.obj = obj
    }
}


Now we can iterate through entries to find our match:

for re in [
    RangedEntry((0..<1), "a"),
    RangedEntry((1..<2), "b"),
    RangedEntry((2..<3), "c")
    ] {
        
        if re.interval ~= 1.9 {
            println("found: \(re.obj)")
            break;
        }
}


Alternatively, we can just use tuples:

for r:(HalfOpenInterval<Float>, String) in [
    ((0..<1), "a"),
    ((1..<2), "b"),
    ((2..<3), "c")
    ] {
        if r.0 ~= 1.9 {
            println("found: \(r.1)")
        }
}


What about more functional constructs?

Let's try out filter (we will continue using tuples):

let value:String? = [
    ((0..<1), "a"),
    ((1..<2), "b"),
    ((2..<3), "c")
    
    ].filter{(tuple:(HalfOpenInterval<Float>, String)) -> Bool in
        return tuple.0 ~= 1.9
        
}.first?.1

println("found: \(value)")


This is O(n), since we will examine the whole array each time. Not so good. Coming back later to this. Also note we assume that the ranges don't overlap.

What if we want to generate the ranges dynamically, say, divide 1...7 in 16 equal parts?
Since in this case the ranges are continuos, we can represent them just as a succession of numbers.
We can use strides for this:

let start:Float = 1
let end:Float = 7
let sections = 16
let intervalLength:Float = (end - start) / Float(sections)


let s = stride(from: start, through: end, by: intervalLength)
Array(s) // see contents in playground

// generate tuples with dummy value objects. The start of the range represents the range, and we associate the value object with it.
let tuples:[(Float, String)] = Array(s).map {(val:Float) -> (Float, String) in
    return (val, "range starts:\(val) ends: \(val + intervalLength)")
}


Now let's try out an alternative approach to =~. Since in this case we know the ranges are sorted in increasing order, we can use this information to find the value.

Let's make a variable for the searched number, to verify results more easily.
let search:Float = 4.12

With this we get retrieve the ranges witch a start value smaller than our searched value:
let filtered = tuples.filter {
    return $0.0 < search
}

The range we are looking for is the rangest with the biggest starting value from all the ranges with a starting value smaller than the searched value Since we know the ranges are sorted increasingly, we can just pick the last one from the filter results:

let val:String? = filtered.last?.1
println("found: \(val)")

// if we didn't know that the values are sorted, we could determine max using e.g. reduce:
let val1:String? = {
    filtered.isEmpty ? nil : filtered.reduce(filtered.first!, {
        return $0.0 > $1.0 ? $0 : $1
    }).1
}()

println("found: \(val1)")


The option with the best performance is a loop, that exits when we find the range.
Since there's no filtering step, we have to add logic to look ahead in the next range. If there's no next, or if its starting value is bigger than searched value, we know we are in the searched range.

let myresult:String? = {
    for (index, tup) in enumerate(tuples) {
        if tup.0 <= search && (index + 1 == tuples.count || tuples[index + 1].0 > search) {
            return tup.1
        }
    }
    return nil
}()

println("found: \(myresult)")


Talking about indices and look-ahead, here is a similar approach using filter (just demonstrative purpose - would not use it):
let val2:String? = Array(enumerate(tuples)).filter { (index:Int, element) -> Bool in
    return element.0 <= search && (index + 1 == tuples.count || tuples[index + 1].0 > search)
}.first?.1.1


println("found: \(val2)")


So is there a way in which we use a functional construct with the performance of for loop?
We need something similar to a find function. This is an example of a find function:
(this is btw a nice to have as array extension, frequently used!)

func find<T>(arr:Array<T>, pred:(element:T)->Bool) -> T? {
    for i in 0..<arr.count {
        let element =  arr[i]
        
        if pred(element: element) {
            return element
        }
    }
    return nil
}


In our current case we need that the predicate, besides of the current element, considers also the next one (note nextElement is optional - when we are examining the last element, there's no next element). So we adjust find a bit:

func findWithNextElement<T>(arr:Array<T>, pred:(element:T, nextElement:T?)->Bool) -> T? {
    for i in 0..<arr.count {
        let element =  arr[i]
        let nextElement = arr[i + 1]
        
        if pred(element: element, nextElement: nextElement) {
            return element
        }
    }
    return nil
}


We would call it like this:

let val4:String? = findWithNextElement(tuples, { (element, nextElement:(Float, String)?) -> Bool in
    return (element.0 <= search) && (nextElement?.0 > search ?? true)
})?.1


println("found: \(val4)")

Montag, 30. Dezember 2013

AngularJS: Reusable components using directives


Sometimes it makes sense to have reusable code fragments, which we can customise depending of the context.

Let's start directly with an example:

In a site there's a list of posts, each of them with a title, content, and author name.

This site also has user profiles, where users can read the posts made by a user ("history").
In this case:

- The history is embedded in the user profile
- Since we already know that all the posts are authored by this user, we will not show the author in each post.


Following DRY (don't repeat yourself), we will create one single template for the posts list, and wrap it in a directive, which we can customise according to the context we are using it.

Steps:


1. Template

We create the template called "entries.html", which contains the list of posts (note I used "entry" in the code instead of "post"):

  • {{entry.title}}

    {{entry.text}}

    {{entry.author}}


Here we see we need to "pass" the entries list and a flag called "mode", which we use to customise the template, according where we use it. In this case it determines if the author is visible.


2. Directive


myApp.directive('entries', function() {
  return {
    restrict: 'E',
    scope: {
      entries: '=',
      mode: '='
    },    
    templateUrl: 'entries.html',
  };
});

Here we see:

1. We restrict the directive to type "element", which means that in HTML we declare the directive as tag.

2. We define scope parameter with keys "entries" and "mode". This basically is how we pass the parameters to the template (this is a pragmatic explanation, for a better understanding read the documentation of directives).

3. We pass the name of the template.


3. Model data

Now we will define our entries list. We will use a service for that (not required, but services lead to a cleaner implementation).

myApp.factory('myModel', function($rootScope) {

  var entries = [
    {
    'title': 'title1',
    'text': 'text1',
    'author': 'author1'
    },
    {
    'title': 'title2',
    'text': 'text2',
    'author': 'author2'    
    }
  ];
  
  return {
    entries: entries
  }
});


This is a very basic service, which holds the model data and exposes it to the outside through the returned object:
{entries: entries}


4. Controller

Now we need a controller, for the the section where we are going to insert the list. For sake of simplicity we will show the "default" (with author) and "history" (without author) lists in the same page, and use the same controller.

myApp.controller('myController', function ($scope, myModel) {
    $scope.entries = myModel.entries; //make entries in model available to controller's scope
});


5. HTML using directive

At last the HTML snippet that uses this controller and the directive, which is self explanatory:
  
Default mode


History mode:




Demo


That's it!



Samstag, 8. Juni 2013

Social login with RPXNow in Lift

I just got Social login (OpenID) working in Lift, using RPXNow. RPXNow is intented to make OpenID login easy. It's free bellow 6 providers.

This guide assumes you have already setup the application in rpxnow.

Here are the steps:

1. Add this JS to the page where login will appear (preferably in head):

(function() {
   if (typeof window.janrain !== 'object') window.janrain = {};
   if (typeof window.janrain.settings !== 'object') window.janrain.settings = {};
   
   janrain.settings.tokenUrl = 'http://localhost:8080/signupr';

    function isReady() { janrain.ready = true; };
   if (document.addEventListener) {
     document.addEventListener("DOMContentLoaded", isReady, false);
   } else {
     window.attachEvent('onload', isReady);
   }

    var e = document.createElement('script');
   e.type = 'text/javascript';
   e.id = 'janrainAuthWidget';

    if (document.location.protocol === 'https:') {
     e.src = 'https://rpxnow.com/js/lib/myapp/engage.js';
   } else {
     e.src = 'http://widget-cdn.rpxnow.com/js/lib/myapp/engage.js';
   }

    var s = document.getElementsByTagName('script')[0];
   s.parentNode.insertBefore(e, s);
})();
Notes:
- http://localhost:8080/signupr is obviously my testing host + signupr is how I named the path to my webservice handler - see step 3.
- https://rpxnow.com/js/lib/myapp/engage.js -> "myapp" is the name of the app given in RPXNow.

  2. Add a placeholder HTML element with id "janrainEngageEmbed" where the login widget has to be inserted: In my case, I want to use it together with the existing login system of lift - so I added it just above lift's login form. In order to do that, I overwrote screenWrap in User singleton:
 override def screenWrap = Full{
    
     
}
3. Add handler to get the token from JS call and sign in the user:
class Boot extends Loggable {
 
 def boot {
        //...
   LiftRules.dispatch.append {
     case req @ Req(List("signupr"), _, _) =>
     val userData:SigninResponse = getLoggedInUserData(S.param("token").openOr(""))
    loginOrRegisterUser(userData)
    
    () => for (hrs <- Box.asA[net.liftweb.http.provider.servlet.HTTPRequestServlet](req.request)) yield {
     new RedirectResponse("/page_to_load_after_login.html", null)
    }
  }
}
}
getLoggedInUserData calls rpxnow api to get logged in user's data:
    
    def getLoggedInUserData(token:String):SigninResponse = {
      val query = Map(
        "apiKey" -> "myapikey",
        "token" -> token
      )

     var queryStr = query.foldLeft("") { (s: String, pair: (String, String)) =>
      s + pair._1 + "=" + pair._2 + "&"
     } //TODO without "&" at the end
     
     queryStr = queryStr.substring(0, queryStr.length - 1)
     
     val url = new URL("https://myapp.rpxnow.com/api/v2/auth_info")
     val conn:HttpURLConnection = url.openConnection().asInstanceOf[HttpURLConnection] 
     conn.setRequestMethod("POST");
     conn.setDoOutput(true)
     conn.connect()
     val osw = new OutputStreamWriter(conn.getOutputStream(), "UTF-8")
     osw.write(queryStr)
     osw.close()
        
     val response = streamToString(conn.getInputStream())
        
     implicit val formats = net.liftweb.json.DefaultFormats //need this for extract to work
     val userData:SigninResponse = parse(response).extract[SigninResponse]
        
     userData
    }
SigninResponse class is just a model class for the returned JSON. The field names may change depending of the provider (there are also more fields). I use with these fields, which I need and are also common in the providers I use:
 case class SigninResponse(stat: String, profile:SigninProfile)
 case class SigninProfile(providerName: String, identifier:String, name:SigninName, displayName:String)
 case class SigninName(formatted: String, givenName:String, familyName:String)
At last this method to add the user to my user database (just to keep track of them), and set the user in the session:
 def loginOrRegisterUser(userData:SigninResponse) = {
  var userBox:Box[User] = User.find(By(User.externId, userData.profile.identifier))
  
  if (userBox.isEmpty) {
   userBox = Full(User.create)

  } else {
//   user = userBox.get
  }
  
  val user:User = userBox.get
  
  user.externId(userData.profile.identifier).
    username(userData.profile.displayName).
    provider(userData.profile.providerName).
    firstName(userData.profile.name.givenName).
    lastName(userData.profile.name.familyName).
    saveMe()

    User.logUserIn(user) //set user in the session
  }
In order for that to work I extended the user object / table with provider, externId and username. For the users registered with the default system, externid and provider are never set.

4. Now I can access these users in the app, like the default users:
User.currentUser

How to load translations in Lift from a database

I added this in Boot.scala:


LiftRules.resourceBundleFactories.append {
    case (key, locale) => new TranslationsResourceLoader(locale)
}

And this is the TranslationsResourceLoader class:

import java.util.Locale
import java.util.ResourceBundle

//important! otherwise scala's Enumeration is used and we get
//compiler errors
import java.util.Enumeration 

class TranslationsResourceLoader(val locale:Locale)
  extends ResourceBundle {

  private val translations:List[Translation] = Translation.findAll()
    .filter(t => t.lang.equals(locale.toString.split("_")(0)))

  def getKeys(): Enumeration[String] = {
   val it = translations.iterator
   new Enumeration[String] {
     def hasMoreElements() = it.hasNext
     def nextElement() = it.next.tkey.toString
   }
 }

  def handleGetObject(key: String):String = {
   translations.find(t => t.tkey.equals(key)).get.value
  }
}
And that's it! Now you can use the translations with the usual internationalization methods. In HTML this would be:

<lift:loc locid="dummykey">translation test<lift:loc>

Or:

<p class="lift:loc?locid="dummykey">translation test<p>

And in code:

import net.liftweb.http.S.?

?("dummykey")

Note: This assumes a (custom) class "Translation". In my case this is mapped to a Translation database table. I'm using Lift's Mapper.

Here are useful links about internationalization in Lift in general:
https://www.assembla.com/spaces/liftweb/wiki/Internationalization/print http://timperrett.com/2009/02/28/new-internationalization-extendability-in-lift/