GithubHelp home page GithubHelp logo

wazarr94 / haxball_bot_headless Goto Github PK

View Code? Open in Web Editor NEW
46.0 8.0 73.0 532 KB

Ready-to-go scripts and functions for the HaxBall Headless API !

License: MIT License

JavaScript 100.00%
haxball haxball-bot

haxball_bot_headless's Introduction

HaxBot

Description

This project has been designed to help people who do not know how to code to be able to host a room with multiple options.

This is a new version, which capitalizes on the latest Haxball update that notably introduced the noPlayer option.

The files of the last version are still accessible, along with the README file in the OLD folder. Their use is discouraged.

How to use

Download the project or the script you want to use on your computer.

For editing the code, I highly recommand the use of Visual Studio Code as it is a very complete IDE. You will need it to change the room options.

The options are at the top of the code, and they are numerous. For example, you can set the name of the room, add a headless token, change the default stadiums, edit the team size for the public room, etc.

Running the script

Local machine:

  1. Open the Haxball headless page
  2. Open devtools using F12 and select the console
  3. Copy and paste the content of the script of your choice
  4. If you haven't added a headless token from the token page, complete the captcha
  5. The room is now open, press Ctrl + Click to open it (keep the headless room tab open)

VPS:

My recommandation for when you are using a server is to use Ubuntu 18.04 as it is both cheaper and more powerful for hosting rooms. If you are not familiar with Linux, you can always use Windows and the same method as for a local machine. For Ubuntu, use the following method:

  1. Install haxroomie by entering in the terminal:
