Git Product home page Git Product logo

redis's Introduction

redis

AMPHP is a collection of event-driven libraries for PHP designed with fibers and concurrency in mind. This package provides non-blocking access to Redis instances. All I/O operations are handled by Revolt event loop, so you should be familiar with the basics of it.

Installation

This package can be installed as a Composer dependency.

composer require amphp/redis

Usage

<?php

require __DIR__ . '/vendor/autoload.php';

use function Amp\Redis\createRedisClient;

$redis = createRedisClient('redis://');

$redis->set('foo', '21');
$result = $redis->increment('foo', 21);

\var_dump($result); // int(42)

Security

If you discover any security related issues, please use the private security issue reporter instead of using the public issue tracker.

License

The MIT License (MIT). Please see LICENSE for more information.

redis's People

Contributors

assertchris avatar bilge avatar brstgt avatar brzuchal avatar ekinhbayar avatar enumag avatar fedott avatar gitomato avatar glowdan avatar kelunik avatar rdlowrey avatar robberphex avatar rodion-k avatar staabm avatar trowski 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

redis's Issues

Add LICENSE

There should be a LICENSE with the license in it.

bug on evalSha function

Hi,

There is a bug on evalSha function in lib/Redis.php (l. 1754)
PHP Warning: array_merge(): Argument #3 is not an array in vendor/amphp/redis/lib/Redis.php on line 1755
PHP Fatal error: Uncaught TypeError: Argument 1 passed to Amp\Redis\Client::send() must be of the type array, null given, called in vendor/amphp/redis/lib/Redis.php on line 1755 and defined in vendor/amphp/redis/lib/Client.php:111

Fix by casting type array on third argument : (array) sizeof((array) $keys)
Thank you

1.x RemoteExecutor#143 Call to a member function fail() on null

Hi,
Thanks for your handy library.
With the newest 1.x version we found a (possible) bug:

Call to a member function fail() on null
in /var/www/html/vendor/amphp/redis/src/RemoteExecutor.php at line 143

https://github.com/amphp/redis/blob/1.x/src/RemoteExecutor.php#L135C17-L145C18
introduced with
ed5555e

/*#135*/ } finally {
/*#136*/     $temp = $queue;
/*#137*/     $queue = [];
/*#138*/     $connect = null;
/*#139*/     $socket->close();
/*#140*/ 
/*#141*/     while ($temp) {
/*#142*/         $deferred = \array_shift($queue);
/*#143*/         $deferred->fail($error);
/*#144*/     }
/*#145*/ }

If I understand correctly:
$queue is emptied in #137, but the old reference is stored in $temp.
In the while-loop the array_shift call on (now empty) $queue will always return null.
I don't know the bigger picture with the $temp dereferencing, but only with the local context, I guess in #142 it should use $temp instead of $queue.

Cannot write session to redis storage

Hallo,

we use the amphp/http-server to run a Long-running PHP Webserver. For session handling we use the amphp/http-server-session package and this package to store session data in redis. Our system and solution works like expected, but after some time (6h-1d) the following error occurs when trying to create a new session and store it in redis:

