Git Product home page Git Product logo

guava's Introduction

Guava: Google Core Libraries for Java

Latest release Build Status OpenSSF Best Practices

Guava is a set of core Java libraries from Google that includes new collection types (such as multimap and multiset), immutable collections, a graph library, and utilities for concurrency, I/O, hashing, primitives, strings, and more! It is widely used on most Java projects within Google, and widely used by many other companies as well.

Guava comes in two flavors:

Adding Guava to your build

Guava's Maven group ID is com.google.guava, and its artifact ID is guava. Guava provides two different "flavors": one for use on a (Java 8+) JRE and one for use on Android or by any library that wants to be compatible with Android. These flavors are specified in the Maven version field as either 33.1.0-jre or 33.1.0-android. For more about depending on Guava, see using Guava in your build.

To add a dependency on Guava using Maven, use the following:

<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>33.1.0-jre</version>
  <!-- or, for Android: -->
  <version>33.1.0-android</version>
</dependency>

To add a dependency using Gradle:

dependencies {
  // Pick one:

  // 1. Use Guava in your implementation only:
  implementation("com.google.guava:guava:33.1.0-jre")

  // 2. Use Guava types in your public API:
  api("com.google.guava:guava:33.1.0-jre")

  // 3. Android - Use Guava in your implementation only:
  implementation("com.google.guava:guava:33.1.0-android")

  // 4. Android - Use Guava types in your public API:
  api("com.google.guava:guava:33.1.0-android")
}

For more information on when to use api and when to use implementation, consult the Gradle documentation on API and implementation separation.

Snapshots and Documentation

Snapshots of Guava built from the master branch are available through Maven using version HEAD-jre-SNAPSHOT, or HEAD-android-SNAPSHOT for the Android flavor.

  • Snapshot API Docs: guava
  • Snapshot API Diffs: guava

Learn about Guava

Links

IMPORTANT WARNINGS

  1. APIs marked with the @Beta annotation at the class or method level are subject to change. They can be modified in any way, or even removed, at any time. If your code is a library itself (i.e., it is used on the CLASSPATH of users outside your own control), you should not use beta APIs unless you repackage them. If your code is a library, we strongly recommend using the Guava Beta Checker to ensure that you do not use any @Beta APIs!

  2. APIs without @Beta will remain binary-compatible for the indefinite future. (Previously, we sometimes removed such APIs after a deprecation period. The last release to remove non-@Beta APIs was Guava 21.0.) Even @Deprecated APIs will remain (again, unless they are @Beta). We have no plans to start removing things again, but officially, we're leaving our options open in case of surprises (like, say, a serious security problem).

  3. Guava has one dependency that is needed for linkage at runtime: com.google.guava:failureaccess:1.0.2. It also has some annotation-only dependencies, which we discuss in more detail at that link.

  4. Serialized forms of ALL objects are subject to change unless noted otherwise. Do not persist these and assume they can be read by a future version of the library.

  5. Our classes are not designed to protect against a malicious caller. You should not use them for communication between trusted and untrusted code.

  6. For the mainline flavor, we test the libraries using OpenJDK 8, 11, and 17 on Linux, with some additional testing on newer JDKs and on Windows. Some features, especially in com.google.common.io, may not work correctly in non-Linux environments. For the Android flavor, our unit tests also run on API level 19 (KitKat).

guava's People

Contributors

bezier89 avatar cgdecker avatar cgruber avatar cpovirk avatar cushon avatar dependabot[bot] avatar dimo414 avatar dorireuv avatar eamonnmcmanus avatar erikvanderpoel avatar gk5885 avatar gkdn avatar graememorgan avatar herbyderby avatar java-team-github-bot avatar jbduncan avatar jrtom avatar kluever avatar kstanger avatar lowasser avatar lukesandberg avatar martinkretzschmar avatar netdpb avatar nick-someone avatar nymanjens avatar ronshapiro avatar stefanhaustein avatar sumitbhagwani avatar williamcollishaw avatar yorickhenning 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

guava's Issues

Filler for Non-Existent Issue

Filler for non-existent Google Code issue 47.

This issue only exists to ensure that GitHub issues have the same IDs they had on Google Code. Please ignore it.

Filler for Non-Existent Issue

Filler for non-existent Google Code issue 45.

This issue only exists to ensure that GitHub issues have the same IDs they had on Google Code. Please ignore it.

quickselect?

Original issue created by kevinb9n on 2007-10-31 at 08:50 PM


