Git Product home page Git Product logo

lua-moon's Introduction

Moon -- A C Binding Toolkit for Lua

This library provides new convenience functions for binding C types to Lua as userdata for Lua 5.1, Lua 5.2, and Lua 5.3. It supports objects with different lifetimes, polymorphic type checking, type-safe binding of tagged unions or embedded structs, properties and methods at the same time, and uniform handling of pointers to objects using a simple and small set of API functions.

Using this Library

This package includes a header file moon.h and the corresponding source file moon.c. To use this package you need to include the header file wherever you want to call one of the macros/functions defined within. If you just have a single source file where you want to use those functions, you are done: moon.h includes moon.c and makes every function static. If you have multiple source files that need functions/macros from this library, this approach is flawed, because you will end up with multiple versions of the same functions. Instead include the header wherever you need it, but when you compile those source files, define the macro MOON_PREFIX to a unique name to use for all functions in the moon library. You also have to compile and link moon.c using the same define. This approach will change the common moon_ prefix to your custom prefix behind the scenes to avoid linker errors in case another library also links to moon.c. The header file moon_flag.h can be included whenever needed, but it depends on the functions defined in moon.c. The moon_dlfix.h header is completely independent, but relies on some platform specific functions.

Reference

This section lists all provided macros/functions.

moon.h/moon.c

The main part of the moon toolkit.

MOON_EXPORT, MOON_IMPORT, MOON_LOCAL

#define MOON_EXPORT
#define MOON_IMPORT
#define MOON_LOCAL

Macros for specifying symbol visibility.

MOON_CONCAT

#define MOON_CONCAT( _a, _b )

A macro that evaluates both arguments and joins them together. You can use that to build valid C identifiers with custom prefixes or suffixes.

MOON_STRINGIFY

#define MOON_STRINGIFY( _v )

A macro that has the same effect as #_v, but works outside of a macro substitution.

moon_object_header

typedef struct {
  unsigned char   flags;
  unsigned char   cleanup_offset;
  unsigned char   vcheck_offset;
  unsigned char   object_offset;
} moon_object_header;

Common data structure shared by all userdata objects created via the moon toolkit. The object may have optional fields following the memory of this header structure, stored at the given offsets. The flags field is a bit mask describing the details of the object. A pointer to this header can be obtained by using plain lua_touserdata on a moon object.

moon_object_cast

typedef void* (*moon_object_cast)( void* );

Function pointer type for conversion functions used by moon_defcast.

moon_object_destructor

typedef void (*moon_object_destructor)( void* );

Function pointer type for cleanup functions of moon objects.

MOON_OBJECT_IS_VALID, MOON_OBJECT_IS_POINTER

#define MOON_OBJECT_IS_VALID    0x01
#define MOON_OBJECT_IS_POINTER  0x02

Values stored in the flags field of the moon_object_header structure. The only value interesting for users of the library is the MOON_OBJECT_IS_VALID flag which is reset automatically by the moon_killobject function to signal that the destructor has already run.

moon_defobject

/*  [ -nup, +0, e ]  */
void moon_defobject( lua_State* L,
                     char const* metatable_name,
                     size_t userdata_size,
                     luaL_Reg const* methods,
                     int nup );

This function creates a new metatable and registers the functions in the luaL_Reg array (functions starting with double underscores __ go into the metatable, functions starting with a fullstop . are setup as properties, and the rest goes into a table used by the __index metafield). Property functions act as __index and __newindex functions at the same time, i.e. they should return a value when called with two arguments, and assign the third value when called with three. If the luaL_Reg array also contains an __index and/or __newindex function, those functions are called as fallbacks when method/property lookup has failed. In case a metatable with the given name already exists, an error is raised. The userdata_size is stored in the metatable for the moon_newobject function -- use a size of 0 to prohibit use of moon_newobject (e.g. for incomplete types). If nup is non-zero, it pops those upvalues from the current Lua stack top and makes them available to all registered functions (metamethods, property functions, and methods). A __gc metamethod and a default __tostring metamethod are provided by moon_defobject as well.

