Activate your free membership today | Log-in

Wednesday, April 29th, 2009

Birth of the datagrid element in HTML 5

Category: HTML, Standards

Mark Pilgrim has nicely discussed the new HTML 5 datagrid element on his latest This Week in HTML 5:

In the datagrid data model, data is structured as a set of rows representing a tree, each row being split into a number of columns. The columns are always present in the data model, although individual columns might be hidden in the presentation.

Each row can have child rows. Child rows may be hidden or shown, by closing or opening (respectively) the parent row.

Rows are referred to by the path along the tree that one would take to reach the row, using zero-based indices. Thus, the first row of a list is row “0″, the second row is row “1″; the first child row of the first row is row “0,0″, the second child row of the first row is row “0,1″; the fourth child of the seventh child of the third child of the tenth row is “9,2,6,3″, etc.

The chains of numbers that give a row’s path, or identifier, are represented by arrays of positions, represented in IDL by the RowID interface.

The root of the tree is represented by an empty array.

Each column has a string that is used to identify it in the API, a label that is shown to users interacting with the column, a type, and optionally an icon.

The possible types are as follows:

Keyword Description
text Simple text.
editable Editable text.
checkable Text with a check box.
list A list of values that the user can switch between.
progress A progress bar.
meter A gauge.
custom A canvas onto which arbitrary content can be drawn.

Each column can be flagged as sortable, in which case the user will be able to sort the view using that column.

Columns are not necessarily visible. A column can be created invisible by default. The user can select which columns are to be shown.

When no columns have been added to the datagrid, a column with no name, whose identifier is the empty string, whose type is text, and which is not sortable, is implied. This column is removed if any explicit columns are declared.

Each cell uses the type given for its column, so all cells in a column present the same type of information.

Posted by Dion Almaer at 4:26 am
6 Comments

++++-
4.8 rating from 23 votes

Tuesday, April 28th, 2009

Happy Birthday, Opera

Category: Fun, Opera

You may have already seen Opera’s celebratory home page marking their fifteenth anniversary:

But did you also notice the comic depicting their founders’ story?

Happy Birthday, Opera.

Posted by Ben Galbraith at 10:58 am
6 Comments

++++-
4 rating from 28 votes

CSS3 Template Layout through jQuery

Category: CSS, jQuery

Alexis Deveria of “When Can I Use…” fame recently told us about his latest project:

A jQuery plug-in to provide support for the CSS Template Layout Module. For those of you unfamiliar with this specification, it provides a relatively easy way to make a table-like layout using CSS. Until recently it was known as the “CSS Advanced Layout Module”.

His full blog entry goes into a bit more detail.

We covered John Resig’s thoughts on the CSS3 Advanced Layout Module before; you know, the idea of visually writing a table layout in your CSS file?

Alexis’ project is hosted at Google Code, and it includes various examples. Check it out!

Posted by Ben Galbraith at 8:30 am
16 Comments

+++--
3.3 rating from 41 votes

vice-versa: the noble act of getting the best of all browsers

Category: JavaScript

Andrea Giammarchi has a vision to have the best of all browsers available to him in JavaScript land. He has created vice versa as a project to explore this ideal and incredibly hard vision to attain:

Studying the DOM, which is notoriously a mess, I often "travel" between the MDC and the MSDN to solve a specific trouble which could cause a lot of headaches because of "some" missed W3C implementation. At the same time, bearing in mind that the most used browser is the one with the slowest JavaScript engine, I always try to find out solutions able to complete a task without killing performances. In most of the cases, I simply realized that since other browsers are fast and more powerful, it makes sense to bring some not standard functionality inside these browsers rather than implement, when it is possible, a missed functionality in Internet Explorer. As basic example, to convert an XML document into a string, we would like to use an XMLSerializer instance, but what is that wrong with Microsoft xml attribute shortcut?

JAVASCRIPT:
  1.  
  2. // other browsers way
  3. var xmls = new XMLSerializer;
  4. var string = xmls.serializeToString(myXMLDocument);
  5.  
  6. // Internet Explorer way
  7. var string = myXMLDocument.xml;
  8.  

Moreover, document.evaluate is amazing stuff, but the most common call to this function is this one:

JAVASCRIPT:
  1.  
  2. var xpresult = document.evaluate(XPathSelector, myXMLDocument, null, 0 /* as ANY_TYPE */, null);
  3.  

