GithubHelp home page GithubHelp logo

equenos / dislash.py Goto Github PK

View Code? Open in Web Editor NEW
170.0 9.0 29.0 980 KB

A Python wrapper for discord slash-commands and buttons, designed to extend discord.py.

Home Page: https://dislashpy.readthedocs.io/en/latest

License: MIT License

Python 100.00%
discord discord-api slash-commands discord-py buttons components message-components context-menu application-commands python bot

dislash.py's Introduction

Warning

This library is no longer maintained in favor of disnake. Disnake is an updated version of discord.py with the latest API features implemented. The syntax for slash commands is very convenient so we really recommend using disnake if you're planning to switch to slash commands before April 2022.

If you have any questions, join Our Discord Server

dislash.py

Discord PyPi Python

An extending library for discord.py that allows to build awesome message components and slash commands.

Note about the future of discord.py

Since discord.py will no longer stay up to date, we decided to create a fork: disnake. It has all features of dpy 2.0 + application commands.

Table Of Contents

  1. Installation
  2. Features
  3. Examples
  4. Creating a slash command
  5. Creating Buttons
  6. Creating Menus
  7. Creating context menus
  8. Links
  9. Downloads

Installation

Run any of these commands in terminal:

pip install dislash.py
python -m pip install dislash.py

Features

  • Supports automatic registration of slash-commands
  • Supports manual and automatic sharding
  • Convenient decorator-based interface
  • Works with discord.py <=1.7.3, >=2.0.0a

Examples

💡 This library requires discord.py.

Creating a slash command

from discord.ext import commands
from dislash import InteractionClient

bot = commands.Bot(command_prefix="!")
inter_client = InteractionClient(bot, test_guilds=[12345, 98765])
# If 'test_guilds' param isn't specified, the commands are registered globally.
# Global registration takes up to 1 hour.

@inter_client.slash_command(
    name="hello", # Defaults to the function name
    description="Says hello",
    guild_ids=test_guilds
)
async def hello(inter):
    await inter.reply("Hello!")

bot.run("BOT_TOKEN")

Creating buttons

This example shows how to send a message with buttons.

from discord.ext import commands
from dislash import InteractionClient, ActionRow, Button, ButtonStyle

bot = commands.Bot(command_prefix="!")
inter_client = InteractionClient(bot)

@bot.command()
async def test(ctx):
    # Make a row of buttons
    row_of_buttons = ActionRow(
        Button(
            style=ButtonStyle.green,
            label="Green button",
            custom_id="green"
        ),
        Button(
            style=ButtonStyle.red,
            label="Red button",
            custom_id="red"
        )
    )
    # Send a message with buttons
    msg = await ctx.send(
        "This message has buttons!",
        components=[row_of_buttons]
    )
    # Wait for someone to click on them
    def check(inter):
        return inter.message.id == msg.id
    inter = await ctx.wait_for_button_click(check)
    # Send what you received
    button_text = inter.clicked_button.label
    await inter.reply(f"Button: {button_text}")

bot.run("BOT_TOKEN")

Creating menus

This example shows how to send a message with a menu.

from discord.ext import commands
from dislash import InteractionClient, SelectMenu, SelectOption

bot = commands.Bot(command_prefix="!")
inter_client = InteractionClient(bot)

@bot.command()
async def test(ctx):
    msg = await ctx.send(
        "This message has a select menu!",
        components=[
            SelectMenu(
                custom_id="test",
                placeholder="Choose up to 2 options",
                max_values=2,
                options=[
                    SelectOption("Option 1", "value 1"),
                    SelectOption("Option 2", "value 2"),
                    SelectOption("Option 3", "value 3")
                ]
            )
        ]
    )
    # Wait for someone to click on it
    inter = await msg.wait_for_dropdown()
    # Send what you received
    labels = [option.label for option in inter.select_menu.selected_options]
    await inter.reply(f"Options: {', '.join(labels)}")