Call to a member function write() on null
#0 [internal function]: Amp\Redis\RespSocket->Amp\Redis\{closure}()  
#1 /usr/share/app/vendor/amphp/amp/lib/Coroutine.php(67): Generator->current()  
#2 /usr/share/app/vendor/amphp/amp/lib/functions.php(96): Amp\Coroutine->__construct()
#3 /usr/share/app/vendor/amphp/redis/src/RespSocket.php(70): Amp\call()  
#4 /usr/share/app/vendor/amphp/redis/src/RemoteExecutor.php(74): Amp\Redis\RespSocket->write()  
#5 [internal function]: Amp\Redis\RemoteExecutor->Amp\Redis\{closure}()  
#6 /usr/share/app/vendor/amphp/amp/lib/Coroutine.php(67): Generator->current()  
#7 /usr/share/app/vendor/amphp/amp/lib/functions.php(96): Amp\Coroutine->__construct()  
#8 /usr/share/app/vendor/amphp/redis/src/RemoteExecutor.php(80): Amp\call()  
#9 /usr/share/app/vendor/amphp/redis/src/RemoteExecutor.php(55): Amp\Redis\RemoteExecutor->enqueue()  
#10 [internal function]: Amp\Redis\RemoteExecutor->Amp\Redis\{closure}()  
#11 /usr/share/app/vendor/amphp/amp/lib/Coroutine.php(118): Generator->send()
#12 /usr/share/app/vendor/amphp/amp/lib/Internal/Placeholder.php(46): Amp\Coroutine->Amp\{closure}()
#13 /usr/share/app/vendor/amphp/amp/lib/Coroutine.php(151): Amp\Coroutine->onResolve()
#14 /usr/share/app/vendor/amphp/amp/lib/functions.php(96): Amp\Coroutine->__construct()
#15 /usr/share/app/vendor/amphp/redis/src/RemoteExecutor.php(62): Amp\call()
#16 /usr/share/app/vendor/amphp/redis/src/Redis.php(1101): Amp\Redis\RemoteExecutor->execute()
#17 [internal function]: Amp\Redis\Redis->Amp\Redis\{closure}()
#18 /usr/share/app/vendor/amphp/amp/lib/Coroutine.php(67): Generator->current()
#19 /usr/share/app/vendor/amphp/amp/lib/functions.php(96): Amp\Coroutine->__construct()
#20 /usr/share/app/vendor/amphp/redis/src/Redis.php(1110): Amp\call()
#21 /usr/share/app/vendor/amphp/redis/src/Mutex/Mutex.php(170): Amp\Redis\Redis->eval()
#22 [internal function]: Amp\Redis\Mutex\Mutex->Amp\Redis\Mutex\{closure}()
#23 /usr/share/app/vendor/amphp/amp/lib/Coroutine.php(67): Generator->current()
#24 /usr/share/app/vendor/amphp/amp/lib/functions.php(96): Amp\Coroutine->__construct()
#25 /usr/share/app/vendor/amphp/redis/src/Mutex/Mutex.php(199): Amp\call()
#26 /usr/share/app/vendor/amphp/http-server-session/src/Session.php(147): Amp\Redis\Mutex\Mutex->acquire()
#27 [internal function]: Amp\Http\Server\Session\Session->Amp\Http\Server\Session\{closure}()
#28 /usr/share/app/vendor/amphp/amp/lib/Coroutine.php(67): Generator->current()
#29 /usr/share/app/vendor/amphp/amp/lib/functions.php(96): Amp\Coroutine->__construct()
#30 /usr/share/app/vendor/amphp/http-server-session/src/Session.php(328): Amp\call()
#31 [internal function]: Amp\Http\Server\Session\Session->Amp\Http\Server\Session\{closure}()
#32 /usr/share/app/vendor/amphp/amp/lib/Coroutine.php(118): Generator->send()
#33 /usr/share/app/vendor/amphp/amp/lib/Success.php(41): Amp\Coroutine->Amp\{closure}()
#34 /usr/share/app/vendor/amphp/amp/lib/Coroutine.php(151): Amp\Success->onResolve()
#35 /usr/share/app/vendor/amphp/amp/lib/functions.php(96): Amp\Coroutine->__construct()
#36 /usr/share/app/vendor/amphp/http-server-session/src/Session.php(329): Amp\call()
#37 /usr/share/app/vendor/amphp/http-server-session/src/Session.php(163): Amp\Http\Server\Session\Session->synchronized()
#38 OWN_CLASS_FOR_SESSION_OPENING(48): Amp\Http\Server\Session\Session->open()

Here is our setup for the session driver:

$sessionSerializer = new CompressingSerializeSerializer();
$host = 'someHost';
$port = 6379;
$pass = 'somePassword';

