nestoria new design
DESCRIPTION
Nestoria is a property search engine that indexes millions of properties every day. Since mid 2006 the product has evolved into a service must run on multiple devices and browsers. In this talk I introduce Nestoria New Design and the context in which this project was born, and discuss some of the challenges our company has faced during the project. This talk was presented as part of the Commercial Computing Lecture Series at the University of Birmingham.TRANSCRIPT
![Page 1: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/1.jpg)
Nestoria New DesignSavio Dimatteo
Perl Developer,
Lokku Ltd.
Commercial Computing Lecture Series
Birmingham University
5 December 2013
![Page 2: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/2.jpg)
Who am I?
● Savio Dimatteo
● Perl Developer at Nestoria property search engine
● working on a LAMP stack since 2 years [ “P” = “Perl” ]
● maintenance/frontend/backend projects
● currently working on: “Nestoria New Design”
![Page 3: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/3.jpg)
Lokku
● dev team: 6 people● product team: 2 people● commercial team: 8 people
![Page 4: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/4.jpg)
Nestoria
● property search engine
● 8 countries, 6 languages
● 1.3 million search requests per day
● 10 million properties indexed every day
![Page 5: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/5.jpg)
Nestoria
![Page 6: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/6.jpg)
Nestoria Internally
![Page 7: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/7.jpg)
Nestoria Internally
![Page 8: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/8.jpg)
Nestoria Externally
![Page 9: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/9.jpg)
Nestoria Externally
![Page 10: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/10.jpg)
Nestoria Externally
![Page 11: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/11.jpg)
Nestoria Externally
![Page 12: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/12.jpg)
Nestoria Stack
● HTML::Mason
● jQuery/jQueryUI
● XHTML Strict
● Apache, mod_perl
● MySQL
![Page 13: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/13.jpg)
Nestoria Over Time
![Page 14: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/14.jpg)
Nestoria Over Time
![Page 15: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/15.jpg)
Legible Listings Layout
![Page 16: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/16.jpg)
Legible Listings Layout
● ~200KB more CSS
● + ~6% daily clicks than in previous design
● exception: India
○ older devices
■ lower resolutions
■ slower connections
![Page 17: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/17.jpg)
Nestoria New Design
![Page 18: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/18.jpg)
Nestoria New Design
![Page 19: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/19.jpg)
Setting and Resources
● ~4 months time
![Page 20: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/20.jpg)
Nestoria New Design
![Page 21: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/21.jpg)
Challenges
![Page 22: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/22.jpg)
Challenge #1Getting the Design Right
![Page 23: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/23.jpg)
What you get:
○ spacing
○ fonts
○ colors
○ sizes
● Looks good!
New Design Specs
![Page 24: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/24.jpg)
What you get:
○ spacing
○ fonts
○ colors
○ sizes
● Looks good! BUT
New Design Specs
![Page 25: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/25.jpg)
Improvement via user tests
![Page 26: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/26.jpg)
Improvement via user tests
![Page 27: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/27.jpg)
Smaller Graphical Tweaks
![Page 28: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/28.jpg)
Logic not yet implemented
![Page 29: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/29.jpg)
Exact dimensions
![Page 30: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/30.jpg)
“Australian” Prices?
● Offers Above $545,000
● $439,950-$469,950
● POA
● Supurb Value offers above $1.49M
![Page 31: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/31.jpg)
“Australian” Prices?
![Page 32: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/32.jpg)
Implementing “impossible” specs
1. stick to the spec as much as possible
2. follow the principles the spec is based on
3. be inventive
4. talk to people
![Page 33: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/33.jpg)
Implementing “impossible” specs
1. stick to the spec as much as possible
2. follow the principles the spec is based on
3. be inventive
4. talk to people
Australian prices!
![Page 34: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/34.jpg)
Australian Prices!
● no collision
● leave as is
![Page 35: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/35.jpg)
Australian Prices!
● collision
● detect collision (Javascript)
if ($titleLink.position().left + $titleLink.width() >= $titleAside.position().left) {
}
![Page 36: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/36.jpg)
Australian Prices!
● detect collision (Javascript)
if ($titleLink.position().left + $titleLink.width() >= $titleAside.position().left) {
… $listingContainer.addClass(‘nst-collision-detected’); …
}
● Add ‘nst-collision-detected’ CSS rule to fix the issue
![Page 37: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/37.jpg)
Challenge #2Building UI components
![Page 38: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/38.jpg)
New Sliders
![Page 39: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/39.jpg)
New Sliders
● disabled (any price allowed)
![Page 40: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/40.jpg)
New Sliders
● left-bounded range
![Page 41: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/41.jpg)
New Sliders
● bounded range
![Page 42: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/42.jpg)
New Sliders
● single value
![Page 43: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/43.jpg)
New Sliders - click
![Page 44: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/44.jpg)
New Sliders - click
![Page 45: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/45.jpg)
New Sliders - click and drag
![Page 46: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/46.jpg)
New Sliders - touch
![Page 47: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/47.jpg)
New Sliders - touch and drag
![Page 48: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/48.jpg)
How would you do create a slider like that?
![Page 49: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/49.jpg)
jQueryUI
“ jQuery UI is a curated set of user interface interactions,
effects, widgets, and themes built on top of the jQuery
JavaScript Library. ”
![Page 50: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/50.jpg)
jQueryUI - sliders
![Page 51: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/51.jpg)
jQueryUI - sliders
![Page 52: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/52.jpg)
jQueryUI - sliders
Can’t click!
![Page 53: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/53.jpg)
jQueryUI - sliders
Can’t click!
Can’t touch!
![Page 54: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/54.jpg)
jQueryUI - touch support
● jQuery UI Touch Punch
“ jQuery UI Touch Punch is a small hack that enables the
use of touch events on sites using the jQuery UI user
interface library. ”
● Can’t touch sliders on Silk Browser (Kindle Fire HD).
![Page 55: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/55.jpg)
Why building our own sliders?
● complex yet specific user interactions
● it’s tempting to hack into jQuery UI sliders to add touch
support (forbidden!)
● would need to include jQuery UI (23KB, minified)
● we already plan to increase complexity of slider UI!
![Page 56: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/56.jpg)
jquery.nstSlider.js - usage
<div class="nst-slider-outer" data-step="20" data-min="20” data-max="220">
<div class="nst-slider-inner">
<div class="nst-slider-grip-left"></div>
<div class="nst-slider-grip-right"></div>
</div>
</div>
![Page 57: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/57.jpg)
jquery.nstSlider.js - usage
$('.nst-slider-outer').nstSlider({
'valueChangedCallback' : function(min, max) {
$('.nst-slider-min').text(min);
$('.nst-slider-max').text(max);
}
});
![Page 58: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/58.jpg)
jquery.nstSlider.js - Idea
outer bar(gray bar)
leftgrip
rightgrip
position:absolute;left: 0px;
position:absolute;right: 0px;
inner barposition:relative;
![Page 59: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/59.jpg)
jquery.nstSlider.js - Idea
outer bar(gray bar)
leftgrip inner bar
leftgrip
rightgripinner bar
![Page 60: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/60.jpg)
jquery.nstSlider.js - Idea
outer bar(gray bar)
leftgrip
rightgripinner bar
left: <sth>px;
<sth>
![Page 61: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/61.jpg)
jquery.nstSlider.js - Idea
outer bar(gray bar)
leftgrip
rightgripinner bar
left: <sth>px;width: <sthElse>px;
<sth> <sthElse>
![Page 62: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/62.jpg)
jquery.nstSlider.js - Moving left handle
leftgrip
rightgripinner bar
![Page 63: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/63.jpg)
jquery.nstSlider.js - Moving left handle
leftgrip
rightgripinner bar
![Page 64: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/64.jpg)
jquery.nstSlider.js - Moving left handle
leftgrip
rightgripinner bar
deltaPx
● track deltaPx
![Page 65: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/65.jpg)
jquery.nstSlider.js - Moving left handle
leftgrip
rightgripinner bar
● track deltaPx
● add deltaPx to left CSS property of inner bar
deltaPx
![Page 66: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/66.jpg)
jquery.nstSlider.js - Moving left handle
leftgrip
rightgripinner bar
● track deltaPx
● add deltaPx to left CSS property of inner bar
deltaPx
![Page 67: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/67.jpg)
jquery.nstSlider.js - Moving left handle
leftgrip
rightgripinner bar
● track deltaPx
● add deltaPx to left CSS property of inner bar
● remove deltaPx from width CSS property of inner bar
- deltaPx
![Page 68: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/68.jpg)
jquery.nstSlider.js - Moving left handle
leftgrip
rightgrip
● track deltaPx
● add deltaPx to left CSS property of inner bar
● remove deltaPx from width CSS property of inner bar
● map left , left + width into [rangeMin, rangeMax]
inner bar
left left + width
![Page 69: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/69.jpg)
jquery.nstSlider.js - Moving left handle
leftgrip
rightgrip
● track deltaPx
● add deltaPx to left CSS property of inner bar
● remove deltaPx from width CSS property of inner bar
● map left , left + width into [rangeMin, rangeMax]
→ notify values have changed
inner bar
![Page 70: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/70.jpg)
jquery.nstSlider.js
● easy to use as others jQuery plugins
● highly cross-browser (IE7+, iPhones, not Windows Phones
though)
● ~6KB minified (Closure compiler)
● easily customisable
● more code to maintain
● fixed size for now
![Page 71: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/71.jpg)
Challenge #3Javascript Mistakes
![Page 72: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/72.jpg)
Javascript
● more interactive compontents → more Javascript code
● Javascript:
○ Interacting with the DOM
○ Asynchronous event-handling
○ Single threaded
○ Multiple browsers and devices
○ many libraries out there
![Page 73: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/73.jpg)
Scopingvar result = 1;
function oneOrMore(n) {
result = n;
if (n <= 0) {
var result = Math.abs(n);
result = 1 + result;
}
return result;
}
![Page 74: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/74.jpg)
Scopingvar result = 1;
function oneOrMore(n) {
result = n;
if (n <= 0) {
var result = Math.abs(n);
result = 1 + result;
}
return result;
}
var result = 1;
function oneOrMore(n) {
var result;
result = n;
if (n <= 0) {
result = Math.abs(n);
result = 1 + result;
}
return result;
}
![Page 75: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/75.jpg)
How to not iterate through Javascript arrays
Array.prototype.extraFunc = function () { … };
var myArray = [1, 2, 3, 4];
for (var x in myArray) {
console.log(x);
}
![Page 76: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/76.jpg)
How to not iterate through Javascript arrays
Array.prototype.extraFunc = function () { … };
var myArray = [1, 2, 3, 4];
for (var x in myArray) {
console.log(x);
}
1
2
3
4
extraFunc
![Page 77: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/77.jpg)
How to iterate through Javascript arrays
Array.prototype.extraFunc = function () { … };
var myArray = [1, 2, 3, 4];
for (var i=0; i<myArray.length; i++) {
console.log(myArray[i]);
}
![Page 78: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/78.jpg)
How to not iterate through Javascript objects
var myObj = {
‘key1’ : 1, ‘key2’ : 2, ‘key3’ : 3
};
var k;
for (k in myObj) {
console.log(k, myObj[k]);
}
![Page 79: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/79.jpg)
How to iterate through Javascript objects
var myObj = {‘key1’ : 1, ‘key2’ : 2, ‘key3’ : 3
};
var k;for (k in myObj) {
if (myObj.hasOwnProperty(k)) {
console.log(k, myObj[k]);
}
}
![Page 80: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/80.jpg)
Javascript Code Validation - JSHint● Java-based tool
● parser-based validation
● easy to configure
● very flexible configuration
○ trailing whitespaces
○ naming conventions
○ undeclared variables
![Page 81: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/81.jpg)
JSHint configuration{
"curly" : true,
"camelcase": false,
"eqeqeq" : true,
"forin" : true,
"unused" : true,
"es3" : true,
"trailing" : false,
"devel" : false,
"undef" : true,
"jquery" : true,
"browser" : true,
"globals" : {
"Modernizr" : true,
"$j" : true,
"google" : true,
"LokkuMap" : true,
"GoogleLokkuMap" : true,
"LeafletLokkuMap" : true,
"L": true
}
}
![Page 82: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/82.jpg)
Conclusions
● talk to members of your team during your project
● changing a component completely? just build your own!
● Javascript → mistakes!
○ use code quality tools to avoid mistakes
![Page 83: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/83.jpg)
![Page 84: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/84.jpg)
![Page 85: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/85.jpg)
Conclusions: Nestoria New Design● New design is now live
○ ~3% more daily clicks (all countries)
○ users feel it’s fast (i.e., more clicks per users)
○ we can improve its speed further
○ works in India too!
● the amount Javascript in our codebase is going to grow
○ old motto: “avoid Javascript as much as possible”
○ new motto: “write better Javascript”
![Page 86: Nestoria new design](https://reader033.vdocument.in/reader033/viewer/2022060107/554bacf3b4c905b3618b55f1/html5/thumbnails/86.jpg)
Thank you!http://www.nestoria.com - find a property
http://www.github.com/lokku - open source code
http://www.lokku.com/jobs - work with us!