In internet explorer we have a slightly different function: selectNodes

JAVASCRIPT:
  1.  
  2. var xpresult = myXMLDocument.selectNodes(XPathSelector);
  3.  

The main difference is number of character used to call the standard method rather than IE one, with a completely equal result during iteration where IE nextNode has the same meaning of other browsers iterateNext. Again, if we are in Internet Explorer we can rely in the most ugly property we have ever seen since first JScript implementation over the DOM: document.all. Now, why on earth we love YUICompressor plus gzip "miniaturization" but we prefer a meaningless syntax like this:

JAVASCRIPT:
  1.  
  2. document.getElementsByTagName("*")
  3.  

rather than

JAVASCRIPT:
  1.  
  2. document.all
  3.  

I would love to see us in a world where standards weren't the only way to innovate deeply in the browser, cross browser. We have add-ons in most browsers, but creating multiple versions is a pain. I was excited about Gears as a way to do cross browser work, and maybe if a Gears-like system that allowed many people to write services, we could go further.

Update

Andrea has also just posted on the vice versa selector performance where it does quite well in slickspeed on FFx 3.

Posted by Dion Almaer at 6:18 am
9 Comments

++---
2.7 rating from 37 votes

Even designers are using CSS3? :)

Category: CSS, Design

Sean Martell is my hero. He did the Bespin logos and a bunch of the Mozilla works in general. When Ben and I were in Toronto we got to see him at work at his WACOM tablet, and it is a sight to behold.

I wish I could do that kind of design work, but for me it isn't to be.... my design is left to code :/

Anyway, he has been working a lot on the Fennec (Firefox mobile) design and just
wrote about using CSS3 to build flexible UI elements without recutting UI graphics all over:

Designing UI elements for a mobile browser has taught me a great deal when it comes to creating interactive graphical elements that are to be used in a very small space. Of course, when I say small space, I mean a small space that has the potential to be different for each handset out there. Not only are we talking resolution differences, but the screen DPI can change from device to device as well.

So after resizing and re-slicing the Fennec UI for the second time, I quickly realized that this could be a full-time job for a team of designers depending on the list of handsets Fennec will be appearing on.

Hold the phone… whats this? Firefox 3.5 enables a new slew of fun CSS3 design styles eh? Rounded edges eh? Embedded fonts eh?

* gears turning, monkeys typing, hamsters running *

What if we could replace almost all of the graphical UI elements within Fennec with CSS created equivalents? As a designer, am I comfortable bypassing Photoshop and letting CSS run the pixel rodeo? After a few initial tests, the answer to both of those questions was a very solid “yes”. A solid “friggin’ right” if in Cape Breton.

Here are some nice dark toggles:

with code looking like:

CSS:
  1.  
  2. .toggleONleft {
  3.     font-family: ‘DroidSans-Bold’;
  4.     text-transform:uppercase;
  5.     padding: 0px 8px 0px 12px;
  6.     -moz-border-radius-topleft: 0.5em;
  7.     -moz-border-radius-bottomleft: 0.5em;
  8.     -webkit-border-top-left-radius: 0.5em;
  9.     -webkit-border-bottom-left-radius: 0.5em;
  10.     border-top: 4px solid #aaa;
  11.     border-left: 4px solid #ccc;
  12.     border-right: 4px solid #ccc;
  13.     border-bottom: 4px solid #ccc;
  14.     -moz-border-top-colors:#aaa #bbb #ccc #ddd;
  15.     -moz-border-left-colors:#aaa #bbb #ccc #ddd;
  16.     -moz-border-bottom-colors:#aaa #bbb #ccc #ddd;
  17.     -moz-border-right-colors:#aaa #bbb #ccc #ddd;
  18.     background-color: #ddd;
  19.     display: inline;
  20. }
  21.  
  22. .toggleOFFright {
  23.     font-family: ‘DroidSans-Bold’;
  24.     text-transform:uppercase;
  25.     color:#414141;
  26.     padding: 0px 12px 0px 8px;
  27.     -moz-border-radius-topright: 0.5em;
  28.     -moz-border-radius-bottomright: 0.5em;
  29.     -webkit-border-top-right-radius: 0.5em;
  30.     -webkit-border-bottom-right-radius: 0.5em;
  31.     border-top: 4px solid #ccc;
  32.     border-left: 4px solid #ccc;
  33.     border-right: 4px solid #ccc;
  34.     border-bottom: 4px solid #aaa;
  35.     -moz-border-top-colors:#aaa #fff #fff #fff;
  36.     -moz-border-right-colors:#aaa #dedede #efefef #fafafa;
  37.     -moz-border-left-colors:#aaa #dedede #efefef #fafafa;
  38.     -moz-border-bottom-colors:#aaa #dedede #efefef #fafafa;
  39.     background-color: #fff;
  40.     display: inline;
  41. }
  42.  