$redisConfig = Config::fromUri('redis://' . $host . ':' . $port);
if ($pass) {
	$redisConfig = $redisConfig->withPassword($pass);
}

$remoteExecutorFactory = new RemoteExecutorFactory($redisConfig);
$redisSessionStorage = new RedisStorage($remoteExecutorFactory, $sessionSerializer, $sessionConfig->getTtlSeconds());
$sessionStorage = $redisSessionStorage;
$keyedMutex = new Mutex($remoteExecutorFactory);
$idGenerator = new DefaultIdGenerator();
$sessionDriver = new Driver($keyedMutex, $sessionStorage, $idGenerator);

Until now i could not find a setup to manually force this error.
Thank you in advance!

Wrong order of SELECT and AUTH connection event handlers

Using v0.3.3 when a connection is being created the order of event handlers is wrong.
Currently, it sends SELECT and gets -NOAUTH Authentication required. this is because AUTH is being sent after SELECT and should be sent before.
The second thing is if I get an error like -NOAUTH would like to know about that with a proper exception thrown.

Error while sending big data

There is an error while sending long data to redis:

<?php
        \Amp\run(function () {
            $client = new \Amp\Redis\Client("tcp://localhost:6379");
            $data = [];
            for ($i = 0; $i < 1000; $i++) {
                $data['key' . $i] = mt_rand();
            }
            $stringData = serialize($data);
           $result = yield $client->set("dataArray", $stringData);
        });     
?>

And it throws error:

[08:08:19] critical ErrorException: fwrite(): send of 8192 bytes failed with errno=11 Resource temporarily unavailable in /var/www/travelm3/vendor/amphp/redis/lib/Connection.php:140
Stack trace:

0 [internal function]: League\BooBoo\Runner->errorHandler(8, 'fwrite(): send ...', '/var/www/travel...', 140, Array)

