Giter Site home page Giter Site logo

ramsey / uuid Goto Github PK

View Code? Open in Web Editor NEW
12.3K 137.0 494.0 2.63 MB

:snowflake: A PHP library for generating universally unique identifiers (UUIDs).

Home Page: https://uuid.ramsey.dev

License: MIT License

PHP 100.00%
uuid guid identifiers php php8 uid

uuid's Introduction

ramsey/uuid

A PHP library for generating and working with UUIDs.

Source Code Download Package PHP Programming Language Read License Build Status Codecov Code Coverage Psalm Type Coverage

ramsey/uuid is a PHP library for generating and working with universally unique identifiers (UUIDs).

This project adheres to a code of conduct. By participating in this project and its community, you are expected to uphold this code.

Much inspiration for this library came from the Java and Python UUID libraries.

Installation

The preferred method of installation is via Composer. Run the following command to install the package and add it as a requirement to your project's composer.json:

composer require ramsey/uuid

Upgrading to Version 4

See the documentation for a thorough upgrade guide:

Documentation

Please see https://uuid.ramsey.dev for documentation, tips, examples, and frequently asked questions.

Contributing

Contributions are welcome! To contribute, please familiarize yourself with CONTRIBUTING.md.

Coordinated Disclosure

Keeping user information safe and secure is a top priority, and we welcome the contribution of external security researchers. If you believe you've found a security issue in software that is maintained in this repository, please read SECURITY.md for instructions on submitting a vulnerability report.

ramsey/uuid for Enterprise

Available as part of the Tidelift Subscription.

The maintainers of ramsey/uuid and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. Learn more.

Copyright and License

The ramsey/uuid library is copyright © Ben Ramsey and licensed for use under the MIT License (MIT). Please see LICENSE for more information.

uuid's People

Contributors

1ma avatar awilum avatar backendtea avatar davispeixoto avatar dependabot-preview[bot] avatar dependabot[bot] avatar garak avatar ghola avatar grahamcampbell avatar gsteel avatar jmauerhan avatar jpjoao avatar jwpage avatar lewiscowles1986 avatar localheinz avatar marijn avatar mhujer avatar mjrider avatar mloureiro avatar ocramius avatar pawel-slowik avatar ph0tonic avatar potherca avatar ramsey avatar remicollet avatar simpod avatar szepeviktor avatar vinkla avatar vudaltsov avatar yberkholz 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

uuid's Issues

Uuid::uuid4 returns an object instead of a string

Uuid::uuid4 seems to return an object instead of a string, this seems a bit weird because it fails validation checks (is_string)

The way I use it now is: (string) Uuid::uuid4().

Anyone else have similar issues?

uuid's should be stored in a BINARY(16) field using doctrine for optimal performance.

It would be more performant to save the data in a BINARY(16) field then in a CHAR(36) field.

There are some benchmarks in here: http://iops.io/blog/storing-billions-uuid-fields-mysql-innodb/
And some info here: https://stackoverflow.com/questions/10950202/how-to-store-uuid-as-number

I think it should be rather easy to implement this in the convertToPHPValue and convertToDatabaseValue fields. If you're interested, I'll create a pull request for this.

Validation failing for empty values

Unless I am missing something, most rules should not be validated (or validation should return true) if the input is null or an empty string (except for Required, Length and some others).

There are likely more rules failing for empty values, but the ones I found are:

  • Alpha
  • AlphaNumHyphen
  • AlphaNumeric

Uuid:uuid4() collisions

We are generating about 1M UUID4 a day, and we are getting several hundred collisions a day, such as:

[2015-08-26 21:29:19 +0200] [production-onebipws-1.apache - 17819] [DEBUG] [Request] 
time_total=0.145
"request_id":"fdfb98c1-4367-4f22-b68a-d7cdaedcc069" 

[2015-08-27 00:36:16 +0200] [production-onebipws-1.apache - 17819] [DEBUG] [Request] 
time_total=0.016
"request_id":"fdfb98c1-4367-4f22-b68a-d7cdaedcc069"

The issue seem to be correlated with the same Apache process regenerating the same UUID after several hours. It also seem to be correlated with particular EC2 machines which presents the problem.

We checked to have openssl_random_pseudo_bytes and if it was using a strong algorithm:

root@dev-all-onebip:~/projects/.../onebip-ultimate$  (master) # php -r "var_dump(function_exists('openssl_random_pseudo_bytes'));"                                      
bool(true)
root@dev-all-onebip:~/projects/.../onebip-ultimate$  (master) # php -r 'openssl_random_pseudo_bytes(16, $strong); var_dump($strong);'
bool(true)

How can we debug this problem?

final classes are evil

Please consider dropping the final declaration.
It doesn't seem to serve any practical purpose and makes it harder to integrate the class into our codebase.

Best regards.

Add undashed parameter

Hi,

I created some simple function to create a undashed uuid when I need it and so something like undashedUuid("Vx");

Is it not an idea to implement this per default ?

Versions and namespaces

When I run composer require ramsey/uuid composer gives me the 2.8 version of the library, and then the rest of the instructions on the main page aren't correct - the namespace for 2.8 is still Rhumsaa\Uuid. Either change the instructions on the frontage or change the namespaces in the 2.8 branch.

composer require ramsey/uuid:~3.0@dev

Would do the trick.

Store UUID in an optimized way for InnoDB

From Karthik Appigatla on the Percona blog ("Store UUID in an optimized way"):

  • UUID has 36 characters which makes it bulky.
  • InnoDB stores data in the PRIMARY KEY order and all the secondary keys also contain PRIMARY KEY. So having UUID as PRIMARY KEY makes the index bigger which can not be fit into the memory
  • Inserts are random and the data is scattered.

He goes on to "explain how to store UUID in an efficient way by re-arranging timestamp part of UUID."

While, ramsey/uuid provides COMB sequential UUIDs, these do not rearrange the timestamp part of the UUID to optimize for storage in InnoDB. I'd like to consider the addition of a codec that would help optimize UUIDs as primary keys for the InnoDB engine. Perhaps other database engines require similar optimization techniques, so we should thing about those, as well.

The problem with rearranging the timestamp part of a UUID is that the version number is lost, since it is shuffled around, and there would be no way to determine the original state of the UUID. Whether or not this is important is up for debate.

Allow for a different PRNG

First of, great job! This seems to be one of the most solid UUID implementations for PHP.

I was wondering if you would mind having a dedicated UuidGenerator class which would house all the factories for generating the different Uuid implementations. In particular, this would allow us to inject a different PRNG.

Are you open to such a change?

GUID codec ignores endianness of the host

Basically, the GUID binary storage format is as follows:

Bits Bytes Name GUID endianness UUID endianness
32 4 Data1 Native Big
16 2 Data2 Native Big
16 2 Data3 Native Big
64 8 Data4 Big Big

The current GUID string codec implementation hence is only valid when the code is running on a little-endian host.

A possible fix is to detect in FeatureSet.php the host endianness, and select the appropriate codec (GuidStringCodec for LE hosts, UuidStringCodec for BE hosts) when the FeatureSet is initialized with the GUID flag on.

Change namespace to "Ramsey"

I've received a fair amount of feedback from people about the "Rhumsaa" namespace. Apparently, it causes confusion and makes it difficult to find my packages. On more than one occasion, I've received reports that I have misspelled my namespace (the assumption is that the vendor name of the namespace should be "Ramsey" and I have misspelled it as "Rhumsaa").

In the 3.0 release, I am considering changing the package name to "ramsey/uuid" and the root namespace to "Ramsey."

I'm opening this up for comments to get feedback from those who are using this package. I want to make the upgrade transition as smooth as possible, and I'd like to hear whether this will significantly impact people using "rhumsaa/uuid."

Global namespace collision in ramsay/uuid 3.3 or pre-requisite

As soon as I upgraded from 3.2 to 3.3 via composer, my servers started reporting the following PHP Fatal error:

PHP Fatal error: Call to undefined method Error::GetXML() in [script name]

Downgrading to 3.2, which also removes the prerequisite paragonie/random_compat v2.0.2, fixed the issue. At this point i'm not sure yet if the source of this namespace collision is within ramsey/uuid or the new prerequisite.

Cheers.

[RFC] Implement PHPUnit_Framework_Constraint_IdEquals

Today I was wondering if there is any merit in having a dedicated PHPUnit assertion (e.g. PHPUnit_Framework_Constraint_IdEquals). It would just relay the assertion to Uuid::equals and display a more contextual error message.

What do you think?

[Feature] Make uuid mockable

Hi and thanks for your nice package!

I tried today to write some tests to classes using Uuid::uuid4() but it was not possible. The current structure of the class doesn't allow it to be mocked in unit tests since there is no way to get an instance of the class.

