GithubHelp home page GithubHelp logo

nrdp'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

Watchers

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

nrdp's Issues

Debugging doesnt work

Enabling the debug mode doesnt work.

Configuration:

// Enable debug logging
$cfg["debug"] = false;
$cfg["debug_log"] = "/usr/local/nrdp/server/debug.log";

name 'html' is not defined send_nrdp.py

Ubuntu 20.04
python 3.8

python3 ./send_nrdp.py -u http://[NagiosIP]/nrdp/ -t TOKENXXX -H centos01 -S 0 -o "The host is up and OK"

Result:
"name 'html' is not defined"

I change:
in line 48= import argparse, sys
for =
import argparse, sys, html

And now the result is:
Cannot connect to url.
XML or text declaration not at start of entity: line 3, column 0

or

ERROR - Cannot connect to url: HTTP Error 500: Internal Server Error

Data not proccessing

Server Centos 7.7
Nagios core 4.4.3 (epel repo install)
nrdp 2.0.2
Client Centos 7.7
nsca 2.2.0

Passive commands send
image
Passive commands show up in the checkresults folder
image
Passive commands proccess (the folder automaticly empties)

Nothing showes up in nagios.log about the data being proccessed

Passive checks are enabled
Nagcmd has both apache and nagios users assigned to it
Selinux is disabled

send_nrdp.php is always returning 0

send_nrdp.php returns always 0, except in the function check_args. This makes it impossible to check if the command was successful or not.

send_nrdp.sh not working with arguments when used as an obsessive compulsive command

In send_nrdp.sh this if statement is being used to determine if STDIN is being used:

if [ ! -t 0 ]; then

For the situations when you are piping to the script.

I was configuring the script as an obsessive compulsive command for hosts and services. This was on a Nagios Core server sending results back to a central Nagios XI server. I was using the script in argument mode, passing all the arguments instead of piping them. When I do this, the $xml variable in the script gets reset to nothing and the script fails. You can see this in /var/log/messages with stdout line 01: ERROR: The NRDP Server said BAD XML.

Here are the command definitions:

define command{
	command_name	send_nrdp_host
	command_line	$USER1$/send_nrdp.sh -u https://10.25.5.17/nrdp/ -t XXXXX -H '$HOSTNAME$' -S $HOSTSTATEID$ -o '$HOSTOUTPUT$'
	}

define command{
	command_name	send_nrdp_service
	command_line	$USER1$/send_nrdp.sh -u https://10.25.5.17/nrdp/ -t XXXXX -H "$HOSTNAME$" -s "$SERVICEDESC$" -S $SERVICESTATEID$ -o "$SERVICEOUTPUT$"
	}

Here is nagios.cfg

obsess_over_services=1
ocsp_command=send_nrdp_service
obsess_over_hosts=1
ochp_command=send_nrdp_host

Here is how you can reproduce / troubleshoot.
Make the following changes to the script:
On line 2 add this:

echo -e "`ls -la /proc/$$/fd`"

On line 220 (before if [ ! -t 0 ]; then) add this:
echo $xml
On line 224 (after if [ ! -t 0 ]; then) add this:
echo here
On line 255 (after fi) add this:
echo $xml

Now if you test from the command line:

/usr/local/nagios/libexec/send_nrdp.sh -u https://10.25.5.17/nrdp/ -t XXXXX -H "host" -s "service" -S 0 -o "test"

The output will be something like:

total 0
dr-x------. 2 root root  0 Aug 15 15:01 .
dr-xr-xr-x. 9 root root  0 Aug 15 15:01 ..
lrwx------. 1 root root 64 Aug 15 15:01 0 -> /dev/pts/2
lrwx------. 1 root root 64 Aug 15 15:01 1 -> /dev/pts/2
lrwx------. 1 root root 64 Aug 15 15:01 2 -> /dev/pts/2
lr-x------. 1 root root 64 Aug 15 15:01 255 -> /usr/local/nagios/libexec/send_nrdp.sh
lr-x------. 1 root root 64 Aug 15 15:01 3 -> pipe:[822644]
<checkresult type='service' checktype='1'><servicename>service</servicename><hostname>host</hostname><state>0</state><output><![CDATA[test]]></output></checkresult>
<checkresult type='service' checktype='1'><servicename>service</servicename><hostname>host</hostname><state>0</state><output><![CDATA[test]]></output></checkresult>
Sent 1 checks to https://10.25.5.17/nrdp/