1 /var/www/travelm3/vendor/amphp/redis/lib/Connection.php(140): fwrite(Resource id #222, '*3\r\n$3\r\nset\r\n$9...')

2 /var/www/travelm3/vendor/amphp/amp/lib/UvReactor.php(420): Amp\Redis\Connection->Amp\Redis{closure}('000000005745667...', Resource id #222, NULL)

3 /var/www/travelm3/vendor/amphp/amp/lib/UvReactor.php(402): Amp\UvReactor->invokePollWatcher(Object(stdClass))

4 [internal function]: Amp\UvReactor->Amp{closure}(Resource id #225, 0, 2, Resource id #222)

5 /var/www/travelm3/vendor/amphp/amp/lib/UvReactor.php(93): uv_run(Resource id #62, 1)

6 /var/www/travelm3/vendor/amphp/amp/lib/functions.php(46): Amp\UvReactor->run(Object(Closure))

7 /var/www/travelm3/vendor/amphp/aerys/bin/aerys(96): Amp\run(Object(Closure))

8 {main}

With NativeReactor i get this error on every request. With uv reactor on second and next.

This is really critical.

getMultiple method doesn't work

Hi,

\Amp\Redis\Redis::getMultiple(string $key, string ...$keys) the method receives a key and keys as arguments, but only keys without a first key are passed to array_combine. As a result, we get more answers than there is in the keys.

Result:

ValueError: array_combine(): Argument #1 ($keys) and argument #2 ($values) must have the same number of elements

Subscriber and publisher are leaking open files

I found that the Subscriber and RemoteExecutor open a RespSocket in the connect() promise but fail to close it, taking one open file for the life of the process. In a process with high concurrency of publishers and subscribers, it can easily reach the open file soft limit (usually 1024).

I think it is necessary to provide some way of disconnecting them, maybe in the destructor. I had to create disconnect() methods that call RespSocket::close() on the $connect member promise. Unfortunately, this triggers an exception in RespSocket::51 that I had to disable.

As a side note, I think the reference() and unreference() calls are unbalanced. I removed the reference() in Subscriber::unloadEmitter(), just before the yield $resp->write('unsubscribe', $channel); . I think the object should always have been referenced before.

No error when passing array to set() as value

No error throws when passing an array instead of string to SET().

<?php
(new Host)->use(
    function (\Aerys\Request $req, \Aerys\Response $res) use ($app) {
        $client = new \Amp\Redis\Client("tcp://localhost:6379");
        try {
            $result = yield $client->set("dataArray", ['aaaa' => 'bbbb']);
        } catch (\Exception $e) {
            yield $res->stream('error');
        }
        yield $res->stream('finish');
    });
?>

And it just wait forever.
exceptionHandler really catch "strlen() expects parameter 1 to be string, array given", but then it loop forever.

Problem with redis connection

I found a problem in redis, This is my redis connection configuration:

$config = config('redis');

if (isset($config['host']) && isset($config['port'])) {
    $uri = Config::fromUri('redis://' . $config['host'] . ':' . $config['port'] . '?' . http_build_query([
            'password' => $config['password'] ?? '',
            'timeout' => $config['timeout'] ?? '',
            'database' => $config['database'] ?? 0,
        ]));

    return new Redis(new RemoteExecutor($uri));
}
return null;

I have a infinite loop, After running each query, The redis connect and disconnect from redis server.

image

private function connect(): Promise

image

Missing commands

Hi guys,

Today it added amphp/redis to our project to replace the classic phpredis implementation. I noticed that a couple of commands are missing - e.g. zrangebyscore, zrevrangebyscore and others.

Those commands are quite simple to implement. Would you accept an MR? What are your requirements on tests etc?

Thanks :)

Redis Stack Support

Dear Kelunik

I came across Redis Stack on Redis website. While there are Redis team supported plugins like Jedis that supports Redis Stack, I am posting in here a request to support Redis Stack, that will help PHP community alot.

https://redis.io/docs/stack/

Thank you

bug: Amp_v2

php examples/basic.php
PHP Fatal error:  Uncaught Exception: Invalid file descriptor in /home/vendor/amphp/redis/vendor/amphp/amp/lib/Loop/EvDriver.php:187
Stack trace:
#0 /home/vendor/amphp/redis/vendor/amphp/amp/lib/Loop/EvDriver.php(187): EvLoop->io(Object(Amp\Socket\Socket), 1, Object(Closure), Object(Amp\Internal\Watcher))
#1 /home/vendor/amphp/redis/vendor/amphp/amp/lib/Loop/Driver.php(98): Amp\Loop\EvDriver->activate(Array)
#2 /home/vendor/amphp/redis/vendor/amphp/amp/lib/Loop/Driver.php(71): Amp\Loop\Driver->tick()
#3 /home/vendor/amphp/redis/vendor/amphp/amp/lib/Loop/EvDriver.php(143): Amp\Loop\Driver->run()
#4 /home/vendor/amphp/redis/vendor/amphp/amp/lib/Loop.php(53): Amp\Loop\EvDriver->run()
#5 /home/vendor/amphp/redis/examples/basic.php(11): Amp\Loop::run(Object(Closure))
#6 {main}
  thrown in /home/vendor/amphp/redis/vendor/amphp/amp/lib/Loop/EvDriver.php on line 187
PHP Fatal error:  Uncaught RuntimeException: UV_EBADF: Bad file descriptor in /home/vendor/amphp/redis/vendor/amphp/amp/lib/Loop/UvDriver.php:49
Stack trace:
#0 [internal function]: Amp\Loop\UvDriver->Amp\Loop\{closure}(Resource id #78, -9, 0, Resource id #77)
#1 /home/vendor/amphp/redis/vendor/amphp/amp/lib/Loop/UvDriver.php(163): uv_run(Resource id #22, 1)
#2 /home/vendor/amphp/redis/vendor/amphp/amp/lib/Loop/Driver.php(127): Amp\Loop\UvDriver->dispatch(true)
#3 /home/vendor/amphp/redis/vendor/amphp/amp/lib/Loop/Driver.php(71): Amp\Loop\Driver->tick()
#4 /home/vendor/amphp/redis/vendor/amphp/amp/lib/Loop.php(53): Amp\Loop\Driver->run()
#5 /home/vendor/amphp/redis/examples/basic.php(11): Amp\Loop::run(Object(Closure))
#6 {main}
  thrown in /home/vendor/amphp/redis/vendor/amphp/amp/lib/Loop/UvDriver.php on line 49
PHP Notice:  Object of class Amp\Socket\Socket could not be converted to int in /home/vendor/amphp/redis/vendor/amphp/amp/lib/Loop/NativeDriver.php on line 242

Notice: Object of class Amp\Socket\Socket could not be converted to int in /home/vendor/amphp/redis/vendor/amphp/amp/lib/Loop/NativeDriver.php on line 242
PHP Notice:  Object of class Amp\Socket\Socket could not be converted to int in /home/vendor/amphp/redis/vendor/amphp/amp/lib/Loop/NativeDriver.php on line 248

Notice: Object of class Amp\Socket\Socket could not be converted to int in /home/vendor/amphp/redis/vendor/amphp/amp/lib/Loop/NativeDriver.php on line 248

example for pubsub?

anything wrong? I'm new to amphp

use Amp\Redis\Config;
use Amp\Redis\Redis;
use Amp\Redis\RemoteExecutor;
use Amp\Iterator;
use Amp\Delayed;
use Revolt\EventLoop;
use Amp\Redis\Subscriber;
use Amp\Redis\RedisException;
use Amp\Redis\Subscription;
use Amp\Socket\Socket;

Revolt\EventLoop::run(function () {
    $redisClient = new Subscriber(Config::fromUri('tcp://localhost:6379'));
    do {
        try {
            /** @var Subscription $subscription */
            $subscription = yield $redisClient->subscribe('channel');
            while (yield $subscription->advance()) {
                $message = $subscription->getCurrent();
                print_r($message);
            }
        } catch (RedisException $e) {
            yield new Delayed(1000);
        }
    } while (true);
});

it exited immediately.

Thanks

'evalSha' is deprecated

@kelunik I think that 763f30a is not in place, I think that a redis client must implement API and not decide what is better, I have some old tested logic that works perfect, but after that commit it fail, my opinion is to use @deprecated ?

Client Timeout Bug

redis-server config

# Close the connection after a client is idle for N seconds (0 to disable)
timeout 10
Amp\run(function () 
{
    try
    {
        $client = new \Amp\Redis\Client("tcp://localhost:6379");
        yield $client->set("foo", "21");
        $res = yield $client->get("foo"); 

        print($res . "\n"); //21
    }
    catch (Throwable $e)
    {
        print($e->getMessage());
    }
});

Problem: If you run this code, the loop will be stopped without any error or exception after 10 sec,
Is there any method to catch this ? After some investigation I find where is the problem:

Amp\Redis\ConnectException: Connection went away (read) in amphp/redis/lib/Connection.php:224

This can be a problem for thous who ex: Create a Tcp Server and use 1 redis connection for multiple tcp clients, as I do.

leak

Hi,

  1. Thank you for amazing product (amp)
  2. Code:
Amp\run(function () {
    $client = new \Amp\Redis\Client("tcp://localhost:6379");

    \Amp\once(function() use ($client)
    {
        print("close\n");

        $client->close();
    }, 2000);

    \Amp\repeat(function() use ($client)
    {
        print("repeat\n");
    }, 1000);
});
  1. __destruct on $client is never called, only if loop is stopped,
    but i use Redis in a Tcp Server Loop, and open for each incoming connection a new Redis connection (may be not the best approach), after Tcp connection is closed I try to close Redis connection, but it seams like not dealloc-ing

丹东开发票

丹东开发票〖電ν:188.ν.2028.ν.6526张〗十q:6300.ν.55060】熟悉智能智慧家居领域
据我所了解河北廊坊的房价没有上涨呢,现在的房价也不是很便宜呢,目前这边房子的均价在13413元每平米,今年的房价在9月份涨的比较明显,不过之后几个月的房价是一直在下跌的,不过未来廊坊的房价肯定是会上涨的,房价下跌只是暂时的,主要还是受国家的购房政策的影响,很多人都在观望当中。不过最近几年廊坊的经济发展还是非常快速的,想要在廊坊买房子的现在买就非常合适的,后期房价肯定会上涨的。

subscriber closing abruptly in pubsub

I am trying to use Amphp/redis for Redis Pubsub and everytime I try running subscriber in one putty window and publish messages using another putty window, the first message is being pushed, second message not published and third message making the subscriber to exit

to ensure timeout donot happen, using require in_set based directive as well

I ran redis-cli with MONITOR command beside in another putty window, no errors observed too

please share your inputs

thank you

code in publish.php

require 'vendor/autoload.php';
use Amp\Redis\Config;
use Amp\Redis\Redis;
use Amp\Redis\RemoteExecutor;
use Amp\Iterator;
use Amp\Delayed;
use Amp\Loop;
use Amp\Redis\Subscriber;
use Amp\Redis\RedisException;
use Amp\Redis\Subscription;
use Amp\Socket\Socket;

Amp\Loop::run(static function () {

  // $config = Config::fromUri('tcp://localhost:6379?pass=foobar');
    $redis = new Redis(new RemoteExecutor(Config::fromUri('tcp://localhost:6379')));

    $subscriber = new Subscriber(Config::fromUri('redis://'));

            $result = yield $redis->publish("myChannel","SriRama");

            var_dump($result);

});

code in subscriber.php

require 'vendor/autoload.php';
use Amp\Redis\Config;
use Amp\Redis\Redis;
use Amp\Redis\RemoteExecutor;
use Amp\Iterator;
use Amp\Delayed;
use Amp\Loop;
use Amp\Redis\Subscriber;
use Amp\Redis\RedisException;
use Amp\Redis\Subscription;
use Amp\Socket\Socket;

ini_set('default_socket_timeout', -1);

Amp\Loop::run(static function () {

  // $config = Config::fromUri('tcp://localhost:6379?pass=foobar');
    $redis = new Redis(new RemoteExecutor(Config::fromUri('tcp://localhost:6379')));

    $subscriber = new Subscriber(Config::fromUri('redis://'));

           $subscription = yield $subscriber->subscribe("myChannel");

            yield $subscription->advance();

                 $result = $subscription->getCurrent();

                 var_dump($result);

});

redis-monitor-command-data

Unittest goes in infinite loop

Sorry for may be dump question, but I'm stuck while running phpunit test:

class RedisTest extends \PHPUnit_Framework_TestCase
{
    /**
     * @test
     */
    public function redis()
    {
        \Amp\reactor(\Amp\driver())->run(function () {
            $redis = new \Amp\Redis\Client("tcp://localhost:6379");
            $result = yield $redis->set("test", "123123123");
        });

It done redis set, but then goes in infinite loop:

^C[Current opline: in internal function uv_run]
>00096:             \uv_run($this->loop, $this->immediates ? \UV::RUN_NOWAIT : \UV::RUN_ONCE);
 00097:         }
 00098:

at the same time - if i run something like

    public function redis()
    {
        \Amp\reactor(\Amp\driver())->run(function () {
               yield new \Amp\Pause(500);
        });

Test successfully ends.
I tried additionaly add \Amp\stop(), but it stuck at yield $redis line..
Where i'm wrong?

Timed-out lock never released

If obtaining a lock in fails due to timeout, it appears the lock cannot be obtained again by another request. Guessing this is because the token remains in the queue, but is not removed?

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.