Git Product home page Git Product logo

dunet's People

Contributors

dependabot[bot] avatar domn1995 avatar hwoodiwiss avatar panoukos41 avatar parched avatar raymer avatar saul avatar timothymakkison 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

dunet's Issues

Implicit conversions

As a dunet user, I want some unions to support assigning its members' inner values directly, so that my code is more terse and less noisy.

For example, we should be able to do this:

using Result = Result<System.Exception, string>;

// No `new Result.Err()` required here.
Result exception = new Exception("Boom!");
// No `new Result.Ok()` required here.
Result success = "Success!";
// Compiler error.
Result invalid = 1;

[Union]
public partial record Result<TError, TSuccess>
{
    partial record Ok(TSuccess Value);
    partial record Err(TError Error);
}

Support non-primitive parameters

As a developer, I want my union definitions to support non-primitive parameters, so that I can build more complex and useful unions.

I should be able to do something like this:

using System;

[Union]
interface IResult
{
    void Created(Guid id);
    void Failure(Exception error);
}

This currently fails to compile because the imports are not part of the generated code.

Separate Attributes into another project

Create a separate project with Attributes explicitly defined in code and referenced by the source generator.

This will help to avoid conflicts that generating the attribute current cause and the Attribute will be more easily discoverable.

An example in which the attributes are in a separate project from the source generator (and also not source generated in the project consuming the library)
https://github.com/CommunityToolkit/dotnet/tree/main/src/CommunityToolkit.Mvvm/ComponentModel/Attributes

Example where Attribute can't be discovered
image

Add `Action` based `Match` (or similarly named) method

I am attempting to replace my custom T4 based union generator with dunet. Currently, my implementation generates an Either method which is functionally identical to the Match method generated by dunet, and a Do method, which is similar, but takes an Action for each union case, and does not return a value. Dunet does not appear to currently have such a method. The generated code should be identical to the current Match, except that it would return void rather than TMatchOutput, would take Action instead of Func delegates, and would not need to be generic on TMatchOutput, as there would be no output.

Test GetActualArea fix

Hi,

Currently, the test CanReturnImplementationsOfGenericUnion use default implementation of ToString method for a double. This can cause errors when users have different culture-info settings.

Xunit.Sdk.XunitException
Expected actualArea to be "0.5", but "0,5" differs near ",5" (index 1).
   at FluentAssertions.Execution.XUnit2TestFramework.Throw(String message)
   at FluentAssertions.Execution.TestFrameworkProvider.Throw(String message)
   at FluentAssertions.Execution.DefaultAssertionStrategy.HandleFailure(String message)
   at FluentAssertions.Execution.AssertionScope.FailWith(Func`1 failReasonFunc)
   at FluentAssertions.Execution.AssertionScope.FailWith(Func`1 failReasonFunc)
   at FluentAssertions.Execution.AssertionScope.FailWith(String message, Object[] args)
   at FluentAssertions.Primitives.StringEqualityValidator.ValidateAgainstMismatch()
   at FluentAssertions.Primitives.StringValidator.Validate()
   at FluentAssertions.Primitives.StringAssertions`1.Be(String expected, String because, Object[] becauseArgs)
   at Dunet.Test.GenerateUnionRecord.GenericGenerationTests.CanReturnImplementationsOfGenericUnion(Int32 dividend, Int32 divisor, String expectedOutput) in C:\repos\external-repo\dunet\test\GenerateUnionRecord\GenericGenerationTests.cs:line 104

The suggested fix is to add InvariantCulture parameter.

Note: Creating pull requests is blocked so I present the solution below:
image

Make common members accessible without matching

In TypeScript, if all union cases have a field it may be accessed without matching. For example:

type Animal = 
  | { kind: 'dog', sound: 'woof', ageInDogYears: 12 }
  | { kind: 'cat', sound: 'meow', ageInCatYears: 23 }

const t: Animal = // some value

t.kind // valid, since both have `kind`
t.sound // valid
t.ageInDogYears // error

I believe this library would benefit from this pattern when a property name and type are the same in all cases (TS allows the types to be different in which case it creates an anonymous union type for the return value; I guess it could also be implemented but I see it much less useful).

To implement it the base class needs to match on the type and then return this property, for example:

// Types.cs
[Union]
partial record Animal {
  partial record Dog(string Sound) : Animal;
  partial record Cat(string Sound) : Animal;
}

// Types.gen.cs
partial record Animal {
  // possibly getter would be better
  public string Sound() => this switch {
    Dog(sound) => sound,
    Cat(sound) => sound
  }
}

Problem on the basic usage.

Hi, I've tried to use the basic usage on my machine with SDK .net 6.0.100, but I cannot compile due to the following errors:

  • Program.cs(13, 2): [CS0246] The type or namespace name 'UnionAttribute' could not be found (are you missing a using directive or an assembly reference?);
  • Program.cs(13, 2): [CS0246] The type or namespace name 'Union' could not be found (are you missing a using directive or an assembly reference?);

This is my cproj and my Program.cs:

`

<PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
  <PackageReference Include="Dunet" Version="1.0.0" />
</ItemGroup>

`

`using Dunet;

var shape = new Shape.Rectangle(3, 4);
var area = shape.Match(
circle => 3.14 * circle.Radius * circle.Radius,
rectangle => rectangle.Length * rectangle.Width,
triangle => triangle.Base * triangle.Height / 2
);
Console.WriteLine(area);

[Union]
partial record Shape
{
partial record Circle(double Radius);
partial record Rectangle(double Length, double Width);
partial record Triangle(double Base, double Height);
}`

What I'm missing?

Monad support

As a developer, I want to use this library to generate monads, so that I don't have to write them manually.

I should be able to do something like this:

[Union]
public partial record Option<T>
{
    partial record Some(T Value);
    partial record None();
}

var option = new Option<string>.Some("foo");

var value = option.Match(
    some => some.Value,
    none => ""
);

Console.WriteLine(value); // "foo"
[Union]
public partial record Result<TFailure, TSuccess>
{
    partial record Success(TSuccess Value);
    partial record Failure(TFailure Error);
}

var result = new Result<Exception, string>.Failure(new Exception("Boom!"));
var message = result.Match(
    success => success.Value,
    failure => failure.Error.Message
);

Console.WriteLine(message); // "Boom!"

Anonymous union variants

Some times we want to make a very basic union without naming its variants. We should be able to do something like:

public partial record struct Number : Union<int, double>;

This would enable us to do the following:

var integer = new Number.Int();
var @double = new Number.Double();

Should it support generics?
Should it require you to name its variants or infer from the type name?

Integration tests

As a maintainer, I want a suite of integration tests, so that I can be confident that a changeset will behave correctly for end users.

Inner union compile with error `Cannot implicitly convert type 'X' to 'Y`

Hi. First of all, I'd like to thank you for this excellent library! It is very useful in many contexts! That is great and impressive work! :)

It would be nice if the inner union classes worked. Below is the example that doesn't compile

using Dunet;

Console.WriteLine("Hello, World!");

public class Foo
{
    [Union]
    public partial record R
    {
        public partial record O1();
    }

    public R Bar()
    {
        return new R.O1();
    }
}

The error says: Error CS0029 Cannot implicitly convert type 'Foo.R.O1' to 'Foo.R'
Although below code works just fine:

using Dunet;

Console.WriteLine("Hello, World!");

[Union]
public partial record R
{
    public partial record O1();
}

public class Foo
{
    public R Bar()
    {
        return new R.O1();
    }
}

I would expect that both variants of code compile. The first version could be useful because the result type can be hidden inside the class. Is it possible to fix that?

Annotate Generated Code with GeneratedCodeAttribute

It would be useful and would help tooling like coverage reporters if the generated code was annotated with the GeneratedCodeAttribute.

At the moment, code generated for DU's is counted towards uncovered code:

Example here.
Coverlet finds only method 0.8% coverage in this workflow run, when it should find 50%, as the only uncovered method should be Main

Add Action with the type in the else of a MatchXYZ

I am trying Dunet in a very simple piece of code.

I want to write unit tests where I say: If the returned type is correct, assert some properties, otherwise fail saying that the wrong options was returned.

My DU is:

Union]
internal partial record LogChange
{
    partial record AddNew(Disconnection NewDisconnection);
    partial record UpdateLastEndTime(Disconnection Last, DateTime EndTime);
    partial record UpdateLastEndTimeAndAddNew(Disconnection Last, DateTime EndTime, Disconnection NewDisconnection);
}

So I would like to write the unit test as follows:

var result = BusinessLogic.DetermineLogChanges(e, null);

result.MatchAddNew(
    addNew =>
    {
        Assert.Equal(expectedHardwarUnitId, addNew.NewDisconnection.HardwareUnitId);
        Assert.Equal(expectedState, addNew.NewDisconnection.State);
    },
    // The else should be of the other type that was returned
    @else => Assert.Fail($"Returned {@else} instead of {nameof(BusinessLogic.AddNew)}")
    );

Unfortunately the MatchAddNew() method only has an Action without input parameter as else.