bash <(curl -s https://raw.githubusercontent.com/morko/haxroomie/master/scripts/install-haxroomie-cli-debian.sh)

Keep the default options and enter a password when prompted

  1. Run haxroomie once by entering haxroomie in the terminal and immediately exit by pressing q

  2. Upload your script to the VPS, and remember its path

  3. Enter:

nano /home/haxroomie/.haxroomie/config.js

and press Ctrl + K until the file is empty. Then paste the following script:

let config = {
    room1: {
        autoStart: true,
        roomName: 'YOUR ROOM NAME HERE',
        maxPlayers: 16,
        public: true,
        noPlayer: true,
        token: 'YOUR TOKEN HERE',
        roomScript: '/path/file/Haxbot_public.js',
    },
};

module.exports = config;

Don't forget to change the roomName, maxPlayers, public, token and roomScript options accordingly.

Then, press Ctrl + X, Enter and Enter to save the file.

  1. Enter haxroomie in the terminal to launch the room. Enter min to minimize the process and close the terminal. Your room is open.

For more details about haxroomie, check out their website here.

Functionalities

There are 2 files in this repository, and they have the same core of functionalities, which are the following:

  • Advanced statistics
  • Discord integration
  • Team chat and player chat
  • Goal notification with shot speed
  • Auto game recording
  • Admin system
  • Ban system

and much more!

To discover all the features of the bot, use the command !help to check all commands. To go into the details of a command, type !help <command>.

Versions

There are 2 files, based on whether you want your room to be public or not.

The private file is when there are no restrictions set in place and lets admins do everything.

For the public version, the bot handles setting up the teams correctly, and captains are able to pick their teams thanks to the choosing system, which remained the same as in the previous version.

Personalisation

File

To personalise the file, there are multiple steps to follow.

First, you are going to need the most obvious details, such as the room name, the number of players in the room, or the fact that the room is public or not. If your room isn't public, you can set maxPlayers at 40.

If you need to translate, search for room.sendAnnouncement in the file, and modify the text that follows in your language. For an accurate translation, I recommend using DeepL.

Link to Discord

Here are the steps to follow to link your room to Discord. It will give you the logs of your room and match reports for all matches played in your room.

  1. Create your Discord server or use one where you have admin rights.
  2. Create a log channel and a game channel.
  3. For each channel, create a webhook and copy their links.
  4. Replace roomWebhook by the webhook link of your log channel.
  5. Replace gameWebhook by the webhook link of your game channel.
  6. You have linked your room with Discord!

Once everything is setup, you will be able to check everything that happens in your room, as well as beautiful reports of all games played.

Feedback

If you encounter any bug while using the bot, please file an issue with the complete console error message. Any incomplete issue will not be addressed.

Feel free to leave any suggestions in the Issues tab as well, and I will try to respond to them if I have time to spend on the project.

If you enjoy the bot, consider giving it a star to show your appreciation.

haxball_bot_headless's People

Contributors

juliuskb avatar wazarr94 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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

haxball_bot_headless's Issues

problem

Hi @Wazarr94. How can ban to players from DC?

Could you prepare this feature and share?

And I also need another feature for DC.

             if (scores.red > scores.blue) {
                embeds.color('14958399');
            } else {
                embeds.color('9567999');
            }

Please tell me how to put that's commands?

Error on level 4 BOT.

Hello. I'm having a little problem in this bot. When i use another cmd beyond !help, like !me or !games, the game just crashes. I'm using Opera. But when i use Mozilla, it does not crashes, but don't work and don't even appears in the chat. Ty for the BOT, it's incredible

getGK function does not return the correct player

the majority of the time, the getGK() function returns the wrong player in 3v3 matches (didn't check in 2v2). The reason I think is because for some cases the GKTicks is not incrementing. Though I was not able to find the pattern.

sorry for yet another issue, don't hate me pls 🙁

GK stats?

Hi, I noticed the note that private.js has GK stats added, but it isn't functioning for me and I don't see it in the code.

Thanks!

0

0

stats in a private room?

would it be possible to enable stats in a private room (without auto team balance)? I know it might not be 100% accurate in an admin-managed room, but I'm fine with the small margin of error.

Game time not recording some players

The game log that shows the time played by each player is sometimes not including some players that get subbed in.

i.e. 5 players play in a 4v4 game, 3 played the full game, 1 substitution was made. But it shows as only four players having played.

Giving admin to the player entering the room.

hello, I edited the public bot in my language. but i need your help with something. I do not want the first person to enter the room to be given admin. I just want to give admin to people I want. My room will only be for 10 people. it will be easy to control. so I want to prevent the public bot from giving admin to the players entering the room.

corrupt recording files occasionally

On some occasions, roughly once every 3-4 recordings (sometimes even two or three consecutive ones), the file sent to discord is corrupt (9 bytes), I have tried to find the root cause but couldn't find anything that might be causing this. There's no errors in the console whatsoever.

Do you have any ideas? Thanks

image

custom stats

i saw some room added custom stast to your bot and they were kinda broken, are you thinking to add some? like if it was successful pass or was it crossbar

How admins can write text in different colors

I examined the basic structure of the code and the document. I have to use the sendAnnoncument function, I also understood that neither found an example nor understood it myself.

I want the admins to write in red and I want the answers given by the bot (like !cs, !win, !me) to be in yellow and bold eras.

I'm using Level 4.

Error with level 4

Error message:
Uncaught SyntaxError: Identifier 'roomName' has already been declared

1 vs 1 to 2 vs 2

When the 1vs1 game is occurring and 2 people enter the room, the bot, without restarting, puts the 2 spectators.
I hope that you can fix it
Congrats for this amazing job, I'm sure that it involves lots of work and a big thank you!

TypeError: Cannot read property '3' of undefined

TypeError: Cannot read property '3' of undefined
at getAFK (:314:107)
at :279:71
at Array.filter ()
at updateTeams (:279:33)
at room.onPlayerJoin (:125:5)
at u.rh (headless-min.js:64)
at R.apply (headless-min.js:109)
at Fa.nf (headless-min.js:45)
at Fa.ec (headless-min.js:46)
at A.lh (headless-min.js:63)

I get this error when I try to run the room

0

0

playtime stat printing a huge float number

I'm not sure if this is working fine for everyone, but what I'm experiencing in "!me" command is, the host printing a very long float number for the playtime stat. Is this how it is supposed to look like? I'm guessing not, but what I want to know is whether I'm the only one having this issue or it's the same for others as well.

image

Mute System

Hi Wazarr,

In your latest build doesn't have mute system. ie. admins can mute somebody with command !mute #id and your discord integration system very good but maybe you can add !notify to notify admins when there is a problem in room(trolling, og, bad words etc.). ofc it should has some conditions like cooldown for using this command(2 min). Thanks for update by the way. Most of the previous problems seem to have been resolved.

Saves doesn't counting

Hello, I checked whole stats on localstorage and none of the players has saves, all of them have 0 and when I checked updatePlayerStats() and getGamePlayerStats() function, they don't have saves value,

function updatePlayerStats(player, teamStats) {
	var stats = new HaxStatistics(player.name);
	var pComp = getPlayerComp(player);
	if (localStorage.getItem(authArray[player.id][0])) {
		stats = JSON.parse(localStorage.getItem(authArray[player.id][0]));
	}
	stats.games++;
	if (lastWinner == teamStats) stats.wins++;
	stats.winrate =
		((100 * stats.wins) / (stats.games || 1)).toPrecision(3) + `%`;
	stats.goals += getGoalsPlayer(pComp);
	stats.assists += getAssistsPlayer(pComp);
	stats.ownGoals += getOwnGoalsPlayer(pComp);
	localStorage.setItem(authArray[player.id][0], JSON.stringify(stats));
}
function getGamePlayerStats(player) {
	var stats = new HaxStatistics(player.name);
	var pComp = getPlayerComp(player);
	stats.goals += getGoalsPlayer(pComp);
	stats.assists += getAssistsPlayer(pComp);
	stats.ownGoals += getOwnGoalsPlayer(pComp);
	return stats;
}

and there is no getSavesPlayer() for checking pComp or player saves

and maybe you can add active time for users log on localstorage for checking who's the most active user?
There is timeEntry and timeExit in PlayerComposition class. but I couldn't save on localstorage.

Error in HaxBot_v3.js onPlayerJoin handler

Due to the order of calls being

updateTeams();
updateAdmins();
extendedP.push([player.id, player.auth, player.conn, false, 0, 0, false]);

The script will fail because the player in extendedP is accessed before it is created, so the correct ordering should be

extendedP.push([player.id, player.auth, player.conn, false, 0, 0, false]);
updateTeams();
updateAdmins();

support for v3 map

is there an efficent way to add v3 map between v2 and v4 map? after the v3 its gonna say "if spec is gonna stay in the next game, v4 will be opened"

0

0

0

0

allow a simple restart instead of resetting teams when players.length == 2 * teamSize

I'd like to modify the part where the teams are reset and re-placed randomly in case players.length == 2 * teamSize. Tbh it's more annoying than beneficial at least for the players I know.

Has anyone done it yet? If so, would you please share it? If no, is anyone wiling to help to achieve this correctly? I've tried modifying this part to the following:

startTimeout = setTimeout(() => {
                    room.startGame();
                }, 2000);

is this the correct way to go?

P.S. I'm also doing the same for this part and this part.

last player on red goes spectator when match end

You can watch between 0:47 and 1:30

Summary

  1. Before match end, room has 9 people; specs has 2 afk (which is gambler and Procyon) (maxTeamSize is 3, so there is no problem)

  2. Red Team: wangdu, ihtiyar, z1z0u and Blue Team: loweskjea, KITIGAWA, NNAZYY

  3. After match end, red team goes spectator(wangdu, ihtiyar, z1z0u), bcs blue team wins the match (0:51 on recording)

  4. loweskjea, KITIGAWA, NNAZYY are going to red bcs they are lastWinner. (0:52 on recording)

  5. There is a bug occurs. The latest player for winnerTeam going to spec for no reason, (in this case NNAZYY). (0:53 on recording)

  6. I checked immediately afk players and NNAZYY doesn't afk (0:59, there is chat log 😴 AFK Oyuncular: gambler., which is listing AFK, there is just gambler)

  7. Second bug: Red team captain(1:15 on recording, loweskjea) choose NNAZYY (there is no chat log, weird)

  8. Red team captain (loweskjea, 1:25 on recording) kicked for not selecting player in time period (actually he selected or paired randomly )

https://thehax.pl/forum/powtorki.php?nagranie=680fa95e6ce632077ff5156b493af235 is recording link and
I hope you can understand the issue, this really weird for me :D

plan for GK stats? (not an issue)

Hi, thanks for the awesome script. Since I see you're somewhat still working on the updates, let me ask you this also.

Are you planning to implement any stats for GKs in the close future? At least the clean sheet stat (which you've had in the old version).

how disable choose player?

Everything is great, but i need to deactivate that function cuz its difficult to use for new players plus i think is unfair for the people who has been waiting

haxball how do we mute?

What to write to mute?

!mute <duration = 3> #

I could not.. How should I write in the message?

Let's say he won't be able to write for 60 seconds. player id: 15 !mute 60/15
not like this ?

Critical Error

when I open the room with the bot you shared in the last update, when I move or when I type something in the chat; It throws an error in the console.

When I type on chat something;
Screenshot-20220405234302-566x497

When I try to move:
Screenshot-20220405234428-563x805

for this bugs I can't test but in previous update; when I type !me it gives values as string(Goals: 1, Winrate: %10, GK: 5 etc) But I can't change like Goal count: 1, Win rate: %10, CS: 5

balancing teams problem when players kicked

Hi,
When 1v1 match going on and 1 spectators, if a player joins (which will be banned / kicked for some reason in bot file like bad nickname)
and kicked / banned immediately; there will 2 players in team red and 1 players located in blue. (2v1) It doesn't balancing teams according to players length.

unknown

If we run balanceTeams() in command line on headless page; teams are balancing without any problem. If we are write into onPlayerKick it doesn't work properly.

Help Error [TypeError: Cannot read property 'id' of undefined]

I get the error on the right in the picture, after a certain time it gives this error the bot crash
https://i.hizliresim.com/gCopeu.png
`function updateRoleOnPlayerIn() {
updateTeams();
if (inChooseMode) {
if (players.length == 6) {
loadMap(bigMap, scoreLimitBig, timeLimitBig);
}
getSpecList(teamR.length <= teamB.length ? teamR[0] : teamB[0]);
}
balanceTeams();
}

function updateRoleOnPlayerOut() {
updateTeams();
if (room.getScores() != null) {
var scores = room.getScores();
if (players.length >= 2 * maxTeamSize && scores.time >= (5/6) * game.scores.timeLimit && teamR.length != teamB.length) {
if (teamR.length < teamB.length) {
if (scores.blue - scores.red == 2) {
endGame(Team.BLUE);
room.sendChat("🤖 Ragequit Tespit Edildi. Oyun Bitti 🤖");
setTimeout(() => { room.stopGame(); }, 100);
return;
}
}
else {
if (scores.red - scores.blue == 2) {
endGame(Team.RED);
room.sendChat("🤖 Ragequit Tespit Edildi. Oyun Bitti 🤖");
setTimeout(() => { room.stopGame(); }, 100);
return;
}
}
}
}
if (inChooseMode) {
if (players.length == 5) {
loadMap(classicMap, scoreLimitClassic, timeLimitClassic);
}
if (teamR.length == 0 || teamB.length == 0) {
teamR.length == 0 ? room.setPlayerTeam(teamS[0].id, Team.RED) : room.setPlayerTeam(teamS[0].id, Team.BLUE);
return;
}
if (Math.abs(teamR.length - teamB.length) == teamS.length) {
room.sendChat("🤖 Hiç Seçenek Kalmadı. Bu Durumu Bot Hallediyor... 🤖");
deactivateChooseMode();
resumeGame();
var b = teamS.length;
if (teamR.length > teamB.length) {
for (var i = 0 ; i < b ; i++) {
setTimeout(() => { room.setPlayerTeam(teamS[0].id, Team.BLUE); }, 5i);
}
}
else {
for (var i = 0 ; i < b ; i++) {
setTimeout(() => { room.setPlayerTeam(teamS[0].id, Team.RED); }, 5i);
}
}
return;
}
if (streak == 0 && room.getScores() == null) {
if (Math.abs(teamR.length - teamB.length) == 2) { // if someone left a team has 2 more players than the other one, put the last chosen guy back in his place so it's fair
room.sendChat("🤖 Takımlar Dengeleniyor... 🤖");
teamR.length > teamB.length ? room.setPlayerTeam(teamR[teamR.length - 1].id, Team.SPECTATORS) : room.setPlayerTeam(teamB[teamB.length - 1].id, Team.SPECTATORS);
}
}
if (teamR.length == teamB.length && teamS.length < 2) {
deactivateChooseMode();
resumeGame();
return;
}
capLeft ? choosePlayer() : getSpecList(teamR.length <= teamB.length ? teamR[0] : teamB[0]);
}
balanceTeams();
}

function balanceTeams() {
if (!inChooseMode) {
if (players.length == 1 && teamR.length == 0) {
quickRestart();
loadMap(aloneMap, 0, 0);
room.setPlayerTeam(players[0].id, Team.RED);
}
else if (Math.abs(teamR.length - teamB.length) == teamS.length && teamS.length > 0) {
const n = Math.abs(teamR.length - teamB.length);
if (players.length == 2) {
quickRestart();
loadMap(classicMap, scoreLimitClassic, timeLimitClassic);
}
if (teamR.length > teamB.length) {
for (var i = 0 ; i < n ; i++) {
room.setPlayerTeam(teamS[i].id, Team.BLUE);
}
}
else {
for (var i = 0 ; i < n ; i++) {
room.setPlayerTeam(teamS[i].id, Team.RED);
}
}
}
else if (Math.abs(teamR.length - teamB.length) > teamS.length) {
const n = Math.abs(teamR.length - teamB.length);
if (players.length == 1) {
quickRestart();
loadMap(aloneMap, 0, 0);
room.setPlayerTeam(players[0].id, Team.RED);
return;
}
else if (players.length == 5) {
quickRestart();
loadMap(classicMap, scoreLimitClassic, timeLimitClassic);
}
if (players.length == maxTeamSize * 2 - 1) {
allReds = [];
allBlues = [];
}
if (teamR.length > teamB.length) {
for (var i = 0 ; i < n ; i++) {
room.setPlayerTeam(teamR[teamR.length - 1 - i].id, Team.SPECTATORS);
}
}
else {
for (var i = 0 ; i < n ; i++) {
room.setPlayerTeam(teamB[teamB.length - 1 - i].id, Team.SPECTATORS);
}
}
}
else if (Math.abs(teamR.length - teamB.length) < teamS.length && teamR.length != teamB.length) {
room.pauseGame(true);
activateChooseMode();
choosePlayer();
}
else if (teamS.length >= 2 && teamR.length == teamB.length && teamR.length < maxTeamSize) {
if (teamR.length == 2) {
quickRestart();
loadMap(bigMap, scoreLimitBig, timeLimitBig);
}
topBtn();
}
}
}

function choosePlayer() {
clearTimeout(timeOutCap);
if (teamR.length <= teamB.length && teamR.length != 0) {
room.sendChat("[PV] Bir oyuncu seçmek için verilen listeye numarasını girin 'Üst', 'Rastgele' Veya 'Alt'.", teamR[0].id);
timeOutCap = setTimeout(function (player) { room.sendChat("[PV] Acele Et @" + player.name + ", only " + Number.parseInt(chooseTime / 2) + " Saniye Kaldı Seçmen İçin !", player.id); timeOutCap = setTimeout(function (player) { room.kickPlayer(player.id, " Zamanında Seçmedin !", false); }, chooseTime * 500, teamR[0]); }, chooseTime * 1000, teamR[0]);
}
else if (teamB.length < teamR.length && teamB.length != 0) {
room.sendChat("[PV] Bir oyuncu seçmek için verilen listeye numarasını girin 'Üst', 'Rastgele' Veya 'Alt'.", teamB[0].id);
timeOutCap = setTimeout(function (player) { room.sendChat("[PV] Acele Et @" + player.name + ", only " + Number.parseInt(chooseTime / 2) + " Saniye Kaldı Seçmen İçin !", player.id); timeOutCap = setTimeout(function (player) { room.kickPlayer(player.id, " Zamanında Seçmedin !", false); }, chooseTime * 500, teamB[0]); }, chooseTime * 1000, teamB[0]);
}
if (teamR.length != 0 && teamB.length != 0) getSpecList(teamR.length <= teamB.length ? teamR[0] : teamB[0]);
}

function getSpecList(player) {
var cstm = "[PV] Oyuncular : ";
for (var i = 0 ; i < teamS.length ; i++) {
if (140 - cstm.length < (teamS[i].name + "[" + (i+1) + "], ").length) {
room.sendChat(cstm, player.id);
cstm = "... ";
}
cstm += teamS[i].name + "[" + (i+1) + "], ";
}
cstm = cstm.substring(0,cstm.length - 2);
cstm += ".";
room.sendChat(cstm, player.id);
}
`

0

0

0

0

Remove Admin Problem

Version 4.
Become admin with! claim password. No problem. But there is no command or does not work to cancel admin. Even if I reinstall the server or change my username, the server sees me as admin. What is the solution I cannot undo if I give admin to a player?

Turkish : !claim password ile admin olunuyor. Sorun yok. Ama adminliği iptal etmek için komut yok ya da çalışmıyor. Sunucuyu yeniden kursam da, kullanıcı adımı değişsem de sunucu beni admin görüyor. Bir oyuncuya adminlik verirsem geri alamam çözümü nedir?

Clarification on VPS approach

New to haxball management and I'm trying to understand how to properly set up the VM (ubuntu 18) on which my installation of Haxroomie is running already 2 vanilla rooms with some of saviola777/hhm-plugins plugins.

In your readme you say to write a configuration like this:

    {
        autoStart: true,
        roomName: 'YOUR ROOM NAME HERE',
        maxPlayers: 16,
        public: true,
        noPlayer: true,
        token: 'YOUR TOKEN HERE',
        roomScript: '/path/file/Haxbot_public.js',
    }

But when I checked the content of Haxbot_public.js in your repo, I see that it would "re-initialise" the room.
Can you clarify? Maybe because the token will be the same it will simply "load" the room to be able to access the hooks?
If it's an oversight, can you provide some guidance or a version of the file for VBS?

Thank you

Admin problem

Which command should I use to become admin? I tried everything but nothing works.. (I'm using Firefox and the Version 4 of the JS)

calculateStadiumVariable problem

Hello Wazarr,

Sometimes players are freezing and room closed with an error on console. Here some screenshot about error. It happen in 20-30 times in a day. I hope you can fix
Screenshot from 2022-04-12 16-46-40
Screenshot from 2022-04-12 16-46-43
Screenshot from 2022-04-12 16-46-45
Screenshot from 2022-04-12 16-48-41
Screenshot from 2022-04-12 16-48-46
Screenshot from 2022-04-12 16-48-49

how do we fix this

TypeError: Cannot read property 'id' of undefined
at getSpecList (:560:29)
at updateRoleOnPlayerIn (:401:3)
at room.onPlayerJoin (:731:2)
at u.rh (headless-min.js:64)
at R.apply (headless-min.js:109)
at Fa.nf (headless-min.js:45)
at Fa.ec (headless-min.js:46)
at A.lh (headless-min.js:63)
at Function.Ea.va (headless-min.js:53)
at headless-min.js:49

bot crashes with same reason

bot_crash

i have 2 seperated rooms and sometimes one of them crashes with this error. i looked for possible reasons but i cant stop, do you have any idea

admin spectators stay

The admin will constantly watch the bot name, which will throw players who will not enter the game, I'm just looking for a code for this.

0

0

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.