Giter Club home page Giter Club logo

commodore's People

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

commodore's Issues

Unable to parse argument type: minecraft:player

Hello,

I would like to use commodore and commodore files with my plugin, but when I start the server and the plugin is loaded, I get the following error: Unable to parse argument type: minecraft:player (at line 2).

I use as server software Paper 1.19.3 with the 1.19.4 comes the same error.

Java can't find CommodoreFileReader (ClassNotFoundException)

So I'm trying to implement the api with my current paper Plugin, but I get this error, no matter what I try.

java.lang.NoClassDefFoundError: me/lucko/commodore/file/CommodoreFileReader at sh.plunzi.plunzichatplugin.PlunziChatPlugin.registerCompletions(PlunziChatPlugin.java:120) ~[PlunziChatPlugin-6.9.jar:?] at sh.plunzi.plunzichatplugin.PlunziChatPlugin.register(PlunziChatPlugin.java:113) ~[PlunziChatPlugin-6.9-420.jar:?] at sh.plunzi.plunzichatplugin.PlunziChatPlugin.onEnable(PlunziChatPlugin.java:52) ~[PlunziChatPlugin-6.9.jar:?] at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:264) ~[paper-api-1.18.1-R0.1-SNAPSHOT.jar:?] at org.bukkit.plugin.java.JavaPluginLoader.enablePlugin(JavaPluginLoader.java:370) ~[paper-api-1.18.1-R0.1-SNAPSHOT.jar:?] at org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManager.java:501) ~[paper-api-1.18.1-R0.1-SNAPSHOT.jar:?] at org.bukkit.craftbukkit.v1_18_R1.CraftServer.enablePlugin(CraftServer.java:562) ~[paper-1.18.1.jar:git-Paper-216] at org.bukkit.craftbukkit.v1_18_R1.CraftServer.enablePlugins(CraftServer.java:476) ~[paper-1.18.1.jar:git-Paper-216] at net.minecraft.server.MinecraftServer.loadWorld0(MinecraftServer.java:736) ~[paper-1.18.1.jar:git-Paper-216] at net.minecraft.server.MinecraftServer.loadLevel(MinecraftServer.java:503) ~[paper-1.18.1.jar:git-Paper-216] at net.minecraft.server.dedicated.DedicatedServer.initServer(DedicatedServer.java:313) ~[paper-1.18.1.jar:git-Paper-216] at net.minecraft.server.MinecraftServer.runServer(MinecraftServer.java:1211) ~[paper-1.18.1.jar:git-Paper-216] at net.minecraft.server.MinecraftServer.lambda$spin$0(MinecraftServer.java:317) ~[paper-1.18.1.jar:git-Paper-216] at java.lang.Thread.run(Thread.java:833) ~[?:?] Caused by: java.lang.ClassNotFoundException: me.lucko.commodore.file.CommodoreFileReader at org.bukkit.plugin.java.PluginClassLoader.loadClass0(PluginClassLoader.java:151) ~[paper-api-1.18.1-R0.1-SNAPSHOT.jar:?] at org.bukkit.plugin.java.PluginClassLoader.loadClass(PluginClassLoader.java:103) ~[paper-api-1.18.1-R0.1-SNAPSHOT.jar:?] at java.lang.ClassLoader.loadClass(ClassLoader.java:520) ~[?:?] ... 14 more

I have already tried packaging it as a shaded and a fat jar, neither of which did anything.
IntelliJ can find the class though and doesn't give me any errors either. So idk if I produce a bug in the api or am just not capable of using the api correctly

My code looks somewhat like this:

(Main class)

@Override
    public void onEnable() {
PluginCommand command = getCommand("color");
        command.setExecutor(new DebuggingCommand());

        if (CommodoreProvider.isSupported()) {

            // get a commodore instance
            Commodore commodore = CommodoreProvider.getCommodore(this);
            try {
                registerCompletions(commodore, command);
            } catch (IOException e) {
                Debug.throwException(e);
            }
        }
    }