You can see that the if statement was not true and the then block was not executed, hence the $xml variable is not overwritten with this line of code:
xml=""

To see it fail when Nagios Core uses it, execute this command:
tail -f /var/log/messages

Now go to a service object and force a check, this will cause the obsessive command to be executed, the output will be something like:

Aug 15 15:04:12 core-015 nagios: wproc: OCSP job 22 from worker Core Worker 1973 is a non-check helper but exited with return code 2
Aug 15 15:04:12 core-015 nagios: wproc:   host=DNS1; service=SSH; contact=(none)
Aug 15 15:04:12 core-015 nagios: wproc:   early_timeout=0; exited_ok=1; wait_status=512; error_code=0;
Aug 15 15:04:12 core-015 nagios: wproc:   stdout line 01: total 0
Aug 15 15:04:12 core-015 nagios: wproc:   stdout line 02: dr-x------. 2 nagios nagios  0 Aug 15 15:04 .
Aug 15 15:04:12 core-015 nagios: wproc:   stdout line 03: dr-xr-xr-x. 9 nagios nagios  0 Aug 15 15:04 ..
Aug 15 15:04:12 core-015 nagios: wproc:   stdout line 04: lr-x------. 1 nagios nagios 64 Aug 15 15:04 0 -> /dev/null
Aug 15 15:04:12 core-015 nagios: wproc:   stdout line 05: l-wx------. 1 nagios nagios 64 Aug 15 15:04 1 -> pipe:[823219]
Aug 15 15:04:12 core-015 nagios: wproc:   stdout line 06: l-wx------. 1 nagios nagios 64 Aug 15 15:04 2 -> pipe:[823220]
Aug 15 15:04:12 core-015 nagios: wproc:   stdout line 07: lr-x------. 1 nagios nagios 64 Aug 15 15:04 255 -> /usr/local/nagios/libexec/send_nrdp.sh
Aug 15 15:04:12 core-015 nagios: wproc:   stdout line 08: lr-x------. 1 nagios nagios 64 Aug 15 15:04 3 -> pipe:[823223]
Aug 15 15:04:12 core-015 nagios: wproc:   stdout line 09: <checkresult type='service' checktype='1'><servicename>SSH</servicename><hostname>DNS1</hostname><state>0</state><output><![CDATA[SSH OK - OpenSSH_6.7p1 Raspbian-5+deb8u1 (protocol 2.0)]]></output></checkresult>
Aug 15 15:04:12 core-015 nagios: wproc:   stdout line 10: here
Aug 15 15:04:12 core-015 nagios: wproc:   stdout line 11:
Aug 15 15:04:12 core-015 nagios: wproc:   stdout line 12: ERROR: The NRDP Server said BAD XML

You can see that stdout line 09 shows the content of the $xml variable.
Then stdout line 10 shows that the if statement was true and the then block was executed, hence the $xml variable is overwritten with this line of code:
xml=""
You can see that stdout line 11 shows the empty $xml variable.

Tested on CentOS 7.x, Nagios Core 4.3.2, send_nrdp.sh from master.

send_nrdp.py not working with arguments when used as an obsessive compulsive command

In send_nrdp.py this if statement is being used to determine if STDIN is being used:

if not sys.stdin.isatty():

For the situations when you are piping to the script ... however issue #16 reports this does not work.

I was configuring the script as an obsessive compulsive command for hosts and services. This was on a Nagios Core server sending results back to a central Nagios XI server. I was using the script in argument mode, passing all the arguments instead of piping them. When I do this, the xml variable in the script does not get populated with data and the script fails. You can see this in /var/log/messages with:

stderr line 01: syntax error: line 1, column 0
stdout line 01: Cannot connect to url.

Here are the command definitions:

define command{
	command_name	send_nrdp_host
	command_line	$USER1$/send_nrdp.py -u https://10.25.5.17/nrdp/ -t XXXXX -H '$HOSTNAME$' -S $HOSTSTATEID$ -o '$HOSTOUTPUT$'
	}

define command{
	command_name	send_nrdp_service
	command_line	$USER1$/send_nrdp.py -u https://10.25.5.17/nrdp/ -t XXXXX -H "$HOSTNAME$" -s "$SERVICEDESC$" -S $SERVICESTATEID$ -o "$SERVICEOUTPUT$"
	}

Here is nagios.cfg

obsess_over_services=1
ocsp_command=send_nrdp_service
obsess_over_hosts=1
ochp_command=send_nrdp_host

Here is how you can reproduce / troubleshoot.
Make the following changes to the script:
On line 114 (before self.post_data(options.url, options.token, xml)) add this:
print "xml variable: {0}" . format(xml)

Now if you test from the command line:

/usr/local/nagios/libexec/send_nrdp.py -u https://10.25.5.17/nrdp/ -t XXXXX -H "host" -s "service" -S 0 -o "test"

The output will be something like:

xml variable: <?xml version='1.0'?>
<checkresults>
<checkresult type='service' checktype='1'><hostname>host</hostname><servicename>service</servicename><state>0</state><output>test</output></checkresult></checkresults>

This shows valid data in the xml variable.

To see it fail when Nagios Core uses it, execute this command:
tail -f /var/log/messages

Now go to a service object and force a check, this will cause the obsessive command to be executed, the output will be something like:

Aug 15 17:43:37 core-015 nagios: wproc: OCSP job 45 from worker Core Worker 5429 is a non-check helper but exited with return code 1
Aug 15 17:43:37 core-015 nagios: wproc:   host=DNS1; service=PING; contact=(none)
Aug 15 17:43:37 core-015 nagios: wproc:   early_timeout=0; exited_ok=1; wait_status=256; error_code=0;
Aug 15 17:43:37 core-015 nagios: wproc:   stderr line 01: syntax error: line 1, column 0
Aug 15 17:43:37 core-015 nagios: wproc:   stdout line 01: xml variable: <?xml version='1.0'?>
Aug 15 17:43:37 core-015 nagios: wproc:   stdout line 02: <checkresults>
Aug 15 17:43:37 core-015 nagios: wproc:   stdout line 03:
Aug 15 17:43:37 core-015 nagios: wproc:   stdout line 04: Cannot connect to url.

You can see that stdout line 01 - 03 shows the content of the xml variable, it has not been correctly populated.

Tested on CentOS 7.x, Nagios Core 4.3.2, send_nrdp.py from master.

External Command Permissions

It would be useful if you could define granular permissions for the external commands. For example I want to allow a token to ACKNOWLEDGE_HOST_PROBLEM and ACKNOWLEDGE_SVC_PROBLEM however I don't want it to be able to DISABLE_HOST_CHECK, DISABLE_HOST_SVC_CHECKS, DISABLE_PASSIVE_HOST_CHECKS, DISABLE_PASSIVE_SVC_CHECKS.

I understand that connection to NRDP can be something other than a token, whatever authentication method used would have these permissions used.

NRDP on XI: semicolon changes to colon

Passing check results toward NRDP containing one or multiple semicolon characters in status information field results in semicolon to colon translation as output.

Problem is easily reproducible, just set set send_nrdp.sh -s parameter to something like OK: result1=1; result2=2;​

nrdp_bug

(No output on stdout) stderr:

I am getting the below error and the status is showing Ok and is green
(No output on stdout) stderr:
nagios_error
I am using Nagios Core Version 4.4.4

send_nrdp.php doesnt work in case plugin output contains $delim char

Checks which contains the send_nrdp.php $delim char in plugin_output will not be transmitted.