Is it possible to add an Action as an else, where T is the actual DU value returned?

Async match support

I've been using the library in production code for a while now, and one use that would be useful is an async match method.

The use case here is when the matching logic is asynchronous due to a union being wrapped by a Task.

Suppress switch expression warning

As a dunet user, when using switch expression with dunet-generated unions, I don't want to be warned about the switch expression not being exhaustive when it is provably so.

For example, the following should not emit a warning:

using static Option<int>;

Option<int> option = new Some(1);

var output = option switch
{
    Some some => some.Value.ToString(),
    None => "",
};

[Union]
public partial record Option<T>
{
    partial record Some(T Value);
    partial record None();
}

Unwrap union types

Sometimes, we may want an easy way to get the value out of a union and don't care if the code fails at runtime.

Consider the following union:

[Union]
public partial record Option<T>
{
    public partial record Some(T Value);
    public partial record None;
}

Option<int> integer = 42;

We should be able to do something like this:

// If `integer` is `Option<int>.None` this would throw at runtime.
Option<int>.Some value = integer.UnwrapSome();

Alternatives

var value = integer.SomeOrThrow();
var value = integer.ForceSome();
var value = integer.ToSome();

Record struct union support

We should support declaring unions as record structs for consumers that want value semantics and reduced memory allocations. For example:

using Dunet;

[Union]
partial record struct Option<T>
{
    partial record struct Some(T Value);
    partial record struct None;
}

Mixing and matching structs and classes should not be allowed.

Design note: Since using structs we cannot use abstract and inheritance to resolve the union type. We'll have to use a private discriminant like an enum to support it and switch on it when matching.

Improve samples

As a developer who is considering using Dunet, I want a collection of different real-world samples to help me determine if the library makes sense for my use case.

As a current user of Dunet, I want a collection of different real-world samples to help me better understand how/when to use the library.

Sample ideas:

  • Web application: A result union that models the outcome of some business logic. This result is passed back to a controller to be mapped into the proper response.
  • Improved calculator: Model an operation as a union of operators. Calculator logic depends on the user selected operator.
  • Web Client: Monads to represent different HTTP request results. Option monad for operations that may return nothing. Result monad for an operation that can succeed with a result object or fail with an error object.
  • Implicit conversion sample.
  • A blazor sample would be nice too. Was asked about it on twitter: https://twitter.com/shunjiey/status/1541488240225439744?s=20&t=nCBOdq3MBeNGu6kwE4TV3w

[Union] attribute on an `partial record` instead of `interface`?

Example usage

[Union]
public partial record Result
{
    partial record Ok(string Message);

    partial record Error(Exception Exception)
    {
        // Can override specific methods on the generated types
        public override string ToString() => Exception.ToString();

        // ...or add new ones without resorting to extension methods
        public bool CanIgnore => Exception is OperationCanceledException;
    }
}

// Instantiate the Error case directly:
var result = new Result.Error(new Exception("hi :)"));

// Use the factory methods that return `Result`:
var otherResult = Result.NewError(new Exception("another way"));

result.Match(
    (Result.Ok _) => 1,
    (Result.Error e) => e.CanIgnore ? 1 : 0);

// Can use named arguments to make `match` more explicit:
result.Match(
    error: e => e.CanIgnore ? 1 : 0,
    ok: m => m.Message.Length);

Benefits

  • With the generated code below, it is impossible to create another type that derives from Result as it has a private constructor.
  • It is possible to add your own method to the Result class and the case classes directly rather than having to write them as extension methods.
  • Untested hypothesis, but I imagine the JIT would generate better code with an abstract Match method, as opposed to the extension method that you have currently.

Source generator produces

abstract partial record Result
{
    // No other classes can derive from this class
    private Result() {}

    public static Result NewOk(string message) => new Ok(message);
    public static Result NewError(Exception exception) => new Error(exception);

    public abstract T Match<T>(Func<Ok, T> ok, Func<Error, T> error);

    public sealed partial record Ok : Result
    {
        public override T Match<T>(Func<Ok, T> ok, Func<Error, T> error) =>
            ok(this);
    }

    public sealed partial record Error : Result
    {
        public override T Match<T>(Func<Ok, T> ok, Func<Error, T> error) =>
            error(this);
    }
}

Prefer `_ is _ _` pattern

I don't see the need in Match function, when the is pattern can work just as good (and even better, in terms of performance).

[Union]
partial record Result
{
    partial record Ok();
    partial record Error(string Id);
}
Result result = GetResult();

if(result is not Result.Error error)
    Console.WriteLine("Success");
else
    Console.WriteLine($"Error happened: {error.Id}");