bot.run("BOT_TOKEN")

Creating context menus

This example shows how to create context menus and interact with them.

from discord.ext import commands
from dislash import InteractionClient

bot = commands.Bot(command_prefix="!")
inter_client = InteractionClient(bot)

@inter_client.user_command(name="Press me")
async def press_me(inter):
    # User commands are visible in user context menus
    # They can be global or per guild, just like slash commands
    await inter.respond("Hello there!")

@inter_client.message_command(name="Resend")
async def resend(inter):
    # Message commands are visible in message context menus
    # inter is instance of ContextMenuInteraction
    await inter.respond(inter.message.content)

bot.run("BOT_TOKEN")

Links

Downloads

Downloads Downloads Downloads

dislash.py's People

Contributors

akhildotexe avatar apoo711 avatar bakersbakebread avatar dellyis avatar diogoriba avatar dob9601 avatar equenos avatar hunter2809 avatar johan-naizu avatar lev145 avatar liemeldert avatar m1raynee avatar misilelab avatar predaaa avatar thesadru avatar vcokltfre avatar woidptr 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

dislash.py's Issues

Allow for decorator chaining when a decorator modifies the kwargs

I've got a decorator that adds an additional kwarg to a function and have been using this with the default discord.py framework. This decorator helps integrate django with discord.py by using the user id in the context to fetch the user object from the django database. However, due to the code shown here:

new_func = CommandParent(
func,
name=name,
description=kwargs.get('description'),
options=kwargs.get('options'),
default_permission=kwargs.get("default_permission", True),
guild_ids=kwargs.get('guild_ids'),
connectors=kwargs.get("connectors"),
auto_sync=kwargs.get("auto_sync", True)
)

That kwarg never actually reaches the function.
Would it be possible to add support for additional custom kwargs by exposing all additional kwargs to the command function?

ModuleNotFoundError when trying to import dislash

When trying to import dislash.py, a ModuleNotFoundError: No module named 'discord.webhook.async_' is raised.

Full traceback:
Traceback (most recent call last):
File "main.py", line 2, in
import threading, dislash
File "/opt/virtualenvs/python3/lib/python3.8/site-packages/dislash/init.py", line 4, in
from .interactions import *
File "/opt/virtualenvs/python3/lib/python3.8/site-packages/dislash/interactions/init.py", line 1, in
from .interaction import *
File "/opt/virtualenvs/python3/lib/python3.8/site-packages/dislash/interactions/interaction.py", line 13, in
from discord.webhook.async_ import WebhookMessage
ModuleNotFoundError: No module named 'discord.webhook.async_'

TypeError: emoji() takes 1 positional argument but 2 were given

    @inter_client.slash_command(guild_ids=bonbot_support)
    async def emoji(ctx):
        pass
    @emoji.sub_command(description="steal an emoji with an option to lock it to a role", options=[Option("emoji", "an emoji to steal", OptionType.STRING, required=True),
    Option("role", "A role to lock this emoji to. (User must have this role to use emoji)", OptionType.ROLE)], guild_ids=bonbot_support)
    @slash_commands.guild_only()
    @slash_commands.has_permissions(manage_emojis=True)
    async def steal(self, ctx, emoji, role):
        c = commands.EmojiConverter() # create instance
        emoji_final = await c.convert(emoji) 
        # fetch the emoji asset and read it as bytes.
        emoji_bytes = await emoji_final.read()

        emoji_roles = [role]
        await ctx.guild.create_custom_emoji(name=emoji_final.name, image=emoji_bytes, roles=emoji_roles)
        await ctx.send("Created emoji!", ephemeral=True)

I get this error when I run this code, I even added print("number") after every step and it doesn't print anything. Not sure what is happening, I have asked for help in several servers and nobody can figure it out. When I run the same code as a regular command, (removing the components parts) it works flawlessly. Full error: https://mystb.in/UrwPutsGarlic.apache

Slash Command duplicate and wont change name

