Giter VIP home page Giter VIP logo

multiloader-template's Introduction

MultiLoader Template

This project provides a Gradle project template that can compile Minecraft mods for multiple modloaders using a common project for the sources. This project does not require any third party libraries or dependencies. If you have any questions or want to discuss the project, please join our Discord.

Getting Started

IntelliJ IDEA

This guide will show how to import the MultiLoader Template into IntelliJ IDEA. The setup process is roughly equivalent to setting up the modloaders independently and should be very familiar to anyone who has worked with their MDKs.

  1. Clone or download this repository to your computer.
  2. Configure the project by setting the properties in the gradle.properties file. You will also need to change the rootProject.name property in settings.gradle, this should match the folder name of your project, or else IDEA may complain.
  3. Open the template's root folder as a new project in IDEA. This is the folder that contains this README.md file and the gradlew executable.
  4. If your default JVM/JDK is not Java 21 you will encounter an error when opening the project. This error is fixed by going to File > Settings > Build, Execution, Deployment > Build Tools > Gradle > Gradle JVM and changing the value to a valid Java 21 JVM. You will also need to set the Project SDK to Java 21. This can be done by going to File > Project Structure > Project SDK. Once both have been set open the Gradle tab in IDEA and click the refresh button to reload the project.
  5. Open your Run/Debug Configurations. Under the Application category there should now be options to run Fabric and NeoForge projects. Select one of the client options and try to run it.
  6. Assuming you were able to run the game in step 5 your workspace should now be set up.

Eclipse

While it is possible to use this template in Eclipse it is not recommended. During the development of this template multiple critical bugs and quirks related to Eclipse were found at nearly every level of the required build tools. While we continue to work with these tools to report and resolve issues support for projects like these are not there yet. For now Eclipse is considered unsupported by this project. The development cycle for build tools is notoriously slow so there are no ETAs available.

Development Guide

When using this template the majority of your mod should be developed in the common project. The common project is compiled against the vanilla game and is used to hold code that is shared between the different loader-specific versions of your mod. The common project has no knowledge or access to ModLoader specific code, apis, or concepts. Code that requires something from a specific loader must be done through the project that is specific to that loader, such as the fabric or neoforge projects.

Loader specific projects such as the fabric and neoforge project are used to load the common project into the game. These projects also define code that is specific to that loader. Loader specific projects can access all the code in the common project. It is important to remember that the common project can not access code from loader specific projects.

Removing Platforms and Loaders

While this template has support for many modloaders, new loaders may appear in the future, and existing loaders may become less relevant.

Removing loader specific projects is as easy as deleting the folder, and removing the include("projectname") line from the settings.gradle file. For example if you wanted to remove support for forge you would follow the following steps:

  1. Delete the subproject folder. For example, delete MultiLoader-Template/forge.
  2. Remove the project from settings.gradle. For example, remove include("forge").

multiloader-template's People

Contributors

aegide avatar algorithmlx avatar azuredoom avatar cadiboo avatar darkhax avatar hubry avatar jaredlll08 avatar joel-paul avatar lukebemish avatar merchantpug avatar mramericanmike avatar spinoscythe avatar trikzon avatar vendoau avatar witixin1512 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

multiloader-template's Issues

compatibilityLevel in mixins files

So I'm not really familiar with the whole mixins ecosystem, but I see that the mixins files in common and forge have compatibilityLevel set to JAVA_18 and the ones in fabric and neoforge are set to JAVA_21

Is this intended?

(Minecraft 1.21)

Crash on any ./gradlew command