moon_newobject

/*  [ -0, +1, e ]  */
void* moon_newobject( lua_State* L,
                      char const* metatable_name,
                      moon_object_destructor destructor );

This function allocates a userdata, sets a metatable, and stores the cleanup function for later use by the __gc metamethod or the moon_killobject function. It throws an error if the metatable_name has not been registered via the moon_defobject function. The new userdata object is pushed to the top of the Lua stack, and a pointer to the payload (not the moon_object_header structure) is returned.

moon_newpointer

/*  [ -0, +1, e ]  */
void** moon_newpointer( lua_State* L,
                        char const* metatable_name,
                        moon_object_destructor destructor );

This function allocates a userdata suitable for storing a pointer, sets a metatable, and stores the cleanup function for later use by the __gc metamethod or the moon_killobject function. It is equivalent to moon_newobject with the difference that the payload is stored as a pointer, not inside the userdata memory. The pointer is initialized to NULL when this function returns, and may be set by assigning to the memory location pointed to by the return value.

moon_newfield

/*  [ -0, +1, e ]  */
void** moon_newfield( lua_State* L,
                      char const* metatable_name,
                      int idx,
                      int (*isvalid)( void* p ),
                      void* p );

This function allocates a userdata suitable for storing a pointer, and sets a metatable. It is similar to moon_newpointer, but it is intended for exposing a data structure embedded within another userdata (referenced by stack position idx). The resulting moon object keeps the parent userdata alive by storing a reference in its uservalue table. If idx is 0, no uservalue table is set. Setting a cleanup function is not possible, because the parent userdata is responsible for cleaning up memory and other resources. If an isvalid function pointer is provided, it is called by the moon_checkobject/moon_testobject functions to check whether the object is still valid. This can be used to make sure that a tagged union used as parent userdata still has the correct type, or that the parent userdata hasn't released any necessary resources prior to garbage collection. If the value referenced by idx is a moon object that also has an isvalid check registered, all checks are performed in the order from parent object(s) to child object.

moon_getmethods

/*  [ -0, +(0|1), e ]  */
int moon_getmethods( lua_State* L,
                     char const* tname );

If the metatable identified by tname has methods registered, pushes the methods table and returns LUA_TTABLE. Otherwise nothing is pushed and LUA_TNIL is returned. This function only works for moon objects and raises an error if the metatable tname wasn't registered via moon_defobject.

moon_killobject

/*  [ -0, +0, e ]  */
void moon_killobject( lua_State* L,
                      int idx );

If the moon object at the given stack index is valid, its cleanup function is run, and the object is marked as invalid (to prevent the cleanup function from running again). This function can be used to reclaim resources before the object becomes unreachable.

moon_defcast

/*  [ -0, +0, e ]  */
void moon_defcast( lua_State* L,
                   char const* tname1,
                   char const* tname2,
                   moon_object_cast cast );

Registers the conversion function cast for converting userdata objects of type tname1 to type tname2. The cast function is called automatically by moon_checkobject( L, idx, tname2 ) when applied to an object of type tname1, so function implementations can be reused without extra work. The metatable tname1 must already exist and belong to a moon object type (created via moon_defobject).

moon_checkobject

/*  [ -0, +0, v ]  */
void* moon_checkobject( lua_State* L,
                        int idx,
                        char const* metatable_name );

This function ensures that the value stored at stack index idx

  1. is a full userdata
  2. is a moon object
  3. has the metatable identified by metatable_name or has a cast function to metatable_name registered
  4. has the MOON_OBJECT_IS_VALID flag set
  5. all isvalid functions return a non-zero value (for objects created via moon_newfield)
  6. contains a non-NULL pointer value (for objects created via moon_newpointer or moon_newfield).

If any of those conditions are false, an error is raised. Otherwise this function returns a pointer to the object's memory (meaning the objects created via moon_newpointer and moon_newfield are dereferenced once, and if necessary the registered cast function is called).

moon_testobject

/*  [ -0, +0, e ]  */
void* moon_testobject( lua_State* L,
                       int idx,
                       char const* metatable_name );