So i tried to made a slash command
code:

#Slash Command

slash=SlashClient(Tango())

@slash.command(
    name="echo",
	description="Echo word that you specified",
    options=[
        Option("word", "Specify a word that will get send", Type.STRING, required=True)
    ]
)
async def echo(inter, *,word):
	await inter.reply(word, allowed_mentions=discord.AllowedMentions(everyone=False, users=False, roles=False, replied_user=True))

and it work but, i may found or cause a bug. The slash command name is echo and basically echo an argument but, i accidentally duplicate the command. The echo command and its duplicate work fine but if i remove the command, both name still registered in the bot data and the slash command wont change name if i change the function name, and of course cause errors, one of them is "This interaction failed" and "Invalid interaction application command". My question is, how did the command duplicate and how do i remove it from the bot data?
slash_command

Slash command not working

I tried this code available in the DOcs

import discord
from discord.ext import commands
from dislash import InteractionClient, Option, OptionType

bot = commands.Bot(command_prefix="!")
inter_client = InteractionClient(bot, test_guilds=[12345])

@inter_client.slash_command(
    description="Shows the avatar of the user",
    options=[
        Option("user", "Enter the user", OptionType.USER)
        # By default, Option is optional
        # Pass required=True to make it a required arg
    ]
)
async def avatar(inter, user=None):
    # If user is None, set it to inter.author
    user = user or inter.author
    # We are guaranteed to receive a discord.User object,
    # because we specified the option type as Type.USER

    emb = discord.Embed(
        title=f"{user}'s avatar",
        color=discord.Color.blue()
    )
    emb.set_image(url=user.avatar_url)
    await inter.reply(embed=emb)
    ```
    But  I didnt got any slash command and when I used it an error came Command not found. I tried it with a new bot too but same error

Unregistering a slash command at runtime?

In the bot I'm making I need to create and delete commands on the fly, registering them in the API is easy but I don't know how to handle the dislash part, it seems I can create CommandParent instances and such but I don't know how I would go about deleting them.

Use versions for pip packages

As long as you use "latest" without a version, we need to uninstall and reinstall the dislash.py entirely to get the latest features, such as ContextMenus.

I think I found a Bug

When you try to make a dropdown menu inside of the on_dropdown event it seems to break with this error

"Ignoring exception in on_socket_response
Traceback (most recent call last):
File "C:\Users\runne\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\client.py", line 343, in _run_event
await coro(*args, **kwargs)
File "C:\Users\runne\AppData\Local\Programs\Python\Python39\lib\site-packages\dislash\slash_commands\slash_client.py", line 1050, in _on_socket_response
await self._process_interaction(payload["d"])
File "C:\Users\runne\AppData\Local\Programs\Python\Python39\lib\site-packages\dislash\slash_commands\slash_client.py", line 1141, in _process_interaction
inter = MessageInteraction(self.client, payload)
File "C:\Users\runne\AppData\Local\Programs\Python\Python39\lib\site-packages\dislash\interactions\message_interaction.py", line 46, in init
channel_id = int(msg_data["channel_id"])
KeyError: 'channel_id'"

"@bot.event
async def on_dropdown(inter: MessageInteraction):
if inter.component.custom_id == "HelpModuleMenu":
values = [option.value for option in inter.select_menu.selected_options]
labels = [option.label for option in inter.select_menu.selected_options]
value = values[0]
optionst = ["Test1", "Test2", "Test3"]
options = []
for module in optionst:
options.append(SelectOption(f"{module}", f"{module}"))
await inter.create_response(f"{value} Module has been Selected. Please pick a Command to get the help for that Command.", components=[
SelectMenu(
custom_id="HelpCommandMenu",
placeholder="Choose a minimum of 1 options",
max_values=1,
options=options
)
], ephemeral = True)
elif inter.component.custom_id == "HelpCommandMenu":
values = [option.value for option in inter.select_menu.selected_options]
labels = [option.label for option in inter.select_menu.selected_options]
value = values[0]
await inter.create_response(f"{value} Module has been Selected. Please pick a Command to get the help for that Command.", ephemeral = True)
else:
pass"

TypeError: object of type 'ActionRow' has no len()

NOTE: ONLY HAPPENS IN COGS
The Code:

from dislash import *
@commands.command()
async def cmd(self,ctx,arg):
	row = ActionRow(
		Button(style=ButtonStyle.green, label="My Label Here!!", custom_id="tx")
	)
	def check(inter):
		return inter.author == ctx.author and inter.author.guild_permissions.manage_emojis
	try:
		# SOME SHIT HERE!!
	except:
		# COUNTER

Precise Output in the Terminal:

File "/MY_DIRS/python/lib/python3.9/site-packages/dislash/application_commands/_modifications/old.py", line 105, in send_with_components
     if len(components) > 5:
TypeError: object of type 'ActionRow' has no len()

EDIT: Markdown changes

Reset Cooldown Doesn't Work

I try to use slash_core.BaseSlashCommand.reset_cooldown(inter) to reset the cooldown.
But it shows this error: reset_cooldown() missing 1 required positional argument: 'inter'

Then I try this: slash_core.BaseSlashCommand.reset_cooldown(self, inter)
But it still shows the error: 'SlashCommand' object has no attribute '_buckets'

Unknown Webhook when ApplicationID no equal UserID

I've only messed with Buttons, but I consistently get Unknown Webhook on one bot. Someone else suggested that it is likely due to the Bot's UserID not being the same as the ApplicationID. In this case, that is true. The App was originally personal but was moved to a team, so that is likely when it changed. Maybe I'm missing something, I haven't fully explored everything yet

Jun 16 02:15:32 python[407319]: Traceback (most recent call last):
Jun 16 02:15:32 python[407319]:   File "/mnt/discord/red-data/scgc/cogs/CogManager/cogs/rps/rps.py", line 143, in on_rock
Jun 16 02:15:32 python[407319]:     await inter.reply(type=ResponseType.DeferredUpdateMessage)
Jun 16 02:15:32 python[407319]:   File "/mnt/discord/red-data/scgc/cogs/Downloader/lib/dislash/interactions/interaction.py", line 204, in reply
Jun 16 02:15:32 python[407319]:     return await self.fetch_initial_response()
Jun 16 02:15:32 python[407319]:   File "/mnt/discord/red-data/scgc/cogs/Downloader/lib/dislash/interactions/interaction.py", line 392, in fetch_initial_response
Jun 16 02:15:32 python[407319]:     data = await self._client.http.request(
Jun 16 02:15:32 python[407319]:   File "/home/red/envs/scgc/lib/python3.8/site-packages/discord/http.py", line 250, in request
Jun 16 02:15:32 python[407319]:     raise NotFound(r, data)
Jun 16 02:15:32 python[407319]: discord.errors.NotFound: 404 Not Found (error code: 10015): Unknown Webhook

Local error handlers

Local error handlers will have to work the same way as in discord.py
Minimal syntax:

@slash_commands.command(...)
async def random_command(...):
    # random stuff

@random_command.slash_error
async def some_eh(inter, error):
    # eh stuff 

how to add the labels aaa idk I'm lost

library crash

Hello, I am a discord bot developer. Recently, dislash and other libraries are conflicting or unavailable. Please fix the conflict.

Sending a file in a followup's ephemeral Message will throw a 'Cannot Send Empty Message' error

I tried following up an ephemeral message with a message that contains a file, but it'd say that it cannot send an empty message. When I specified a content, it'd just send the content itself, but not the file.

await interaction.send(type=5, ephemeral=True)
or
await interaction.reply(type=5, ephemeral=True)
or
await interaction.create_response(type=5, ephemeral=True)

and at the end

file = discord.File("/path_to_image/image.png")
await interaction.followup(file=file)

discord.errors.HTTPException: 400 Bad Request (error code: 50006): Cannot send an empty message

discord.errors.NotFound: 404 Not Found (error code: 10062): Unknown interaction

Code:

from dislash import slash_commands
from dislash.interactions import *
from discord.ext import commands
from pyqiwip2p import QiwiP2P
from pyqiwip2p.types import QiwiCustomer, QiwiDatetime

from discord import Embed

import random
import string
import secrets
...
    def create_bill(self, amount, lifetime=45):
        p2p = QiwiP2P(auth_key=self.QIWI_PRIV_KEY)

        # Random bill id
        alphabet = string.ascii_letters + string.digits
        bill_id = ''.join(secrets.choice(alphabet) for i in range(20))

        try:
            p2p.check(bill_id=bill_id).status
        except TypeError: # If bill_id doesn't exist
            bill = p2p.bill(bill_id=bill_id, amount=amount, lifetime=lifetime)
            if p2p.check(bill_id=bill_id).status == "WAITING":
                return (bill_id, str(bill.pay_url))

        # Gegenerate
        return self.create_bill(amount, lifetime)


    @slash_commands.command(
        guild_ids=test_guilds,
        ... 
    )
    async def donate(self, interact):
        amount = interact.data.get("amount")
        bill_id, url = self.create_bill(int(amount), 45)
        await interact.reply(content="OK", embed=Embed(title="Donate Link!", url=url))
...

And when used, the error is called: discard.errors.Not Found: 404 Not Found (error code: 10062): Unknown interaction

According to tests, I found out that the bug most likely occurs because of the line:
bill = p2p. bill(bill_id=bill_id, amount=amount, lifetime=lifetime)

But I couldn't find out why it was happening

Now the code looks like this:

...
    async def donate(self, interact):
        amount = interact.data.get("amount")
        await interact.reply("Loading...")
        bill_id, url = self.create_bill(int(amount), 45)
        await interact.edit(content="OK", embed=Embed(title="Donate Link!", url=url))
...

And this code works, but it has 1 minus, when using the ephemeral=True parameter:

...
    async def donate(self, interact):
        amount = interact.data.get("amount")
        await interact.reply("Loading...", ephemeral=True)
        bill_id, url = self.create_bill(int(amount), 45)
        await interact.edit(content="OK", embed=Embed(title="Donate Link!", url=url))
...

A new error is raised: TypeError: There's nothing to edit. Send a reply first.

Interaction bug

I have this error with slash commands and the same with application commands

image

Error when I start the server

I get this error when I start the server. The 1st request doesn't work.
When I print the ctx, the channel is None for the 1st request but isn't for the next ones.
Then I have this error when I use : await ctx.send(...)

Ignoring exception in on_socket_response
Traceback (most recent call last):
  File "/opt/anaconda3/envs/project/lib/python3.9/site-packages/discord/client.py", line 343, in _run_event
    await coro(*args, **kwargs)
  File "/opt/anaconda3/envs/project/lib/python3.9/site-packages/dislash/slash_commands/slash_client.py", line 1050, in _on_socket_response
    await self._process_interaction(payload["d"])
  File "/opt/anaconda3/envs/project/lib/python3.9/site-packages/dislash/slash_commands/slash_client.py", line 1137, in _process_interaction
    raise err
  File "/opt/anaconda3/envs/project/lib/python3.9/site-packages/dislash/slash_commands/slash_client.py", line 1134, in _process_interaction
    await slash_parent.invoke(inter)
  File "opt/anaconda3/envs/project/lib/python3.9/site-packages/dislash/slash_commands/slash_core.py", line 342, in invoke
    raise err
  File "/opt/anaconda3/envs/project/lib/python3.9/site-packages/dislash/slash_commands/slash_core.py", line 338, in invoke
    await self._maybe_cog_call(self._cog, interaction, interaction.data)
  File "/opt/anaconda3/envs/project/lib/python3.9/site-packages/dislash/slash_commands/slash_core.py", line 131, in _maybe_cog_call
    return await self(inter, **params)
  File "/opt/anaconda3/envs/project/lib/python3.9/site-packages/dislash/slash_commands/slash_core.py", line 95, in __call__
    return await self.func(*args, **kwargs)
  File "project/src/main.py", line 473, in add_notif
    await msg.delete()
  File "/opt/anaconda3/envs/project/lib/python3.9/site-packages/discord/message.py", line 1023, in delete
    await self._state.http.delete_message(self.channel.id, self.id)
AttributeError: 'NoneType' object has no attribute 'id'

I tried with bot.command and it works

@bot.command(
    name="add_notif"
)

But not when I use slash.command


@slash.command(
    name="add_notif"
)

Slash command interaction is expired on arrival

When testing a simple slash command using dislash, when i get to the callback that handles the slash command, the interaction is already expired. The code i'm using to test this:

    @slash_commands.command(
        name="maybe_this_works",
        description="testing slash commands",
        guild_ids=[GUILD_ID]
    )
    async def maybe_this_works(self, inter:Interaction):
        logger.debug(inter)
        logger.debug("snowflake time: " + inter.created_at.isoformat())
        logger.debug("current time: " + dt.datetime.utcnow().isoformat())
        logger.debug("is expired: " + str(inter.expired))
        logger.debug("is sent: " + str(inter._sent))
        await inter.reply("hello!")

Output in discord:
image
Output in logs:

    vote     | maybe_this_works |   47 | DEBUG    | snowflake time: 2021-08-04T15:21:41.611000
    vote     | maybe_this_works |   48 | DEBUG    | current time: 2021-08-04T18:21:41.803420
    vote     | maybe_this_works |   49 | DEBUG    | is expired: True
    vote     | maybe_this_works |   50 | DEBUG    | is sent: False

Result of the logs show that the time being reported by interaction.created_at is not calculated as UTC.

It seems interaction.expired uses interaction.created_at which in turn uses a dislash.py specific implementation of snowflake_time that does not force the timestamp to be created in UTC+0:

def snowflake_time(ID):
return datetime.datetime.fromtimestamp(((ID >> 22) + DISCORD_EPOCH) / 1000)

@property
def created_at(self):
return snowflake_time(self.id)
@property
def expired(self):
utcnow = datetime.datetime.utcnow()
if self._sent:
return utcnow - self.created_at > datetime.timedelta(minutes=15)
else:
return utcnow - self.created_at > datetime.timedelta(seconds=3)

This differs from discord.py's implementation, which forces the timestamp to be calculated in UTC+0:

def snowflake_time(id: int) -> datetime.datetime:
    """
    Parameters
    -----------
    id: :class:`int`
        The snowflake ID.
    Returns
    --------
    :class:`datetime.datetime`
        An aware datetime in UTC representing the creation time of the snowflake.
    """
    timestamp = ((id >> 22) + DISCORD_EPOCH) / 1000
    return datetime.datetime.fromtimestamp(timestamp, tz=datetime.timezone.utc)

If I change dislash's function to use either datetime.datetime.utcfromtimestamp, or discord.py's implementation of snowflake_time, the problem goes away and the interaction is no longer considered expired on arrival.

I can make a pull request to fix that if it would help, I just needed to know which route would you rather use to fix that (change dislash.py's implementation or adopt discord.py's function instead).

ERROR IN DOCS

Here is what I found in the docs of dislash.py

    def check(inter):
        # inter is instance of MessageInteraction
        # read more about it in "Objects and methods" section
        if inter.author == ctx.author
    # Wait for a menu click under the message you've just sent
    inter = await msg.wait_for_dropdown(check)
    # Tell which options you received
    labels = [option.label for option in inter.select_menu.selected_options]
    await inter.reply(f"Your choices: {', '.join(labels)}")

It is noticible that there is no colon after if inter.author ==ctx.author nor the indentation level is equal

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.