...

private void registerCompletions(Commodore commodore, PluginCommand command) throws IOException {
        LiteralCommandNode<?> colorCommand = me.lucko.commodore.file.CommodoreFileReader.INSTANCE.parse(getResource("color.commodore"));
        commodore.register(command, colorCommand);

        commodore.register(command, LiteralArgumentBuilder.literal("color")
                .then(RequiredArgumentBuilder.argument("color-one", StringArgumentType.word()))
                .then(RequiredArgumentBuilder.argument("color-two", StringArgumentType.word()))
                .then(RequiredArgumentBuilder.argument("message", StringArgumentType.greedyString()))
        );
    }
...
(color.commodore file)

color {
  color_one brigadier:string single_word {
    color_two brigadier:string single_word {
        message brigadier:string greedy_phrase;
      }
  }
}

{bug} Commodore sends namespaced commands despite it being removed from the command list

Hello!

I have discovered a minor bug with commodore that would be nice to have fixed.

With normal Spigot commands, namespaced commands (ones that are like "pixelpatriots:tpa") can be removed by changing the "send-namespaced" to false in the spigot.yml file or by listening to PlayerCommandSendEvent and removing it from the command list.

With Commodore, however, despite having both these options enabled (spigot.yml send-namespaced set to false and removing the command from PlayerCommandSendEvent), the command is still in the command list.

Here are a few screenshots:
image
image
image

And yes, I have tried relogging and restarting the server. Neither have worked.

I also may have found the code responsible

