Very High Activity

News

  Analyzed 5 days ago based on code collected 6 days ago.
 
Posted 8 months ago by Brandon Savage
When I was a new PHP developer, I discovered that there’s a myriad of solutions, options, configurations and frameworks available. I thought, how does one sift through all the noise and get something done? How can anyone have a grasp of the best practices in PHP, and make sense out of all the options? Which [...]
Posted 8 months ago by nore...@blogger.com (Nick Cameron.)
Some of the trickiest bugs getting Azure canvas working were with radial gradients. Radial gradients in canvases are very flexible, more so than CSS radial gradients or as commonly found in paint software. Other than the spec,which is not ... [More] particularly user-friendly, I did not find much explanation of how they work. So, here is my understanding.

A gradient is an interpolation between colours across a filled area. The simplest kind of gradient is linear, which is just a linear interpolation. For example, here is a rectangle with a left to right linear gradient from red to green:

A radial gradient interpolates circles, rather than lines, for example here is a simple radial gradient from red to green:
To add clarity, here is the same gradient with the start and end circles added:

The above example is simple because the two circles have the same centre and the 'start' circle is entirely within the 'finish' circle. In addition, there are only two colours involved, the start and end colours. These two issues are pretty much orthogonal, so we'll deal with multiple colours first, and we'll do so in the context of linear gradients, since the issues are the same independent of the type of gradient, and linear ones are simpler.