If it is desired, we could provide an implementation of the quickselect
algorithm.

  public static <C extends Comparable> List<C> quickSelect(
    List<C> list, int count) {}

  public static <T> List<T> quickSelect(
    List<T> list, Comparator<? super T> comparator, int count) {}

I have some code written, but not tested, debugged etc. I would only
bother to finish it up if people actually want it.

More on quickselect: http://en.wikipedia.org/wiki/Quick_select

Python-style zip and enumerate methods

Original issue created by juri.pakaste on 2007-11-04 at 12:27 PM


Two Iterator/Iterable/Collection related methods I seem to be
reimplementing all the time in various languages are zip and enumerate from
Python.

Here's their documentation from CPython 2.5. zip:

zip(seq1 [, seq2 [...]]) -> [(seq1[0], seq2[0] ...), (...)]

Return a list of tuples, where each tuple contains the i-th element
from each of the argument sequences.  The returned list is truncated
in length to the length of the shortest argument sequence.

And enumerate:

   enumerate(iterable) -> iterator for index, value of iterable

   Return an enumerate object. iterable must be an other object that supports
   iteration. The enumerate object yields pairs containing a count (from
   zero) and a value yielded by the iterable argument. enumerate is useful
   for obtaining an indexed list: (0, seq[0]), (1, seq[1]), (2, seq[2]), ...

I've implemented these in a MIT-licensed library for Java, JIterTools, at
http://www.juripakaste.fi/jitertools/ . They operate on Iterators and
Iterables. There's also a variant of zip called zipFill that goes on as
long as there are items in one of the Iterables/Iterators, reading extra
values for exhausted Iterators from an associated function.

I'd love to see all of them/some of them/something like them included in a
well-maintained library of various Collection related things and Google
Collections looks like a prime candidate as long as Commons Collections is
inactive. I'm not particular about the exact details, though. Of the
methods I've implemented, zip is the cleanest with no extra classes needed
for parameters or return values. Both enumerate and zipFill need helper
classes.

Filler for Non-Existent Issue

Filler for non-existent Google Code issue 21.

This issue only exists to ensure that GitHub issues have the same IDs they had on Google Code. Please ignore it.

UniqueList<E>

Original issue created by kevinb9n on 2007-10-23 at 04:14 AM


A UniqueList is a List which rejects duplicate elements (recall that the
modification methods on List, add/add/addAll/addAll/set, are permitted
throw IllegalArgumentException if there's anything they don't like about
the offered element(s)). The same goes for the modification methods on the
list's listIterator().

The nice thing about this restriction is that a UniqueList can be viewed as
a Set in a completely "read-through, write-through" fashion. So the
UniqueList<E> interface would extend List<E> to add this asSet() method. I
don't believe that any subtype of Set is needed for this; AFAIK it just
needs regular Set methods and not much else.

As well, the subList() method could be refined so that it also returns a
UniqueList<E>. Of course, the sublist would throw IAE in response to any
operation that would result in a duplicate element in the parent list.

An AbstractUniqueList<E> class could be provided which only needs the
implementing class to supply a backing List and a backing Set, and
optionally override a few methods for better performance.

Unfortunately, the Collections methods sort(), shuffle(), reverse() and
swap() would fail on a UniqueList. They all make the assumption that the
list being acted upon has no problem with temporarily containing the same
element twice. There's nothing we can do about that -- it's the price you pay.

Copy arbitrary collections

Original issue created by limpbizkit on 2007-11-01 at 02:06 AM


Currently we can't really do this:
   Map<Customer> original = ...
   Map<Customer> copy = Maps.copyOf(original);

Because we don't know the runtime type of original. I propose the following:
  1. Introduce a Copyable<T> interface that allows Collections (and possibly other types) to
provide shallow copies of themselves.
  2. Implement said interface for all collections in the API
  3. Create APIs that can copy an arbitrary Collections. For things that implement Copyable, this
would use that. For the known set of collections in the JDK, this would copy these using the
most appropriate mechanism. For everything else, this should fail with a RuntimeException.

Difficult stuff:

  • deep vs. shallow copies. For collections, I believe shallow copies are best. I 'm not ready to
    expand the copyable interface to anything else.
  • wrapped collections. How to copy a TreeMap that's been wrapped with unmodifiableMap?
  • other views. What do we do when we copy the keySet of a TreeMap?

Provide abilty to put null into immutable map

Original issue created by kuaw26 on 2009-10-06 at 12:38 PM