Posted by Dion Almaer at 5:26 am
11 Comments

++++-
4.6 rating from 20 votes

Monday, April 27th, 2009

MooTools 1.2.2 and the new MooTools More Plugin Library

Category: MooTools

The MooTools team has been busy over the last week. Last Thursday they released MooTools 1.2.2:

MooTools 1.2.2 is a mainly a bug fix release but it also includes an almost entirely new Class.js. The reasoning behind this is that the old Class.js didn’t play nicely with some advanced usages of this.parent() present in the new MooTools-More. We already had the script ready and tested in the MooTools 2.0 branch so we simply “backported” it to 1.2.2. Other than providing the parent fixes, the new Class also features a much more robust inheritance model, especially when dealing with objects.

For example, the objects you implement now in a class are merged if an object with the same name is found in the class prototype:

JavaScript:
  1.  
  2. var Animal = new Class({
  3.     options: {
  4.         color: 'brown',
  5.         says: 'hissss'
  6.     }
  7. });
  8.  
  9. Animal.implement('options', {says: 'meow'});
  10.  
  11. // Animal.prototype.options is now {says: 'meow', color: 'brown'};
  12.  

This is especially useful when overriding default options in classes, such as Request.

Upgrading to this version of MooTools only requires that you drop in the new version. There aren't any changes that require changes to sites that implement these features.

MooTools More

Also with this release comes a large update to the MooTools plugin library, MooTools More. Previously this portion of the project featured about a dozen add-ons. The new release features 48 plugins, adding things like FormValidators, new effects, JSONP support, numerous enhancements to native objects like String and Element as well as robust URI and Date classes. They plan on adding new plugins regularly as this portion of the library grows over the next several months.

Clientcide

Relatedly, MooTools contributor Aaron Newton has released an updated version of the Clientcide MooTools Plugins to support these new plugins. Many of the plugins that are now officially part of the MooTools project came from Clientcide's collection of plugins. For anyone using the Clientcide plugins you can find compatibility scripts on the download page there. He notes that there are one or two breaking changes for users who were using some of the plugins that moved over to MooTools More.

Posted by Rey Bango at 9:34 pm
15 Comments

+++--
3.7 rating from 62 votes

CiteDrag: Cool library that groks the new drag and drop model

Category: HTML, JavaScript, Library

Elijah Grey has a very cool new script CiteDrag that "adds automatically citation (ie. blockquotes, text quotes, ect.) to any dragged content off of the website which is using the script. CiteDrag requires no additional setup other than include the script somewhere on your website."

I just dragged that above text from my blog post where announced the creation of CiteDrag and dropped it into my WordPress “Edit Page” interface, where automatically appeared quoted. Looking into the <blockquote> we can see that it even has the cite attribute defined. That is just one example of how CiteDrag works.

In a browser such as Firefox 3.5 beta (Shiretoku or a Firefox Nightly) go over to the test page and then start to drag the links, text, and image over to the text area.

Very cool work!

Posted by Dion Almaer at 8:21 am
5 Comments

++---
2.4 rating from 5 votes

Google and Mozilla 3D Round-up

Category: 3D, Canvas, SVG

About a month ago, we covered an announcement about Mozilla's plans to basically put OpenGL ES in the browser and call it Canvas 3D and to do so working with a new working group over at the OpenGL standards body, Khronos.

This week, we covered Google's own 3D announcement, a plug-in offering a high-level scene graph API and embedded V8 run-time.

And of course, don't forget about Opera's 3D work, which we covered back in November 2007.

So now there are three approaches to 3D:

  • Mozilla: Low-level, OpenGL wrapper
  • Opera: Mid-level proprietary scene-graph-ish API
  • Google: The full COLLADA monty