Result result = GetResult();

Console.WriteLine(result switch {
    Result.Ok => "Success",
    Result.Error error => $"Error happened: {error.Id}",
    _ => $"Unknown: {result}"
});

Idea: Friendly use of ToString()

For example, I have a union defined like this:

    [Dunet.Union]
    public partial record BussinesLogicResult<T>
    {
        public partial record Ok(T Value);
        public partial record EntityNotFound();
        public partial record UnauthorizedAccess();
    }

Well, I would like to override the ToString() method like this:

    [Dunet.Union]
    public partial record BussinesLogicResult<T>
    {
        public partial record Ok(T Value);
        public partial record EntityNotFound();
        public partial record UnauthorizedAccess();

        public override string ToString()
        {
            return this.Match<string>(ok => ok.Value.ToString(),
                entityNotFound => "Not found.",
                unauthorizedAccess => "Unauthorized access.");
        }
    }

However, this has no effect as a result, because the records are implicitly override ToString() method. And it is necessary to override ToString() separately for each record.

My idea is that if the ToString() method is found in the base record, the public override string ToString() => base.ToString(); code will be generated in the uion members (children).

Match on a specific union value only

Some times we just want to do something given a specific union value, rather than handling all cases explicitly. This is most useful on larger unions.

For example consider the following code:

[Union]
public partial record struct MathResult<T>
    : where T : INumber<T>
{
    public partial record struct Infinity;
    public partial record struct Success(T Value);
    public partial record struct NaN;
    public partial record struct Undefined;
}

MathResult<double> result = // Some complex math calculation.

Some ways we might want to interact with result

  • With a dedicated Match method for each case?
// A `MatchX()` is generated for each member `X` of the union. You must provide an else case.
var value = result.MatchSuccess(
    // If `Infinity, NaN, or Undefined` return 0.
    () => 0
);
  • Perhaps a more imperative, idiomatic C# way?
// A `TryGetX` is generated for each member `X` of the union.
if (result.TryGetSuccess(out var success))
{
    Console.WriteLine(success.Value);
}

Dedicated match method

As a developer, I want a dedicated Match() method, so that consumers of my union type are required to handle each case in order to get a value out of it.

Usage might look something like this:

[Union]
public interface IShape
{
    IShape Circle(double radius);
    IShape Rectangle(double length, double width);
    IShape Triangle(double @base, double height);
}

var shape = new Rectangle(3, 4);
var area = shape.Match(
    circle => 3.14 * circle.Radius * circle.Radius,
    rectangle => rectangle.Length * rectangle.Width,
    triangle => triangle.Base * triangle.Height / 2
);

Console.WriteLine(area); // "12"

Question: make it to work with asp net

Hello,
I'm really sorry to ask here, but I would like to know how can I make it to work with asp (the serialization / deserialization part).

I created from scratch a repro:
https://github.com/titouancreach/repro-dunet

I've no problem in serializating my object to json, but the issue come when I try to deserialize it from json (see .http file)

I would be really grateful if you have any idea.
Thanks very muche

Factory Methods

I was thinking it might be quite nice to have an opt-in feature that makes you rely on factory methods to create the different types within a union. I was thinking this could be another attribute maybe [UnionWithFactory] or something like [Union(factory: true)].

I took the code example from the samples and modified it to show how the factory methods could be used:

using Dunet.Choices;
using Dunet.Shapes;

var rectangle = Shape.Rectangle(10, 10);
var triangle =  Shape.Triangle(10, 10);
var circle = Shape.Circle(10);

var getArea = (IShape shape) =>
    shape switch
    {
        Rectangle rect => rect.Length * rect.Width,
        Circle circle => 2.0 * Math.PI * circle.Radius,
        Triangle triangle => 1.0 / 2.0 * triangle.Base * triangle.Height,
        _ => 0d,
    };

var rectangleArea = getArea(rectangle);
var triangleArea = getArea(triangle);
var circleArea = getArea(circle);

Console.WriteLine($"Rectangle area: {rectangleArea}");
Console.WriteLine($"Triangle area: {triangleArea}");
Console.WriteLine($"Circle area: {circleArea}");

var choice = GetChoice();

if (choice is Yes)
{
    Console.WriteLine("YES!!!");
}

if (choice is No)
{
    Console.WriteLine("NO!!!");
}

static IChoice GetChoice() =>
    Console.ReadLine() switch
    {
        "yes" => Option.Yes(),
        _ => Option.No()
    };

What do you think?

Simplify instantiation of generic-bound union members

Consider the following union:

[Union]
public partial record Option<T>
{
    public partial record Some(T Value);
    public partial record None;
}

