Giter VIP home page Giter VIP logo

node-steam-chat-bot's Introduction

If you'd like to take over this project, please find me on steam or matrix.

GitHub version GitHub tag node Repo Size License

Join the chat at https://gitter.im/Efreak/node-steam-chat-bot Dependency Status Codacy Badge Downloads per month

Stats Downloads

steam-chat-bot

This module is based on the original steam-chat-bot written by bonnici. The original module link is here.

Simplified interface for a steam chat bot. This is a wrapper around Steam for Node.js which is aimed at making an easily configurable chatbot that sits in Steam groups chat rooms and responds to various events. Responses are handled as a set of triggers of various types which can be configured to respond to a number of different chat messages. Steam requires that a user has at least one game before it can join chat rooms (unless it's a mod), so you'll need to buy a game for the bot account or make it a mod before it will be able to join.

If you have Steam Guard enabled you'll get a failed logon attempt the first time you try to log on and you'll be sent a Steam Guard code. Pass this code in with the constructor (below)` and you should be able to log in. A sentry file will be stored, which should allow you to log in with a different computer using the same guard code. If you start getting logon failures again you should delete the sentry file, remove the guard code, and try to log in with neither so you get a fresh code emailed to you.

We also have our very own subreddit. If you like steam-chat-bot, please subscribe to it. We often post news, and other important information. It is also a place for users to get help if something doesn't work.

Installation:

Type npm install steam-chat-bot. If you want to run the development version, type npm install efreak/node-steam-chat-bot#development (or the url to your preferred repo/branch).

To get this running in Windows you'll need to follow the setup instructions for node-gyp and also use a branch of libxmljs as described in this issue (TLDR is to run 'npm install polotek/libxmljs#vendor-src' before 'npm install').

Configuration:

Basic Config:

You almost certainly want more than this in your config, unless you're happy with all the defaults and only having a logTrigger.

var myBot = new ChatBot('username', 'password');
myBot.loadTriggers([
	{
		name: 'logTrigger',
		type: 'LogTrigger',
		options: { roomNames: roomNames }
	}
]);

There are also several example configurations in the examples folder.

If there is no example configuration for a specified trigger, please check the top of the trigger file for information on calling it. The trigger definition files may also have information on more advanced usage than is contained in the readme or wiki or example configs.

Public Functions

There are some public functions available for more advanced/programmatic usage of the bot.

  • chatBot.onLogon(function(bot){code()} - execute code() whenever the bot logs on. You can use this to send yourself a notification whenever the bot logs on, or do pretty much anything else without actually writing a trigger for it.
  • chatBot.redirect(source,destination,code) - set up a web redirect for the bot. You may wish to use this to, say, redirect /help to the bot's website.
  • chatBot.addTrigger(triggerDefinition) - add a single trigger to the bot.
  • chatBot.addTriggers(triggerDefinitionArray) - add an array of triggers to the bot.
  • chatBot.clearTriggers() - remove all triggers from the bot. Note that poorly behaved triggers may not be completely removed if they modify other parts of the bot.

Popular Triggers:

See TRIGGERS or the triggers folder for the full list of triggers and how to use them. If you want to contribute a trigger, please make sure to add a quick description and list of all parameters and how to use them at the top of the trigger file (required) and add a basic usage section to TRIGGERS (also required, need not be in-depth).

Management Triggers

General bot-related and chat-related functions.

  • AddFriendTrigger - Tell the bot to send a friend request.
  • InfoTrigger - Provides information about the status of the bot
  • BanTrigger - bans a user from a groupchat. They do not need to be in chat.
  • DoormatTrigger - Sends a message ("Hello username") to someone when they join the chat.
  • MessageOnJoinTrigger - tells the bot to welcome a specific user with an message
  • SayTrigger - tells the bot to say something
  • SetNameTrigger - changes the bot's name.
  • PlayGameTrigger - tells the bot to play a game. You need to send the game's appid. - options allowpublic and allowprivate (both true by default) allow you to restrict usage of this command to either private or groupchat messages.
  • PlayTrigger - same as above. Not sure why I have two of this plugin; one or the other may not work.
  • LogTrigger - Uses the built-in webserver to server logs in realtime via the browser. Also serves archives.

Trade-related triggers

  • BanCheckTrigger - checks to see if a user has any VAC/economy/community bans via steam API. Requires a steam api key, defined as option apikey in the plugin, or globally defined as a chatBot option steamapikey
  • BitcoinTrigger - does various actions over the BTC network
  • ProfileCheckTrigger - When a user joins, look up their profile in steam API and if they have a private profile, or never bothered to set one up, announce it to the groupchat. Optional option: apikey can be defined in options, overriding any steamapikey can be defined in the bot constructor. If neither is defined, it won't be used (not required).
  • RedditTrigger - Check reddit flair/bans/username on command. Requires access to the /r/SGS API. Note: I will not help you with gaining access to the API, and everything I know about the API is used in this trigger.
  • SteamrepTrigger - checks steamrep API on command. If Steamrep lists the user as a scammer, then bot announces it and gives links for more info. See SteamrepOnJoinTrigger to do this whenever someone joins a chat.
  • MoneyTrigger - Converts between currencies, will require an apikey from https://openexchangerates.org

Other popular triggers

  • BotCommandTrigger - Runs a specified callback when a specific command message is typed.
  • CSGOStatsTrigger - Retrieves a player's csgo stats from steam api
  • ChatReplyTrigger - Detects a message (either an exact match or a "contains" match) and replies with a specified message.
  • CleverbotTrigger - Uses cleverbot to reply to a message, optionally only when a specific word is mentioned.
  • GoogleTrigger - Prints out the title and link of the first search result on Google.
  • LinkNameTrigger - Is given a link and sends the title of the website.
  • OMDBTrigger - Searches IMDB for a specified movie.
  • RandomGameTrigger - Picks a random game from the calling user's games list, or that of any specified user with an open profile.
  • RegexReplaceTrigger - Detects a regex match in a message and uses the matches to construct a reply.
  • SteamIDTrigger - Converts someone's name to a SteamID
  • TranslateTrigger - Translates between languages using hablaa.
  • TumblrTrigger - Allows the bot to post things to a tumblr blog, either by commands, or by monitoring the chatrooms the bot is in for links.
  • WolframAlphaTrigger - Queries Wolfram Alpha. You will need an appId from http://products.wolframalpha.com/api/.
  • YoutubeTrigger - Will respond to a Youtube search term, whether it be a video or a channel.

Writing Triggers

If you look at BaseTrigger.js, you can see a full list of available functions designed to be used from within plugins. You can also use a chatBot.js function() by calling this.chatBot.function() object from inside a trigger. Please see the Wiki for more information.

Heroku

See the bottom of example-heroku.js for an example of a simple webserver and self-pinger that satisfies heroku's requirements of 1 visit per hour to keep a free Dyno running. It also provides some simple statistics when you visit the /stats url. Read the top of the file to set it up correctly with heroku.

After you have example-heroku set up to your liking, follow the instructions here to set up heroku and upload your bot. Once it's uploaded, start it with heroku ps:scale web=1

Testing Policy: forthebadge

In other words, I don't do a whole lot of testing. I do my best not to break things, but stuff happens. If you found or fixed a bug, you know what to do.

Note: Please read about CONTRIBUTING before creating a pull request. If your pull request goes against what is said, it will not be accepted and we will ask you to fix it.

node-steam-chat-bot's People

Contributors

bonnici avatar divinux avatar dungdung avatar efreak avatar jmcortinax avatar kjsmita6 avatar lostandconfused avatar paulschow avatar reploidsham avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

node-steam-chat-bot's Issues

API Triggers

Find all api calls (baseTrigger.js and other triggers) and update them to use either the new chatBot.steamApi() or baseTrigger.steamApi(). (see #89)

hide private messages from live log

ws.onmessage=function(event){
nib=event;
//console.log(event);
if(JSON.parse(event.data).roomId===null) return;
if(JSON.parse(event.data).type === 'roomNames')roomNames=JSON.parse(event.data).names
else if(!window.location.hash ||window.location.hash === '#'+JSON.parse(event.data).roomId){
var li=document.createElement('li');
li.innerHTML=(Autolinker?Autolinker.link(format(JSON.parse(event.data))):format(JSON.parse(event.data)));
document.querySelector('#pings').appendChild(li);window.scrollTo(0,document.body.scrollHeight);
};
}

Pushbullet

  1. Don't ask for api keys in not-so-private messages.
  2. Don't forward messages sent by the person who created the trigger.
  3. Don't send a message more than once to the same person (multiple words get caught)
  4. When pushbullet api key expires, delete it. Attempt to send a chat message to the user.
    • When there's no api key, keep the settings, but ignore them (this shouldn't need any changes)

Internal Webserver - show loaded triggers and help

Several options:

  1. merge webui into steam-chat-bot - done
  2. keep webui as a trigger - done
  3. move it into a separate project that requires steam-chat-bot and possibly manages several of them
  4. move it into a separate repo anyways and figure out a way to import triggers from other packages into steam-chat-bot. (this is likely a good idea anyways).

Ideally, webui would have all the functions shown, and possibly more.

  • default page Private plugin-only
    • Optionally can only be shown to someone logging in via steam openid.
    • Triggers X, Y, Z are loaded, click it for help if there's a trigger.help variable to provide information.
      • trigger.options.webUI=false or trigger.webUI=false should prevent a given trigger from showing
  • Admin page can only be opened by those logging into a whitelisted account via steam openid
    • Allows you to perform actions
      • Say X in Y
      • Load/unload triggers
      • change trigger options without loading/unloading them
      • change options that are currently only changeable in the constructor (ie, global ignores)
    • Shows live bot logs
      • live chat logs are already available in logTrigger, don't show that crap
      • Configurable log level
      • Showing in console is easy. If we can find a way to scroll it through a div, that would be better.
    • Allows server-side file management (ie, downloading, uploading of individual files)
    • Start bot, logon fail due to missing guard code => enter guardcode into webui instead of restarting the bot.

cannot call method 'crc32' of undefined

Hi, I get this error everytime I start up my bot:

C:\Users\Kyle\node_modules\steam-chat-bot\node_modules\steam\lib\steam_client.js
:149
var keyCrc = require('crc').buffer.crc32(cryptedSessKey);
^
TypeError: Cannot call method 'crc32' of undefined
at SteamClient.handlers.(anonymous function) (C:\Users\Kyle\node_modules\ste
am-chat-bot\node_modules\steam\lib\steam_client.js:149:38)
at SteamClient._netMsgReceived (C:\Users\Kyle\node_modules\steam-chat-bot\no
de_modules\steam\lib\steam_client.js:105:26)
at Connection.emit (events.js:95:17)
at Connection.readPacket (C:\Users\Kyle\node_modules\steam-chat-bot\node_mo
dules\steam\lib\connection.js:50:8)
at Connection.emit (events.js:92:17)
at emitReadable
(_stream_readable.js:410:10)
at emitReadable (_stream_readable.js:406:5)
at readableAddChunk (_stream_readable.js:168:9)
at Connection.Readable.push (_stream_readable.js:130:10)
at TCP.onread (net.js:528:21)

Not really sure what the problem is, maybe i'm missing a module?

OMDB year fix

In the OMDB trigger, when I added the year argument I realized that you can't ask for a movie if it has 2 words. I will implement a fix for this. Putting this here as a reminder.

Not install

~/test# npm install steam-chat-bot
npm WARN engine steam-chat-bot@2.0.1: wanted: {"node":"0.12.x","npm":"1.4.x"} (current: {"node":"0.12.0","npm":"2.11.2"})
Killed
~/test# make: Entering directory `/usr/local/lib/node_modules/steam-chat-bot/node_modules/ws/node_modules/utf-8-validate/build
  CXX(target) Release/obj.target/validation/src/validation.o
  SOLINK_MODULE(target) Release/obj.target/validation.node
  COPY Release/validation.node
make: Leaving directory `/usr/local/lib/node_modules/steam-chat-bot/node_modules/ws/node_modules/utf-8-validate/build'

at this point the installation stops
NodeJS: v0.12.0
npm: v 2.11.2
OS: Debian
Help me, please!

More APIs to add

logTrigger websocket server breaks on clearTrigger

logTrigger modifies the built-in http server, and there's no way to clean itself up. For the time being at least, just reinitialize the http server when we cleartriggers.

Maybe see about adding an onUnload function to modules for cleanup.

Add examples to translate trigger

I will be adding examples of how words are used in a sentence in translate trigger. This is just a reminder for me since I'll forget.

Bot won't join chat

So my bot doesn't join when the Auto-join chat trigger is added. My code is:

{ 
        name: "AcceptChatInvite", 
        type: "AcceptChatInviteTrigger", 
        options: { 
            chatrooms: { "103582791435108754": "Hello, the chat bot has arrived!" }, 
            autoJoinAfterDisconnect: true
        } 
    },

Since that didn't work, I tried to use myBot.joinChat('103582791435108754'); to join, but that doesn't work either.

Documentation

It would be nice to have everything documented, but that's unlikely at this point. At the very least, I want to get all the important stuff documented. Also, all documentation should go on the website #78

LinkName triggers every second time

Hey guys, terribly sorry about this one.

Don't know how this slipped past me, but LinkName triggers only on every second link. The reason as I understand it, is that the exec method doesn't reset to beginning every time it's called as described here:

http://www.codeitive.com/7xNxUgkVUP/why-is-javascript-regex-matching-every-second-time.html

Several solutions are described in the link, for my local bot I went with the hacky one- just calling exec again after I got the link once to reset its index back to 0, as shown here in line 54:

http://hastebin.com/sariboxodi.coffee

Works just fine now, but as always, you might have a more elegant solution ;)

Fix new youtube issue

So I updated youtube to the newest version, but I am getting an error everytime I start up my bot. It goes something like this:

2015-05-01T04:05:56.396Z - error: TypeError: Cannot read property 'params' of null
    at YoutubeTrigger._respond (/Users/Kyle/node_modules/steam-chat-bot/lib/triggers/youtubeTrigger.js:44:27)
    at YoutubeTrigger._respondToChatMessage (/Users/Kyle/node_modules/steam-chat-bot/lib/triggers/youtubeTrigger.js:39:14)
    at BaseTrigger.onChatMessage (/Users/Kyle/node_modules/steam-chat-bot/lib/triggers/baseTrigger.js:86:27)
    at /Users/Kyle/node_modules/steam-chat-bot/lib/chatBot.js:478:41
    at Function._.each._.forEach (/Users/Kyle/node_modules/steam-chat-bot/node_modules/underscore/underscore.js:158:9)
    at ChatBot._onChatMsg (/Users/Kyle/node_modules/steam-chat-bot/lib/chatBot.js:477:5)
    at SteamClient.<anonymous> (/Users/Kyle/node_modules/steam-chat-bot/lib/chatBot.js:127:91)
    at SteamClient.emit (events.js:118:17)
    at SteamClient.handlers.(anonymous function) (/Users/Kyle/node_modules/steam/lib/handlers/friends.js:261:8)
    at SteamClient._netMsgReceived (/Users/Kyle/node_modules/steam/lib/steam_client.js:106:26)

If anyone knows how to fix it, please open a pull request, as I have no idea how.

Log improvements

In progress.

Main log displays everything as usual, but only logs warnings, errors to file, not general chat.

New trigger logs each groupchat/userchat to a different file, serves live/updating logs that can be filtered by groupchat as well as static downloads (download of userchats disabled).
(This issue is mainly a reminder to myself)

Migrate logins

Get the bot logging in again (without any triggers at all).

  • This may or may not be a good time to dump the username and password fields from the bot constructor and just make a straight object.

Triggers not working, please answer

so it seems that all of the triggers that require an api do not work for me (steamrep, YouTube, etc). Does anyone else have these issues/know how to fix them? Thanks.

IRC trigger

Instances of irc should be available to other instances of the trigger so as not to require multiple bots for the same network. One possible method is below.

var setupNetwork = function(network) {
    this.chatBot.irc[network] = require('irc');
    .......
}

if(this.chatBot.irc && this.chatBot.irc[network] {
    setupRelay(network, chatroom, group);
} else if this.chatBot.irc {
    setupNetwork(network);
    setupRelay(network, chatroom, group);
} else {
    this.chatBot.irc = {}
    setupNetwork(network);
    setupRelay(network, chatroom, group);
}

node-steam no longer supports node.js 0.10.x

seishun/node-steam#123

/home/action/workspace/node-steam-chat-bot/node_modules/steam/lib/steam_client.js:150                                                                              
  var cryptedSessKey = require('crypto').publicEncrypt(fs.readFileSync(__dirna                                                                                     
                                         ^                                                                                                                         
TypeError: Object #<Object> has no method 'publicEncrypt'                                                                                                          
    at SteamClient.handlers.(anonymous function) (/home/action/workspace/node-steam-chat-bot/node_modules/steam/lib/steam_client.js:150:42)                        
    at SteamClient._netMsgReceived (/home/action/workspace/node-steam-chat-bot/node_modules/steam/lib/steam_client.js:106:26)                                      
    at Connection.EventEmitter.emit (events.js:95:17)                                                                                                              
    at Connection._readPacket (/home/action/workspace/node-steam-chat-bot/node_modules/steam/lib/connection.js:50:8)                                               
    at Connection.EventEmitter.emit (events.js:92:17)                                                                                                              
    at emitReadable_ (_stream_readable.js:408:10)                                                                                                                  
    at emitReadable (_stream_readable.js:404:5)                                                                                                                    
    at readableAddChunk (_stream_readable.js:165:9)                                                                                                                
    at Connection.Readable.push (_stream_readable.js:127:10)                                                                                                       
    at TCP.onread (net.js:528:21)

Allow triggers to perform cleanup

There's currently no way for triggers to perform cleanup functions when they get removed. Add an onUnload that gets called when we run removeTrigger() and clearTriggers(). Added due to #80.

Test "new" core functions

Added functions last September(?) I think I fully implemented them, so they should work, but I still haven't tested them yet.

Functions:

  • _onLoggedOff - bot logged off. Yes, we can see this other ways, but it might be useful anyways
  • _onFriend - when someone sends a friend request? Or when someone adds/removes the bot? Can't remember 😦
  • _onGroup - Same as above, for groups
  • _onAnnouncement - when someone posts an announcement. The text isn't included in the event, IIRC, just the fact that an announcement occurred
  • _onRichPresence - no clue.

Announcement function should be removed and left to a trigger.

_onAnnouncement crashes bot

For now, fix this. After that, add more error handling.

/home/chatbots/node_modules/steam-chat-bot/lib/chatBot.js:141
 function(groupID, headline) { that._onAnnouncement(that.maingroup, headLine);
                                                                    ^
ReferenceError: headLine is not defined
    at SteamClient.<anonymous> (/home/chatbots/node_modules/steam-chat-bot/lib/chatBot.js:141:108)
    at SteamClient.emit (events.js:110:17)
    at SteamClient.handlers.(anonymous function) (/home/chatbots/node_modules/steam-chat-bot/node_modules/steam/lib/handlers/friends.js:319:10)
    at SteamClient._netMsgReceived (/home/chatbots/node_modules/steam-chat-bot/node_modules/steam/lib/steam_client.js:106:26)
    at SteamClient.handlers.(anonymous function) (/home/chatbots/node_modules/steam-chat-bot/node_modules/steam/lib/steam_client.js:192:10)
    at SteamClient._netMsgReceived (/home/chatbots/node_modules/steam-chat-bot/node_modules/steam/lib/steam_client.js:106:26)
    at Connection.emit (events.js:107:17)
    at Connection._readPacket (/home/chatbots/node_modules/steam-chat-bot/node_modules/steam/lib/connection.js:50:8)
    at Connection.emit (events.js:104:17)
    at emitReadable_ (_stream_readable.js:424:10)

[Request] Private message on join

Any chance of a trigger that sends each user that joins the chat a private message, with a cache so it doesn't spam people would be nice.

Cheers

Create website

Use existing template, but get all documentation in it.

As #79 is completed, add to website.

It would be nice to have the documentation also get served by the bot's internal webserver,

Webserver in chatBot.js

Move the webserver out of logTrigger and into chatBot.js, and provide api functions other triggers can use.

Required for #56.

Release 2.1.1

  • No code added to development after today, except fixes for existing bugs (that means no WebUI) and typos, formatting, etc.
  • Update changelog(!)
  • Make sure to get correct version number in package.json this time, last time npm had the wrong version. Then release.
    • update package.json to 2.1.1 in development.
    • merge development into master.
    • push master to github (there's a couple extra commits for the readme, IIRC). I'll probably forget to rebase first and just force-push, though, so be aware.
    • update package.json to 2.1.1-dev in development.
    • rebase webui on top of development
    • push development & webui to github.
    • release on github from master branch.
    • ~24hours later, release 2.1.1 on npm if no bugs found yet. Basically, I just need a little tiny bit more testing--All I've really tested is webui, and that's not gonna be included.
      • Make sure changelog is up to date (again) before releasing.

Add tests

After some thinking and some motivational sessions, I've decided to start/finish writing tests for the bot. These tests will be available in the spec folder, and will follow the current testing style by bonnici, using Jasmine and Sinon.

IMDB trigger

Add a trigger to grab info from IMDB. Wolfram has nice info, but no ratings. imdb-api looks to be the most recently module to use, short of ripping off someone else's code.

Fix live logs

The linkifier isn't working correctly for the group names.

example.js and readme

Is the example.js file meant to show all available options? I can't find an example for the JointChatTrigger. And the AcceptChatInviteTrigger in it doesn't seem to work for me.

alternative-non-fs-config branch needs testing and finishing

We need a few tests of this on heroku before merging. I've looked it over and it looks good to me, but I don't have a heroku setup right now. It requires the Firebase addon, which can be gotten for free. It should also be tested on a local version.

If anyone's willing to test it out, please post results here.

Process:

  1. Download heroku toolbelt and install
  2. run heroku login in your command prompt/shell to login
  3. git clone git://github.com/Efreak/node-steam-chat-bot.git && cd node-steam-chat-bot && git checkout alternative-non-fs-config && heroku create (clone the bot, switch branches, and make it a heroku app)
  4. edit example-heroku.js with your settings and either save with the same name, or edit Procfile and the next command with the new name
  5. git add example-heroku.js Procfile && git commit -m "update config" && git push heroku master (push everything to heroku)
  6. heroku ps:scale web=1
  7. heroku open - open the bot's internal webserver in your browser
  8. If you're going to actually use this bot, rather than just testing it, you'll want to set up Pingdom or something similar to visit it every so often, or Heroku will shut down your dyno. Same deal with openshift and other free providers.

Suggestions for changes are in the wiki

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.