Giter Site home page Giter Site logo

showdownjs / showdown Goto Github PK

View Code? Open in Web Editor NEW
13.9K 198.0 1.6K 7.78 MB

A bidirectional Markdown to HTML to Markdown converter written in Javascript

Home Page: http://www.showdownjs.com/

License: MIT License

JavaScript 73.45% HTML 26.55%
showdown javascript markdown markdown-parser markdown-flavors gfm html converter html-converter

showdown's People

Contributors

bandantonio avatar butchmarshall avatar cybercase avatar danielruf avatar dchester avatar dennisss avatar dependabot[bot] avatar erisds avatar greenkeeper[bot] avatar henrahmagix avatar jasonmit avatar kkaefer avatar langpavel avatar lovethesource avatar martinbeentjes avatar meteorlxy avatar pdeschen avatar remy avatar rheber avatar schmijos avatar stevemao avatar syntaxrules avatar teleological avatar tivie avatar tpxp avatar tsndr avatar tstone avatar twitwi avatar vladimirv99 avatar voltanfr 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

showdown's Issues

Architecture & Process Changes

Showdown is evolving. I'm interested in exploring options for making larger code architecture and project process changes here.

I'd love to hear from @pdeschen, @tstone and the Showdown community at large regarding the following ideas and any others.

Regarding project management, I'm wondering whether it's time to move things to a Showdown github "organization". I feel a number of the recent contributors ought to be given commit rights and the newly added extension mechanism opens the door for Showdown, um..., extensions and my sense is that it would likely be good for those to be managed individually.

Regarding recording/maintaining the historical record, I feel it's important to be sure we continue to recognize Showdown's roots and John Fraser as the original author. On the other hand, it feels like much of the original examples, the Perl code, etc. could be moved "out of the way". My suggestion here is to create a "legacy" branch (and tag?) which would make it easy to find that stuff, but just as easy to leave it behind and move forward unencumbered.

Thoughts?

Define an extension syntax

It should probably be capable of:

  • Categorizing the extension as either language extension or output modification
  • Give developers the option of a simple regex/replace syntax, regex/function syntax, or straight out callback function to do whatever you want
  • Extensions should be able dynamically loaded on either the client or server ,then a new converter instantiated with them
  • Allow multiple language modifications to be included in a single extension (ie. a github extension would include 40 or 50 modifications)

Suggestions for implementations can be discussed below:

Parsing escaped html entities

Showdown has been awesome so far, I just have a small issue with escaped html. For example I encode all html entities before running showdown on the user input. Therefore text like
<http://google.com> // Looks like github is parsing the link with html entities
no longer works because the regexs are not checking for escaped entities.
I have tweaked the regex to look like this:

// autolinking  
text = text.replace(/(?:<|&lt;)((https?|ftp|dict):[^'">\s]+)(?:>|&gt;)/gi,"<a href=\"$1\">$1</a>");  
[ignore]  

Im sure this may affect other parts of the code but this is the only piece that I have changed so far.

Ignore syntax inside <pre> totally

I found that some syntax are not ignored inside <pre> or code block (```). For example image embedding syntax. Also all extensions are not ignored. Is there a tag to ignore all syntax?

Passing in an URL

Hi, I'm thinking about using Showdown in my next small project but I can't grasp it. Is there any way to pass in a URL (to a Markdown file) so it outputs the HTML?

npm module out of date

This is probably one of the more important issues to me. Anyone know who is managing the module in the npm system?

Emphasis in a link

A _ in a link match for emphasis.

Try with link:
[https://github.com/an_emphasis_link]()

Incorrect parsing of underscore and asterisk

If you have text like this:

Hello.this\_is\_a\_variable
and.this.is.another_one

Showdown incorrectly parses it as:

Hello.this<em>is</em>a<em>variable
and.this.is.another</em>one

To fix it, replace lines 984-988:

text = text.replace(/(?![\])(\*\*|__)(?=\S)([^\r]*?\S[*_]*)\1/g,
    "<strong>$2</strong>");

text = text.replace(/(?![\])(\*|_)(?=\S)([^\r]*?\S)\1/g,
    "<em>$2</em>");

I'm not a regex pro, but as far as I can tell adding the negative lookahead (?![\]) before the groups works fine. This tells the regex to skip those characters if they're escaped with the backslash '' character.

Thanks!

Grunt lint task needs to be updated with Grunt upgrade.

The current Grunt lint test isn't identifying issues properly, and should probably just be substituted with grunt-contrib-jshint when Grunt is upgraded. This will identify a handfull of errors (below) that need to be cleaned up.

Running "jshint:src" (jshint) task
Linting src/showdown.js ...ERROR
[L120:C19] W122: Invalid typeof value 'undefind'
if (typeof module !== 'undefind' && typeof exports !== 'undefined' && typeof require !== 'undefind') {
[L120:C86] W122: Invalid typeof value 'undefind'
if (typeof module !== 'undefind' && typeof exports !== 'undefined' && typeof require !== 'undefind') {
[L272:C4] W099: Mixed spaces and tabs.
          [ \t]*
[L273:C4] W099: Mixed spaces and tabs.
          \n?        // maybe one newline
[L274:C4] W099: Mixed spaces and tabs.
          [ \t]*
[L276:C4] W099: Mixed spaces and tabs.
          [ \t]*
[L277:C4] W099: Mixed spaces and tabs.
          \n?        // maybe one newline
[L278:C4] W099: Mixed spaces and tabs.
          [ \t]*
[L280:C4] W099: Mixed spaces and tabs.
          (\n*)        // any lines skipped = $3 attacklab: lookbehind removed
[L281:C4] W099: Mixed spaces and tabs.
          ["(]
[L282:C4] W099: Mixed spaces and tabs.
          (.+?)        // title = $4
[L283:C4] W099: Mixed spaces and tabs.
          [")]
[L284:C4] W099: Mixed spaces and tabs.
          [ \t]*
[L287:C3] W099: Mixed spaces and tabs.
        /gm,
[L288:C3] W099: Mixed spaces and tabs.
        function(){...});
[L315:C2] W033: Missing semicolon.
}
[L440:C2] W033: Missing semicolon.
}
[L512:C2] W033: Missing semicolon.
}
[L531:C2] W033: Missing semicolon.
}
[L606:C5] W099: Mixed spaces and tabs.
    (               // wrap whole match in $1
[L616:C2] W033: Missing semicolon.
}
[L619:C12] W041: Use '===' to compare with 'undefined'.
  if (m7 == undefined) m7 = "";
[L622:C13] W099: Mixed spaces and tabs.
  var link_id   = m3.toLowerCase();
[L626:C13] W041: Use '===' to compare with ''.
  if (url == "") {
[L627:C21] W041: Use '===' to compare with ''.
    if (link_id == "") {
[L633:C29] W041: Use '!==' to compare with 'undefined'.
    if (g_urls[link_id] != undefined) {
[L635:C35] W041: Use '!==' to compare with 'undefined'.
      if (g_titles[link_id] != undefined) {
[L652:C15] W041: Use '!==' to compare with ''.
  if (title != "") {
[L661:C2] W033: Missing semicolon.
}
[L720:C2] W033: Missing semicolon.
}
[L725:C13] W099: Mixed spaces and tabs.
  var link_id   = m3.toLowerCase();
[L731:C13] W041: Use '===' to compare with ''.
  if (url == "") {
[L732:C21] W041: Use '===' to compare with ''.
    if (link_id == "") {
[L738:C29] W041: Use '!==' to compare with 'undefined'.
    if (g_urls[link_id] != undefined) {
[L740:C35] W041: Use '!==' to compare with 'undefined'.
      if (g_titles[link_id] != undefined) {
[L765:C2] W033: Missing semicolon.
}
[L812:C2] W033: Missing semicolon.
}
[L858:C53] W032: Unnecessary semicolon.
      list = list.replace(/\n{2,}/g,"\n\n\n");;
[L878:C22] W004: 'list' is already defined.
      var list = list.replace(/\n{2,}/g,"\n\n\n");;
[L878:C57] W032: Unnecessary semicolon.
      var list = list.replace(/\n{2,}/g,"\n\n\n");;
[L889:C2] W033: Missing semicolon.
}
[L960:C2] W033: Missing semicolon.
}
[L1041:C2] W033: Missing semicolon.
}
[L1046:C2] W033: Missing semicolon.
}
[L1053:C3] W099: Mixed spaces and tabs.
//   include literal backticks in the code span. So, this input:
[L1055:C4] W099: Mixed spaces and tabs.
//     Just type ``foo `bar` baz`` at the prompt.
[L1057:C3] W099: Mixed spaces and tabs.
//     Will translate to:
[L1059:C4] W099: Mixed spaces and tabs.
//     <p>Just type <code>foo `bar` baz</code> at the prompt.</p>
[L1067:C4] W099: Mixed spaces and tabs.
//     ... type `` `bar` `` ...
[L1069:C3] W099: Mixed spaces and tabs.
//     Turns to:
>> Too many errors. (73% scanned).

I'm working on getting this all cleaned up 🚰

bug - Automatic Extension Loading (node only)

I found misspelling.
please fix 'undefind' to 'undefined'.

showdown.js , line 120

//
// Automatic Extension Loading (node only):
//
if (typeof module !== 'undefind' && typeof exports !== 'undefined' && typeof require !== 'undefind') {
if (typeof module !== 'undefined' && typeof exports !== 'undefined' && typeof require !== 'undefined') {

Github style code blocks don't auto-escape HTML

<'s and >'s should be converted to &lt; and &gt;

Example:

```html
<div>HTML!</div>
\```

(The leading \ is there to get github to not close the codeblock on [backtick][backtick][backtick])

URLs are improperly escaped

Converting the following Markdown:

http://example.com/'onmouseover='alert(document.cookie)'/

yields the following HTML:

<p><a href='http://example.com/'onmouseover='alert(document.cookie)'/'>http://example.com/'onmouseover='alert(document.cookie)'/</a></p>

which in turn is parsed by the browser as:

<p><a href="http://example.com/" onmouseover="alert(document.cookie)" '="">http://example.com/'onmouseover='alert(document.cookie)'/</a></p>

The reason is that URLs are improperly escaped before being inserted into href attributes.

I discovered this by accident while writing a tutorial on XSS. It's a defect in the Showdown library that would allow for unintended script injection if Markdown weren't designed to allow inline HTML to begin with.

<style> tag is removed

Markdown.pl version 1.0.1 passes through my inline <style> tag unmodified. Showdown removes it.

(Seems like this repo isn't maintained actively anymore perhaps....)

a parse bug

markdown text:

* list

        + item

             - subitem

               The HTML has a superfluous newline before this
               paragraph.

             - subitem

               The HTML here is unchanged.

             - subitem

               The HTML is missing a newline after this
               list subitem.

correct markdown parse :

  • list

    + item
    
         - subitem
    
           The HTML has a superfluous newline before this
           paragraph.
    
         - subitem
    
           The HTML here is unchanged.
    
         - subitem
    
           The HTML is missing a newline after this
           list subitem.
    

the showdown parse :

list

+ item


 - subitem


   The HTML has a superfluous newline before this
   paragraph.


 - subitem


   The HTML here is unchanged.


 - subitem


   The HTML is missing a newline after this
   list subitem.

Extensions Documentation

The documentation for building extensions seems to be pretty good. However, I've been unsuccessful at getting extensions to load.

A couple errors when following the documentation:

  1. TypeError: showdown is not a constructor. I've found that removing the () after "new Showdown"
new Showdown().converter({ extensions: 'twitter' });

... seems to help. However, I hit another hurdle.

  1. I keep getting a "TypeError: converter_options.extensions.forEach is not a function". Upon further inspection, the converter_options array is just an array of strings. There is no forEach function assigned to them.

I'm not really sure how to proceed and I haven't seen any working extension examples anywhere. Is there any way they could be included in the example?

Thanks!

no need for new, benchmarked refactor results

So I was messing with this for fun. Didnt like the code style, and had a theory that if I pulled out a bunch of large regexes and functions into variables outside of the functions there would be a bit of a performance boost. Well you can see the lackluster results here http://jsperf.com/showdown-basic-optimizations

I would suggest doing away with the constructor newing tho, there is no need for it. Just return the makeHtml function as seen in the ShowdownMod code block in the jsperf page.

Can't upload your library to my repo?

I tried integrating your library to my project, but when I went on my repo to the javascript folder, the "showdown" folder is not clickable. Deploying also doesn't work since it seems to just be a blank unclickable folder. Is there some sort of licensing issue? I eventually got it to work by just copying the parts I needed (showdown/src/). Still curious though

Underscores in words

As described in Github flavoured markdown, it makes no sense to italicise parts of a word.

Underscores in words usually refer to something like a variable or field name so it is particularly bad when these are parsed out and converted to italics.

Please can showdown be changed to use the github rules for this.

Thanks.

Safe output

Hi
I've noticed that Showdown doesn't escape the HTML tags.
With Python port of markdown it's possible to have safe output by passing the safe arg to markdown converter, and all the html tags will be removed or replaced by a word.

I guess it's better to just strip HTML tags and remove them completely.

Adding multiple titles/headers with the same content produces invalid markup.

Creating a title/header adds the content of the header to the header markup tag's id attribute.

For example:

# foobar
# foobar

produces:

<h1 id="foobar">foobar</h1>
<h1 id="foobar">foobar</h1>

If setting an id attribute is necessary for #hash linking, it should keep track of duplicates appending a unique identifier. e.g. foobar-1, foobar-2, etc or a timestamp foobar-1389214127156, foobar-1389214127157, etc.

If setting an id attribute is unnecessary, this functionality should be removed altogether.

Where could I find your documentation?

I would like to find out if the showdown can escape produced html.
Apparently here it does not do so.
Don't see the answer in comments of the script (sure, I could just miss it)

Markdown Extra footnote support

I'm closing down my fork since I can't spare the time to develop this. Maybe you could keep the issue around to see if someone else picked it up...

Nested block quotes

According to the Markdown syntax page ( http://daringfireball.net/projects/markdown/syntax ), markdown is supposed to support nested blockquotes. The example is given...

> This is the first level of quoting.
>
> > This is nested blockquote.
>
> Back to the first level.

What HTML should this produce? Based on the markdown and text in the example, I would assume the HTML output should be:

<blockquote>
  <p>This is the first level of quoting.</p>

  <blockquote>
    <p>This is nested blockquote.</p>
  </blockquote>

  <p>Back to the first level.</p>
</blockquote>

However showdown right now produces:

<blockquote>
  <p>This is the first level of quoting.</p>

  <blockquote>
    <p>This is nested blockquote.
    Back to the first level</p>
  </blockquote>
</blockquote>

Is this still in active development?

This is a very nice project. However, I am hesitant to use this because of the pending issues and PRs. Seems like this is not active anymore.

Is this project abandoned? If so, kindly tell me some alternative similar to this one please.

Publish in npm

Can you please publish this module in npm? npm makes it easy to install dependencies for JavaScript projects

Output of anchor broken

In the example:

[This is a test](http://example.com) foo bar foo

The output is

<p><a href="http://example.com">This is a test</a>foo bar foo</p>

Notice there is no space after the closing </a> tag.

Tested on OSX 10.8 in Chome 27, Firefox 21, Opera 15

Use with wmd

I am trying to use your version of showdown with wmd, but because of the namespace differences and possibly other issues, the scripts are incompatible.

I am currently using a version of showdown that has

var Attacklab = Attacklab || {}
Attacklab.showdown = Attacklab.showdown || {}

Your version has

var Showdown = {};

Is it possible you can revert your modifications to appear same as original so that it is compatible with other scripts such as wmd?

发的萨芬

标题1

标题2

标题3

  • 列表1
    测试
  • 列表2
  • 列表3

我是斜体
测试文字里面,我是粗体,很简单
我是粗体

水平线


如果文字后面紧跟着水平线,看看是什么效果

XSS vulnerability

It seems that link and image titles can be abused easily. Here's and example:

[Poolparty!](http://www.missionmission.org/wp-content/uploads/2013/08/pool-party-560x328.jpg" onmouseover=alert(document.cookie) id=test)

This is prevented on titles but not in urls. Fix is pretty easy:

url = escapeCharacters(url,"*_");
url = url.replace(/"/g,"&quot;");

Header level start

Hi,
I have a following usecase:

H1 Package.name
H2 SubPackage.name
(showdown.makeHtml(SubPackage.description))

So it would be great if I could call showdown.makeHtml(SubPackage.description,3)
so that in case there is following code in SubPackage.description

\#Given
\#When
\#Then

I could get output like this:
H1 Package.name
H2 SubPackage.name
H3 Given
H3 When
H3 Then

a table extension output bug

Try this markdown text,the output will be 3 tables:

 | table 1 | Col 2     |
 |======== |===========|
 | row1    | value     |
 | row2    | Value     |

 | table 2 | Col 2     |
 |======== |===========|
 | row1    | value     |
 | row2    | Value     |

how to fix:

edit table.js in line 58-60

      var i=0, lines = text.split('\n'), tbl = [], line, hs, rows, out = [];
      for (i; i<lines.length;i+=1) {

to:

      var i=0, lines = text.split('\n'),  line, hs, rows, out = [];
      for (i; i<lines.length;i+=1) {
      var tbl = [];

Passing variable into Extension

I believe I have the need for variables to be passed into extensions. Please correct me if I am not thinking about the solution correctly.

My scenario is tagging a piece of content that will be excluded/included at compile time. I know that I could hide information via classes but I need the content not to be compiled in. This is a well known technique by technical writers for single sourcing documentation (for example in DocBook using attributes, eg revision, condition).

In my overly simple example, I want to only include the content when condition='a'. a is obviously the value that I want to hand in at compile time to base the exclusion on. So, in the code below, a is hardcoded but I would like to pass it in - suggestion below. At this stage, let's not worry about it being in html.

Extension

function(converter) {
        return [
            { type: 'output', filter: function(source){
                var regex = /<\w+\s+(condition)='a'.*?>(.*?)<\/.*?>/gmi;
                return source.replace(regex, "");
            }}
        ];
    };

Markdown

a<span condition='a'>tagging</span>

Compiled to HTML

<p>a</p>

Would I be thinking about it wrong to want options as a second parameter?

var options = { condition: 'a' };
var converter = new Showdown.converter({ extensions: [mine], options });

Extension: mine

function(converter, options) {
        return [
            { type: 'output', filter: function(source){
                console.log(options.condition);
                return source;
            }}
        ];
    };

Extension for Embedding YouTube

Has anyone written this already? The README has an example of this, but I don't see support for it. Wanted to check if it was available before writing my own.

Dom elements and templates together can cause problems.

I'm having a small issue with showdown that is causing problems with my rendering.

{{#markdown}}
This is parsed.

<p>{{> test}}</p>

#This is not parsed.

<p>
{{> test}}
</p>

This is parsed.

{{/markdown}}

And the test template:

<template name="test">Testtext</template>

This is resulting in the part with '#' not being parsed. If I remove the newline between the

and {{> test}} it works fine.

This is the resulting html:

<p>This is parsed.</p>

<p>Testtext</p>

#This is not parsed.

<p>
Testtext
</p>

<p>This is parsed.</p>

I've ended up switching to metoer-markdown as it seems to handle this fine. I could just eliminate the newline but as my

and templates have way more attributes than this simple example I'd prefer not to for clean-ness. It if could be fixed it might save someone else some confusion in the future!

Add additional block elements

The list of block elements in https://github.com/coreyti/showdown/blob/master/src/showdown.js#L328 is incomplete.

This is causing problems in rendering markdown as showdown adds additional <br /> to block elements that aren't on that list. We currently experience this issue in TryGhost/Ghost#2312 where an <audio> tag breaks because of showdown adding additional HTML line breaks inside the element.

@coreyti Not sure if this project is still active, but if you are up to merging a PR for this I'd be happy to send one.

Broken with Browserify

I attempted to use showdown with browserify and ran into a failure. The failure is due to Showdown trying to access the file system, based on the existence of require/etc.

My main question is.. why, why is it even doing this? If we look at the code in question..

//
// Automatic Extension Loading (node only):
//

if (typeof module !== 'undefind' && typeof exports !== 'undefined' && typeof require !== 'undefind') {
    var fs = require('fs');

    if (fs) {
        // Search extensions folder
        var extensions = fs.readdirSync((__dirname || '.')+'/extensions').filter(function(file){
            return ~file.indexOf('.js');
        }).map(function(file){
            return file.replace(/\.js$/, '');
        });
        // Load extensions into Showdown namespace
        Showdown.forEach(extensions, function(ext){
            var name = stdExtName(ext);
            Showdown.extensions[name] = require('./extensions/' + ext);
        });
    }
}

Why is fs even being used here? This seems like a complex solution for something that a simple index.js file would handle just fine. On top of that, if an index.js file was used then Browserify would work out of the box.

\Z not functional in Chrome 20

Showdown already works around JavaScript's missing \Z in some parts of the code, but not in _StripLinkDefinitions. This causes link definitions with the "Z" character to fail. See gist.

[link]: http://example.com/beforeZafter

The text "after" will be left floating at the end of the converted text.

Ajax response in extensions

I'm trying to develop a plugin which will send the key to server and get the text.
Looks like ajax implementation is not working in my custom plugin. Is there any way to do that?

replace : function(match, prefix, content, suffix) {
                $.ajax({
                      type: "GET",
                      url: 'data/data.json',
                      async: false,
                      success : function(data) {
                          return data.txt';
                      }
                  });
}

Latest grunt-mocha module requires grunt update.

When running npm install:

npm ERR! peerinvalid The package grunt does not satisfy its siblings' peerDependencies requirements!
npm ERR! peerinvalid Peer [email protected] wants grunt@~0.4

package.json specifies: "grunt-mocha": "*" which is grabbing v0.4.7. We need to either set an older version of grunt-mocha that's compatible with grunt-0.3.17, or upgrade grunt to 0.4.

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.