Crashes with:
symbol: class TagKey
location: class FuelRegistryImpl
C:\Users\myUser\Notebook\common\src\main\java\dev\bookkeepersmc\notebook\registry\content\impl\FuelRegistryImpl.java:117: error: cannot find symbol
public static void add(Map<Item, Integer> map, TagKey tag, int i) {

About 150 of these errors, don't know why. Worked fine and then just started with these problems.

[1.19] Unreachable Minecraft packages and classes when using Fabric

Heyo,

I am currently trying to make use of the 1.19 branch of this template in order to create a basic mod which simply adds a couple of blocks.
The Forge-aspect of the template is working as expected, but I am running into a wall when it comes to Fabric.

  1. I've cloned the repo
  2. ran Your Project > Common > Tasks > vanilla gradle > decompile
  3. ran Your Project > Forge > Tasks > forgegradle runs > genIntellijRuns

and then went on to add Blocks for 1.19.2 to Fabric as shown on the Fabric wiki and on Kaupenjoes Fabric 1.19 Tutorial.

This is where the trouble begins and I do not know where the problem is:

I can not call new Identifier(...), IntelliJ IDEA can not find or access net.minecraft.util.Identifier. My IntelliJ IDEA version is IntelliJ IDEA 2023.2.4

I'm using the following verions set in my gradle.properties

minecraft_version=1.19.2

# Forge
forge_version=43.2.21
forge_loader_version_range=[43,)
forge_version_range=[43,)
minecraft_version_range=[1.19,)

# Fabric
fabric_version=0.76.1+1.19.2
fabric_loader_version=0.14.24

Would anyone here happen to know what the cause of this might be, or would anyone be able to help with this?

Cheers,
Griefed

Package 'net.minecraft.client' does not exist

Versions:

  • Java: 17.0.8.1 (Eclipse Adoptium 17.0.8.1+1)
  • Gradle: 8.1.1
  • Groovy: 3.0.15
  • OS: Windows 10 10.0 amd64

Template:

  • Branch: 1.20.2

Error:

Screenshot 2023-12-20 160717


This is a fresh start of the MultiLoader Template, I haven't changed a single value I just ran these operations:

  • Your Project > Common > Tasks > vanilla gradle > decompile
  • Your Project > Forge > Tasks > forgegradle runs > genIntellijRuns
  • Your Project > Forge > Tasks > forgegradle runs > Client

1.20.2 gradle problems with common

every time i'm trying to start up a project the common main keeps getting these errors
:common:main: Could not find org.spongepowered:mixin:0.8.5. Required by: project :common :common:main: Could not find com.google.code.findbugs:jsr305:3.0.1. Required by: project :common :common:main: Could not resolve net.minecraft:joined:1.20.2. Required by: project :common :common:test: Could not find com.google.code.findbugs:jsr305:3.0.1. Required by: project :common :common:test: Could not resolve net.minecraft:joined:1.20.2. Required by: project :common
when trying to run the decompile i get
`Execution failed for task ':common:decompile'.

Failed to calculate the value of task ':common:decompile' property 'javaLauncher'.
Failed to calculate the value of property 'languageVersion'.
> Could not resolve all artifacts for configuration ':common:decompiler'.
> Could not find org.vineflower:vineflower:1.10.1.
Required by:
project :common
`

Show an example of calling back into platform specific code

In Patchouli and Botania, we use a serviceloader interface called IXplatAbstractions, implemented once by each loader, to allow down calls from Common code back into loader-specific code. This is probably something that is needed often enough that this template should probably have an example of it.

Lots of errors and warnings, and a question

I was trying to develop a mod using this template and in the build.gradle files, lots of warnings were coming up about plugins and compileOnly project(":common").
Do not know why this is happening.

And a question:
On other multiloader projects, NOT architectury, when they add a Non-full block with Official Mappings or ParchmentMC, the constructor says public. On my project, these classes have a protected constructor, so I can't use them. Does anyone know why this is happening and how to fix it? I have already run Common/decompile.

Maven Publishing

The current Maven publishing configuration has a few issues and will require some changes to work with a multiproject setup. It looks like you've fixed most of these in your Clumps implementation but I would like to see some of these changes backported here.

Common Artifacts

The Common artifacts are not published currently. While normal Forge and Fabric mods can still use MultiLoader projects without the Common artifacts other MultiLoader projects would greatly benefit from having them available. For example imagine writing a CraftTweaker addon in a MultiLoader project. It would make sense for this addon to define new ZenCode natives in the Common project. The same would be true for a GameStage or WAILA addon.

Inconsistent Artifact Coordinates

The artifact coordinates for the Forge and Fabric artifacts are not consistent. The version number also differs between version and structure. There would be a lot to gain from standardizing this, especially now that we publish so many artifacts and other MultiLoader projects will be defining them three times. One benefit would be that it becomes easier to share coordinates with others, and make it easier to locate when traversing the maven manually. This will also aid in creating 3rd party tools or helpers to lookup artifacts. For example a helper method that accepts a group, project name, and version and will automatically create dependencies using the template "${group}:${name}-${platform}-${mc_version}:${version}" in the correct subprojects.

My proposed changes would include the following.

  • Group keeps the same structure. If there were any loader-specific references here they should be removed.
  • Name should be suffixed with the platform name (forge/fabric/common) and include the game version.
  • Version should continue on from the highest major version. So if Forge is 1.0.2 and Fabric is 8.0.12 the next joint release should become 9.0.13 for both.

Old Artifact Coordinates

// https://maven.blamejared.com/com/blamejared/clumps/Clumps/6.0.0.27/
group:'com.blamejared.clumps', name:'Clumps', version:'6.0.0.27'

// https://maven.blamejared.com/com/blamejared/clumps/Clumps-fabric-1.17.1/7.0.8/
group:'com.blamejared.clumps', name:'Clumps-fabric-1.17.1', version:'7.0.8'

New Artifact Coordinates

// https://maven.blamejared.com/com/blamejared/clumps/Clumps/6.0.0.27/
group:'com.blamejared.clumps', name:'Clumps-forge-1.17.1', version:'7.0.9'

// https://maven.blamejared.com/com/blamejared/clumps/Clumps-fabric-1.17.1/7.0.8/
group:'com.blamejared.clumps', name:'Clumps-fabric-1.17.1', version:'7.0.9'

Misc Improvements

  • Gradle module file is still published but only for forge. Should be disabled for both.
  • Forge's mapped artifact suppression should no longer be needed.

Implementing test mod

Hey I'm trying to implement a testmod for each fabric and forge.
I tried multiple things now but I run into several problems when I try different things.

Goal is that fabric test sources have access to common test & main sources. Forge test sources should have access to common test & main. And common test has access to main sources.

My tries:

Using testFixtures:

Instead of common test a testFixtures sourceset exists. From the gradle wiki it tells that testFixtures has access to main but they don't have and I could not figure out why.

Dependency to sourceSets example:

adding this to Fabric and Forge gradle:
Sources seems to have access to each other. At least I don't have errors in the IDE.

    testImplementation project(":Common").sourceSets.main.output
    testImplementation project(":Common").sourceSets.test.output

###Runconfig for Fabric:
-> Results into fabric just starts without the test mod loaded.

        testClient {
            client()
            source = sourceSets.test
            setConfigName("Test Minecraft Client")
            ideConfigGenerated(true)
            runDir("../run")
        }

Runconfig for Forge:

--> Crashes because some packages are exported by multiple mods. I assume it's because the mod or the testmod exports the same package? The package names are different. So I don't really understand whats happening here.

        clientTest {
            parent runs.client
            environment 'MOD_CLASSES', 'dummy' // From Forge: FG will replace this but it's needed to run
            mods {
                modClientRun {
                    source sourceSets.main
                    source project(":Common").sourceSets.main
                }
                "${mod_id}_test" {
                    source sourceSets.test
                    source project(":Common").sourceSets.test
                }
            }
        }

When I look into the build folders the resources are correct and the mods have their mods.toml or fabric.mod.json file.

I mostly tried to learn from this and the links they added: https://stackoverflow.com/questions/5644011/multi-project-test-dependencies-with-gradle

And sorry for my english ._.'

Help using loom in common module

Hello, I have attempted changing my common module to use fabric loom, but I get an error when running the game that I can't solve.

The TLDR of why I want to do this is two reasons. First, the supposed performance improvements. However more importantly, I want to create a new module which my fabric module would depend on that would itself depend on the fabric api. When trying to create this module, I get the same error.

Attempt

You can view my attempt here: dodogang@e4882ea

However, the only changes are in the Common/build.gradle

plugins {
-   id 'org.spongepowered.gradle.vanilla' version '0.2.1-SNAPSHOT'
+   id 'fabric-loom' version '0.12-SNAPSHOT'
}
dependencies {
+   minecraft "com.mojang:minecraft:${minecraft_version}"
+   mappings loom.officialMojangMappings()
+
    compileOnly group:'org.spongepowered', name:'mixin', version:'0.8.5'
    implementation group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.1'
}

However, this gives the following error when running both Fabric Client and Forge Client

Circular dependency between the following tasks:
:Common:prepareRemapJar
\--- :Fabric:jar
     \--- :Fabric:classes
          \--- :Fabric:compileJava
               \--- :Common:remapJar
                    \--- :Common:prepareRemapJar (*)

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.

The full build output is provided here, however it doesn't give much more information than what is above.

I have exhausted my knowledge of gradle today trying to figure out why this error is occurring. I expect there is a loom flag I don't know about that would solve this. Either way, if you have a lead on what can fix this error I'd love to here it :)