Test scenario:

11:46:22 [root@lab01]:/usr/local/modpd/libexec# cat test_data.txt
localhost_1     Multiline output with tabs      0       first line      with tab\nsecond line with\ttab

11:46:28 [root@lab01]:/usr/local/modpd/libexec# cat -vet test_data.txt
localhost_1^IMultiline output with tabs^I0^Ifirst line^Iwith tab\nsecond line with\ttab$

11:46:30 [root@lab01]:/usr/local/modpd/libexec# cat test_data.txt | ./send_nrdp.php --usestdin --token="12345678" --url=https://nrdpuser:[email protected]:443/nrdp

NRDP check results can overflow into /tmp

Normally NRDP check results end up in $cfg["check_results_dir"] but if e.g. the disk is full the results can end up in /tmp instead, resulting in thousands/millions of files in /tmp and a full disk, etc. on large setups.

The problem is caused by the use of $tmpname = tempnam($cfg["check_results_dir],"c");
As per the official documentation of tempnam it is not garanteed that the file created is actually in the requested directory. NRDP should check if the created file is actually in $cfg["check_results_dir]. If not it should delete the file and return an error, e.g. "handle_api_error(ERROR_BAD_CHECK_RESULTS_DIR);"
This is applicable for both nrdp/server/index.php and nrdp/server/plugins/nagioscorepassivecheck/nagioscorepassivecheck.php

send_nrdp.py - Does not accept STDIN or File

Help states the following:

  -d DELIM, --delim=DELIM
                        With only the required parameters send_nrdp.py is
                        capable of processing data piped to it either from a
                        file or other process. By default, we use t as the
                        delimiter however this may be specified with the -d
                        option data should be in the following formats one
                        entry per line.

When I try piping to it I get an error:

printf "centos01\t0\tThe host is up and OK\n" | ./send_nrdp.py -u http://10.25.5.2/nrdp/ -t XXXXX
Cannot connect to url.
syntax error: line 1, column 0

In addition there is currently no way of reading from a file (the help about says you can). Looking at the script there are comments that this is a to-do item.

Bug - check_results_dir does not work if it's symlinked

When having the check_results_dir point to a path that contains a symlink, PHP's file_exist function doesn't work properly:

http://php.net/manual/en/function.file-exists.php#73904

You can validate like so:

mkdir /testing
mv /usr/local/nagios/var/spool /testing/
ln -s /testing/spool /usr/local/nagios/var/spool
chown -h nagios.nagios /usr/local/nagios/var/spool
chown nagios.nagios /testing
chmod 775 /testing

Then go to http://YOURSERVER/nrdp/ and submit a check result and you will receive:

<result><status>-1</status><message>BAD CHECK RESULTS DIR</message></result>

Permit additional cmd=submitcheck handler plugins

I wrote a plugin to duplicate checkresults requests to backup NRDP servers, but found the plugin callback gets registered after the nagioscorepassivecheck plugin which calls exit(). I could rename it so the plugins' alphabetical sorting takes care of this issue, but I'd rather have a more general fix if possible.

Maybe the nagioscore plugins can remove their exit() calls and the missing handler warning can be prefixed with if (!headers_sent())?

Or maybe a new CALLBACK_PREPROCESS_REQUEST could be added for calling plugin functions that don't write output or exit?

Or maybe add an option to register_callback() that prepends functions instead of appending?

What do you think?

how to use JSONDATA check in Webhook body

Hi

I would like use JSONDATA nrpe check with the webhook. Here is my curl command which works fine.

curl -f -d 'token=TOKEN&cmd=submitcheck&JSONDATA={
  "checkresults": [
    {
      "checkresult": {
        "type": "service",
        "checktype": "1"
      },
      "hostname": "node2",
      "servicename": "Cron_Err",
      "state": "1",
      "output": "Cron_Err in Warning state"
    }
  ]
}'  http://nagios.domain.com/nrdp/

But when I use it in Webhook it gives me error as

TypeError: Invalid template! Template should be a \"string\" but \"object\" was given as the first argument for mustache#render(template, view, partials)\n

Here is my Webhook

        "body": {
          "dataType": "json",
          "data": {
            "cmd": "submitcheck",
            "token": “TOKEN”,
            "JSONDATA": {
              "checkresults": [
                {
                  "checkresult": {
                    "type": "service",
                    "checktype": "1"
                  },
                  "hostname": “node2",
                  "servicename": "Cron_Err",
                  "state": "1",
                  "output": "Cron_Err in Warning state"
                }
              ]
            }
          }
        }

So, I am not sure what should be the right body section and how to define the token and cmd section in the body section.

Any help is appreciated.

Wrong var name for debug file

Hello,

The var name for debug file is wrong in the "config.inc.php" :

// Where should the logs go?
$cfg["debug_log"] = "/home/nrdp/server/debug.log";

But in
"server/includes/utils.inc.php" , line 406
You are using another name for the variable

$file = grab_array_var($cfg, "debug_file", "/usr/local/nrdp/server/debug.log");

send_nrdp.py - Cannot connect to url if it does not end with a /

Example:

./send_nrdp.py -u 'http://10.25.5.2/nrdp' -t XXXXX -H centos01 -S 0 -o "The host is up and OK" 
Cannot connect to url.
junk after document element: line 1, column 40

However if the URL ends with a / then it works:

./send_nrdp.py -u 'http://10.25.5.2/nrdp/' -t XXXXX -H centos01 -S 0 -o "The host is up and OK"

There is no output when it works (as expected).

Script should be updated to test that the URL ends with a / and add it if it does not.

Package has been moved.

I am following the installation docs...
Here:
https://support.nagios.com/kb/article/nrdp-installing-nrdp-from-source-602.html
& Here
https://github.com/NagiosEnterprises/nrdp/

However the package(s) seem to have been removed or relocated.

Computername:~ User$ wget https://github.com/NagiosEnterprises/nrdp/archive/1.5.2.tar.gz
--2018-05-30 11:42:42--  https://github.com/NagiosEnterprises/nrdp/archive/1.5.2.tar.gz
Resolving github.com... 192.30.253.113, 192.30.253.112
Connecting to github.com|192.30.253.113|:443... connected.
HTTP request sent, awaiting response... 302 Found
Location: https://codeload.github.com/NagiosEnterprises/nrdp/tar.gz/1.5.2 [following]
--2018-05-30 11:42:43--  https://codeload.github.com/NagiosEnterprises/nrdp/tar.gz/1.5.2
Resolving codeload.github.com... 192.30.253.121, 192.30.253.120
Connecting to codeload.github.com|192.30.253.121|:443... connected.
HTTP request sent, awaiting response... 404 Not Found
2018-05-30 11:42:43 ERROR 404: Not Found.

Is there another location I can pull the source from?

http://<nagios ip>/nrdp not working

Hey guys. I've been using Nagios for almost 2 years now.
I've had all our configuration as active checks. Now, we need some passive checks since we can't reach some remote machines.
After following the steps, and installing nrdp on my ubuntu 15, I saw that my apache is on apache2 folder, and not on httpd. I did the NRDP configuration on my apache2 conf-available folder.
After restarting apache, I can't reach http:///nrdp. it just says "The requested URL /nrdp was not found on this server."
Do I have to do anything diferente as this being apache2? httpd folder dsn't exist on my machine.
Ty in advance

send_nrdp.php produces handle_api_error(msg=BAD XML)

send_nrdp.php uses wrong method for converting strings to html entities. Depending on the chars in the plugin output this can result in an invalid xml and produces the following error: handle_api_error(msg=BAD XML) on the NRDP server.
I will provide a fix via a pull request.

NRDP JSONDATA check doesn't works and get message as "NO DATA"

Hi

I trying to use the NRDP check using the JSONDATA and it's not working and gives message as "NO DATA", while XMLDATA works fine.

Here are my commands and error

JSONDATA test

curl -f -d 'token=TOKEN&cmd=submitcheck&JSONDATA={ "checkresults": [ { "checkresult": { "type": "service", "checktype": "1", }, "hostname": "node2", "servicename": "Cron_Err", "state": "1", "output": "Cron_Err in Warning state", } ] }'  http://nagios.domain.com/nrdp/
<?xml version="1.0" encoding="utf-8"?>
<result>
  <status>-1</status>
  <message>NO DATA</message>
</result>

XMLDATA test

curl -f -d "token=TOKEN&cmd=submitcheck&XMLDATA=<?xml version='1.0'?><checkresults><checkresult type='service' checktype='1'><hostname>node2</hostname> <servicename>Cron_Err</servicename><state>1</state><output>Cron_Err in Warning state</output></checkresult></checkresults>" http://nagios.domain.com/nrdp/
<?xml version="1.0" encoding="utf-8"?>
<result>
  <status>1</status>
  <message>OK</message>
    <meta>
       <output>1 checks processed.</output>
    </meta>
</result>

So is there I am missing anything in the JSONDATA command syntax.

Thank You,

send_ndrp.sh behaves abnormally when using paths with spaces in them

Issue 0: Using -f '/tmp/ foo bar/ b a z.dat' results in "[: too many arguments" error:

# /usr/local/nrdp/clients/send_nrdp.sh -f '/tmp/ foo bar/ b a z.dat' -u https://example.com/nrdp -t mytoken -H "testhost" -S 0 -o "This is test 1"
/usr/local/nrdp/clients/send_nrdp.sh: line 293: [: too many arguments

Issue 1: Using -D '/tmp/ foo bar' results in "[: foo: binary operator expected" error:

# /usr/local/nrdp/clients/send_nrdp.sh -D '/tmp/ foo bar' -u https://example.com/nrdp -t mytoken -H "testhost" -S 0 -o "This is test 1"
/usr/local/nrdp/clients/send_nrdp.sh: line 298: [: foo: binary operator expected

[RFE] Adding debugging sensor lines into nrdp server code

Hi

I am hoping one can turn on debug flag in nrdp config file and the flow of receiving xml data from nrdp client, from httpd and writing commands to nagios server activities be logged into a file.

This will help greatly when nrdp server is not working.

PLEASE respect ports given in the URL to access NRDP via send_nrdp.php!

PLEASE respect ports given in the URL to access NRDP via send_nrdp.php! A quick patch to v1.8 would be as follows, but apparently I can't branch this out.

301a302
>     if ($url_parts['port'] != "") { $port=":" . $url_parts['port']; } else { $port="80:"; }
318c319
<             $page = $url_parts['scheme'] . '://' . $url_parts['host'] . $url_parts['path'];

---
>             $page = $url_parts['scheme'] . '://' . $url_parts['host'] . $port . $url_parts['path'];
368c369
<         $fp = fsockopen($url_parts['host'], 80, $errno, $errstr, 30);

---
>         $fp = fsockopen($url_parts['host'], $port, $errno, $errstr, 30);

NRPD 2.0.1 does not work with SSL

It seems like NRPD 2.0.1 (and possibly 2.0.2) does not work with the following option set in config.inc.php:

$cfg["require_https"] = true;

The issue was reported on the Nagios Support forum here:

https://support.nagios.com/forum/viewtopic.php?t=54905#288621

I was able to recreate it in Nagios XI 5.6.5 with NRPD 2.0.1. Accessing NRDP by going to:

https://<ip address>/nrdp/

generates the "HTTPS REQUIRED" error in the GUI.

Additional info:
I was hoping for find some clues in the logs, so I enabled debugging by setting:

$cfg["debug"] = true;
$cfg["debug_log"] = "/usr/local/nrdp/server/debug.log";

in config.inc.php, however the debug.log didn't get created. Am I missing something?

Support JSON in addition to XML

With Logserver using JSON, and the XI 5 API doing the same, it makes sense for NRDP to follow suit. Besides, JSON is much nicer to work with that XML anyway.

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.