Code Monkey home page Code Monkey logo

fuse's Introduction

Fuse.js

Node.js CI Version Downloads code style: prettier Contributors License

Supporting Fuse.js

Through contributions, donations, and sponsorship, you allow Fuse.js to thrive. Also, you will be recognized as a beacon of support to open-source developers.


Silver Sponsors


Introduction

Fuse.js is a lightweight fuzzy-search, in JavaScript, with zero dependencies.

Browser Compatibility

Fuse.js supports all browsers that are ES5-compliant (IE8 and below are not supported).

Documentation

To check out a live demo and docs, visit fusejs.io.

Develop

Here's a separate document for developers.

Contribute

We've set up a separate document for our contribution guidelines.

fuse'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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  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

fuse's Issues

substrings only match if occur in first 41 characters

"zyxwvutsrqpomnlkjihgfedcbaabcdefghijklmnopqrstuvwxyz".length == 52

searching for "pqrstuv" finds nothing..
searching for "opqrstu" gets a match.

"zyxwvutsrqpomnlkjihgfedcbaabcdefghijklmno".length == 41

95% of my strings are less than length 41 anyway & 99.9% of searches are substrings that occur in the first 41 characters anyway. Another fix is to split the string in half across two keys.

Anyway - thought it was worth posting this issue just FYI since lots of people will use fuse.js

Issue with IDs of zero

Thanks for the awesome plugin.

When using a numerical ID, values of 0 are returned as undefined. For example, if the result array should be [0, 10, 20] it is returned as [undefined, 10, 20].

Key weighting - enhancement

Love the library so far, great work! One potential enhancement, (which if I find time I would love to do myself). Sometimes you want certain keys to have a stronger weighting. For example if you were searching for "Cheese" through the following library of books, you would maybe want "French Cheeses" to be your top match, however at the moment "101 Sandwiches" would take top billing due to a higher score in the description field.

[{
    "title": "French cheeses",
    "description": "Pictures and descriptions of all the cheeses France has to offer"
 }, {
    "title": "101 Sandwiches",
    "description": "Cheese, Ham, Pickle sandwich all the things"
}]

What I propose is an optional more advanced syntax for keys, where you provide some kind of modifier to that key making it less/more important than it's siblings. The final scoring could then be skewed via it's modifier.

keys = [{
  label: 'title',
  modifier: 1,
}, {
  label: 'description',
  modifier: 0.5,
}]

Feature request: Highlighting Search key's in the result.

Very simple and nice plugin. I have been looking for such fuzzy search library for calender app i am trying to build. I was hoping if there was some way to highlight or mark the query string in the result set.
What i am asking is based on command pallet in sublime text. I search for string 'rown' in search box ( eg.. on your website ). And the result set are shown with the query value visible. eg like in bold, "dan b rown ", " ro b gra n t ".

Options id return void if id is a number