Setup fails on Mac with Loom 0.11-SNAPSHOT

When attempting to load/reload the project with IDEA on Mac, setup fails with the following error:

Could not determine the dependencies of task ':Fabric:configureClientLaunch'.
> Could not create task ':Fabric:extractNatives'.
   > Could not create task of type 'ExtractNativesTask'.
      > Could not resolve all files for configuration ':Fabric:minecraftNatives'.
         > Could not find java-objc-bridge-1.0.0-natives-osx.jar (ca.weblite:java-objc-bridge:1.0.0).
           Searched in the following locations:
               https://repo.maven.apache.org/maven2/ca/weblite/java-objc-bridge/1.0.0/java-objc-bridge-1.0.0-natives-osx.jar

Possible solution:
 - Declare repository providing the artifact, see the documentation at https://docs.gradle.org/current/userguide/declaring_repositories.html

This does not occur with a normal Fabric setup on the same machine. Tested by loading the Fabric Example Mod, which also uses Loom 0.11.

Workaround:
Switch back to Loom 0.10-SNAPSHOT.

Registering Screen handlers?

Registering screen handlers in common module:

Fabric goes like this:

    public static final MenuType<MyScreenHandler> MY_SCREEN_HANDLER =
            Registry.register(BuiltInRegistries.MENU, new ResourceLocation(MyMod.MOD_ID, "my_screem"),
                    new ExtendedScreenHandlerType<>(MyScreenHandler::new));