Why ImmutableMap check value for null?
What should I do if I want to put null value?

May by it would be reasonable to introduce:
ImmutableMap.allowNullValues().<all nice methods of ImmutableMap>

Or do not check value for null.

Filler for Non-Existent Issue

Filler for non-existent Google Code issue 49.

This issue only exists to ensure that GitHub issues have the same IDs they had on Google Code. Please ignore it.

Filler for Non-Existent Issue

Filler for non-existent Google Code issue 18.

This issue only exists to ensure that GitHub issues have the same IDs they had on Google Code. Please ignore it.

Filler for Non-Existent Issue

Filler for non-existent Google Code issue 46.

This issue only exists to ensure that GitHub issues have the same IDs they had on Google Code. Please ignore it.

Filler for Non-Existent Issue

Filler for non-existent Google Code issue 48.

This issue only exists to ensure that GitHub issues have the same IDs they had on Google Code. Please ignore it.

com.google.common.util.concurrent.Executors should be renamed to Executors2

Original issue created by cky944 on 2009-11-13 at 04:26 PM


Given that the functionality of com.google.common.util.concurrent.Executors
is (from my inspection, anyway) supposed to complement that of
java.util.concurrent.Executors, it's reasonable to expect to import both
classes together.

Thus, in order to reduce import conflicts, using a name like Executors2
should be considered, in line with how Google Collections has a
Collections2 that complements java.util.Collections.

Filler for Non-Existent Issue

Filler for non-existent Google Code issue 29.

This issue only exists to ensure that GitHub issues have the same IDs they had on Google Code. Please ignore it.

Filler for Non-Existent Issue

Filler for non-existent Google Code issue 50.

This issue only exists to ensure that GitHub issues have the same IDs they had on Google Code. Please ignore it.

Filler for Non-Existent Issue

Filler for non-existent Google Code issue 41.

This issue only exists to ensure that GitHub issues have the same IDs they had on Google Code. Please ignore it.

Filler for Non-Existent Issue

Filler for non-existent Google Code issue 43.

This issue only exists to ensure that GitHub issues have the same IDs they had on Google Code. Please ignore it.

Predicates.forFunction(Function<T, Boolean>)

Original issue created by jonhnnyweslley on 2007-10-23 at 07:06 PM


  /**
   * Returns a predicate that evaluates to the same result as the
   * given function.
   */
  public static <T> Predicate<T> forFunction(
      final Function<T, Boolean> predicate) {
    checkNotNull(predicate);
    return new FunctionPredicate<T>(predicate);
  }

  /** @see Predicates#forFunction(Function) */
  private static class FunctionPredicate<T>
      implements Predicate<T>, Serializable {
    private final Function<T, Boolean> function;

private FunctionPredicate(final Function<T, Boolean> function) {
  this.function = function;
}

public boolean apply(final T t) {
  return Boolean.TRUE.equals(function.apply(t));
}

private static final long serialVersionUID = -4940925077935486606L;

  }

Usage examples:
  private static final Predicate<Object> ALWAYS_TRUE =
      forFunction(Functions.constant(Boolean.TRUE));

  private static final Predicate<Object> ALWAYS_FALSE =
      forFunction(Functions.constant(Boolean.FALSE));

Javadoc bug (typo) in com.google.common.io.Resources

Original issue created by ivo.wever on 2009-09-17 at 06:35 PM


What steps will reproduce the problem?

  1. Open 'http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/
    google/common/io/Resources.html'
  2. Read the class documentation.
  3. Note that "Note that even those these methods use URL parameters," does
    not make any sense, because 'those' should be 'though'.

What version of the product are you using? On what operating system?
svn trunk as of 2009-09-17

Filler for Non-Existent Issue

Filler for non-existent Google Code issue 37.

This issue only exists to ensure that GitHub issues have the same IDs they had on Google Code. Please ignore it.

Joiner seems to be missing

Original issue created by ted.dunning on 2009-09-18 at 10:33 PM


Why is Joiner not in the library? It is mentioned in the pdf sketch and
seems like a natural function to include. What happeneed?

What steps will reproduce the problem?

  1. Look at rough sketch pdf
  2. Note it mentions Joiner
  3. Look at API docs and jars, note Joiner is missing

What version of the product are you using? On what operating system?

0.1

BloomFilter<E>

Original issue created by kevinb9n on 2007-10-23 at 04:02 AM


A BloomFilter is a useful data structure.

  http://en.wikipedia.org/wiki/Bloom_filter

