Giter Site home page Giter Site logo

zeroc-ice / ice Goto Github PK

View Code? Open in Web Editor NEW
2.0K 183.0 589.0 179.9 MB

All-in-one solution for creating networked applications with RPC, pub/sub, server deployment, and more.

Home Page: https://zeroc.com

License: GNU General Public License v2.0

Makefile 0.21% Python 5.69% Java 17.49% JavaScript 5.44% C++ 42.28% C 0.16% C# 15.29% HTML 0.02% PHP 1.19% CSS 0.28% Objective-C 0.23% Objective-C++ 0.56% Ruby 1.38% Yacc 0.35% Lex 0.15% Roff 0.01% Shell 0.01% MATLAB 3.26% Slice 4.15% TypeScript 1.85%
rpc ice zeroc rpc-framework hacktoberfest

ice's People

Contributors

aikoven avatar albert-github avatar alexmnazarenko avatar andidog avatar bentoi avatar bernardnormier avatar bold84 avatar corywinter avatar cruppstahl avatar dennsporcic avatar dependabot[bot] avatar dessa avatar dgboone avatar ethindp avatar externl avatar gajin2 avatar grembo avatar harvey-liu avatar hasufell avatar insertcreativityhere avatar marclaukien avatar mdorner avatar mopfattn avatar newhook avatar niuxu18 avatar pepone avatar reecehumphreys avatar spruiell avatar wilstoff avatar wmanth 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

ice's Issues

Ice.SocketException running JavaScript test suite

On Windows when run the JavaScript test suite with --browser Firefox geckodriver.exe keeps running after the tests finish and a second attempt to run the test suite will fail with Ice.SocketException

Environment:

  • selenium-gecko-driver 0.20.1
  • Firefox 59.0.2
  • Windows 10

Replace Ice::Application in utilities

We no longer use Ice::Application in ice-demos. We should do the same for Ice utilities / admin tools, including:

./IceBox/Admin.cpp:class Client : public Ice::Application
./icegriddb/IceGridDB.cpp:class Client : public Ice::Application
./IcePatch2/Client.cpp:class Client : public Ice::Application
./IceStorm/Admin.cpp:class Client : public Ice::Application
./IceStorm/IceStormDB.cpp:class Client : public Ice::Application

Research /dev/urandom concurrent access

We currently assume that concurrent reads of /dev/urandom can return the same bytes, which was true years ago but may not longer be true today.

As a result, we synchronize reads to /dev/urandom (within the same process):
https://github.com/zeroc-ice/ice/blob/v3.7.1/cpp/src/IceUtil/Random.cpp#L31

and also replace 15 random bits in UUIDs by our PID, resulting in only 122 - 15 = 107 random bits, see:
https://github.com/zeroc-ice/ice/blob/v3.7.1/cpp/src/IceUtil/UUID.cpp#L131

We could possibly use instead a C++ Random Number Engine: http://en.cppreference.com/w/cpp/numeric/random

ICE-8843

Replica logging when icegridnode connects to icegridregistry

When icegridnode (attempts) to connect to the IceGrid registry, it logs:

Replica: trying to establish session with replica `Master'
Replica: established session with replica `Master'

This is rather confusing, since it's just a node connecting to the registry.

ICE-8621

Support for HTML5 Javadoc

starting with Java9 it's possible to generate HTML5 with JavaDoc. Improvements include a search bar and better accessibility... This requires fixing at leat one thing in our code, the use of which is no longer supported with HTML5. We'd also have to ensure that we always build doc JARs with Java 9 or 10. The setting can be changed in library.gradle.

Remove cfg files created by Glacier2/staticFiltering

The test create some cfg but doesn't remove them, will be better to remove them than just gitignore them

dpkg-source: info: local changes detected, the modified files are:
 ice-debian-packaging/cpp/test/Glacier2/staticFiltering/client.cfg
 ice-debian-packaging/cpp/test/Glacier2/staticFiltering/router.cfg
 ice-debian-packaging/cpp/test/Glacier2/staticFiltering/server.cfg

IceGrid federation

It would be helpful to support IceGrid federation, preferably as a built-in IceGrid feature, and otherwise as a demo.

By federation I mean:

  • you have 2 or more independent IceGrid deployments
  • you want to make calls between clients and servers in these IceGrid deployments using indirect proxies

The "federation" could be a Locator that first checks the "local" IceGrid registry, and then checks the remote IceGrid registry(ies) if it can't find the adapterId/well-known ID locally.