Performs the same checks as moon_checkobject, but returns NULL if any of those conditions are false instead of raising an error.

moon_checkint

/*  [ -0, +0, v ]  */
lua_Integer moon_checkint( lua_State* L,
                           int idx,
                           lua_Integer min,
                           lua_Integer max );

This function works like luaL_checkinteger but additionally ensures that the given value is in the range [min, max], or else an error is thrown.

moon_optint

/*  [ -0, +0, v ]  */
lua_Integer moon_optint( lua_State* L,
                         int idx,
                         lua_Integer min,
                         lua_Integer max,
                         lua_Integer def );

Similar to moon_checkint but uses the default value def if the value at the given stack position is nil or none.

moon_atexit

/*  [ -0, +1, e ]  */
int* moon_atexit( lua_State* L,
                  lua_CFunction cleanup );

This function puts an integer-sized userdata (initialized to 0) in the registry and sets the given cleanup function as __gc metamethod. The userdata is also pushed to the top of the Lua stack, and returned as an int pointer. Use this function if you want to call a cleanup function when the Lua state is closed, but only if some initialization succeeded. The usual approach is as follows:

  1. Call moon_atexit registering your cleanup function.
  2. Do your initialization.
  3. If successful, you set the int pointer to non-zero, which is almost atomic and can't fail, and pop the userdata.
  4. When the cleanup function is called, check for a non-zero value before actually cleaning up.

moon_setuvfield

/*  [ -1, +0, e ]  */
void moon_setuvfield( lua_State* L,
                      int idx,
                      char const* key );

This function pops the value at the top of the stack and stores it under key in the environment/uservalue table of the object at stack position idx.

moon_getuvfield

/*  [ -0, +(0|1), e ]  */
int moon_getuvfield( lua_State* L,
                     int idx,
                     char const* key );

This function works similar to luaL_getmetafield, but it looks for key in the environment/uservalue table of the object at index idx, and pushes the corresponding value to the top of the stack. If there is no uservalue table or no such field, nothing is pushed and LUA_TNIL is returned. Otherwise, the return value is the type of the pushed value.

moon_getcache

/*  [ -0, +1, e ]  */
void moon_getcache( lua_State* L,
                    int idx );

This function looks up and pushes a weak-valued table under a private key in the table given by index idx (often LUA_REGISTRYINDEX). If the weak-valued table doesn't exist yet, it is created automatically. This function is useful to map lightuserdata to full userdata, but it can also be used to cache full userdata for enum values (using separate caches per enum type), etc.

moon_stack_assert

/*  [ -0, +0, v ]  */
void moon_stack_assert( lua_State* L,
                        ... );

This "function" is implemented as a macro that evaluates to void if NDEBUG is defined. If it is not, it tries to match the type specifications (strings) given as arguments to the values at the top of the Lua stack. Every mismatch is reported on stderr, and finally the whole Lua stack is dumped to stderr using the moon_stack function below, and an error is raised. Currently the following type specifications are supported:

  • "n": nil
  • "b": boolean
  • "l": lightuserdata
  • "i": integer (equivalent to "d" before Lua 5.3)
  • "d": number (think double)
  • "s": string
  • "t": table
  • "f": function
  • "u": userdata
  • "c": coroutine
  • "a": any (non-nil) value

You can combine the single letter options to express alternatives, so e.g. "tf" means: table or function.

moon_stack

/*  [ -0, +0, - ]  */
void moon_stack( lua_State* L );

This "function" is also implemented as a macro that evaluates to void in case NDEBUG is defined. Otherwise it prints the current contents of the Lua stack in human-readable format to stderr.

moon_absindex

Compatiblity macro for lua_absindex, but also available on Lua 5.1 as a function.

moon_derive

int moon_derive( lua_State* L );

A lua_CFunction that may be registered as part of your module and allows Lua code to subclass a moon object. When called it expects two strings as arguments: a new (non-existing) type name and an old (existing) type name of a moon object type. It sets up the new type name as an alias to the old type but with a different methods table. The new methods table (initially a copy of the methods of the old type) is returned.