if (command instanceof PluginCommand) {
String fallbackPrefix = ((PluginCommand) command).getPlugin().getName().toLowerCase().trim();
aliasesStream = aliasesStream.flatMap(alias -> Stream.of(
alias,
fallbackPrefix + ":" + alias
));

(though I'm not sure, as I don't 100% understand how it works)


June 2023 Edit

I also feel I should mention that this is not the case with normal Spigot/Paper commands. I can safely remove their namespaced versions without any trouble using both the options I mentioned above (i.e., spigot config file and PlayerCommandSendEvent).

1.19.1 support

Version 2.0 seems to have some issues with 1.19.1. The completion itself works fine, but when trying to execute the command, the game doesn't seem to recognize the command: Unknown or incomplete command, see below for error.
Removing the commodore registration fixes the issue.

Issue with suggestions

So I'm attempting to add suggestions to the commands like so

public class Commands {
	public static void register(PluginCommand command, Commodore commodore) {
		LiteralArgumentBuilder<Object> commandBuild = LiteralArgumentBuilder.literal("foo")
				.then(
					RequiredArgumentBuilder.argument("bar", StringArgumentType.string())
						.suggests((context, builder) -> {
							builder.suggest("bara");
							builder.suggest("barb");
							return builder.buildFuture();
						})
				);
		commodore.register(command, commandBuild);
		
	}
}

However when doing so, the only time a player is able to actually properly use the tab completion is when you reload the server while the players are online. If a player is to (re)join in, then it requires a reload in order for them to tab complete

Parameter hints when defocusing the tab suggestion box no longer appear without typing a character

The "hints" that appear indicating expected command arguments when you press escape to exit the box with tab suggestions no longer seem to appear as of 1.19 / new commodore versions. This affects LuckPerms, too.

Reproduce (using LP as an example, though you can use this library in another project and experience the same results).

  1. Fire up a server with the latest Luckperms running Paper (supporting commodore 2.1+)
  2. Type /luckperms user player permission set
  3. You will be presented with a list of tab suggestions. Press ESC to exit the window
  4. You should see the remaining parameters to enter on the command. Instead, you see an (incorrect) syntax error.

Example of this occurring with my plugin. Here, I've pressed ESC and expect the field name I am on "name" to appear as a hint; [<name>]
image

Expected result, with LuckPerms:
image

Actual result (Commodore 2.2 / Paper 69950d5 / Minecraft 1.19.1):
image

However, parameter hints will appear if you type a character into the field work.
image

This does not mirror Vanilla behavior, where hints are able to display even before typing a character.
image

Thank you for your work!

Reliably detect CommandDispatcher synchronisation

I glanced through the source code and saw that each registration was potentially re-obtaining a CommandDispatcher instance and scheduling a new task which seems hacky and is detrimental to performance.

May I suggest adding a listener for a ServerLoadEvent in the CommandoreImpl instead? The event is called after the server is loaded/reloaded and CommandDispatcher synchronisation by Spigot has been completed. That way the CommandDispatcher instance can be cached and the register method won't have to schedule a task to register the commands.

Detach .commodore parser into it's own project/repo.

This request is somewhat a Commodore and LuckPerms request at the same time, but since it's related to the .commodore parser it goes here.

So this is a request for my port of LuckPerms onto fabric (Here, it's almost ready to go except for brigadier completions).

I want to use the normal brigadier tree generated from the .commodore without the complexity of building my own tree for compatibility sakes with the rest of the code. However I cannot bundle commodore into the fabric jar for the obvious reason of bukkit interfaces and etc being present in the code.

One possible solution I suggest would be to detach the .commodore parser into a project both the main commodore project and my little LP spinoff [which I hope to PR in the near future] could use without risk of bundling libraries that shouldn't be there.

Of course I could lazily copy the parser code but that would do horribly for abstraction and likely cause rejection of PR.

Using commodore makes commands not usable with command blocks

When declaring a command in commodore, the command does not execute anymore in a command block, but still does work in chat.

A possible fix, like the current code do with setCustomSuggestionProvider, is to set the executes property of each command node to the instance of BukkitCommandWrapper (that also implements com.mojang.brigadier.Command).
I already tried that by manually doing it on a specific command, and it works properly now.

It seems that the execution of the command blocs is directly parsed with the vanilla CommandDispatcher of the server, instead of being parsed by the Bukkit command dispatcher.

StackOverflow when used in the /execute command

If you type a command like:
/execute as <your username here> run lp group

then you add a space to get tab completions, you get this stacktrace:

[00:21:23 ERROR]: Exception when test attempted to tab complete execute as test run lp group
org.bukkit.command.CommandException: Unhandled exception executing tab-completer for 'execute as test run lp group ' in org.bukkit.craftbukkit.v1_15_R1.command.VanillaCommandWrapper(execute)
        at org.bukkit.command.SimpleCommandMap.tabComplete(SimpleCommandMap.java:250) ~[patched_1.15.2.jar:git-Paper-143]
        
        at org.bukkit.craftbukkit.v1_15_R1.CraftServer.tabCompleteCommand(CraftServer.java:1757) ~[patched_1.15.2.jar:git-Paper-143]
        at org.bukkit.craftbukkit.v1_15_R1.CraftServer.tabComplete(CraftServer.java:1729) ~[patched_1.15.2.jar:git-Paper-143]
        at org.bukkit.craftbukkit.v1_15_R1.command.BukkitCommandWrapper.getSuggestions(BukkitCommandWrapper.java:49) ~[patched_1.15.2.jar:git-Paper-143]
        at com.mojang.brigadier.tree.ArgumentCommandNode.listSuggestions(ArgumentCommandNode.java:71) ~[patched_1.15.2.jar:git-Paper-143]
        at com.mojang.brigadier.CommandDispatcher.getCompletionSuggestions(CommandDispatcher.java:596) ~[patched_1.15.2.jar:git-Paper-143]
        at com.mojang.brigadier.CommandDispatcher.getCompletionSuggestions(CommandDispatcher.java:579) ~[patched_1.15.2.jar:git-Paper-143]
        at org.bukkit.craftbukkit.v1_15_R1.command.VanillaCommandWrapper.tabComplete(VanillaCommandWrapper.java:59) ~[patched_1.15.2.jar:git-Paper-143]
        at org.bukkit.command.SimpleCommandMap.tabComplete(SimpleCommandMap.java:244) ~[patched_1.15.2.jar:git-Paper-143]

        ... repeats a lot

Caused by: java.lang.StackOverflowError
        at com.google.gson.internal.LinkedTreeMap.<init>(LinkedTreeMap.java:60) ~[patched_1.15.2.jar:git-Paper-143]
        at com.google.gson.JsonObject.<init>(JsonObject.java:33) ~[patched_1.15.2.jar:git-Paper-143]
        at net.minecraft.server.v1_15_R1.IChatBaseComponent$ChatSerializer.serialize(IChatBaseComponent.java:345) ~[patched_1.15.2.jar:git-Paper-143]
        at net.minecraft.server.v1_15_R1.IChatBaseComponent$ChatSerializer.serialize(IChatBaseComponent.java:184) ~[patched_1.15.2.jar:git-Paper-143]
        at com.google.gson.internal.bind.TreeTypeAdapter.write(TreeTypeAdapter.java:81) ~[patched_1.15.2.jar:git-Paper-143]
        at com.google.gson.Gson.toJson(Gson.java:669) ~[patched_1.15.2.jar:git-Paper-143]
        at com.google.gson.Gson.toJson(Gson.java:648) ~[patched_1.15.2.jar:git-Paper-143]
        at com.google.gson.Gson.toJson(Gson.java:603) ~[patched_1.15.2.jar:git-Paper-143]
        at com.google.gson.Gson.toJson(Gson.java:583) ~[patched_1.15.2.jar:git-Paper-143]
        at net.minecraft.server.v1_15_R1.IChatBaseComponent$ChatSerializer.a(IChatBaseComponent.java:435) ~[patched_1.15.2.jar:git-Paper-143]
        at net.minecraft.server.v1_15_R1.Entity.bS(Entity.java:2886) ~[patched_1.15.2.jar:git-Paper-143]
        at net.minecraft.server.v1_15_R1.EntityHuman.lambda$c$5(EntityHuman.java:2000) ~[patched_1.15.2.jar:git-Paper-143]
        at net.minecraft.server.v1_15_R1.IChatBaseComponent.a(IChatBaseComponent.java:131) ~[patched_1.15.2.jar:git-Paper-143]
        at net.minecraft.server.v1_15_R1.EntityHuman.c(EntityHuman.java:1999) ~[patched_1.15.2.jar:git-Paper-143]
        at net.minecraft.server.v1_15_R1.EntityHuman.getScoreboardDisplayName(EntityHuman.java:1989) ~[patched_1.15.2.jar:git-Paper-143]
        at net.minecraft.server.v1_15_R1.Entity.getCommandListener(Entity.java:3167) ~[patched_1.15.2.jar:git-Paper-143]
        at org.bukkit.craftbukkit.v1_15_R1.command.VanillaCommandWrapper.getListener(VanillaCommandWrapper.java:68) ~[patched_1.15.2.jar:git-Paper-143]
        at org.bukkit.craftbukkit.v1_15_R1.command.VanillaCommandWrapper.tabComplete(VanillaCommandWrapper.java:55) ~[patched_1.15.2.jar:git-Paper-143]
        
        at org.bukkit.command.SimpleCommandMap.tabComplete(SimpleCommandMap.java:244) ~[patched_1.15.2.jar:git-Paper-143]
        at org.bukkit.craftbukkit.v1_15_R1.CraftServer.tabCompleteCommand(CraftServer.java:1757) ~[patched_1.15.2.jar:git-Paper-143]
        at org.bukkit.craftbukkit.v1_15_R1.CraftServer.tabComplete(CraftServer.java:1729) ~[patched_1.15.2.jar:git-Paper-143]
        at org.bukkit.craftbukkit.v1_15_R1.command.BukkitCommandWrapper.getSuggestions(BukkitCommandWrapper.java:49) ~[patched_1.15.2.jar:git-Paper-143]
        at com.mojang.brigadier.tree.ArgumentCommandNode.listSuggestions(ArgumentCommandNode.java:71) ~[patched_1.15.2.jar:git-Paper-143]
        at com.mojang.brigadier.CommandDispatcher.getCompletionSuggestions(CommandDispatcher.java:596) ~[patched_1.15.2.jar:git-Paper-143]
        at com.mojang.brigadier.CommandDispatcher.getCompletionSuggestions(CommandDispatcher.java:579) ~[patched_1.15.2.jar:git-Paper-143]
        at org.bukkit.craftbukkit.v1_15_R1.command.VanillaCommandWrapper.tabComplete(VanillaCommandWrapper.java:59) ~[patched_1.15.2.jar:git-Paper-143]
        
        ... repeats a lot

Add more information for beginners

I like the system of the .commodore file, but with it comes additional stuff which may seem hard to understand, especially if you're a beginner at understanding tab-completion and command suggestions.

What is quotable_phrase for? What does single_word change? Are colours changeable, or set?
Those are only a few of the many questions I had to ask about the file system itself. I can't imagine how it must feel like for people who want to use the code-version instead.

So having a separate wiki, where you list the various options and their respective usage would be a good way to give information to beginners who stumble upon this and wonder how to use it.

Server not supported on Paper 1.18.2

I'm running commodore w/ my plugin and it is crying and I can't figure out why. Below is my main class, and below that is my error. This is on paper #272

class Main : JavaPlugin() {
    companion object {
        lateinit var plugin: Main
        lateinit var db: Jedis
    }
    lateinit var commodore: Commodore

    override fun onEnable() {
        saveDefaultConfig()
        db = Jedis(config.getString("address"), config.getInt("port"))
        val auth = config.getString("auth")
        if (auth != null) db.auth(auth)

        commodore = CommodoreProvider.getCommodore(this)
        plugin = this

        enableFeatures()

        super.onEnable()
    }

    private fun enableFeatures() {
        //Punishments()
    }
}
[22:44:33 ERROR]: Error occurred while enabling rats v1.0.0 (Is it up to date?)
ninja.carter.rats.commodore.BrigadierUnsupportedException: Brigadier is not supported by the server.
        at ninja.carter.rats.commodore.CommodoreProvider.getCommodore(CommodoreProvider.java:73) ~[rats-1.0.0-all.jar:?]
        at ninja.carter.rats.Main.onEnable(Main.kt:24) ~[rats-1.0.0-all.jar:?]
        at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:264) ~[paper-api-1.18.2-R0.1-SNAPSHOT.jar:?]
        at org.bukkit.plugin.java.JavaPluginLoader.enablePlugin(JavaPluginLoader.java:370) ~[paper-api-1.18.2-R0.1-SNAPSHOT.jar:?]
        at org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManager.java:501) ~[paper-api-1.18.2-R0.1-SNAPSHOT.jar:?]
        at org.bukkit.craftbukkit.v1_18_R2.CraftServer.enablePlugin(CraftServer.java:559) ~[paper-1.18.2.jar:git-Paper-272]
        at org.bukkit.craftbukkit.v1_18_R2.CraftServer.enablePlugins(CraftServer.java:473) ~[paper-1.18.2.jar:git-Paper-272]
        at net.minecraft.server.MinecraftServer.loadWorld0(MinecraftServer.java:664) ~[paper-1.18.2.jar:git-Paper-272]
        at net.minecraft.server.MinecraftServer.loadLevel(MinecraftServer.java:431) ~[paper-1.18.2.jar:git-Paper-272]
        at net.minecraft.server.dedicated.DedicatedServer.initServer(DedicatedServer.java:316) ~[paper-1.18.2.jar:git-Paper-272]
        at net.minecraft.server.MinecraftServer.runServer(MinecraftServer.java:1163) ~[paper-1.18.2.jar:git-Paper-272]
        at net.minecraft.server.MinecraftServer.lambda$spin$0(MinecraftServer.java:315) ~[paper-1.18.2.jar:git-Paper-272]
        at java.lang.Thread.run(Thread.java:833) ~[?:?]