Where should the web go? Mozilla's Chris Blizzard compares the debate to Canvas vs. SVG:

Canvas is a very simple API, much like what we’ve proposed to Khronos for 3D support. It’s well-scoped, well understood and integrates very well with other web technologies. And it’s been getting a huge amount of traction on the web. People are writing all kinds of really neat technology on top of it, including useful re-usable libraries for visualization. Have a look through Google’s own promotional site for Chrome - a huge number of them use canvas. It has traction. And we’ve gone through a couple of iterations - we’ve added support for text and a couple of other odds and ends once we understood what people were trying to do with it.

Now compare this to SVG and SMIL. Each of those specs are multi-hundred page documents with very large APIs and descriptions of how to translate their retained-mode graphics into something that’s usable on the web. (SVG 1.1 is a 719 page PDF. SVG 1.2 Tiny is 449 pages. The spec for SMIL is a 2.7MB HTML file.) We’ve seen some implementation of SVG and SMIL in browsers, but it’s been slow in coming and hasn’t seen full interoperability testing nor any real pick up on the web. The model for these specs was wrong, and I think it shows.

Chris doesn't directly say that Google's approach is "wrong", but he wonders if the Google proposal of a bigger and more ambitious API would represent too great a compatibility burden for browser vendors and developers.

In the comments of his post, Henry Bridge of the Google O3D team replied; here's a lightly edited excerpt:

We agree that to keep a standards process focused, APIs should be as minimal as possible while remaining useful, and so we would likely keep things like that out of any first attempt at a standard and, as you say, let it evolve over time. But the usefulness question brings up an important, and we think, unresolved point. We’d love to build the animation and skinning system in JS, but we just couldn’t get a JS-based animation system fast enough — even on our retained-mode API. Javascript is getting faster all the time and we love that, but until someone builds some apps it’ll be hard to know what’s fast enough.

Standardizing [an Open GL-like] immediate mode API for JS makes total sense. It’s a well defined problem, lots of people know GL, and we think it will be useful. But some of the demos we wrote _already_ don’t run well without a modern JS implementation, and moving to [Open GL] won’t help that (but we’d love to be proven wrong). That’s why we think it makes sense to explore both an immediate and a retained mode 3D, and make sure they work well together.

What do you think?

Posted by Ben Galbraith at 7:00 am
14 Comments

+++--
3.9 rating from 19 votes

Excuse me, maybe, the foundries, erm, let’s mess with em?

Category: Editorial

Mark Pilgrim has a certain style, and it was in full force on his latest post on font issues that we have on the Web.

Some people are offended by tone and such, but if you ignore that, Mark is actually normally spot on!

In this case, the font world feels like the DRM world of music. They can battle up hill all they want, but if they don't start working with their users (who are willing to pay for fonts, just like we are willing to pay for music!) they will find themselves in big trouble.

I was chatting with a GFX engineer on Firefox and after a fun time talking about how freaking fun it is to get fonts right cross platform (holy subtle-ties batman!) he pointed to a nice M+ font (multiple weights etc):

There are tons of great open source fonts out there. One day, instead of looking up to the foundries in their ivory towers in the sky, we will look down on the floor and see the gold is right there! And, then what? What will the foundries have after they push everyone to go the open source route?

Let's enjoy font squirrel and find some nice friendly fonts and use them to make the Web more fontific, and hope that the other chaps work out how to play nicely.

Posted by Dion Almaer at 6:07 am
7 Comments

+++--
3.9 rating from 16 votes

Friday, April 24th, 2009

280Slides, Cappuccino, Atlas, and Aristo

Category: Atlas, Cappuccino, Component, Design, Video

Francisco Tolmasky presented on the latest goodies from 280North at JSConf. In the past we've given the 280North guys a bad time for talking about 280Slides and their other stuff using... Keynote. I don't know if he used Keynote at JSConf, but Francisco published the slides using the 280Slides web-based presentation viewer, which is also embeddable:

(We like the embedded viewer, but did they have to make it swallow common keystrokes? On Firefox OS X, once we embed this IFrame, APPLE-W makes the slide turn white. 10 points for a cool feature, -100 points for hijacking the browser in this context.)

The slides make for a good review of Cappuccino but just include brief mentions of the other interesting bits, such as the new Aristo theme designed by SOFA and the amazing Atlas.