When I try to run your exemple, there is an issue with the ids. Indeed if the field given is a number, the result is not something like [1,2,4] but [,,]. Maybe I do something worong but I spend about an hour to make it work without success.
I found a solution, in your deepValueHelper function, I changed

 if (!remaining && typeof value === 'string') {

to

 if (!remaining && (typeof value === 'string' || typeof value === 'number'  )) {

Now it works like a charm, but as I am not really a javascript developer, I am afraid it will break something. Could you please confirm it's a bug and my solution can go live?

Thank you.

PS: Fuse is awesome and spared me a few hours of (bugged) development

Demo filter doesn't work properly

I tried using demo example filtering with "omw" string on simplified original data with default options. I get completely wrong results.

Data:

[
   { title: "Old Man's War" },
   { title: "The Lock Artist" },
   { title: "HTML5" },
   { title: "Right Ho Jeeves" },
   { title: "Incompetence" }
]

Options:

var options = {
  caseSensitive: false,
  includeScore: false,
  shouldSort: true,
  threshold: 0.6,
  location: 0,
  distance: 100,
  maxPatternLength: 32,
  keys: ["title","author.firstName"]
};
var fuse = new Fuse(list, options); // "list" is the item array
var result = fuse.search("omw");

I would expect to get "Old Man's War" item, but got this one instead:

[
  {
    "title": "Incompetence"
  }
]

Can't set threshold to 0

in fuse.js:

// At what point does the match algorithm give up. A threshold of '0.0' requires a perfect match
// (of both letters and location), a threshold of '1.0' would match anything.
MATCH_THRESHOLD = options.threshold || 0.6,

If we put a threshold of 0.0 in the options, the code above will use a threshold of 0.6 ( 0.0 || 0.6 ).
Same thing for:

MATCH_DISTANCE = options.distance || 100,

Exact matches have same score (0) as partial matches

Hey,

I've briefly tested your library with data extracted from OpenStreetMaps. I'm using objects that look like this:

    {
      "type": "node",
      "id": 2953129298,
      "lat": 7.9361803,
      "lon": -11.3474922,
      "tags": {
        "gns:ufi": "-1314862",
        "name": "Bo",
        "place": "hamlet",
        "source": "GNS",
        "unocha:pcode": "SLE01021400041"
      }
    },

Here is an example of my results (I've cut the list). I've searched for "Bo". However, there is multiple Bo entries in my list and those are returned in different places since all have score 0.

[
  "Bo hamlet",
  "Borwaila hamlet",
  "Bobe hamlet",
  "Bonge hamlet",
  "Bondie Mosque village",
  "Bokaria village",
  "Boma hamlet",
  "Bonga hamlet",
  "Bonjema hamlet",
  "Bomotoke hamlet",
  "Bombo hamlet",
  "Bondam hamlet",
  "Bom hamlet",
  "Bonma hamlet",
  "Borobofu hamlet",
  "Borma village",
  "Bonjema hamlet",
  "Bonkohun hamlet",
  "Bonkomataka hamlet",
  "Bombe hamlet",
  "Bohol village",
  "Bolabombor village",
  "Boroso hamlet",
  "Borbana hamlet",
  "Bonthe town",
  "Bombalibana hamlet",
  "Bomemahun hamlet",
  "Bolota hamlet",
  "Bo hamlet",
  "Bonkofoton hamlet",
  "Bondebu hamlet",
  "Bobowaleh hamlet",
  "Bo hamlet",
  "Bolia hamlet",
  "Boma hamlet",
  "Bopo hamlet",
  "Boiguru hamlet",
  "Boma hamlet",
  "Bohun hamlet",
  "Bonaia hamlet",
  "Boto hamlet",
  "Bohol hamlet",
  "Bongka hamlet",
  "Boria hamlet",
  "Boronka hamlet",
  "Boli hamlet",
  "Bouria hamlet",
  "Bolleh village",
  "Bondua hamlet",
  "Boyipie hamlet",
  "Boalakarafaia hamlet",
  "Bokaria hamlet",
  "Bokaria hamlet",
  "Bomuvulahun hamlet",
  "Bokarikondea hamlet",
  "Bobobu hamlet",
  "Bomatok hamlet",
  "Bompiya village",
  "Bobarsene village",
  "Bolyine village",
  "Bonjema village",
  "Bomdei hamlet",
  "Boabu hamlet",
  "Bokeni hamlet",
  "Bondobu hamlet",
  "Bompeworo village",
  "Bobobu hamlet",
  "Bohun hamlet",
  "Boajibu village",
  "Bokuma hamlet",
  "Bomahun hamlet",
  "Boabu hamlet",
  "Bongor Town village",
  "Bobobu hamlet",
  "Bondoma hamlet",
  "Bontiworo hamlet",
  "Bobobu hamlet",
  "Bohehun hamlet",
  "Bombe hamlet",
  "Bondayirahun hamlet",
  "Borokonko hamlet",
  "Bololo hamlet",
  "Bombohun hamlet",
  "Bowama hamlet",
  "Bonganema hamlet",
  "Bopan hamlet",
  "Bopo hamlet",
  "Bonjema hamlet",
  "Bonge hamlet",
  "Bopon hamlet",
  "Bomi hamlet",
  "Boloma hamlet",
  "Bomatok hamlet",
  "Bombadu hamlet",
  "Bobobu hamlet",
  "Boumu Samba village",
  "Bongoya hamlet",
  "Bokolu hamlet",
  "Bomu hamlet",
  "Bo hamlet"
]

I would expect to see all exact matches at the top. But it seems that a lot of entries have score 0, including partial matches. Is this expected behavior?

Expose the searcher

I'm liking the fuzzy search but would love to be able to integrate it into my current search function.

I was wondering if it's possible to expose the Searcher as well as Fuse so that it's possible to just get the score for any given match without the list handling and sorting it already does.

This would make it much easier to integrate into more complex algorithms.

search in nested array

I have a nested object like this:

[
  {
    name: 'levelA',
    number: 12341,
    district: [
      {
        name: 'levelB',
        number: 12341,
        township: [
          {
            name: 'levelC',
            number: 12341,
            tv: [
              {
                name: 'levelD',
                number: 12341
              }
            ]
          }
        ]
      }
    ]
  },
  {
    name: 'levelA2',
    number: 12341,
    district: [
      {
        name: 'levelB2',
        number: 12341,
        township: [
          {
            name: 'levelC2',
            number: 12341,
            tv: [
              {
                name: 'levelD2',
                number: 12341
              }
            ]
          }
        ]
      }
    ]
  }
]

I want to filter the result by name at all levels so I write the search like this:

let fuse = new Fuse(data, {
  keys: ['name']
});
fuse.search(keywords);

But this only return me the result in the first level of name. I'm not sure how to index the name in the second or deeper level because it's not an object.

Maybe something like this keys: ['name', 'district.name']?

@krisk Any ideas? Thanks.

invalid-meta fuse.js is missing "ignore" entry in bower.json

bower install fuse.js
bower fuse.js#* not-cached git://github.com/krisk/Fuse.git#*
bower fuse.js#* resolve git://github.com/krisk/Fuse.git#*
bower fuse.js#* download https://github.com/krisk/Fuse/archive/1.2.2.tar.gz
bower fuse.js#* extract archive.tar.gz
bower fuse.js#* invalid-meta fuse.js is missing "ignore" entry in bower.json
bower fuse.js#* resolved git://github.com/krisk/Fuse.git#1.2.2
bower fuse.js#~1.2.2 install fuse.js#1.2.2

I know this is minor, but user don't want to download that tests anyway… so why not?

Variable conflict when using optional includes

There is a conflict with the variable i in getItem().

It's using i to loop through the include array.

for(var i = 0; i < options.include.length; i++)

However this conflicts with the i in getItem(), so when the loop sets the property:

rawResults[i][includeVal]

It will reference the wrong array element and also cause an error if the include length is longer than the raw results.

Big Dataset test

I tried using Fuse on a data set containing approximately 9000 rows, yes I did read about its limiting nature for huge data sets, but the search result I got were highly inconsistent, it simply gave an empty response no matter what parameter threshold was set. I guess you should detect the failure of alogrithm somewhere and some how return the error

Web Workers for the browser

I started an implementation of something similar, but used Webworkers posting results back and forth for asynchronous searching in the browser.
Mine was a mess and didn't work ultimately, but I wanted to suggest it here in case there was interest in it. It really helped in larger datasets in my testing.

Free word order and parts of words

I really love the fuzziness but fuse.js seems not to find entries when the words are in another order or only parts are entered. Uni Mannheim is much closer to FH Mannheim than to University Mannheim now.

Space separated patterns

Let's assume I have multiple keys for example, firstName, lastName, and profession.

Now if given the following entry:
{
firstName : 'joe'
lastName: 'bloggs'
profession: 'banker'
}

I'd like a hit to occur for the following search values:
"joe"
"bloggs banker"
"joe bloggs"

What's the most efficient way of accomplishing this?

ability to limit the number of results

I'd like to implement an autocompletion service for public transport stations. Since no user is going to read through more than 5 autocompletions, I want to limit them. The benefit would be a faster search.

export index

I want export fuzzy index with in an object for next loading

Can you add a new method for this?

Search with pattern.length > 32 doesn't work

If I set maxPatternLength > 32 and use a search pattern that is 33 characters, all items are matched. Looking at the code, I think that this is because matchmask wraps rolls over back to 1 when patternLen is 33 (I don't really have a handle on the algorithm though).

 this.matchmask = 1 << (this.patternLen - 1);

Maybe an error should be thrown when setting maxPatternLength > 32 as it doesn't appear to be a valid value.

able to return for which key the result rows are returned

Is it possible to add a key property on each result row which specifies the row is associated with the one of the specified keys in the fuse options.

basically if i have author , title in the keys

the result row will have a property called key:'author' - if this result row is created from this key search.

thanks

Fuse is not finding elements when searching for first letter of the item (default settings)

As you can see below, when searching for the first letter of the first record nothing is found, if I search for any other letter of the record, it is found (in this example search term is 'o' - second letter of 'pompki')

Search term: p
fuse.js:25 ---------
Record: ["pompki"]
fuse.js:25 Score for "p": [1]
fuse.js:25 Individual word score average: 1
fuse.js:25 Full text score: 0.001
fuse.js:25 Average 0.5005
fuse.js:25 ---------
Record: ["hura", "z", "serwera"]
fuse.js:25 Score for "p": [1, 1, 1]
fuse.js:25 Individual word score average: 1
fuse.js:25 Full text score: 1
fuse.js:25 Average 1
fuse.js:25 ---------
Record: ["trawers"]
fuse.js:25 Score for "p": [1]
fuse.js:25 Individual word score average: 1
fuse.js:25 Full text score: 1
fuse.js:25 Average 1
fuse.js:25 Sorting....
fuse.js:25 ------------
Output:
[]
exercise-list.jsx:24 []
fuse.js:25 =====================
Search term: o
fuse.js:25 ---------
Record: ["pompki"]
fuse.js:25 Score for "o": [0.01]
fuse.js:25 Individual word score average: 0.01
fuse.js:25 Full text score: 0.01
fuse.js:25 Average 0.01
fuse.js:25 ---------
Record: ["hura", "z", "serwera"]
fuse.js:25 Score for "o": [1, 1, 1]
fuse.js:25 Individual word score average: 1
fuse.js:25 Full text score: 1
fuse.js:25 Average 1
fuse.js:25 ---------
Record: ["trawers"]
fuse.js:25 Score for "o": [1]
fuse.js:25 Individual word score average: 1
fuse.js:25 Full text score: 1
fuse.js:25 Average 1
fuse.js:25 Sorting....
fuse.js:25 ------------
Output:
[Object]

Update demo

It looks like some changes in the code have been made, such as:
'includeScore' : true
changing to:
'include' : ['score']

However the demo http://kiro.me/exp/fuse.html still uses the old structure.

Array of arrays returned if argument "key" is used

Hi, from the examples it seems that using a "key" argument should return a simple array populated with the same property name, e.g. key="id" >> [2,4,5,6]

Instead, an array of arrays is returned: [ [2], [4], [5], [6] ]

The problem can be reproduced in the examples page by providing "title" as the key argument.

Cheers

Include a changelog

The bump from 1.2.x to 1.3.x broke something in my project. It'd be nice to be able to look at a changelog to see what I need to do to get onto 1.3.x.

is there a way to search an object instead of an array?

I'm using normalizr to get an object with the ids as keys, so I can access specific items without iterating every time through the array.
I've seen that fuse can be configured to return only the results ids, which is nice for my purpose. But then it does not take my nested object.

Example:

const collection = {
  135 : {
    name : 'foo',
    _id : 135
  },
  187 : {
    name : 'bar',
    _id : 187
  }
}

the search always returns an empty array :(

Feature: Option to set max pattern length

  1. Awesome library
  2. Would setting a max pattern length of more than 32 characters break the algorithm?
  3. If not, it would be a good feature to be able to increase it or at least have the option to still do a search on the first 32 chars instead of throwing an error.

I can also take a look at implementing this, but need to understand if there is a hard constraint in the algorithm for the 32 char max pattern or if it is just there for efficiency purposes, etc.

Thanks!

Error while matching

(new Fuse(['testingnew'])).search('pw') is a match?! Why? p is not even in "testingnew"

add advanced search logic

This is almost so bad ass:

I'd like to do advanced searches like:

cats || dogs -> return any object containing cats or dogs in any value
cats && dogs -> return objects that have a value containing cats and dogs
name:rob && pet:dog -> return objects who's field "name" is equal to rob and who's field "pet" is equal to dog

reported scores are all 0 (same as first result)

There is a bug that I think I have chased down to the getItem function where it is returning the value from the options.include array for the first result item. I noticed this with an include: ["score"] case I was using, but I suspect it would impact other values in this array as well.

Essentially, the bug is that the for loop uses a local variable i, but this is also the name of the argument to the getItem() function. In Chrome, this results in referencing the i variable in the for loop, which is 0 in my case, so it is returning the score from rawResult[0] instead of the one desired.

I changed for loop to use j and it fixed this issue for me:

var getItem = function(i) {
      var resultItem;

      if(options.include.length > 0) // If `include` has values, put the item under result.item
      {
        resultItem = {
          item: rawResults[i].item,
        };

        // Then include the includes
        for(var j = 0; j < options.include.length; j++)
        {
          var includeVal = options.include[j];
          resultItem[includeVal] = rawResults[i][includeVal];
        }
      }
      else
      {
        resultItem = rawResults[i].item;
      }

      return resultItem;
    };

I hope this helps. I would be happy to submit a pull request if desired.

John

Please publish on npm

I understand naming isn't easy :(

With the raise of tools like Browserify and Webpack it is convenient to think of dependency in terms of npm install. Thanks!

Score exact matches higher over location

From what I see bitapScore weights matches higher the closer to the "location" given when creating a search over exact matches.
EX: Query "egg" on a list that contains: "----- leggings" and "--------- -------- eggs" would rank the "leggings" higher than the "eggs" item because the "location: 0". Due to the nature of my items I can't guarantee where the keywords would be in the object names, even as an approximation.

Any thoughts into how I would modify the current bitap scoring to ignore/minimize the effect of location scoring over matches (is this even possible, I might be misunderstanding the whole algorithm).

One other way I can see would be to possibly randomize of keywords in my items/split them at " ", however this would cause bigram matches (ex: "chocolate milk") to rank lower.

Doesn't work on Chromium

It doesn't work on Chromium Version 28.0.1462.0 (192082) maybe you want to take a look on this.

duplicate results

just quoting someone from the comments

"Hi, nice tool. I'm getting duplicate search results when the search term is found in two different keys (eg. title and description)."

but I'm having pretty much the same problem

Having problems on node 5.6

Fuse seems to be giving me errors, I'm not totally sure if this is because sys is deprecated or something else. I'm using node v5.6.0. Here is the ouput of the command line. I realize I'm not passing any parameters to new Fuse(), but it doesn't seem to make a difference. Thanks for any help.

node --version
v5.6.0

node

let Fuse = require('fuse')
(node) sys is deprecated. Use util instead.
undefined
Fuse
{ fuseContent: [Function], fuseFile: [Function] }
let a = new Fuse()
TypeError: Fuse is not a function
at repl:1:31
at REPLServer.defaultEval (repl.js:252:27)
at bound (domain.js:287:14)
at REPLServer.runBound as eval
at REPLServer. (repl.js:417:12)
at emitOne (events.js:95:20)
at REPLServer.emit (events.js:182:7)
at REPLServer.Interface._onLine (readline.js:211:10)
at REPLServer.Interface._line (readline.js:550:8)
at REPLServer.Interface._ttyWrite (readline.js:827:14)

semver tags

Could you git tag the current release 1.0.0? At the moment, bower installs with "*" for the version range because there are no tags.

Highly inaccurate search

It looks like there is a problem finding longer search terms. Let's say you want to search for an ID.

Setup:

options = {
    keys: ['device'],
    id: 'id',
    threshold: 0.5
};

devices = [{id: 1, device: "51250603CR00052"}];

var fuzzy = new Fuse(tempStock, options);
var result = fuzzy.search( "51250603CR00052" );

Problem

This would return [1]. But if you just leave one out, let's say the last number, the result will be empty. Additionally if the device string contains one or more letters, the result will be empty too.

Example

devices = [{id: 1, device: "51250603CR00052a"}];
devices = [{id: 1, device: "a 51250603CR00052"}];
var result = fuzzy.search( "51250603CR0005" );

These all result in an error. The first has an additional "a" at the end. The second has a prefixed string "a " and the third is missing the last character "2".

wrong result

Hi, I just tried Fuse and I found a bug:
I searched for: "the book of lies" (on the demo site, title only, in-casesensitive)
And it returned:

The Book of Lies, Brad Meltzer
The Book of Samson, David Maine
The Code of the Wooster, P.D. Woodhouse
The Lock Artist, Steve Hamilton
The Lost Symbol, Dan Brown
The Grand Design, Stephen Hawking

The 3. and the last two shouldn't be here if I'm right (because of the letter 'k' )
BTW, It's a really great project and thank you!

Feature request: Only begin search after typing N characters

Thanks for an amazing plugin. It is so simple to use and works so well.

I have a feature request. Would it be possible to add an option to specify that the search should only begin after the user has entered N characters?

I find that with longer lists, beginning the search after typing one character can result in a very long results list. This can be slow to render in the browser, especially on mobile.

version of Fuse

Hi,
Is it possible to add version info about Fuse and do a 'release' on github or official website? Can help people know what version of Fuse they use, easier to maintain files and control source code version, thanks!

Add plugin functionality

There have been many requests for features and/or enhancements to the library. Some of them are outside the scope or intent of Fuse. Others, however, are in a good position to be included. I'm thinking instead of modifying the core code, we could add extensible pieces to the library - essentially a plugin functionality.

Instead of forcing my vision, I'm interested into what everyone else thinks on how the API should look like.

Tell me your thoughts 😄

over 32 characters

Is there a reason for not switching algorithms at 33 characters to an exact match algorithm? It would be seemless to the user and improve user experience (most people typing that much are wanting a fairly exact match anyway).

As it stands in my current project, I have to deal with the error by checking the length and falling back to str.indexOf(searchStr) each time. Building this in seems much more desirable.

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.