Proposed straw-man API follows. It shares only four methods in common with
Collection, and adds two of its own.

/**
 * A probabilistic "shadow" of a set of elements, useful
 * when the set itself would be too expensive to maintain in
 * memory and query directly. A Bloom filter can give false
 * positivites, but never false negatives. That is, adding
 * an element to the filter guarantees that {@link
 * #mightContain} will return {@code true}, but {@link
 * #mightContain} returning {@code true} does not guarantee
 * that this element was ever actually added to the filter.
 /
public final class BloomFilter<E> implements Serializable {
  /
*
   * Returns {@code true} if it is possible
   * (probability nonzero) that {@code element} is contained
   * in the set represented by this Bloom filter. If this
   * method returns {@code false}, this element is
   * definitely not present. If it {@code true}, the
   * probability that this element has not actually
   * been added is given by {@link
   * #getFalsePositiveProbability()}.
   */
  public boolean mightContain(@Nullable E element) { ... }

  /**
   * Returns the probability that {@link #mightContain} will
   * return {@code true} for an element not actually
   * contained in this set.
   */
  public double getFalsePositiveProbability() { ... }

  /**
   * Adds {@code newElement} to this Bloom filter, so that
   * {@code mightContain(newElement)} is now guaranteed to
   * return {@code true}.
   *
   * @return true if the Bloom filter changed as a result of
   * this call
   */
  public boolean add(@Nullable E newElement) { ... }

  // self-explanatory methods:
  public boolean addAll(Iterable<? extends E> elements) { ... }
  public boolean isEmpty() { ... }
  public void clear() { ... }
}

Creating immutable sorted sets from already-ordered data

Original issue created by kevinb9n on 2007-10-23 at 04:22 AM


Occasionally you have a List of elements which you already know to be in
sorted order. The canonical example is the results from a SQL query with an
ORDER BY clause.

You know the data to be sorted, yet you have no way to offer the niceties
of the SortedSet/NavigableSet APIs to your callers. In order to construct a
TreeSet/etc., you must re-engineer the appropriate comparator that can be
used to sort the data -- but the data is already sorted!

I believe the way out of this is a method Sets.immutablePreSortedSet(List).
 This method would copy the elements out of the list, assuming that
whatever order they come out in is the order you want. It would not demand
a comparator from you (although, if you can provide one, perhaps it should
accept it, as this could speed up some of the operations. and if you don't
provide one, what should the set's comparator() return? Should it return a
Comparators.givenOrder()?).

This idea is not fully-formed, but it's a shame to see methods forced to
use List to model data which is often known to be dup-free and is ordered,
not indexed.

`Predicate` missing

Original issue created by [email protected] on 2009-09-17 at 02:39 PM


In com.google.com.base: The interface Predicate exists in Google
Collections, but is missing in Guava. However, it is at least used in Guava
by CharMatcher.

Is the idea to keep the interface in Collections for further development
and have Guava in a somewhat incomplete state until integration of the
former or was it just forgotten to copy it?

Regards,
Jochen Kupperschmidt

Filler for Non-Existent Issue

Filler for non-existent Google Code issue 42.

This issue only exists to ensure that GitHub issues have the same IDs they had on Google Code. Please ignore it.

[Patch] Add a target to build a jar file

Original issue created by [email protected] on 2009-12-12 at 07:17 PM


Here's a small patch to build a jar file from the project. This would make it
easier for people to use the jar in projects before it gets Mavenized.

diff --git a/build.xml b/build.xml
index fb0b0e4..3f43b1a 100644
--- a/build.xml
+++ b/build.xml
@@ -21,6 +21,10 @@
     </javac>
   </target>

+  <target name="jar" depends="compile">
+    <jar destfile="google-guava.jar" basedir="build/classes" />
+  </target>
+
   <target name="clean"
       description="Remove generated files.">
     <delete dir="build"/>

Filler for Non-Existent Issue

Filler for non-existent Google Code issue 39.

This issue only exists to ensure that GitHub issues have the same IDs they had on Google Code. Please ignore it.

Filler for Non-Existent Issue

Filler for non-existent Google Code issue 25.

This issue only exists to ensure that GitHub issues have the same IDs they had on Google Code. Please ignore it.

Upgrade to Java 6

Original issue created by kevinb9n on 2007-11-01 at 08:12 PM


We will upgrade to requiring Java 6, but will create a Java 5-compatible
branch and will include both forms in our release.