The start, end, and any intermediate colours are called colour stops. Each gradient must have at least two colour stops - the start and end colours - and may have any number of additional, intermediate colour stops. The syntax for these things is (I've elided the details of gradient creation for now):

  var context = canvas.getContext('2d');
  var gradient = context.create...Gradient(...);
  gradient.addColorStop(0, 'red');
  gradient.addColorStop(1, 'green');
  context.fillStyle = gradient;
  ...

The gradient will blend smoothly from red to green. The first parameter to addColorStop can be thought of as the parameter in a parametric equation; 0 is the start of the gradient, and 1 is the end. In fact, the gradient will shade from negative to positive infinity. Outside the start and end colour stops, the colour is extrapolated. For example, here is a gradient fill that shows the gradient outside the 0,1 range; the black lines are at 0 and 1 on the gradient:

Additional colour stops add intermediate colours, for example adding

  gradient.addColorStop(0.5, 'blue');

gives a gradient from red to blue to green (again the black lines are at the colour stops):

And here's a more complex example,

  gradient.addColorStop(0, 'red');
  gradient.addColorStop(0.1, 'blue');
  gradient.addColorStop(0.3, 'red');
  gradient.addColorStop(1, 'green');

in linear and radial versions:

OK, now back to just two colours, and more complex radial gradients. The syntax to create a radial gradient is:

  createRadialGradient(x0, y0, r0, x1, y1, r1)

where *0 define the position and radius of the starting circle (where the gradient parameter is 0), and the *1 arguments define the end circle (where  the gradient parameter is 1). If we offset the two circles (but circle 0 is still completely inside circle 1), then we get a skewed version of the simple radial gradient:
But, if the circles are not inside one another, then we get a cone:
Huh?

The gradient is interpolated from positive to negative infinity, just like with linear gradients. In the radial case, you can think of the gradient being drawn by stroking many incremental circles between the start and end circles. The position and radius of the circles are interpolated between x0, y0, r0 at t=0 (where t is the gradient parameters discussed above) and x1, y1, r1 at t=1. The interpolation is extrapolated to larger and larger circles as t tends to positive infinity, and to smaller and smaller circles as the radius disappears to 0, somewhere between t=0 and t=-infinity. This is what gives the cone shape. To illustrate, I have added the circles at t=0 and t=1 and a line along the centres of all the hypothetical circles:

The shading of the gradient is also kind of interesting; the shading is limited to the cone and is a gradient from the 'left' side of the t=0 circle to the 'left' side of the  t=1 circle. In particular, the gradient extends across the t=0 circle, but the t=1 circle is a solid colour. That is in contrast to the simple case (where t=0 circle is entirely inside t=1 circle) where t=0 is a solid colour and t=1 is shaded. To understand this we need two concepts: that the gradient is drawn from positive infinity to negative infinity (technically, towards negative infinity until the radius of circles becomes 0), and that what is drawn is not overdrawn. In the example, the gradient is drawn right-to-left, getting less green and more red as we go. The gradient goes between the left side of the circles because we draw from the right and do not overdraw. Note that left or right does not make a difference, we draw from circle 1 to circle 0, so the gradient will go from the side of circle 1 closest to circle 0, to the side of circle 0 furthest from circle 1.

There is nothing which says that circle 0 must be the smaller circle, so we can create a gradient from the 'opposite' sides of the circles by swapping the definition of the circles in the createRadialGradient call and the colours of colour stops:
The final case is if the two circles overlap, but neither is entirely contained in the other. We can apply the same understanding as the separate circles case (and of couse, that understanding applies to the simplest case too). In fact the gradient looks similar, just with a more compressed cone:

We can see the cone stretch out as the circles get further apart (in the first example, the circles are just one pixel apart):
  And there is the interesting case where the edges of the circles touch. This looks like the case where circle o is inside circle 1, except that the solid blue colour stops at the edge of the circles. One pixel further, and we are back to the simple case: [Less]
Posted 8 months ago by Anant
A group of around 200 Mozillians gathered in Warsaw, Poland last week for the European MozCamp of 2012. My last MozCamp was the one in Prague back in 2009, so it was wonderful to be able to participate and meet with the European community after so ... [More] long. There was a mix of familiar and new faces, a great sign of a growing and vibrant community!

The theme of the weekend was Mobilize Mozilla, which to me meant rallying the Mozilla community around our various mobile efforts which includes Firefox for Android and FirefoxOS. For years, Firefox on Desktop has been and still remains Mozilla’s flagship product, but there was never a doubt that Mozilla’s mission was much larger than Firefox. The opening keynote was by Tristan and Mitchell, which covered some general updates on various Mozilla activities around the world and specifically Europe, but also some inspiring comments on why our priorities at Mozilla are the way they are. I especially liked Mitchell’s emphasis on building quality products that people love to use. As Mozillians, we’re clear on what our values are, but no piece of software can perfectly represent them. Even Firefox isn’t perfect, which is why we’re improving the security and privacy it can offer with every release. What matters is that we’re taking small steps, each one bringing us closer to the “perfect product”. Now that we’re building mobile products, we’re going to be challenged with some decisions that may be hard to make. In times like this, it’s important to keep the big picture in mind; Mozilla can’t do any good if it becomes obsolete!

The second keynote was by Jay Sullivan, who gave us an overview of where we are with all our products currently, and what’s coming up in the future. There were some pretty cool demos as well, and I had the wonderful opportunity to showcase BananaBread, a 3D FPS built by azakai and several other Mozillians, using only HTML5 – no plug-ins. It uses emscripten to convert the open source Cube2 game engine “Sauerbraten” from C++ to JavaScript, and the performance is pretty smooth. As a gamer, I must say that I’m very impressed!

This was followed by a demo of the latest features in Firefox for Android by Wesley Johnston. He showed us how smooth scrolling is (no more checker-boarding!) and some of the latest WebAPIs and CSS3 transitions in action. My favourite new feature is the reader mode, now available on the Beta – go check it out! Andres Martinez from Telefonica then gave us a good look at the new FirefoxOS on a real device. The Gaia UI has come a long way, he showed us the task switcher, music player, the browser and a game. It was nice to see music still playing in the background throughout the demo. Gavin Sharp gave us a preview of the new Social API that’s landing in the nightlies. The Labs folks had been working on it for a while, and it’s very close to actually landing in Firefox, thanks to a bunch of effort by Gavin & team. We tried to follow that with a WebRTC demo, unfortunately, we ran into technical difficulties while on stage Thankfully, we were able to successfully repeat the demo later in the day, during a session on WebRTC that Timothy Terriberry and I ran. Paul Rouget then took the stage and showed us some of the new developer tools hotness, including tilt and the command line.

The morning session had two more keynotes in store, David Slater gave us an overview of Marketing at Mozilla. He also revealed our top secret plan for marketing Firefox on desktop – more t-shirts! This was followed by caution that the strategy for mobile will have to differ, and a glimpse of what’s in store. Check out about:home in your Firefox for a cute little Android animation! He then invited community members to come forth with their crazy ideas, we’re going to need them to compete with other industry giants with piles of cash! Get in touch with Gen Kanai, he’ll patiently listen, no matter how crazy the idea The final keynote of the day was by Mark Surman, who gave us an update on various efforts by the Foundation, and like at CampusParty, made a case for building a generation of WebMakers. The Chad Vader Friday parody was played again, and good times were had!

We rounded off the morning session with a showcasing of the community quilt – a 90 second lightning talk by one representative from each community. I learnt a lot about how our community operates on the ground, what challenges they’re facing and what they’re most proud of. The rest of MozCamp was filled with sessions and fun activities, but I won’t get into the details of them all or this post will get way too long! However, I will mention that I loved the buddy program at this MozCamp. My buddy was Anas El Husseini, who does localization in Arabic, among other things; and we had a great time swapping stories. It’s just awesome to part of a community that’s so wide and diverse.

If you ever get a chance to attend a MozCamp, I’d highly encourage it – it’s a blast!

P.S. Slides from our WebRTC session are here, if you’re interested.

[Less]
Posted 8 months ago by Benjamin Kerensa
Growing Ubuntu in Oregon!
  
In an effort to continue to grow not only the Ubuntu User (and Contributor) community in Oregon but also the amount of people using Free Open Source Software in general, I spent the afternoon visiting local ... [More] libraries to distribute brochures and Ubuntu CD’s.

So if you know someone in Portland specifically who needs some Ubuntu in their life then send them down to the Belmont, Gregory-Heights or Midland branches of the Multnomah County Library. Hopefully in the coming months distribution will expand to the Marion County and Washington County Library Systems.

As always if you need information about if you need help getting started on Ubuntu and live in Oregon then visit the Ubuntu Oregon website! And don’t forget we have at 12.10 release party coming up next month which you can RSVP for right here!

 

Subscribe to my blog’s RSS feed here and leave some comments below!

 

This post originally on Ubuntu in Oregon [Less]
Posted 8 months ago by nore...@blogger.com (Robert)
Let me clear up any confusion about what our plans are for audio APIs in Firefox.

Some MediaStream support has landed in Firefox 17. We have the ability to create MediaStreams containing the output of media elements and use them as a source ... [More] for other media elements. I need to make some changes to those APIs based on feedback we start evangelizing them for real. We can also create MediaStreams via getUserMedia (when that feature is preffed on in about:config).

The work on MediaStreams Processing that I did as an alternative to the Web Audio API is on the back-burner. Our priority is to implement Web Audio. Our plan is to implement AudioNodes using the same infrastructure as MediaStreams under the hood --- to reduce code duplication and to ensure that Web Audio/MediaStreams integration is perfect. Some core infrastructure for MediaStreams that are produced by processing inputs to outputs --- ProcessedMediaStreams --- already landed, to support the features above. Currently Ehsan is working on the IDL/DOM API side and I have some more work to do on the MediaStreams infrastructure side. We don't have a specific date set for Web Audio support, but it is a high priority.

At some point we will revisit MediaStreams Processing to get the features that Web Audio is missing, e.g., seamless stitching together of an audio and video playlist from a series of clips. That is lower priority. [Less]
Posted 8 months ago by Greg Wilson
I have a Mac. It has a power adapter:

The plug that goes into the power outlet looks like this:

I am in Oslo. Their power outlets look like this:

I brought a universal adapter with a double-round mode:

but its ... [More] input looks like this:

Whoops: a North American plug with a round ground pin won’t fit. My old Mac adapter fit—it didn’t have the ground pin, just two flat power pins that folded down into the brick. That’s why I thought this would work, but no, I upgraded my power adapter, and it broke backward compatibility.

Luckily, the shop at Heathrow Airport sells gadgets that have UK output pins:

and three-pin round-ground North American input slots:

which means I can cobble this together to recharge my laptop:

Tomorrow, I will show this to students in the workshop I’m teaching and ask, “Does your software look like this?” [Less]
Posted 8 months ago by John
tl;dr: If you are a remotie…or if you work with someone who is a remotie… I’d love to hear from you.

Whenever “remoties” come up in discussion, I continue to be surprised by the level of interest people have about this. ... [More]

Its not just a polite “oh, that’s interesting”. Its a suddenly intense outpouring of personal war stories – “oh really? Let me tell you about the time when…”. Some of those stories were told as validation (“yes, we did what you do, and we’re happy it worked for us also” or “we didn’t do what you do, and it ended badly“). Some of these stories were told in denial (“we tried that once, it didn’t work out, which proves it is not ever possible“). Some of these stories were told in despair (“…so now my company wont hire any remoties“). But all of these stories were told with intense personal fervor, sometimes years after the fact!

This shouldn’t have surprised me. As Homa Bahrami pointed out when I met her in Mozilla Summit 2011, and again in meetings this summer, working with remoties is a hard people-organizational problem, not a software-organization problem. Homa also pointed out the intense, long term impact this can have on someone’s personal life and entire career, which explained some of the passionate responses I’ve received so far.

Stepping back, I realized that while most of the people I’ve talked with so far are in the computer business, I’ve also heard similar stories from university lecturers, book publishers, public relations people, medical doctors and traveling sales reps.

This got me thinking about how to contact even more people who work remotely… hence this blog post.

If you are a remotie…or if you work with someone who is a remotie… I’d be really interested to hear from you.

Do you have examples of things that did (or did not!) work for you?
Do you have ideas of things you haven’t tried, but which you think might help?

As usual, you can post comments below. I do also understand this is a personal thing, especially if you are still working in the situation. Therefore, if you want to email me privately instead, please email me at “joduinn -at- mozilla -dot- com”, and put “remoties” somewhere in the subject. I will, of course, honor any requests to keep feedback anonymous, all I ask that you give me any working email address in case something is unclear, and I want to contact you with any followup questions.

Thanks!
John.
=====

Meanwhile, here’s a collection of useful links I’ve found about working remotely. If you know of others, please let me know.

http://oduinn.com/blog/2012/04/04/we-are-all-remoties/
http://www.forbes.com/sites/jacquelynsmith/2012/08/16/how-to-succeed-at-working-from-home/
http://venturebeat.com/2012/08/26/forget-silicon-valley-build-your-startup-where-you-live/
http://lifehacker.com/5940580/why-remote-workers-are-more-yes-more-engaged
http://blogs.hbr.org/cs/2012/08/are_you_taking_your_people_for.html
http://zachholman.com/posts/how-github-works/ [Less]
Posted 8 months ago by stak
I was going through the conference proceedings for ICSE 2012 to see if there was anything particularly interesting. One of the short papers I found was called "An Integrated Bug Processing Framework" and described a tool to automatically bisect code ... [More] and find regressions based on bug reports. Although it was a two-page paper and very short on implementation details, it seemed like a good idea to incorporate at Mozilla.

Tracking down changesets that introduced regressions is harder to do on the Mozilla codebase than at most other places I've worked at, because of the size and complexity of the code. Finding the regressing changeset almost always involves bisecting nightlies or code, as opposed to doing a quick code inspection and hg blame. I recently had to do this for a Fennec bug, and it was rather tedious. (I actually ended up updating mozregression to work with Fennec, and submitted a pull request which is still pending, but even so, testing each bisection build for the error was annoying).

What would be awesome is if we modified our approach to fixing regressions slightly, and made it more test-driven. Instead of bisecting the regression, patching the code, and writing a test, we could write the test first, then use that in an automated bisection script to find the regressing changeset, and then patch the code. The test would also (by definition) be a test for the patch, and could be submitted to the repository along with the fix. This would make it much easier to track down the regressing changeset, and also ensure that patches have tests to go with them. [Less]
Posted 8 months ago
Lately I have being very entusiastic about clojurescript, but I keep running into small annoyances that I just can not get over with. I think it may be useful to provide a feedback form a user who’s primary language for the past decade was JS ... [More] , which brings me to a folloing point:

1. Enable github issues

At the moment clojure discussion group is the only place for providing feedback. Group is very active and it’s clojure (not clojurescript) discussion group so most of the discussions are not really relevant to me. I find keeping up with all the noise there hard, and would personally have created bunch of issues reports already if I could have submitted them on github.

2. Accessing properties with computed names

I find API for accessing properties with computed names awkward:

#!env/scheme
(aget js/require.extensions ".cljs")

At least because documentation of get function, matches better my intent then aget’s. Also I find use case common enough, that I think a syntax sugar would be more appropriate.

3. Setting properties with computed names

API for setting properties with computed names is even clunkier:

#!env/scheme
(set! (aget js/require.extensions ".cljs") compile)

I think extending set! special form would make a lot more sense:

#!env/scheme
(set! js/require.extensions ".cljs" compile)

4. Regural expressions

I really enjoy how simple regular expressions translate to JS:

#!env/scheme
#"[^a-z\s]" ;; => /[^a-z\s]/

Although I could not find any way to create regular expressions with advance search flags, other then by using RegExp constructor:

#!env/scheme
(js/RegExp. "\\w+\\s" "g") ;; => /\w+\s/g
(js/RegExp. "^\\-\\-\\w*$" "m") ;; => /^\-\-\w*$/m
(js/RegExp. "foo" "i") ;; => /foo/i

I wish literal syntax had support for search flags, maybe even via clojure tags.

5. Try / catch

In clojure and inherently clojurscript catch clause of the try special form takes error type, error name and expressions:

#!env/scheme
;; for Clojurescript use js/Object as type
(try
(/ 1 0)
(catch js/Object e
(.log js/console e)))

I do understad that it makes sence on JVM, but it definitely does not on JS. I really wish that error type was either optional or was removed entirely in clojurescript.

7. Less dependency on JVM

While I fully understand rational behind dependency on JVM, it’s still painful for someone coming from JS who’s not comfortable with configuring class paths. Tools like leiningen also spend more time on booting JVM then on performing actual tasks. I think clojurscript could be significally more successful among JS developers if they could strat witout any dependencies (even if they will have to deal with them later once they’re more comfortable).

Overall I’m pretty happy with clojurscript, it’s pretty young project and I hope it will only get better and more accessible over time! [Less]
Posted 8 months ago
We need to clarify our story on rvalue lifetimes. This is related to
issue #3387 and also various recent and not-so-recent
discussions on IRC.

The basic question is how long an rvalue lives when the program creates
pointers into ... [More] it. To understand the rough issues, first consider this
program:

let x = foo();
match x {
Some(ref y) => {...}
None => {...}
}

Here, the result of foo() is stored into a local variable. The
match clause then creates a pointer to the interior of this local
variable (i.e., into the stack) called y. But what if we eliminated
the variable x:

match foo() {
Some(ref y) => {...}
None => {...}
}

This seems to read fine, but when you think about it it’s a little
strange. Where does the result of foo() live, after all?

The answer is that rustc creates a temporary home on the stack.
Basically, it transforms the second example into the first. Now, the
question at hand is, how long does this temporary live?

Actually, there are a number of related questions. It turns out it’s
pretty hard to come up with a system that seems to address all the
desired use cases.

Here are some related scenarios where this question comes up:

An expression like &foo(): the desired semantics is basically the
same as above: introduce a temporary on the stack, write the result
of foo() into this temporary, and then return a pointer to
it. Again we must decide how long this temporary lives.
An expression like &[1, 2, 3]: this allocates a temporary vector
on the stack and returns a slice. How long should it live?

In all of these cases, there is a sort of hard limit: the value cannot
live longer than the innermost enclosing loop or function. That would
require dynamically sized stack frames, which we do not want.
However, there is a range of other possible answers.

One time when it becomes very important to have a good answer to this
question is when destructors come into play. It is nice if we can
make a rule that makes it very predictable when a destructor will
execute.

There are two basic approaches we can take:

Come up with a rule for how long rvalues live, hopefully a simple
one, and enforce it in the region checker.
Using the region checker, infer the liftime of any pointers into
the rvalue temporary, and make it live as long as those pointers
but no longer. It is an error if that would cause the rvalue’s
lifetime to exceed the innermost enclosing loop or function.

A simple rule?

It turns out to be hard to find a rule that both matches intution and
covers the various use cases. Our first thought was “rvalues
temporaries live as long as the innermost enclosing statement”. This
works well for the match statement given above, for example. However,
it doesn’t work well for examples like:

let foo = &bar();
let foo = &[1, 2, 3];

Because, in these cases, the value would only live as long as the
let statement iself, you could never use foo at all, as it would
point into deallocated memory. We could say, well, in a let statement,
the value lives as long as the enclosing block. OK, then what about this:

let foo = if cond { &bar() } else { &qux() };

Well, maybe we say that a tail expression is not a statement (it’s not, after all)
and is sort of a part of the enclosing statement, so this example would mean
that &bar() and &qux() would live as long as the enclosing block.

OK, then what about if we wrote it this way:

let foo;
if cond {
foo = Some(&bar());
} else {
foo = None;
}

Hmm, this is more troublesome. We’d have to look at the assignee, see that is
a variable, and decide that the lifetime of any rvalue temporaries will be
the lifetime of that variable.

OK, then what about this:

let foo = { mut f: None };
if cond {
foo.f = Some(&bar());
}

Hmm, to accommodate this, we have to do a borrowck style analysis to
figure out what the rvalue lifetime is, because we have to consider
where the field f resides. Of course we have the code to do this,
but this rule is looking more and more complex!

Not only that, but such a rule can lead to some pretty counterintuitive results.
For example:

let foo;
if cond {
foo = match bar() {
Some(x) => x * x,
None => 0
};
}

Now, here, the result of match bar() is being assigned to foo, so
I guess the lifetime of the temporary rvalue for bar() ought to be
the same as the block enclosing foo. But that means that this
rvalue will live much longer than we expect, and much longer than it
needs to. So perhaps we “reset” to the enclosing statement when we
descend into a match statement—and perhaps other statements too,
like calls. That seems to more-or-less yield what I intuitively
expect.

In these situations, it is perhaps instructive to consider what C++
does. Near as I can tell from reading the spec, the C++ rule is that
“a temporary lives as long as the outermost enclosing expression,
unless it is assigned to an rvalue reference, in which case it may
live longer”. This is basically the rule I just described. This is
not, in my opinion, a simple rule: it’s a “do what I mean” (DWIM) rule
that tries to approximate what it thinks you wanted. One advantage
we’d have over C++, of course, is that with regions we could report an
error if you thought that the rvalue would live longer than it will.

A simple rule!

Well, there is one rule we could say. We can just assign rvalue
temporaries the maximal lifetime. They can all live as long as the
innermost enclosing loop or function body. In that case, all of the
prior examples will work just fine. The price we pay is that (1) the
stack space (and any uniques/other variables within) lives longer than
you might expect and (2) destructors run rather late, probably much
later than the user anticipated.

So, if you have something like this:

loop {

if cond {
let foo = a_function();
let bar = &a_function();

// foo is dropped here
}

// bar is dropped here
}

It might be surprising that foo and bar would have different
lifetimes here.

Give up on rules?

An alternative then is to drop the idea of a rule and to basically say
that we use inference to decide how long to keep a temporary around.
Basically, we will infer a suitable lifetime (subject to the maximal
constraint) such that the rvalue outlives all existing pointers, and
free it after that lifetime expires. From a user’s point of view, I
think this means that you don’t get a hard guarantee about when the
dtor runs. Essentially, values will get dropped sometime between when
the last reference to them goes out of scope and the maximal
constraint of the innermost enclosing loop/function body.

The main difference between using inference and using the “DWIM” rule
from the first section is that inferences makes certain code forms
possible that the DWIM rule does not support. For example, you could
write:

let x = match foo() {
Some(ref y) => y,
None => &0
};

Here, the call to foo() yields a result which will be stashed on the
stack. Under the DWIM rule, this result would live only as long as
the let statement itself. Under inference, though, we can see that
the user creates a reference into this value and that it is assigned
to x, so the rvalue would live at least until x goes out of scope
(same with the &0 rvalue that occurs in the None case).

So what should we do?

I don’t know. To be honest, any one of these alternatives seems
viable. The DWIM rule is probably the most work, because we already
have to do region inference anyhow. The simple rule is probably too
simple and will end up being more surprising than either of the
others, despite its simplicity. Inference is the most flexible but
gives the weakest guarantees (though in practice I think it would be
fairly predictable). I lean towards inference.

There is a related question. Right now, if you create a pointer into
the interior of a managed box, borrowck will ensure that this box
remains rooted for the lifetime of that pointer. This seems to be
more-or-less the same thing as ensuring that an rvalue’s stack slot
lives long enough to outlive any pointers into it. So perhaps we can
subject such “auto-rooting” to a similar rule as rvalue references; or
maybe managed data is different. It is called “managed” for a reason,
after all. [Less]
 

 
 

Creative Commons License Copyright © 2013 Black Duck Software, Inc. and its contributors, Some Rights Reserved. Unless otherwise marked, this work is licensed under a Creative Commons Attribution 3.0 Unported License . Ohloh ® and the Ohloh logo are trademarks of Black Duck Software, Inc. in the United States and/or other jurisdictions. All other trademarks are the property of their respective holders.