This federation could also help enforce uniqueness (for adapter IDs and well-known IDs) across IceGrid registries.

ICE-5854

Add support for weak_ptr in C++11?

We should consider adding a metadata "cpp:weak" that remaps shared_ptr to weak_ptr to let the user avoid strong cycles. This metadata could apply to:

  • operation parameters of type class
  • struct and class data members of type class (I don't see how a cycle could be possible with an exception)
  • sequence and dictionaries<K, V>, where V is a class

ICE-8546

Eliminate catch(const char*)

We should not throw or catch C-strings (or any type not derived from std::exception), yet we have quite a number of catch(const char*) in the code:

./python/modules/IcePy/Slice.cpp:    catch(const char* msg)
./cpp/src/IceGrid/Client.cpp:    catch(const char* msg)
./cpp/src/IceGrid/Topics.cpp:    catch(const char* msg)
./cpp/src/slice2py/Main.cpp:    catch(const char* msg)
./cpp/src/Glacier2Lib/Application.cpp:    catch(const char* ex)
./cpp/src/slice2cs/Main.cpp:    catch(const char* msg)
./cpp/src/slice2java/Main.cpp:    catch(const char* msg)
./cpp/src/slice2cpp/Main.cpp:    catch(const char* msg)
./cpp/src/slice2html/Main.cpp:        catch(const char* err)
./cpp/src/slice2html/Main.cpp:    catch(const char* msg)
./cpp/src/IcePatch2/Calc.cpp:    catch(const char* ex)
./cpp/src/slice2confluence/Main.cpp:        catch(const char* err)
./cpp/src/slice2confluence/Main.cpp:    catch(const char* msg)
./cpp/src/slice2js/Main.cpp:    catch(const char* msg)
./cpp/src/Ice/Service.cpp:    catch(const char* msg)
./cpp/src/Ice/PluginManagerI.cpp:                catch(const char* msg)
./cpp/src/Ice/Application.cpp:    catch(const char* msg)
./cpp/src/Ice/Application.cpp:    catch(const char* msg)
./cpp/src/slice2php/Main.cpp:    catch(const char* msg)
./cpp/src/slice2matlab/Main.cpp:    catch(const char* msg)
./cpp/src/slice2rb/Main.cpp:    catch(const char* msg)
./cpp/src/slice2objc/Main.cpp:    catch(const char* msg)
./ruby/src/IceRuby/Slice.cpp:        catch(const char* msg)

ICE-8639

PHP crash with windows debug builds

Hit this assert with PHP debug build on Windows

 	php_ice.dll!failwithmessage(void * retaddr=0x00007ffa8d703f08, int crttype=1, int errnum, const char * msg=0x000000fa19bfc640)	C++
 	php_ice.dll!_RTC_StackFailure(void * retaddr=0x00007ffa8d703f08, const char * varname=0x00007ffa8d7c83f0)	C++
 	php_ice.dll!_RTC_CheckStackVars(void * frame=0x000000fa19bfca90, _RTC_framedesc * v=0x00007ffa8d7c86c0)	C++
>	php_ice.dll!zif_IcePHP_defineClass(_zend_execute_data * execute_data=0x000002cb52013870, _zval_struct * return_value=0x000002cb52013490) Line 3750	C++
 	php7ts_debug.dll!ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_USED_HANDLER(_zend_execute_data * execute_data=0x000002cb52013250) Line 879	C
 	php7ts_debug.dll!execute_ex(_zend_execute_data * ex=0x000002cb52013030) Line 432	C
 	php7ts_debug.dll!zend_execute(_zend_op_array * op_array=0x000002cb5208b000, _zval_struct * return_value=0x0000000000000000) Line 475	C
 	php7ts_debug.dll!zend_execute_scripts(int type=8, _zval_struct * retval=0x0000000000000000, int file_count=3, ...) Line 1483	C
 	php7ts_debug.dll!php_execute_script(_zend_file_handle * primary_file=0x000000fa19bfebd0) Line 2577	C
 	php.exe!do_cli(int argc=11, char * * argv=0x000002cb5226c320) Line 994	C
 	php.exe!main(int argc=11, char * * argv=0x000002cb5226c320) Line 1381	C
 	php.exe!invoke_main() Line 65	C++
 	php.exe!__scrt_common_main_seh() Line 253	C++
 	php.exe!__scrt_common_main() Line 296	C++
 	php.exe!mainCRTStartup() Line 17	C++
 	kernel32.dll!BaseThreadInitThunk�()	Unknown
 	ntdll.dll!RtlUserThreadStart�()	Unknown

php-crash

The status of a server started by hand does not show up in the IceGridGUI

Using the IceGrid/simple demo, when I start a server on the command line:

C:\builds\ice\demo\IceGrid\simple>server --Ice.Config=C:\builds\ice\demo\IceGrid
\simple\db\node\servers\SimpleServer-1\config\config "--Ice.Default.Locator=Demo
IceGrid/Locator:tcp -p 12000" --Ice.ServerId=SimpleServer-1

This server does not show up as running in the GUI.

The idea to implement this support:

  • IceGrid dynamic registration needs to be enabled (with IceGrid.Registry.DynamicRegistration)
  • the server registers its process admin facet with the registry and maintains a connection up to the registry
  • the connection between the server and the registry is used to monitor the liveliness of the server
  • the server needs to implement a retry mechanism to ensure the connection to the registry remains up
  • We could use bi-dir over this connection to allow the registry to invoke on the admin facets (without needed to enable admin endpoints on the server). We have to consider the case when registries are replicated.

ICE-671

use ifndef around OS specific headers

running abi-compliance-checker on Linux fails because SChannel.h required headers are not present

The GCC parameters:
  gcc -fdump-translation-unit -fkeep-inline-functions -c -x c++-header -fpermissive -w "/tmp/luuFWXCKGm/dump1.h"  -I/opt/Ice-3.7.0/include -I/usr/include/php/20160303/ext/standard

In file included from /tmp/luuFWXCKGm/dump1.h:162:0:
/opt/Ice-3.7.0/include/IceSSL/SChannel.h:15:10: fatal error: wincrypt.h: No such file or directory
 #include <wincrypt.h>
          ^~~~~~~~~~~~
compilation terminated.

We should use appropriate #ifdef/#endif constructs to only process this headers in the supported OS

Allow AMD and non-AMD servants to be generated

Right now, it's not possible to generate both an AMD and non-AMD version of the same servant. This is problematic for "callback" interfaces that are supposed to be implemented by users.

Take for example the Glacier2::PermissionsVerifier interface. We currently only ship a non-AMD servant in our libraries. It's not ideal because the user might very well want to implement this with AMD if the implementation needs to be async (it might need to send an HTTP request to a 3rd party for verification... such as Apple/Sony servers in case of a game).

Proposed solution:

When the user specifies ["+amd"] in front an interface, we generate 2 servant base classes:

  • the regular base class, that takes into account ["amd"] metadata data in front of operations (so it can get a mix of AMD and non-AMD operation implementations)
  • a second base class named XxxAsync with all operations mapped to AMD
  • regarding inheritance, an Async class would inherit from other Async class when available (meaning the base interfaces have also +amd); otherwise it derives from the regular non-Async C++ classes/Java interfaces etc.
    The various OperationResult structs would stay only in the main servant base class - no duplication.

These two base classes are independent, and the user chooses which one to derive from. This is basically what we already do for Blobject, with Blobject and BlobjectAsync.

This would deal properly with the following scenario:

  1. I want a mix of amd and non-amd operation on my servant implementation (has always worked)
  2. I need to implement one or more operation as amd, but the library with the servant base class did not generate them as amd => I regenerate with ["+amd"] added (small downside: I need to implement all operations as amd)
  3. a library wants to provide both amd and non-amd base classes for the same interface (it uses ["+amd"] in front of the interface)

ICE-5516

IceBox start/stop and load order

The IceBox.LoadOrder property allows you to specify the initialization ordering of your IceBox services – services not listed are initialized afterwards in an undefined order.

Later on, we added the ability to start / stop services one by one. start/stop ignores IceBox.LoadOrder completely.

Say you stop the 2nd service in the LoadOrder; the 3rd and up services in the load-order are not affected, although they may depend on this service.

With start/stop, we ask the caller (e.g. iceboxadmin, IceGridGUI) to know these dependencies and start/stop services in the correct sequence. This is not very user-friendly.

A better approach would be specify dependencies between IceBox services, very much like with Windows Services.

For example:
IceBox.Service.Hello.DependOn=IceStorm

Tidy up marshal exceptions

The following marshaling exceptions are thrown by the run time, but never caught:

  • ProxyUnmarshalException
  • StringConversionException
  • EncapsulationException

I don't see any conceivable reason for why an application would want to catch these exceptions specifically, seeing that the all relate to marshaling errors that indicate that a request was internally inconsistent.

I'd like to replace these with MarshalException, with appropriate message strings. At the moment, we are carrying the generated code for these exceptions around for no good reason.

class and deprecated in PropertyNames.xml

It would be nice if I could deprecate an entire class-instance with deprecated=true, e.g.

<property name="Admin" class="objectadapter" deprecated="true"/>

i.e. all corresponding properties would be marked deprecated.

Currently, this deprecated=true is ignored.

ICE-2420

Considering adding pkg-config support for Linux and macOS installations.

Then users can do pkg-config --libs zeroc-ice, pkg-config --variable=slicedir zeroc-ice, and more.

To limit the number of pc files, this would require linking with -Wl,-as-needed; otherwise, all libraries get written in the resulting image. These pc files would be:

zeroc-ice
zeroc-ice++11
zeroc-freeze

ICE-7184

PermissionVerifier and SSLPermissionVerifier

Currently they are declared by and compiled in Glacier2, and used by both IceGrid and Glacier2.

This can be confusing. You may implement a "Glacier2" permission verifier (or "Glacier2" ssl permission verifier) to be used by IceGrid for authorization although you don't use Glacier2 at all.

I think it would be clearer to move them to their own module and maybe library.

ICE-1282

Rework test util Application

(From @bentoi)

Our tests need some helpers to:

  • hide differences between platforms (Java CLI vs Android, C++ CLI vs iOS vs UWP, etc).
    • output should either go to stdout, be buffered, go to a GUI
    • the server readiness logic is different between a CLI server and a server bundled into a shared library started by a GUI
  • reduce the boilerplate code needed for setting up the communicator, parsing properties, etc.

Right now, we have an application class for the following language mappings:

  • Java/Java-Compat: test.util.Application (most likely introduced with the Android support)
  • C#: TestCommon.Application (I believe it was introduced with the Silverlight support)

For C++/Objective-C, we use a number of functions and macros from TestCommon.h to help with the communicator initialization and the "wait/ready" logic required for the driver to wait for server readiness. Many of these were introduced for the iOS / UWP support.

For Python, Ruby, PHP we don't use any helpers.

For JavaScript, clients/servers do follow a number of conventions (they export some variables such as _test, _server, _clientAllTests, _runServer... which are used by the test controller / runner to start the client or server).

Obviously, we didn't pay much attention to consistency across mappings for the test helpers .

Python/Ruby/PHP and JavaScript don't support being run concurrently with other tests because they don't support the --Test.BasePort property which allows to specify the base port that the client or server should use. Adding support for this would be good and some helpers could be useful to more easily get test endpoints, ports, etc.

So if we want to revisit this for tests, I see two options:

  1. get rid of the application class and replace it with some other helper(s)
  2. embrace the test application class and port/use it consistently with all the mappings

I'm not a big fan of classes with static methods and static data members... I'd rather keep an application class which can easily be instantiated to run a client or server.

ICE-8531

Provide new Glacier2 helpers

The Glacier2 helper class derives from Ice::Application, which is now essentially deprecated, and replaced by built-in language constructs (CommunicatorHolder and CtrlCHandler in C++).

We should provide Glacier2 helpers that don't depend on Ice::Application.

ICE-8688

Hit StreamSocket assert

On Windows 10 I hit an assert in StreamSocket when running JavaScript tests against the C++ x64 debug servers build with Visual Studio 2017
stack.txt

Don't check Ruby proxy types when marshaling proxy parameters

Ruby is a weakly-typed scripting language, where all error detection occurs at runtime. parameters in a method declaration/definition don't have any type. Ruby usually detects that a parameter is not of the desired type when the program tries to call a method on this parameter that is not implemented.

In keeping with this philosophy, we should not enforce proxy types for in parameters of Ice operations called from IceRuby. This checking does not add value. With the checking you get an error at runtime, and without the checking you either:

  • don't get an error, because your proxy actually denotes an object with the desired interface [the most likely situation], or
  • get another runtime error when the server calls a missing operation on this proxy [less common, and consistent with Ruby's programming philosophy]

ICE-2070

Update IceGrid GUI delete button

When editing an application the delete button is a red X. I (and maybe others?) often mistake this to be an undo/cancel button.

Seems like it would be more intuitive to use something like a trash can.

See ICE-5706

Warn about sync calls in UI thread

It would be nice to have the ability to get a warning (or at least a trace) for sync calls made from a specific thread, such as the UI thread in a graphical application.

ICE-7559

Need joinString with escapes

Properties::getPropertyAsList[WithDefault] and the underlying IceUtilInternal::StringUtil::splitString parses a string into a string sequence with escape-support for elements that contain white space or commas. However, we don't have a helper function to do the reverse--combine a string sequence into a single string with escapes as appropriate.

Such a "joinString with escapes" would be useful:

  • in the IceBox service manager, when it writes the property Ice.Admin.Facets of a service communicator
  • in IceGridGUI, when the LogFilterDialog displays trace categories

ICE-5702

Make Ruby proxies smarter

In Ruby, an Ice proxy could intercept a missing method and provide it automatically. This would be useful (and meaningful) when the corresponding operation is provided by the most derived interface of the target object.

This way, you could type:

irb> prx = ic.stringToProxy('GINA/Measurement-5')
irb> prx.getCurrentMeasurement() 

instead of

irb> prx =
GINA::Measurement::MeasurementServerPrx::checkedCast(ic.stringToProxy('GINA/Measurement-5'))
irb> prx.getCurrentMeasurement() 

In Ruby, it is possible to catch a "method not defined exception" and instead of just failing, provide the method and proceed.

Here, prx could automatically cast itself to the target's most derived type, with something like:

   # ask the target for its most derived type
   mostDerivedTypeId = self.ice_id(ctx);
   # somehow include the corresponding proxy mixin code
   generatedPrxMixin = ...
   include generatedPrxMixin
   # try again

Another less transparent possibility (but still much more convenient than the current situation) would be to add a new method that returns a proxy with the most derived interface, e.g.

   prx = prx.ice_getFullInterface()

ICE-2074

Set alternate Windows report mode for tests and research minidumps

Right now, when running an exe in debug mode and an assert occurs, a dialog pops up with "Abort", "Retry" and "Cancel" buttons which ends up causing the tests to hang. We could modify this default behavior to instead just print a message on the console, see: https://msdn.microsoft.com/fr-fr/library/1y71x448.aspx

We should also check if Windows minidumps can help debug failures in crash or hang situations

http://www.debuginfo.com/articles/effminidumps.html
https://support.microsoft.com/en-us/help/241215/how-to-use-the-userdump.exe-tool-to-create-a-dump-file
https://support.microsoft.com/en-us/help/931673/how-to-create-a-user-mode-process-dump-file-in-windows-vista-and-in-wi

Deprecate slice2java meta option

slice2java provides a "meta" option unlike other Slice compilers. It should have been deprecated in Ice 3.7 when we deprecated various slice compiler options, but was not.

ICE-8537

Ice 3.6 for Gentoo and tests

(apologies for the long post)

hello

i am the current gentoo maintainer of the Ice Package.
as part of the stabilization process we do run the testsuite, keep in mind that we are still at 3.6.3, i plan to update that but i still need the current revision marked stable.

the first and foremost question, which will make the rest of the report obsolete, i suppose, is are we actually supposed to run tests? some upstreams dislike that.

onto the test failures then:

these i have encountered myself and filtered out as a result:

a little word about the sandbox Ice is build in.
its to avoid the clobber the system during the build be it filesystem or network wise, it normally run as root (this can be changed but it is not usually done)

no internet access in the sandboxed build environment / limited udp support in the sandbox (IIRC) so: no upstream issue in failing:

  • Ice/udp
  • IceSSL

works with OPTIMIZE=yes, fails with OPTIMIZE=no

  • IceUtil/stacktrace

these were tested with latest 3.6 git branch

now are these which appeared in the gentoo bugtracker, these i have not encountered myself so no idea about them.

IceGrid/Admin has kind of failed on me once but never again, i see that there is 0a37d62 so thats probably ok to be filtered?
IceBox/Configuration feels odd. we use a patch from pld-linux which removes ${binsuffix} so why is this even happening? see https://github.com/gentoo/gentoo/blob/master/dev-libs/Ice/files/Ice-3.6.3-no-arch-opts.patch for the patch

this was with 3.6.3

for 3.7 i'm not sure how to handle the tests yet and i'm currently not near my dev machine to check how i did that, but i think i had to call allTests.py for every phase which is kind of sad when it worked just fine before with make test, but yes i do know you revamped the build system with 3.7

Add icegridadmin service status

You can start and stop a service with icegridadmin, however you currently can't figure out it if it's running or not.

ICE-8268

Fix ESLint reported issues

We should go throw ESLint report and fix this issues, some of this just need to adjust our eslint configuration in .eslintrc.js others might need code fixes

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.