moon_downcast

int moon_downcast( lua_State* L );

A lua_CFunction that may be registered as part of your module and allows Lua code to change the type of a moon object to a type created via moon_derive. It is typically used in constructors of derived types, and expects a moon object and the new type name as arguments. If successful, the object (with its metatable replaced) is returned.

moon_flag.h

moon_flag.h is a macro file, that can be included multiple times and each time defines a new userdata type as a type-safe representation of a given enum/flag type in Lua. The resulting userdata values support + (bitwise or, in Lua 5.3 also |), - (create a new value with certain bits cleared), and calling (test if all bits are set). For Lua 5.3 also bitwise "and" and bitwise "not" are defined. Parameters are passed as macros before including the macro file. Any arguments and all internal macros are #undefed before leaving the macro file. The following parameters are recognized:

  • MOON_FLAG_NAME (required): A metatable name used for defining a userdata type.
  • MOON_FLAG_TYPE (required): The underlying enum/flag type that is handled by the custom userdata.
  • MOON_FLAG_SUFFIX (required): All defined functions have this suffix (and the moon_flag_ prefix) to make them unique.
  • MOON_FLAG_NOBITOPS (optional): If this macro is defined, no metamethods for bitwise operations are created. This includes __add, __sub, and __call metamethods. If you do this, you should think about using strings and luaL_checkoption instead of userdata for representing your flags in Lua.
  • MOON_FLAG_NORELOPS (optional): If this macro is defined, the __eq metamethod is not created.
  • MOON_FLAG_USECACHE (optional): The constructor function for this flag looks in a local cache before creating a new full userdata, and returns the cached value if possible. This way each enum/flag value has at most one userdata associated with it.
  • MOON_FLAG_EQMETHOD( _a, _b ) (optional): If you need a custom comparison operation instead of the usual ==, define this macro.

The following (static) functions will be defined, unless they are disabled via one of the parameter macros above:

/*  [ -0, +0, e ]  */
void moon_flag_def_SUFFIX( lua_State* L );
/*  [ -0, +1, e ]  */
void moon_flag_new_SUFFIX( lua_State* L, TYPE value );
/*  [ -0, +0, v ]  */
TYPE moon_flag_get_SUFFIX( lua_State* L, int idx );

int moon_flag_add_SUFFIX( lua_State* L );
int moon_flag_sub_SUFFIX( lua_State* L );
int moon_flag_call_SUFFIX( lua_State* L );
int moon_flag_and_SUFFIX( lua_State* L ); /* Lua 5.3+ */
int moon_flag_not_SUFFIX( lua_State* L ); /* Lua 5.3+ */
int moon_flag_eq_SUFFIX( lua_State* L );

The last six are metamethods and not supposed to be called from C. moon_flag_def_SUFFIX defines the new type, creates the metatable and registers all metamethods. moon_flag_new_SUFFIX pushes a userdata representing the given value to the top of the Lua stack, while moon_flag_get_SUFFIX returns the corresponding enum value from a userdata on the Lua stack (or raises an error).

moon_dlfix.h

On Linux and BSDs (and possibly other Unix machines) binary extension modules aren't linked to the Lua library directly, but instead expect the main executable to reexport the Lua API. If you don't have control over the main executable (e.g. you are writing a plugin for a 3rd party program), you are out of luck. This header file tries to reexport the Lua API from the shared library linked to your plugin to make it available for extension modules. It relies on some platform specific tricks, so it probably won't work everywhere.

MOON_DLFIX

#define MOON_DLFIX()

This macro uses the dynamic linker to search for the Lua API in an already loaded shared library and reexport it for extension modules. If the necessary linker tricks don't work on the given platform, this macro evaluates to a void expression, and you will continue to get the usual unresolved symbol errors when loading a binary extension module.

MOON_DLFIX_LIBNAME

If the builtin heuristics fail to find the shared Lua library you can specify the library name/path by defining this macro.

MOON_DLFIX_LIBPREFIX