And like this in forge:

    public static final DeferredRegister<MenuType<?>> MENUS =
            DeferredRegister.create(ForgeRegistries.MENU_TYPES, MyMod.MOD_ID);

    public static final RegistryObject<MenuType<MyScreen>> MY_SCREEN =
            registerMenuType("my_screen", MyScreen::new);


    private static <T extends AbstractContainerMenu> RegistryObject<MenuType<T>> registerMenuType(String name, IContainerFactory<T> factory) {
        return MENUS.register(name, () -> IForgeMenuType.create(factory));
    }

    public static void register(IEventBus eventBus) {
        MENUS.register(eventBus);
    }

How do you make this in common? Both use loader-specific resources, and common cannot use these resources.

Parchment mappings

Currently, parchment mappings cannot be used on MultiLoader-Template, as the Common project uses vanillagradle, which only supports mojang mappings. This means that when, for instance, navigating code in IntelliJ, code in the Common part will link to the normal, mojmaps-without-parameter-names mappings, even if the Forge or Fabric buildscripts are changed to use parchment. This could be fixed by switching the Common setup to use loom, though I am not sure what other routes might be possible. I do know that there is currently a pull request draft for mapping support open on vanillagradle, but I am not sure what the timeline looks like for that.

1.19 - Unable to resolve gradle dependencies

Starting this morning, I'm starting to see an error like this across all my multiloader projects:

I get the same error pulling the 1.19 branches from here and running build.

No changes on my end to any of the build.gradle files -- it appears any dependency i put in my common module's build.gradle will throw a similar error.

> Could not resolve all files for configuration ':Common:compileClasspath'.
   > Could not resolve net.minecraft:joined:1.19.2.
     Required by:
         project :common
      > Could not resolve all files for configuration ':common:mergetool'.
         > Could not find net.minecraftforge:mergetool:1.2.3.
           Required by:
               project :common

I have the suspicion that mergetool is the real culprit for this given all the mess over at forge lately.

No "runs" generated for Forge

Following the guide I see that at the end it mentions:

 Under the `Application` category there should now be options to run Fabric and NeoForge projects.

Is there a reason as to why the options to run Forge are not generated?

Forge build fails with Index 0 out of bounds for length 0

When using a fresh clone of the multi loader template, ForgeGradle is running into an odd exception in reobfJar during build. I've tried experimenting with removing certain parts of the template, but couldn't pinpoint what exactly is causing the issue.

org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':forge:reobfJar'.
        ...
Caused by: java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0
        ...
        at net.minecraftforge.srgutils.InternalUtils.loadNamed(InternalUtils.java:39)
        at net.minecraftforge.srgutils.InternalUtils.load(InternalUtils.java:28)
        at net.minecraftforge.srgutils.IMappingFile.load(IMappingFile.java:27)
        at net.minecraftforge.srgutils.IMappingFile.load(IMappingFile.java:22)
        at net.minecraftforge.gradle.userdev.tasks.RenameJarInPlace.apply(RenameJarInPlace.java:66)

Full Stacktrace

Also reported at MinecraftForge/ForgeGradle#937

Setting up Yarn mappings?

How would I set up yarn mappings for this? I'd like to stick with the mappings I'm familiar with and also setup some older Fabric projects with this template.

Fabric's mapping changing is straightforward but I'm stuck on the Forge part as I require a channel and a MC version, is there an alternative to Architectury Loom that I have to use for such a task?

Could not parse version number component 'minecraft'!