Collisions occurring in COMB sequential UUID test

The presence of Xdebug appears to slow things down significantly enough that COMB sequential UUIDs generated during tests have no collisions, but if tests run in an environment without Xdebug, then tests will almost always produce duplicate COMB UUIDs.

To reproduce (using a VirtualBox VM with Vagrant):

git clone https://github.com/ramsey/uuid.git
cd uuid/
vagrant init ubuntu/trusty64
vagrant up
vagrant ssh
cd /vagrant
sudo apt-get install php5 php5-curl
curl -sS https://getcomposer.org/installer | php
./composer.phar install
./vendor/bin/phpunit --verbose

You will see a consistent test failure like this:

1) Ramsey\Uuid\UuidTest::testUuid4Comb
Failed asserting that '30303030-3030-4030-b030-8351f882227f' is greater than '30303030-3030-4030-b030-8351f8822280'.

/vagrant/tests/UuidTest.php:839

Now, install Xdebug and run the test again:

sudo apt-get install php5-xdebug
./vendor/bin/phpunit --verbose

Tests will consistently pass.

Remove Xdebug, and tests consistently fail again:

sudo apt-get remove php5-xdebug
./vendor/bin/phpunit --verbose

We need to revisit COMB generation to see what can be done to ensure consistent, sequential UUIDs.

Use with single file

Hi,

Is it possible to use your version using a single file without the composer part ?

file.php:

create DateTime with nanoseconds

The uuid1 is using nanoseconds, but the UuidInterface returns a DateTime object which does not include the nanoseconds.

DateTime can handle it if you adjust the initialization:

\DateTime::createFromFormat('U.u', sprintf('%.f', ($this->getTimestamp() - 0x01b21dd213814000) / 1e7))

__toString() in UuidInterface

Oh, I've heard on Twitter something about 4.0 :P

So, speaking about that, there's something that always bother me. I like to cast UUID objects to string for persistence and representation, but there's no __toString() method in UuidInterface.

Ok, I could typehint against Uuid class, but if I do that, PHPStorm complains that return type of Uuid::uuid4() (UuidInterface) is not compatible with the expected type (Uuid).

So, could you add __toString() method in UuidInterface for next 4.0 version?

Tests fail on 32 bit systems without Moontoast/BigNumber

When running the test suite on a 32-bit system with Moontoast/BigNumber install, one of the tests fail due to an exception message mismatch (which should not even be thrown the failing test is actually one that simulates the absence of Moontoast):

PHPUnit 4.8.3 by Sebastian Bergmann and contributors.
Warning:    The Xdebug extension is not loaded
        No code coverage will be generated.

........... .........................SSSSSSSSSSSSSSSSSSSSSSSSSSS  63 / 184 ( 34%)
SSSSSSSSSSSSSSSSSSSSSS...............S........S....S....S...... 126 / 184 ( 68%)
..........S...................SS.SS......................F

Time: 48.99 seconds, Memory: 6.25Mb

There was 1 failure:

1) Rhumsaa\Uuid\UuidTest::testGetInteger
Failed asserting that exception message 'When calling Rhumsaa\Uuid\Uuid::calculateUuidTime on a 32-bit system, Moontoast\Math\BigNumber must be present in order to generate version 1 UUIDs' contains 'Cannot call Rhumsaa\Uuid\Uuid::getInteger without support for large integers'.

FAILURES!
Tests: 184, Assertions: 1830, Failures: 1, Skipped: 58.
root@debian:~/uuid# cat composer.lock | grep moontoast
            "name": "moontoast/math",
                "url": "https://github.com/ramsey/moontoast-math.git",
                "url": "https://api.github.com/repos/ramsey/moontoast-math/zipball/fce28a9d1e73e73376cb44e5e581675d15fbe2f3",
            "homepage": "https://github.com/moontoast/math",

Works as primary key with Doctrine ?

Hi !

Great job with this lib. Exactly what we need. Thanks.

We just found a small issue and I just want to be sure I use it in the right way before writing any PR.

If I put my primary key in my doctrine mapping with your custom type, it works pretty well on persist operation. But on find method I get :
Warning: Illegal offset type in /Users/Tim/www/cqrs-afsy/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php line 2480

I understand the problem Doctrine met :
$idHash = isset($class->associationMappings[$class->identifier[0]]) ? $data[$class->associationMappings[$class->identifier[0]]['joinColumns'][0]['name']] : $data[$class->identifier[0]];