Currently, to instantiate the Some variant, we must write the following:

var some = new Option<int>.Some(42);

Since the generic type parameter is bound to the union, we must define the type parameter every time since it cannot be inferred from the type passed to the union member. It would be nicer to be able to do the following:

// Inferred as `Option<int>.Some` since `42` is an integer.
var someInt = Option.Some(42);
// Inferred as `Option<string>.Some`.
var someStr = Option.Some("foo");

Allow matching with static functions

One issue with .Match is that it allocated objects for case matching functions to capture the closure. C# has a mechanism to prevent this from happening with a static keyword on lambda. However, for it to work the "closure" state has to be threaded manually.

Consider an example of such a match function called .FoldMatch based on your Expression example implemented in the Expression class. Functions StaticEvaluate and EvaluateUniqueVar show how such a utility could be used:

// Adapted from https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/discriminated-unions#using-discriminated-unions-for-tree-data-structures

using System.Collections.Immutable;
using Dunet;
using static Expression;

var environment = new Dictionary<string, int>()
{
    ["a"] = 1,
    ["b"] = 2,
    ["c"] = 3,
};

var expression = new Add(new Variable("a"), new Multiply(new Number(2), new Variable("b")));

// Evaluate a + 2 * b
var result = Evaluate(environment, expression);

Console.WriteLine(result); // 5

static int Evaluate(Dictionary<string, int> env, Expression exp) =>
    exp.Match(
        number => number.Value,
        add => Evaluate(env, add.Left) + Evaluate(env, add.Right),
        multiply => Evaluate(env, multiply.Left) * Evaluate(env, multiply.Right),
        variable => env[variable.Value]
    );

// Allows to evaluate expressions without allocating lambdas
static int StaticEvaluate(Dictionary<string, int> env, Expression exp) =>
    exp.FoldMatch(
        env,
        static (_, number) => number.Value,
        static (e, add) => StaticEvaluate(e, add.Left) + StaticEvaluate(e, add.Right),
        static (e, multiply) => StaticEvaluate(e, multiply.Left) * StaticEvaluate(e, multiply.Right),
        static (e, variable) => e[variable.Value]
    );

// An example of how to thread state through a recursive function
// It simulates a (made up) use case where variables can be used only once
static (IImmutableDictionary<string, int> state, int result) 
    EvaluateUniqueVar(IImmutableDictionary<string, int> env, Expression exp) =>
    exp.FoldMatch(
        env,
        static (e, number) => (e, number.Value),
        static (e, add) =>
        {
            (e, var left) = EvaluateUniqueVar(e, add.Left);
            (e, var right) = EvaluateUniqueVar(e, add.Right);
            
            return (e, left + right);
        },
        static (e, multiply) =>
        {
            (e, var left) = EvaluateUniqueVar(e, multiply.Left);
            (e, var right) = EvaluateUniqueVar(e, multiply.Right);
            
            return (e, left * right);
        },
        static (e, variable) => (e.Remove(variable.Value), e[variable.Value])
    );

[Union]
public partial record Expression
{
    partial record Number(int Value);

    partial record Add(Expression Left, Expression Right);

    partial record Multiply(Expression Left, Expression Right);

    partial record Variable(string Value);
    
    public T FoldMatch<T, TState>(
        TState state,
        Func<TState, Number, T> number,
        Func<TState, Add, T> add,
        Func<TState, Multiply, T> multiply,
        Func<TState, Variable, T> variable
    ) => this switch
    {
        Number x   => number(state, x),
        Add x      => add(state, x),
        Multiply x => multiply(state, x),
        Variable x => variable(state, x),
        _          => throw new InvalidOperationException()
    };
}

Async Action Match

#65 implemented synchronous matching with Action<T>. Let's implement the asynchronous version as well, like what exists for Func<T>.

Cannot have multiple union definitions with same name

Dunet doesn't currently support generating two unions with the same name in separate namespaces. This is due to the source generated output file being named after the union record's name here:

context.AddSource($"{unionRecord.Name}.g.cs", SourceText.From(result, Encoding.UTF8));

While most users probably won't run into this, I believe we should still support this use case to be more user friendly or prevent a silent failure that may be frustrating.

Implicit conversions clash with required union properties

Consider the following union:

[Union]
internal partial record HttpQueryResult<TBody>
{
  public required HttpStatusCode StatusCode { get; init; }
  public required Uri? RequestUri { get; init; }

  public partial record Success(TBody Body);
  public partial record Failure(string Error);
}

This code fails to compile because the generated implicit conversions do not initialize the required properties.

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.