I have this error with the following parameters:
#Project
version=1.0.0
group=com.example.examplemod
#Common
minecraft_version=1.20.1
#Forge
forge_version=47.1.3
#Fabric
fabric_version=0.87.0+1.20.1
fabric_loader_version=0.14.2
#Mod options
mod_name=ExampleMod
mod_author=Jared
mod_id=examplemod
#Gradle
org.gradle.jvmargs=-Xmx3G
org.gradle.daemon=false

[18:07:44] [main/INFO] (FabricLoader/GameProvider) Loading Minecraft [email protected]_20_1.layered+hash.2198-v2 with Fabric Loader 0.14.2
[18:07:44] [main/DEBUG] (FabricLoader/GamePatch) Found game constructor: net.minecraft.client.main.Main -> net.minecraft.client.Minecraft
[18:07:44] [main/DEBUG] (FabricLoader/GamePatch) Patching game constructor <init>(Lnet/minecraft/client/main/GameConfig;)V
[18:07:44] [main/DEBUG] (FabricLoader/GamePatch) Run directory field is thought to be net/minecraft/client/Minecraft/gameDirectory
[18:07:44] [main/DEBUG] (FabricLoader/GamePatch) Applying brand name hook to net/minecraft/client/ClientBrandRetriever::getClientModName
[18:07:44] [main/DEBUG] (FabricLoader/GamePatch) Applying brand name hook to net/minecraft/server/MinecraftServer::getServerModName
[18:07:44] [main/DEBUG] (FabricLoader/GamePatch) Patched 3 classs
[18:07:44] [main/ERROR] (FabricLoader) Uncaught exception in thread "main"
java.lang.RuntimeException: net.fabricmc.loader.api.VersionParsingException: Could not parse version number component 'minecraft'!
	at net.fabricmc.loader.impl.metadata.BuiltinModMetadata$Builder.<init>(BuiltinModMetadata.java:177) ~[fabric-loader-0.14.2.jar:?]
	at net.fabricmc.loader.impl.game.minecraft.MinecraftGameProvider.getBuiltinMods(MinecraftGameProvider.java:114) ~[fabric-loader-0.14.2.jar:?]
	at net.fabricmc.loader.impl.discovery.ModDiscoverer.discoverMods(ModDiscoverer.java:118) ~[fabric-loader-0.14.2.jar:?]
	at net.fabricmc.loader.impl.FabricLoaderImpl.setup(FabricLoaderImpl.java:210) ~[fabric-loader-0.14.2.jar:?]
	at net.fabricmc.loader.impl.FabricLoaderImpl.load(FabricLoaderImpl.java:187) ~[fabric-loader-0.14.2.jar:?]
	at net.fabricmc.loader.impl.launch.knot.Knot.init(Knot.java:148) ~[fabric-loader-0.14.2.jar:?]
	at net.fabricmc.loader.impl.launch.knot.Knot.launch(Knot.java:68) ~[fabric-loader-0.14.2.jar:?]
	at net.fabricmc.loader.impl.launch.knot.KnotClient.main(KnotClient.java:23) ~[fabric-loader-0.14.2.jar:?]
	at net.fabricmc.devlaunchinjector.Main.main(Main.java:86) ~[?:?]
Caused by: net.fabricmc.loader.api.VersionParsingException: Could not parse version number component 'minecraft'!
	at net.fabricmc.loader.impl.util.version.SemanticVersionImpl.<init>(SemanticVersionImpl.java:113) ~[fabric-loader-0.14.2.jar:?]
	at net.fabricmc.loader.impl.util.version.VersionParser.parseSemantic(VersionParser.java:45) ~[fabric-loader-0.14.2.jar:?]
	at net.fabricmc.loader.impl.metadata.BuiltinModMetadata$Builder.<init>(BuiltinModMetadata.java:175) ~[fabric-loader-0.14.2.jar:?]
	... 8 more
Caused by: java.lang.NumberFormatException: For input string: "minecraft"
	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:67) ~[?:?]
	at java.lang.Integer.parseInt(Integer.java:668) ~[?:?]
	at java.lang.Integer.parseInt(Integer.java:786) ~[?:?]
	at net.fabricmc.loader.impl.util.version.SemanticVersionImpl.<init>(SemanticVersionImpl.java:107) ~[fabric-loader-0.14.2.jar:?]
	at net.fabricmc.loader.impl.util.version.VersionParser.parseSemantic(VersionParser.java:45) ~[fabric-loader-0.14.2.jar:?]
	at net.fabricmc.loader.impl.metadata.BuiltinModMetadata$Builder.<init>(BuiltinModMetadata.java:175) ~[fabric-loader-0.14.2.jar:?]
	... 8 more

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.