Fortunately, there is a recent video of a talk by Francisco on March 30 to the CocoaHeads user group:

Enjoy!

Posted by Ben Galbraith at 11:00 am
9 Comments

+++--
3.6 rating from 24 votes

CSS Browser Hacks

Category: CSS, Tip

Paul Irish tries not to use CSS browser hacks anymore and instead "uses IE's conditional comments to apply classes to the body tag, but he put up a concise list of browser specific hacks he has used:

CSS:
  1.  
  2. /***** Selector Hacks ******/
  3.  
  4. /* IE 6 and below */
  5. * html #uno  { color: red }
  6.  
  7. /* IE 7 and below */
  8. *:first-child+html #dos { color: red }
  9.  
  10. /* IE 7 and modern browsers */
  11. html>body #tres { color: red }
  12.  
  13. /* Modern browsers (not IE 7) */
  14. html>/**/body #cuatro { color: red }
  15.  
  16. /* Opera 9.27 and below */
  17. html:first-child #cinco { color: red }
  18.  
  19. /* Safari */
  20. html[xmlns*=""] body:last-child #seis { color: red }
  21.  
  22. /*safari 3+, chrome 1+, opera9+, ff 3.5+ */
  23. body:nth-of-type(1) #siete { color: red }
  24.  
  25. /* safari 3+, chrome 1+, opera9+, ff 3.5+ */
  26. body:first-of-type #ocho {  color: red }
  27.  
  28. /* saf3, chrome1+ */
  29. @media screen and (-webkit-min-device-pixel-ratio:0) {
  30.  #diez  { background: #FFDECE; border: 2px solid #ff0000  }
  31. }
  32.  
  33. /***** Attribute Hacks ******/
  34.  
  35. /* ie6 and below */
  36. #once { _color:blue }
  37.  
  38. /* ie7 and below */
  39. #doce { *color: blue } /* or #color:blue */
  40.  
  41. /* 'Modern Browsers' includes IE8, whether you agree or not.. :) */
  42.  

He has included a test page and you can view the different browsers via browsershots.

Finally, he links to another concise list... of JavaScript sniffs.

Posted by Dion Almaer at 10:35 am
14 Comments

+++--
3.3 rating from 32 votes

Mouse Gestures with GWT

Category: Flash, Fun, Gears, UI

Marc Englund wrote to us about his recent experiments with mouse gestures and GWT:

SimpleGesture is a GWT (and IT Mill Toolkit) implementation of the mouse gesture recognition method described by Didier Brun at bytearray.org (as I understand it). It allows you to register easy to understand (human readable) gestures, and receive events when these occur. Additionally, SimpleGesture can record new gestures, so that you don't have to write them by hand.

In this video demo, he's using a Wii to show it off (this confused me at first, but he's using the Wii as a mouse and isn't doing anything with the Wii-specific inputs):

You can also play with a live demo.

SimpleGesture relies on a bit of Flash to do its thing:

I have used the bytearray mouse gesture library for a Flash project before, and I love how simple the method is, and yet it works very well.
The method works by assigning a number depending on which direction the mouse moves in (moving right will produce "0", moving down will produce "2", and so on), and comparing the resulting string of numbers to the registered gestures. The gesture with the lowest Levenshtein distance (and below a set threshold), is considered a match.

Posted by Ben Galbraith at 9:00 am
5 Comments

+++--
3.5 rating from 22 votes

Blackberry Storm using Raphael (SVG/VML) and SoundManager

Category: JavaScript, SVG, Showcase, jQuery

Brad Neuberg pointed me to a Blackberry Storm site that uses Raphael, jQuery, and SoundManager to offer an SVG / VML (for IE) experience.

HTML:
  1.  
  2. <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.0/jquery-ui.min.js"></script>
  3. <script src="/js/soundmanager2-nodebug-jsmin.js"></script>
  4. <script src="/js/raphael-min.js"></script>
  5. <script src="/js/trig-min.js"></script>
  6.  

Posted by Dion Almaer at 6:48 am
2 Comments

+++--
3 rating from 22 votes

Thursday, April 23rd, 2009

myPatterns: XPath / RegEx for JS Objects

Category: JavaScript, Library

Nic Volanschi pointed us to myPatterns:

myPatterns is a new library adding custom notations for data structures in JS (and also C). It's really useful for writing elegant programs using general pattern matching.