For some OSes all loaded shared libraries is searched for an ELF object that contains the Lua symbols. Since this procedure also finds shared objects that have the Lua library as a dependency, the library name is checked for a known prefix to make sure that only the actual Lua library is exported. The default is "liblua", but you can change it by defining this macro.

Contact

Philipp Janda, siffiejoe(a)gmx.net

Comments and feedback are always welcome.

License

moon is copyrighted free software distributed under the Tiny license. The full license text follows:

moon (c) 2013-2016 Philipp Janda

You may do anything with this work that copyright law would normally
restrict, so long as you retain the above notice(s) and this license
in all redistributed copies and derived works.  There is no warranty.

lua-moon's People

Contributors

siffiejoe 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

Watchers

 avatar  avatar  avatar  avatar

Forkers

yuhangwang

lua-moon's Issues

How to wrap a struct instantiated in C?

I have a struct that I have instantiated in C. I would like to instantiate this from C, push it into Lua such that I can call moon_checkobject() and return it from the stack again, as well as call the instance methods that I've attached using moon_defobject().

I was unable to do this using the stock lua-moon functions. Here is a bit of code showing the gist.

struct MyObject
{
    int x;
    int y;
};

int luaopen_MyObject(lua_State* L)
{
    luaL_Reg const _instance_methods[] = {
        { "__index", __index },
        { "__newindex", __newindex },
        { "SomeMethod", someMethod},
        { NULL, NULL }
    };
    luaL_Reg const _static_methods[] = {
        { "new", __new },
        { NULL, NULL }
    };
    moon_defobject(L, "MyObject", sizeof(struct MyObject), _instance_methods, 0);
    lua_newtable(L);
    luaL_setfuncs(L, _static_methods, 0);
    return 1;
}

Later on, to "check" it from the Lua stack, I use moon_checkobject. This works

moon_checkobject(L, 1, "MyObject");

I also found moon_testobject(L, 1, "MyObject")

My problem comes when I attempt to do this:

struct MyObject *instance;
instance = calloc(1, sizeof(struct MyObject));
/* what do I call now to get it on to the stack and 
   properly associated with the object I defined with moon_defobject()?  
   moon_newobject() is not right*/

I know that I can push this object on to the stack as userdata. But that is going around lua-moon. It isn't getting me what I want (an object that I can add stuff to the metatable -- and it won't call the instance methods that way either)

I was able to get closer using my own "wrapper". But I'm not able to extend my objects from lua yet. The metatable was not accessible through my wrapper. I could amend the wrapper, but I was wondering instead if I have just misunderstood the lua-moon api. Maybe there's an existing way to do this. Underneath, it looks like lua-moon is doing a wrapper thing already. (moon_object_header).

What is the proper way to do this with lua-moon? Must I strictly instantiate my class using moon_newobject()? I'm hoping that isn't the case (since the wrapper I made already almost does everything)

I didn't see anything like a moon_wrapobject or moon_castobject or something convenient. Maybe there's an idiomatic way to do this that I'm missing?

Any advice?

Request to start tagging releases

I enjoy using your library. I was just wondering if you could start tagging some releases? I've been using the library on a little project for a year or so, I had a question and went back to GitHub to review the code so I can answer my question. But now I just noticed that the API has changed and there is not a tag for me to go back and reference the previous API. For instance, moon_checkudata and moon_testudata are gone now. I'm not entirely sure which commit represents the version that I'm using in my project so that I can go back and reference it. I'm going to figure that out by bisecting, so it's going to be OK. I just thought I'd toss in a friendly request to start tagging some releases.

Maybe this is just a reflection of the library not yet having any formal releases yet?

In any event, it's a nice library. Good job on it.

Add a __gc or destructor to be called when the gc fires

I have been doing memory cleanup manually (calloc/free). Now I'd like to give __gc a shot. I'm a little confused on how to set this up. When do it as follows, the __gc method is never called. In moon.c, I can see that there is a default __gc being added, but no way to add my own except for when I use moon_newobject. I am trying something like this...