with type uuid $idHash will be an object and then doctrine try to use it as array key on line 2480.

Have I missed anything or should I propose PR to doctrine ? Anyone use this lib on Doctrine without these kinds of problem ?

How can I integrate this library with CodeIgniter?

Okay, this is not an "issue" as per se, but rather a question.

How can I integrate this with CodeIgniter?

  1. I included this inside the application/third_party folder in CodeIgniter.
  2. Ran composer there to include all the dependencies.
  3. I also made another file named uid.php in the application/libraries folder, where I wrote the following code:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); 

require_once APPPATH."third_party/uuid/vendor/autoload.php";

use Rhumsaa\Uuid\Uuid;
use Rhumsaa\Uuid\Exception\UnsatisfiedDependencyException;

?>
  1. But, when I try out the sample code inside a Controller file's index() function just to try it out, it says
( ! ) Fatal error: Class 'Uuid' not found in /var/www/public/application/controllers/login.php on line 18
Call Stack
#   Time    Memory  Function    Location
1   0.0001  242688  {main}( )   .../index.php:0
2   0.0009  244688  require_once( '/var/www/public/system/core/CodeIgniter.php' )   .../index.php:202
3   0.0314  664784  call_user_func_array:{/var/www/public/system/core/CodeIgniter.php:360} ( )  .../CodeIgniter.php:360
4   0.0314  665048  Login->index( ) .../CodeIgniter.php:360

I'm not even sure I'm doing something wrong.
How can I include this library? Please help! :)

Serializable Uuid's.

Hi Ben,

I've been using Uuid's instead of incremental ID's for some time now. In some situations I've had to implement the Serializable interface due to output corruption when using regular serialization. An example where this happens is the when an object is stored in native PHP sessions. Would you be open to a PR which makes the Uuid class serializable? My initial thought would be to implement it like this:

public function serialize()
{
    return $this->toString();
}

public function unserialize($serialized)
{
    $uuid = self::fromString($serialized);
    $this->codec = $uuid->codec;
    $this->converter = $uuid->converter;
    $this->fields = $uuid->fields;
}

Like the JsonSerializable, the interface could then be added to the UuidInterface.

Let me know what you think, I'll happily submit a PR with tests.

Can't install 3.0 on php 7

When I try to install with constraint ^3.0 on php7 I get the following error:

Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - ramsey/uuid 3.1.0 requires php >=5.4 -> your PHP version (7.0.2-2+deb.sury.org~trusty+1) or value of "config.platform.php" in composer.json does not satisfy that requirement.
    - ramsey/uuid 3.0.1 requires php >=5.4 -> your PHP version (7.0.2-2+deb.sury.org~trusty+1) or value of "config.platform.php" in composer.json does not satisfy that requirement.
    - ramsey/uuid 3.0.0 requires php >=5.4 -> your PHP version (7.0.2-2+deb.sury.org~trusty+1) or value of "config.platform.php" in composer.json does not satisfy that requirement.
    - Installation request for ramsey/uuid ^3.0 -> satisfiable by ramsey/uuid[3.0.0, 3.0.1, 3.1.0].

With constraint ^2.8 the lib install's fine

Performance edge-case issue in SystemNodeProvider

As discussed here with @jmauerhan , there is a performance issue in SystemNodeProvider for environments where the MAC address cannot be extracted from network interface configuration output.

In order to preserve BC, SystemNodeProvider should also provide a mechanism for caching "failed" MAC address detection, otherwise an exec call is used everytime that SystemNodeProvider::getNode() is called.

Example cases where this could happen:

  • Setups where the ifconfig (or OS specific variant) is not available
  • User does not have sufficient rights to run ifconfig (or OS specific variant)

Use a math library other than moontoast/math

A math library is not required for this library unless users want to operate on the UUID as a 128-bit integer. For this purpose, the library has suggested moontoast/math as an optional dependency, and internally, this is what ramsey/uuid uses, if it is present. However, moontoast/math is no longer maintained.

I will either create a ramsey/math library that allows the use of different adapters for working with large numbers, or I want to find an existing math library that provides similar functionality.

Tests failing with doctrine/dbal 2.4.0

Since we have specified doctrine/dbal version with >=2.3, Composer now pulls down version 2.4.0 of doctrine/dbal. When running phpunit with this version, we see the following fatal error:

PHP Fatal error:  Class 'Doctrine\Tests\DBAL\Mocks\MockPlatform' not found in /home/ramsey/source/ramsey/uuid/tests/Rhumsaa/Uuid/Doctrine/UuidTypeTest.php on line 27
PHP Stack trace:
PHP   1. {main}() /usr/bin/phpunit:0
PHP   2. PHPUnit_TextUI_Command::main() /usr/bin/phpunit:46
PHP   3. PHPUnit_TextUI_Command->run() /usr/share/php/PHPUnit/TextUI/Command.php:129
PHP   4. PHPUnit_TextUI_TestRunner->doRun() /usr/share/php/PHPUnit/TextUI/Command.php:176
PHP   5. PHPUnit_Framework_TestSuite->run() /usr/share/php/PHPUnit/TextUI/TestRunner.php:346
PHP   6. PHPUnit_Framework_TestSuite->run() /usr/share/php/PHPUnit/Framework/TestSuite.php:705
PHP   7. PHPUnit_Framework_TestSuite->runTest() /usr/share/php/PHPUnit/Framework/TestSuite.php:745
PHP   8. PHPUnit_Framework_TestCase->run() /usr/share/php/PHPUnit/Framework/TestSuite.php:775
PHP   9. PHPUnit_Framework_TestResult->run() /usr/share/php/PHPUnit/Framework/TestCase.php:769
PHP  10. PHPUnit_Framework_TestCase->runBare() /usr/share/php/PHPUnit/Framework/TestResult.php:648
PHP  11. Rhumsaa\Uuid\UuidTypeTest->setUp() /usr/share/php/PHPUnit/Framework/TestCase.php:821

One solution is to update composer.json to use version ~2.3.0 of doctrine/dbal, but I don't think this is a good solution, since it means users of the UUID library (who also use doctrine/dbal) will need to continue to use the older version of doctrine/dbal.

Rather, we should update the UUID library so that it can work with both the older version of doctrine/dbal, as well as the newer version.

Introduce Argument Validation for collections (arrays of single type)

There are multiple methods which accept arguments which should be an array of a single type. An example is here: d975f0f

     /**
     * Constructs a `FallbackNodeProvider` using an array of node providers
     *
     * @param NodeProviderInterface[] $providers Array of node providers
     */
    public function __construct(array $providers)
    {
        $this->nodeProviders = $providers;
    }

There is currently no validation or enforcement that the array must contain only the correct class, or at least one item.

I suggest this be added to places which use an array of a single type. This would be a BC-breaking change.

There are some ways to do this that I can think of:

  • Handling the validation at each place it's needed, so in the above case, validating in the constructor. This would be the easiest for people updating to adapt to, in most cases they won't need to change anything.
  • A Collection class which handles the validation in it's constructor, and then updating these methods to accept the Collection object. This places the logic in one place, is much easier for testing, but would be more work for users upgrading to the new version.
  • The Collection class as above, but creating an instance of it in the constructors/other methods which currently accept the arrays, and passing the arrays into it there. This would allow the logic to be fairly consolidated, would still require a test for the methods but a simpler test, and would be less changes for the users upgrading.

Move moontoast/math and symfony/console requirements to require-dev and/or suggest

We're only using the library parts of uuid. I just noticed you now have 2 extra dependencies. Why?

The moontoast/math I can partly understand (though I think we don't even touch the methods that use it), but the readme still talks about it being optional.

The symfony/console dependency however is only for if you want to use the CLI tool?

Confusing

Very minor issue, but you should maybe set the default branch (on GitHub) to master? - it's pretty confusing, arriving here from packagist, the title on the landing page header matches the new package name, but the README below is screaming "this package is deprecated!". I was on the GitHub page twice this week before I realized it doesn't default to the master branch ;-)

Symfony console version 2.4 dependency

Hi,

I'm wondering if there is a reason for the dependency on version 2.4, as 2.3 is the LTS (long term support) version of Symfony and its components. I would like to use this package in a production project which is using 2.3 components and I feel it's unnecessary to upgrade just for this.

Thanks.

Gez

Examples issue

use Rhumsaa\Uuid\Uuid; should be change to use Ramsey\Uuid\Uuid;

Uniformly distributed UUID (UUID COMB)

One of the drawbacks of using a UUID as identifier in a RDBMS is that they are not uniformly distributed. To prevent a decrease in performance it is possible to create a different kind of UUID which contains a timestamp part with a high time resolution (ms).

Would you be open to a PR that would add this functionality?

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.