Based on the changes listed in

http://java.sun.com/javase/6/docs/technotes/guides/collections/changes6.html

we'll have some work to do...

API -

  • Adopt NavigableFoo in place of SortedFoo throughout the API
  • Add ForwardingNavigableFoo, ForwardingDeque
  • Add factory methods for the new implementations to Lists/Sets/Maps

Impl -

  • Add @Override to methods newly eligible for it
  • Adopt the new AbstractMap.Simple(Immutable)Entry classes in place of our
    custom code wherever possible

probably other stuff I'm not thinking of.

Filler for Non-Existent Issue

Filler for non-existent Google Code issue 33.

This issue only exists to ensure that GitHub issues have the same IDs they had on Google Code. Please ignore it.

Filler for Non-Existent Issue

Filler for non-existent Google Code issue 36.

This issue only exists to ensure that GitHub issues have the same IDs they had on Google Code. Please ignore it.

Filler for Non-Existent Issue

Filler for non-existent Google Code issue 22.

This issue only exists to ensure that GitHub issues have the same IDs they had on Google Code. Please ignore it.

Filler for Non-Existent Issue

Filler for non-existent Google Code issue 16.

This issue only exists to ensure that GitHub issues have the same IDs they had on Google Code. Please ignore it.

Filler for Non-Existent Issue

Filler for non-existent Google Code issue 28.

This issue only exists to ensure that GitHub issues have the same IDs they had on Google Code. Please ignore it.

Filler for Non-Existent Issue

Filler for non-existent Google Code issue 44.

This issue only exists to ensure that GitHub issues have the same IDs they had on Google Code. Please ignore it.

Filler for Non-Existent Issue

Filler for non-existent Google Code issue 23.

This issue only exists to ensure that GitHub issues have the same IDs they had on Google Code. Please ignore it.

Filler for Non-Existent Issue

Filler for non-existent Google Code issue 38.

This issue only exists to ensure that GitHub issues have the same IDs they had on Google Code. Please ignore it.

Filler for Non-Existent Issue

Filler for non-existent Google Code issue 24.

This issue only exists to ensure that GitHub issues have the same IDs they had on Google Code. Please ignore it.

FluentIterable

Original issue created by jonhnnyweslley on 2007-10-22 at 05:12 PM


Hi,

Last weekend I thought:
"Why not to use functional programming with Java? More precisely using
Google Collections!"
...

Minutes later... Voila!!!
I can to write pieces of code as:

names.select(new Regexp(".*e$")).transform(new GetLength()).select(new
OddNumber())

I wanted to move this code to a fluent interface. Now, I dont need the
verbose syntax of the static methods, and, mainly, this code is more easy
to read.

The attached jar file contains the full source code with:

  • FunctionalIterable interface, with all methods documented
  • StandartFunctionalIterable class, the default implementation
  • StandartFunctionalIterableTest class, the show case class

About Fluente Interface:
http://martinfowler.com/bliki/FluentInterface.html
http://en.wikipedia.org/wiki/Fluent_interface

Filler for Non-Existent Issue

Filler for non-existent Google Code issue 17.

This issue only exists to ensure that GitHub issues have the same IDs they had on Google Code. Please ignore it.

Filler for Non-Existent Issue

Filler for non-existent Google Code issue 40.

This issue only exists to ensure that GitHub issues have the same IDs they had on Google Code. Please ignore it.

Maven repo

Original issue created by b.k.oxley on 2009-09-16 at 04:03 PM


Top issues for me -- when you begin releasing jar files, please provide
some kind of maven support for them. Ideal would be to include the
binary/source/javadoc triplet jars in the maven central repo.

Filler for Non-Existent Issue

Filler for non-existent Google Code issue 20.

This issue only exists to ensure that GitHub issues have the same IDs they had on Google Code. Please ignore it.

Use javax.annotation.* consistently

Original issue created by montsean on 2009-09-25 at 02:39 PM


Any chance of making consistent use of javax.annotation.* for clarifying
null safety of method params and return values? FindBugs users would thank
you for it.

Using the concurrency annotations would help as well to document thread safety.

Filler for Non-Existent Issue

Filler for non-existent Google Code issue 34.

This issue only exists to ensure that GitHub issues have the same IDs they had on Google Code. Please ignore it.

Filler for Non-Existent Issue

Filler for non-existent Google Code issue 26.

This issue only exists to ensure that GitHub issues have the same IDs they had on Google Code. Please ignore it.

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.