int myobject_open(lua_State* L)
{
    luaL_Reg const _instance_methods[] = {
        { "__index", __index },
        { "__newindex", __newindex },
        { "__gc", __gc},
        { NULL, NULL }
    };
    luaL_Reg const _static_methods[] = {
        { "new", __new },
        { NULL, NULL }
    };
    moon_defobject(L, MYTYPENAME, sizeof(my_type), _instance_methods, 0);
    lua_newtable(L);
    luaL_setfuncs(L, _static_methods, 0);
    return 1;
}

Later, the __gc method is not being called.

I haven't been using moon_newobject() and maybe that's the problem. Instead, at certain points in my program, I am callocing structs and then passing them as lua objects. I would prefer to continue that.

cast between incompatible function types from ‘moon_object_cast’

I've come across an issue while compiling. I have been looking at this project in some time (just came back to it). I wanted to document this issue. I've upgraded moon and lua to latest versions.

In file included from /home/user/project1/contrib/lua-moon/moon.h:19,
                 from /home/user/project1/contrib/lua-moon/moon.c:14:
/home/user/project1/contrib/lua-moon/moon.c: In function ‘moon_defcast’:
/home/user/project1/contrib/lua-moon/moon.c:528:25: error: cast between incompatible function types from ‘moon_object_cast’ {aka ‘void * (*)(void *)’} to ‘int (*)(lua_State *)’ {aka ‘int (*)(struct lua_State *)’} [-Werror=cast-function-type]
   lua_pushcfunction( L, (lua_CFunction)cast );
                         ^
/home/user/project1/build/packages/lua/src/lua-5.3.5/src/lua.h:350:53: note: in definition of macro ‘lua_pushcfunction’
 #define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0)

How to extend an object

I'd like to extend my objects. I'm not sure how to do this.

My Lua code resembles this:

    local _C = {}
    -- shouldn't I be setting the metatable here?

    -- this is called from C
    function _C:setup()
        print(self.name) -- this works fine
        self:some_method_in_c() -- this works fine

        -- this fails
        self:hello_world()
    end

    function _C:hello_world()
        print('Hello, World')
    end

    return _C

In C, I do something like this to load the script file. (1 file == 1 extended object)

    struct MyObject *load_my_object(const char *contents_of_lua_file)
    {
        struct MyObject my_object = malloc(...)

        /* initialize my_object */

        r == luaL_dostring(L, contents_of_lua_file);
        if (r != LUA_OK)
            /* error handling*/

        /* then save the object into the registry */
        my_object->saved_lua_index = luaL_ref(L, LUA_REGISTRYINDEX);
    }

Later on, when I go to call the setup function from C:

void call_setup(struct MyObject *my_object)
{
    void **p;

    lua_rawgeti(L, LUA_REGISTRYINDEX, my_object->saved_lua_index);

    lua_getfield(L, -1, "setup");
    if(!lua_isfunction(L, -1))
    {
        /* error handling */
    }

    /* push self (WRONG OBJECT) */
    p = moon_newpointer(L, "MyObject", 0);
    *p = my_object;

    if (LUA_OK != lua_pcall(L, 1, 0, 0))
    {
        /* error handling */
    }
}

This is no good because "self" is my_object. It should be _C (from the Lua script).

This is where my mental block arises. I think I should be passing _C as self, but then how do I setup the metatable in the Lua script back when I loaded it? I suspect this is more of an implementation issue. Given my particular arrangement of things, where is the opportunity to setup the metatable in Lua? What would this code look like?

Is there a lua-moon idiom for extending an object from Lua?

Related to #2, is there a way to extend the object without implementing __newindex in C?

struct MyObject *instance;
instance = calloc(1, sizeof(struct MyObject));
*moon_newpointer(L, "MyObject", free) = instance;

And then in Lua

local instance = getInstanceCreatedOnCSide()
instance.x = 10

Currently it errors out saying attempt to index a userdata value.

I could implement a __newindex function in C to handle this (it's what I am currently doing)

I was wondering if there was an idiomatic way to do this.

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.