Caused by: java.lang.ExceptionInInitializerError
        at ninja.carter.rats.commodore.MinecraftArgumentTypes.<clinit>(MinecraftArgumentTypes.java:80) ~[rats-1.0.0-all.jar:?]
        at ninja.carter.rats.commodore.CommodoreProvider.checkSupported(CommodoreProvider.java:46) ~[rats-1.0.0-all.jar:?]
        at ninja.carter.rats.commodore.CommodoreProvider.<clinit>(CommodoreProvider.java:40) ~[rats-1.0.0-all.jar:?]
        ... 12 more
Caused by: java.lang.NoSuchFieldException
        at java.util.Optional.orElseThrow(Optional.java:403) ~[?:?]
        at ninja.carter.rats.commodore.MinecraftArgumentTypes.<clinit>(MinecraftArgumentTypes.java:77) ~[rats-1.0.0-all.jar:?]
        at ninja.carter.rats.commodore.CommodoreProvider.checkSupported(CommodoreProvider.java:46) ~[rats-1.0.0-all.jar:?]
        at ninja.carter.rats.commodore.CommodoreProvider.<clinit>(CommodoreProvider.java:40) ~[rats-1.0.0-all.jar:?]
        ... 12 more```

Clarify Spigot support

From the recent commits and a quick look at the Discord server, I take it that Spigot support has been dropped for Minecraft >= 1.19? I have no issues with this really, I totally understand the maintenance burden involved. But either way, I feel like it makes sense to document this somewhere, in the README for example.

Not working

Hi, I've tried everything but not worked for me :(
Even creating a new project and copying literally everything you say on the README didn't work.
And do Luckperms have commodore, because it didn't show for me as you say in commodore resource post.

Deeper into the API, less of an issue more of some help needed.

Hey, so i'm trying to add multiple options to one arg, like argument one has 3+ options, which show up in that vertical list, i've seen it on several 1.13 plugins, and i'm wondering if that's what this API does? or is that a completely different feature.

EDID: nevermind, i'm stupid, it's TabCompletion.

Registering aliases?

I was wondering if it's possible to register aliases to certain commands using the commodore file format. Right now I have something like this:

InputStream is = //...
LiteralCommandNode<?> commandNode = CommodoreFileFormat.parse(is);
CommandNode hologramCmd = commandNode.getChild("hologram");
LiteralCommandNode child = LiteralArgumentBuilder.literal("holo")
               .redirect(hologramCmd)
               .build();

commandNode.addChild(child);
commodore.register(command, commandNode);

which is obviously not that great since I'd have to write something like shown above for all aliases. Is there a better solution for this?

1.19.1 Not working for client side of servers(PaperMC)

Basicly I tried using LuckPerms on my 1.19.1 PaperMC server but, it just keep saying "An unexpected error occured trying to execute that commmand". So I tried it on the console it executed the command PLEASE FIX THIS SOON...

Allow using a custom suggestion provider with the bukkit command overload of register()

I'm using a custom suggestion provider for the arguments so I'm using #register(LiteralCommandNode) but I've discovered that it leaves minecraft:command tab completion in (I also register plugin:command so I get a minecraft:plugin:command option as well). If I use #register(Command, LiteralCommandNode) then it replaces my suggestion provider with Bukkit's. An option would be useful in this case where I can let Commodore deal with Bukkit's things but let me use the vanilla method.

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.