Coder Social home page Coder Social logo

breeze's Introduction

Breeze Build Status

Breeze is a library for numerical processing. It aims to be generic, clean, and powerful without sacrificing (much) efficiency.

This is the 2.x branch. The 1.x branch is 1.x.

The latest release is 2.1.0, which is cross-built against Scala 3.1, 2.12, and 2.13.

Documentation

Using Breeze

Building it yourself

This project can be built with SBT 1.2+

SBT

For SBT, add these lines to your SBT project definition:

libraryDependencies  ++= Seq(
  // Last stable release
  "org.scalanlp" %% "breeze" % "2.1.0",
  
  // The visualization library is distributed separately as well.
  // It depends on LGPL code
  "org.scalanlp" %% "breeze-viz" % "2.1.0"
)

Previous versions of Breeze included a "breeze-natives" artifact that bundled various native libraries. As of Breeze 1.3, we now use a faster, more friendly-licensed library from @luhenry called simply "netlib". This library is now bundled by default.

Maven

Maven looks like this:

<dependency>
  <groupId>org.scalanlp</groupId>
  <artifactId>breeze_2.13</artifactId>
  <version>2.1.0</version>
</dependency>

Other build tools

[http://mvnrepository.com/artifact/org.scalanlp/breeze_2.12/2.1.0] (as an example) is a great resource for finding other configuration examples for other build tools.

See documentation (linked above!) for more information on using Breeze.

History

Breeze is the merger of the ScalaNLP and Scalala projects, because one of the original maintainers is unable to continue development. The Scalala parts are largely rewritten.

(c) David Hall, 2009 -

Portions (c) Daniel Ramage, 2009 - 2011

Contributions from:

  • Jason Zaugg (@retronym)
  • Alexander Lehmann (@afwlehmann)
  • Jonathan Merritt (@lancelet)
  • Keith Stevens (@fozziethebeat)
  • Jason Baldridge (@jasonbaldridge)
  • Timothy Hunter (@tjhunter)
  • Dave DeCaprio (@DaveDeCaprio)
  • Daniel Duckworth (@duckworthd)
  • Eric Christiansen (@emchristiansen)
  • Marc Millstone (@splittingfield)
  • Mérő László (@laci37)
  • Alexey Noskov (@alno)
  • Devon Bryant (@devonbryant)
  • Kentaroh Takagaki (@ktakagaki)
  • Sam Halliday (@fommil)
  • Chris Stucchio (@stucchio)
  • Xiangrui Meng (@mengxr)
  • Gabriel Schubiner (@gabeos)
  • Debasish Das (@debasish83)
  • Julien Dumazert (@DumazertJulien)
  • Matthias Langer (@bashimao)
  • Mohamed Kafsi (@mou7)
  • Max Thomas (@maxthomas)
  • @qilab
  • Weichen Xu (@WeichenXu123)
  • Sergei Lebedev (@superbobry)
  • Zac Blanco (@ZacBlanco)

Corporate (Code) Contributors:

And others (contact David Hall if you've contributed and aren't listed).

Common Issues

Segmentation Fault or Other Crashes on Linux

Netlib, the new low level BLAS library Breeze uses, in turn uses OpenBLAS by default on Linux, which has some quirky behavior w.r.t. threading. (Please see luhenry/netlib#2). As work arounds:

  • Use MKL, if possible
  • Increase the size of the stack of Java threads with -Xss10M (set the Java threads' stack size to 10 Mbytes)
  • Make sure OpenBLAS doesn't use the parallel implementation by defining the environment variable OPENBLAS_NUM_THREADS=1
  • Compile a custom version of OpenBLAS that unconditionally define USE_ALLOC_HEAP at https://github.com/xianyi/OpenBLAS/blob/develop/lapack/getrf/getrf_parallel.c#L49

breeze's People

Contributors

adampauls avatar bashimao avatar benfradet avatar bwignall avatar darrenjw avatar davedecaprio avatar devonbryant avatar dlwh avatar dramage avatar dreamquster avatar fommil avatar fozziethebeat avatar gabeos avatar hl475 avatar jacobandreas avatar jaketimothy avatar jasonbaldridge avatar jrj-d avatar knavely avatar ktakagaki avatar laci37 avatar luhenry avatar mengxr avatar nikdon avatar rahulpalamuttam avatar rakeshchalasani avatar rtreffer avatar sethtisue avatar weichenxu123 avatar zacblanco avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

breeze's Issues

Failure in breeze.stats.distributions.Gamma.mle

I encountered this case that fails: can you confirm?

import breeze.stats.distributions.Gamma
    val mean = 2.834312
    val meanOfLogs = -0.689661
    val n=5.000000
    val ss = Gamma.SufficientStatistic(n, meanOfLogs, mean)
    val (k, theta) = Gamma.mle(ss)

Compilation fails with SBT when using DenseVector(index) inside for expression and using toSet

Today I ran across a bug during the "specialize" phase of the Scala compiler/sbt.

The following fails to compile (with an assertion error):
def test() = {
val row = DenseVector(1,2,3,4)
for (j <- 0 until row.length if (row(j) > 3)) yield j
}

whereas the following compiles

def test() = {
val row = DenseVector(1,2,3,4)
for (j <- 0 until row.length if (5 > 3)) yield j
}

As you can see, the only difference is that row(j) has been replaced by a concrete value.
This also works:
def test() = {
val row = DenseVector(1,2,3,4)
for (j <- 0 until row.length if (row.valueAt(j) > 3)) yield j
}

I'm using SBT 12.2 with Scala 2.10.1. I also tried with Scala 2.10.0 with no difference.

Stack trace: https://gist.github.com/tburny/5650247
Source: https://github.com/tburny/bayesian-personalized-ranking/blob/8312ce8fe623ab1480b911e93beed96da6b0e0b9/src/main/scala/de/burnynet/BPRModel.scala
in methods usersWhichRatedItemPositive and positiveItemRatingsByUser

support log scale in plots

Right now the only reason why I didn't do my last whole project in scala was because I couldn't generate plots with log scale (at least on y axis). I can see it isn't just my problem.

Slices give weird result

Not sure exactly whats going on here.
Code like the following shows the issue:

import scala.util.Random
val data = DenseMatrix.fill(300, 300) {Random.nextDouble}
val rng = 0 until 10
val just_200 = data(rng, 200)
val all_cols = data(rng, ::)
val just_200_again = all_cols(::, 200)
just_200 == just_200_again

Unify functionality in PQN and LBFGS.

We've just added a Projected Quasi Newton algorithm for general constrained optimization.
It shares a lot in common with LBFGS, and common functionality should be abstracted out.

Merge Matrix functionality from Bayes-Scala Linear.class

For the purpose of Gaussian operations, such as marginal or conditional, I implemented some linear algebra functionality as a part of Bayes-Scala project
https://github.com/danielkorzekwa/bayes-scala/blob/master/src/main/scala/dk/bayes/gaussian/Linear.scala

I rejected scalala (breeze), mostly because of poor documentation and some missing functionality that I needed. I propose merging Linear scala to breeze-math project.

Core features of Linear class that I need:

  • nice syntax for add, subtract, multiply matrices: def +, def -, def *, for use case example look here:
    https://github.com/danielkorzekwa/bayes-scala/blob/master/src/main/scala/dk/bayes/gaussian/CanonicalGaussian.scala (def marginalise)
  • multiply number by a matrix with scala implicits,
  • matrix operations for removing row, column from a matrix (again, useful for some gaussian operations:
    • def filterNotRow(rowIndex: Int):Matrix
    • def filterNotColumn(columnIndex: Int): Matrix
    • def filterNot(rowIndex: Int, columnIndex: Int): Matrix = filterNotRow(rowIndex).filterNotColumn(columnIndex)

Matrix power

Is there any function to calculate the n-th or x-th power of a DenseMatrix?

Shaped solve (\) of transposed and sliced matrix does not work

Hi,
this is not the same as bug #29, since it also involves slicing.

scala> import breeze.linalg._
import breeze.linalg._

scala> val A=DenseMatrix((1.0,0.0),(1.0,-1.0))
A: breeze.linalg.DenseMatrix[Double] =
1.0 0.0
1.0 -1.0

scala> val i = DenseMatrix.eyeDouble
i: breeze.linalg.DenseMatrix[Double] =
1.0 0.0
0.0 1.0

scala> i \ A.t(::,1)
res11: breeze.linalg.DenseVector[Double] = DenseVector(1.0, 0.0)

The result result should be DenseVector(1.0,-1.0). Actually, the result is correct if we use copy or toDenseVector.

scala> i \ A.t(::,1).copy
res12: breeze.linalg.DenseVector[Double] = DenseVector(1.0, -1.0)

Implement :+ for Arrays in NumericOps.Arrays

:+ (and other operators) should work on Array as expected:

import NumericOps.Arrays._

scala> Array(1.0, 2.0) :* 2.0
res9: Array[Double] = Array(2.0, 4.0)

scala> Array(1.0, 2.0) :+ 2.0
res10: Array[Double] = Array(1.0, 2.0, 2.0)

examples of how to create features from text

would be great to have some examples of how to create feature vectors from text. There is some doc about tokenization, but how to I vectorize from there? Are there built in tools for doing n-grams, computing tf/idf weight and applying stoplists?

Spire integration

Hey, first off, great library. I'm one of the authors of Spire (w/ Erik Osheim @non). Looking over some of the type classes, we seem to be duplicating some work (wrt algebra type classes). Breeze has a much larger scope than Spire, so I was wondering if there was anything you'd like to see in Spire that'd let you replace breeze.math with Spire's type classes (checkout spire.algebra). A VectorSpace typeclass seems a minimum, but is there anything else?

If you all are amenable, I could try submitting a PR for a version of breeze that uses Spire's type classes where appropriate. If you aren't interested, than no worries, just le me know and I won't do the work :)

https://github.com/non/spire

Problems with distributions.Gamma.SufficientStatistics?

Do you define the ss's to be (n, meanOfLogs, mean) or (n, sumOfLogs, sum)?
The implementation of the * operator follows the latter while the + operator follows the former. In particular,
ss*2 != ss + ss

I assume you meant line 155:

def *(weight: Double) = SufficientStatistic(n*weight, meanOfLogs, mean)

efficiency: Adding a cache wrapper to vectors

Methods that inspect all active values in a vector are often used frequently in applications and can get significant performance boosts if these values are cached. As an example, code that compares sparse vectors to dense vectors using euclidean distance can be significantly improved if the dense vector has a cache for the norm. This is also the case for using other metrics such as cosine similarity. We should include a mechanism for adding a lightweight cache to existing vectors.

Calling toString on a DenseMatrix with zero rows and some columns throws java.lang.UnsupportedOperationException: empty.max

Try the following in the REPL:

This works:

scala> breeze.linalg.DenseMatrix.zeros[Int](0,2).toString
scala> breeze.linalg.DenseVector[Int]().toString

This throws java.lang.UnsupportedOperationException: empty.max :

scala> breeze.linalg.DenseMatrix.zeros[Int](0,2).toString
java.lang.UnsupportedOperationException: empty.max
    at scala.collection.TraversableOnce$class.max(TraversableOnce.scala:201)
    at scala.collection.immutable.Vector.max(Vector.scala:63)
    at breeze.linalg.Matrix$class.colWidth$1(Matrix.scala:68)
    at breeze.linalg.Matrix$class.toString(Matrix.scala:73)

The culprit is the following line:

    def colWidth(col : Int) =
      (0 until showRows).map(row => this(row,col).toString.length+2).max

which should be replaced by:

    def colWidth(col : Int) =
      if (showRows > 0) (0 until showRows).map(row => this(row,col).toString.length+2).max else 0

or something approaching.

Thanks for any correction!

Denis

CSCMatrix does not support element-wise multiplication.

The following code:

val m = CSCMatrix.rand(10, 10)
val m2 = CSCMatrix.rand(10, 10)
m :* m2

fails with the following error:

<console>:13: error: could not find implicit value for parameter op: breeze.linalg.operators.BinaryOp[breeze.linalg.CSCMatrix[Double],breeze.linalg.DenseMatrix[Double],breeze.linalg.operators.OpMulScalar,That]
              m :* m2

scalanlp.ra.Signature shouldn't rely on String.hashCode

While there is nothing wrong with basing the signature on a hash of its name, simply using String.hashCode to produce such a hash causes problems: The implementation of String.hashCode is up to the specific JRE in use; thus, the same name may yield different hashes on different systems, even if the name in question is the same throughout.

KuhnMunkres Fails when number of rows > number of cols

There's an IndexOutOfBounds exception thrown if the number of rows is greater than the number of columns. For example,

  val testMatrix = Seq(
    Seq(1.0,0.0,3.0),
    Seq(0.0,1.0,1.0)
  )

  val testMatrixTranspose = Seq(
    Seq(1.0, 0.0),
    Seq(0.0, 1.0),
    Seq(3.0, 1.0)
  )

  val result = KuhnMunkres.extractMatching(testMatrix)
  val result2 = KuhnMunkres.extractMatching(testMatrixTranspose)

breeze requires GLIBC 2.14 and dumps a shared object in /tmp?

Hi,

This report is going to sound overly critical so I wanted to start by saying that I like breeze a lot. I've been experimenting with it for a few months now as a candidate alternative to octave. Breeze has a lot of potential and I'd love to see it succeed.

I pulled recently and observed the following (X is a dense matrix I created; that code is omitted):

scala> val d = det(X)
-- org.jblas ERROR Couldn't load copied link file: java.lang.UnsatisfiedLinkError: /tmp/jblas2892023685856654603libjblas.so: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.14' not found (required by /tmp/jblas2892023685856654603libjblas.so).

You probably got an error about an unsatisfied link error. Probably you are
running an old version of GLIBC. Your program will run, just more slowly.
d: Double = -0.018931735319476457

Two observations about this error:

  1. No errors about missing dependencies (glibc 2.14) were reported at build time.
  2. I verified this file /tmp/jblas2892023685856654603libjblas.so is created when I take the determinant. I delete that file, re-build breeze, run a REPL, import breeze.linalg._, make a matrix...and the file is still not there. det(X), and I get the above warning and suddenly that shared object file exists.

Both 1 and 2 are undesirable behaviors to me:

  • It's not clear why a library like breeze should depend on any specific version of glibc; the C or Fortran libraries on which it depends can be (were in the past?) compiled for older versions. Furthermore, this dependence will force me to set useNativeLibraries to false. I'm not in a position to upgrade my operating system at this time, and I'm not inclined to try installing an alternate C library set and deal with the inevitable linker and C compiler problems just so that I can use breeze with native libraries.
  • Where on earth is this jblas2892023685856654603libjblas.so library file coming from if it's not being built by the build process? I don't find it anywhere in the distribution. Why is it placed in /tmp? What (besides file system permissions) stops a malicious user from dumping arbitrary object code into that file? I can't say I'm comfortable with unknown (to me) object code appearing seemingly out of nowhere in /tmp and running on my machine when I'm goofing around with matrices.

I understand setting useNativeLibraries to false would work around these specific concerns, but I want to use the native libraries. I'm experimenting with an implementation of multidimensional scaling over top of breeze and I'd like it to be as fast as possible. Are there plans to address these issues?

Thanks!

Anthony

Uniform Distribution

The pdf of the uniform distribution is non-zero outside of the boundaries

  def unnormalizedLogPdf(x: Double) = 0.0

  def logNormalizer = entropy;

  def mode = mean;

  def entropy = math.log(high - low)

Beta.sample() fails for extreme values

The following case fails (Beta.sample() generates NaNs) because a and b are too small:

    val a = 0.0014364182264741652
    val b = 0.0024709345620239687
    val n = 100000
    val samples = (0 until n).map(i=>(new Beta(a, b)).draw() ).toArray
    val mean = samples.sum / n
    val true_mean = a / (a+b)
    assert(math.abs(mean - true_mean) < 1e-2, (mean, true_mean))

My current workaround is to rescale the parameters while preserving the first moment:

  def sampleBeta(a:Double, b:Double):Double = {
    val thresh = 1e-2
    if (math.min(a,b) < thresh) {
      val x = math.min(a,b)
      sampleBeta(thresh * a / x, thresh * b / x)
    } else {
(new Beta(a, b)).draw()
    }

Shaped solve (\) of transposed matrix does not work

If I try to use the \ operator on a transposed DenseMatrix, it does not work (it gives the same result of the non-transposed matrix)

Example:

scala> import breeze.linalg._
import breeze.linalg._

scala> val A = DenseMatrix((1.0,0.0),(1.0,-1.0))
A: breeze.linalg.DenseMatrix[Double] =
1.0 0.0
1.0 -1.0

scala> val t = DenseVector(1.0,0.0)
t: breeze.linalg.DenseVector[Double] = DenseVector(1.0, 0.0)

scala> A \ t
res0: breeze.linalg.DenseVector[Double] = DenseVector(1.0, 1.0)

scala> A.t \ t
res1: breeze.linalg.DenseVector[Double] = DenseVector(1.0, 1.0)

breeze.stats.distributions.Beta.sample() gives incorrect results

The current implementation of the sampling of the beta distribution seems incorrect.
More precisely, if I create a Beta(3,2) and sample from it, the occurence of events x<1e-3 is two order of magnitude more frequent than when using scipy and apache commons.
I assume this one is quite hard to debug, I would for now advise using apache commons instead.

Sorry, no patch for this one. Consider is a low-priority as far as I am concerned.

Counter.count ambiguous method signature

I'm curious how one is supposed to use Counter.count in the Counter.count(List("hey", "there", "list")) form rather than the Counter.count("this", "is", "my", "sentence")?

Will not every instance matching TraversableOnce[K] also match K*? And in that case, the compiler will always complain, and it will be impossible to use that form of the method.

Of course I can do Counter(my_list.groupBy(identity).mapValues(_.size)), but that seems to be missing the point of Counter.

Considering how limited the use of K* is in the programmatic setting, I would recommend simply striking out that method signature.

Specific error:

scala> Counter.count(List("hey", "there", "list"))
<console>:17: error: ambiguous reference to overloaded definition,
both method count in object Counter of type [K](items: K*)breeze.linalg.Counter[K,Int]
and  method count in object Counter of type [K](items: TraversableOnce[K])breeze.linalg.Counter[K,Int]
match argument types (List[java.lang.String])
              Counter.count(List("hey", "there", "list"))

Tests fail, but sbt reports everything is fine

openSUSE 11.4, sbt 0.12

When I run tests, the summary looks great, maybe except final error:

[info] Passed: : Total 85, Failed 0, Errors 0, Passed 85, Skipped 0
[error] breeze-math/test:test: Tests unsuccessful

however when I scroll all messages, it appears there are a lot of errors burried among messages, just sbt "forgot" to report and count them. Errors like:

(ERROR) (FirstOrderMinimizer.scala:73) Failure! Resetting history: breeze.optimize.LineSearchFailed: Grad norm: 2.4058 Dir Norm: 0.0709

-- org.jblas ERROR Couldn't load copied link file: java.lang.UnsatisfiedLinkError: /tmp/jblas265468506203409291libjblas.so: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by /tmp/jblas265468506203409291libjblas.so).

[error] Error during tests:
[error] breeze.linalg.LinearAlgebraTest

[error] Could not run test breeze.linalg.LinearAlgebraTest: java.lang.UnsatisfiedLinkError: org.jblas.NativeBlas.dpotrf(CI[DII)I

-- org.jblas ERROR Couldn't load copied link file: java.lang.UnsatisfiedLinkError: /tmp/jblas8788535870427962319libjblas.so: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by /tmp/jblas8788535870427962319libjblas.so).

Reshape and flatten needed

As far as I can tell, the main linear algebra operations missing compared to Numpy or Matlab are reshape and flatten. They should probably produce views rather than copy.

Long/BigInt matrices

Can't multiply Long-matrices:

scala> var temp = DenseMatrix.zerosLong;
temp: breeze.linalg.DenseMatrix[Long] =
0 0 0
0 0 0
0 0 0

scala> temp(2,2) = 1

scala> temp * temp
:40: error: could not find implicit value for parameter op: breeze.linalg.operators.BinaryOp[breeze.linalg.DenseMatrix[Long],breeze.linalg.DenseMatrix[Long],breeze.linalg.operators.OpMulMatrix,That]
temp * temp

Can't create BigInt matrices:

scala> var temp = DenseMatrix.onesBigInt;
:38: error: could not find implicit value for evidence parameter of type breeze.math.Semiring[BigInt]
var temp = DenseMatrix.onesBigInt;

Can't create spire SafeLong matrices:

scala> var temp = DenseMatrix.onesSafeLong;
:38: error: could not find implicit value for evidence parameter of type breeze.math.Semiring[spire.math.SafeLong]
var temp = DenseMatrix.onesSafeLong;

Gaussian distribution

Two small issues,

  1. I believe the unnormalizedLogPdf is off by a factor of 1/2
  override def unnormalizedLogPdf(t: Double) = {
    val d = (t - mu)/sigma;
    -d *d
  } 
  1. Scalala.library.numerics.erf is incorrect about 0. I've added a ticket for it here, but I wasn't sure if you wanted to address the issue yourself.

Thanks!

detail split of responsability between Breeze/Nak/Chalk

Just to operationalize this some: update web page to reflect existence of Nak and Chalk, and to point to their documentation.

the scalanlp page says that "Breeze is the core set of libraries for ScalaNLP, including linear algebra, numerical computing, optimization, machine learning, and text processing". But it seems from this issue response that Nak is the part responsible for text processing (feature extraction etc.). Looking at chalk, it seems like it's a wrapper on openNLP, so is this an annotation tool (chunk, POS, ..)?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.