To explain myPatterns, let's introduce a standard JavaScript object:

JavaScript:
  1. {
  2.   name: { firstname: "John", lastname: "Smith" },
  3.   children: [
  4.     { firstname: "Eric", gender: "male", born: 1991 },
  5.     { firstname: "Deborah", gender: "female", born: 1996 }
  6.   ]
  7. }

Using myPattern, you can write a test to check if this object represents a person whose first child is a boy 18 years old:

JavaScript:
  1. (s = match(x, "{name:{lastname: %l}, children:[{gender: 'male', born: %b} | %x]}"))
  2. && new Date().getFullYear() - s.b == 18

The website explains the pattern above:

In the above, the match() statement both checks whether the object has a certain form (e.g. that the children field is an array containing a first element of a given form), and returns a "substitution" object s having the following value: {l: "Smith", b: 1991, x: [ {firstname: "Deborah" , born: 1996} ]}.

Furthermore, using your own notations, you could write the same condition more concisely, and with your own personal touch, for example:

JavaScript:
  1. s = match(x, "<%first ~ %last: [boy(18) | %rest]>")

In the above, the object is noted in a more concise way, and the age of the first son is directly specified in the pattern, as if it was stored in the object, taking advantage of active patterns to compute the age on the fly.

Neat!

Posted by Ben Galbraith at 8:00 am
5 Comments

++---
2.5 rating from 32 votes

More Web Workers in Action

Category: HTML, Standards

Another day, another Paul Rouget HTML 5 demo :) This time he does something fun with Web Workers to allow you to see the difference that you can get when you use them.

His latest simulation has him implementing Simulated Annealing (in video) which is useful for finding the shortest path between several points in a canvas.

If you run the demo demo and watch the animated PNG you will see how smooth the world is based on if the animation stops from time to time. Try it with workers on and off to see.

We have been using Workers in Bespin from the get go. Malte Ubl is doing very cool work to ironout the differences between different Web Worker implementations (Firefox, Safari, and Gears). For example, through his abstraction you get the standard importScripts in Gears too, and it includes a mutex abstraction to boot. This has been crucial for us as we add more JS intensive features to the code editor such as realtime syntax checking, rich syntax highlighting, JSLint error reports inline, and more.

We have found that you do have to be careful with Workers though. You don't want to fire too many off as you end up with a raging CPU if you aren't careful, so Malte and others are working on a slicing plan that will keep the CPU down but also keep the UI responsive. We will report back.

Posted by Dion Almaer at 7:14 am
Comment here

++++-
4.1 rating from 16 votes

How many ways can you iterate over an array in JavaScript?

Category: JavaScript, Tip

Myk is one of the nicest chaps that I have had the pleasure to sit closely to in Mozilla building "S".

He has a nice little tip on the many syntaxes that you can use to iterate over arrays in various JavaScript implementations and standards. Some folks had some interesting points on the various approaches:

for each in:

JAVASCRIPT:
  1.  
  2. for each (var item in [1, 2, 3]) alert(item);
  3.  

The MDC docs for "for each" say not to iterate arrays that way, too, so I never use it on them. The usual (would need to guard with hasOwnProperty() issue).

JavaScript 1.6 added the Array.forEach method:

JAVASCRIPT:
  1.  
  2. [1, 2, 3].forEach(function(item) { alert(item) });
  3.  

JavaScript 1.7 added array comprehensions for array initialization:

JAVASCRIPT:
  1.  
  2. var squares = [item * item for each (item in [1, 2, 3])];
  3.  

I just realized I can (ab)use comprehensions to iterate arrays with Perl-like syntax by throwing away the result:

JAVASCRIPT:
  1.  
  2. [alert(item) for each (item in [1, 2, 3])];
  3.  

I can iterate object properties the same way:

JAVASCRIPT:
  1.  
  2. var obj = { foo: 1, bar: 2, baz: 3 };
  3. [alert(name + "=" + obj[name]) for (name in obj)];
  4.  

Edward Lee points out how to use Iterators:

JAVASCRIPT:
  1.  
  2. [alert(key + "=" + val) for ([key, val] in Iterator({a:1,b:2,c:3}))]
  3.  

Posted by Dion Almaer at 4:29 am
18 Comments

+++--
3.2 rating from 33 votes

« Previous PageNext Page »