Giter Site home page Giter Site logo

nookipedia / nookipedia-api Goto Github PK

View Code? Open in Web Editor NEW
40.0 9.0 12.0 1.14 MB

Nookipedia's custom API for querying data from the Animal Crossing video game series.

Home Page: https://api.nookipedia.com/

License: MIT License

Python 94.59% CSS 0.78% HTML 4.63%
nookipedia api flask wiki hacktoberfest

nookipedia-api's Introduction

nookipedia-api

The Nookipedia API is a free RESTful service provides endpoints for retrieving Animal Crossing data pulled from the Nookipedia wiki, the largest community-driven encyclopedia about the series. Built using Python and Flask, the key benefit of using this API is access to clean structured data spanning the entire Animal Crossing series, pulled from information that is constantly updated and expanding as editors work on the wiki.

Visit https://api.nookipedia.com/ for more information.

Support

Our primary method of supporting users and developers is through the Nookipedia Discord; API users and contributors are granted access to the private #wiki-api channel where they can participate in a community of practice and receive near round-the-clock support.

You may also open an issue here on GitHub if you need help, would like to request a feature, or have a bug to report.

Contributing

Anyone is welcome and encouraged to contribute to this API!

See the contributing guide for full details and guidance.

Technical Overview

Nookipedia, which runs on the MediaWiki wiki software (same as Wikipedia), utilizes the Cargo extension. Cargo lets editors store data from templates in structured databases. For example, if you visit any villager's article on Nookipedia (e.g. Rosie), there is an infobox at the top-right of the page; all that information as defined in the infobox is also stored in a database on the backend so that it can be queried elsewhere on the wiki, or externally by third parties. See Nookipedia's Project Database for more information.

This API is essentially a wrapper for the MediaWiki Cargo API that comes as part of the extension. See the MediaWiki cargoquery endpoint for how Cargo tables can be queried directly.

While the Cargo API is freely available for querying, we have our custom-built API for the following reasons:

Deployment

This application requires Python 3 and venv.

This application has the following dependencies from apt get:

  • software-properties-common
  • memcached
  • libmemcached-dev
  • sqlite3

Before running this application:

  • Create a virtual environment by running python3 -m venv env && source env/bin/activate. Check if this is successful if (env) is added at the beginning of your prompt.
    • For those running csh or fish instead of the default shell, replace activate with activate.csh or activate.fish.
  • Install the requirements of the project by running pip install -r requirements.txt
  • Create the database for storing admin/client secrets. Replace <> values with your desired values. Note that the API requires a UUID key (<uuid>) to make calls
$ sudo sqlite3 <desired_db_name>.db
sqlite3> CREATE TABLE <keys_table_name> ( key varchar(32), email TEXT, project TEXT );
sqlite3> CREATE TABLE <admin_keys_table_name> ( key varchar(32) );
sqlite3> INSERT INTO <keys_table_name> VALUES ( "<uuid>", "test", "test" );
sqlite3> .exit 0;
  • In config.ini:
    • Fill in the SECRET_KEY with a long random string of bytes (used for securely signing the session cookie; learn more)
    • Fill in the names for the DATABASE, DB_KEYS, and DB_ADMIN_KEYS with <desired_db_name>.db, <keys_table_name>, and <admin_keys_table_name> (fill in values respective to what was used to instantiate the database above)
    • The AUTH section is optional. Nookipedia bot-owners and administrators may authenticate into the wiki to enable higher query limits by generating a username and password at Special:BotPasswords.
  • In dashboard-config.cfg, change the dashboard's password to something other than the default admin.

Local / Dev

flask run --host=0.0.0.0. Easy.

Note that Flask's built-in server is not suitable for production.

Production

There are a variety of options out there for setting up a proper production server (cloud services, Gunicorn, uWSGI, etc.). Visit Flask's deployment page for a list of options.

Nookipedia's API is deployed via uWSGI and nginx. If you'd like to set up something similar and need help, feel free to get in touch.

Licensing

The Nookipedia API codebase is licensed under the MIT license. See license file for full text.

Dependencies are copyright their respective authors and used under their respective licenses.

nookipedia-api's People

Contributors

angelolz avatar dependabot[bot] avatar janreggie avatar kevinpayravi avatar makupi avatar maxswa avatar micalobia avatar o-k-a-y avatar vmar97 avatar zzrrbbit 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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nookipedia-api's Issues

Create Helper function for building the `field` parameter

Currently, we just have really long strings to represent a list of fields, e.g.

  • Art
  • Bugs
  • Interior
    This makes it extremely difficult to track changes between versions. The solution for this would be a function that's as simple as:
def generate_fields(*fields):
    return ','.join(fields)

This would make black format it to separate lines when there's a lot, which makes it much easier to track on Git when we can see line by line what was added.

Working on PR now

New Horizons material endpoint

It'd return data from a cargo table that doesn't exist yet, probably would be called nh_material
It would just be information on materials that can be used in crafting, like the ones in these tables

Sort of a compliment to the recipe endpoint mentioned in issue #20 and PR #25

API Experienced fatal error

When using the fish or bugs endpoint (maybe others, I didn't check too closely), it returns an error when excludedetails=true and month are set at the same time.

Add new artwork fields

Most notably texture_url and fake_texture_url, although it seems there are a few other things like themes.

Would be willing to do a PR for it, might depend on when #55

New Horizons item endpoints

We need endpoint(s) for New Horizons items.

Refer to our full list of tables:
https://nookipedia.com/wiki/Nookipedia:Project_Database#List_of_tables

Our item tables are split into multiple tables (nh_furniture, nh_clothing, nh_photo, nh_tool) and their respective _variation tables, which will need to be joined on querying. We will likely want four different endpoints due to the varying attributes each type of item has.

Getting the data from the table won't be difficult, but we will need a good structure for dealing with variations, as well as including recipe information.

Consider storing query limits in a config file

When querying Cargo tables, we define a limit for the number of items the query should return. This can periodically change with game updates, and so we should consider storing all query limits in a single config file for easier maintenance + tracking.

New Horizons artworks

To go alongside critters, we need an endpoint for New Horizons artworks.

Artworks structured data has already been established with [nh_art](https://nookipedia.com/wiki/Special:CargoTables/nh_art), just needs some missing details filled in (namely forgery details) and then build the endpoint.

Consistent buy/sell param names

For 1.3, we currently have buy_price / sell_price for artworks, but buy / sell for recipes. We should decide which one to use consistently throughout the API.

Account for NH critters with varying time availability by month

Two fish in New Horizons (Char + Cherry Salmon) have different time availability depending on the month:

Time: 4 PM - 9 AM
North months: Mar - Jun
South months: Sep - Dec

Time: All day
North months: Sep - Nov
South months: Mar - May

Our New Horizons critter endpoints need to updated to account for this, by providing time on a per-month basis by hemisphere. While all bugs and sea creatures have uniform time availability, it is probably a good idea to provide the same for consistency, as well as to protect against the possibility that Nintendo decides to change spawn times in the future (Nintendo changed spawn rates for bugs in 1.2.0, so while such a change is very unlikely it is not outside the realm of possibility).

Today endpoint

A "today" endpoint that returns the day's events. These would include villager birthdays as well as in-game activities across all games.

Boilerplate cleanup

The code has a lot of boilerplate, and I'd like to reduce it some by making helper functions and such

For example:

  • Every list generation from multiple fields is pretty much the exact same code
  • All the version checks could be a function call to something like minimum_accepted_version and maximum_accepted_version
  • A lot of request.args.get calls could be simplified (example below)
if request.args.get('excludedetails') and request.args.get('excludedetails') == 'true'

# 'false' could be replaces with just '', or not be there at all, but this is clearer to what's happening
if request.args.get('excludedetails', 'false') == 'true'

I'd be willing to do any or all of these changes, just not sure which ones are wanted, so any feedback would be nice.

Duplicated Villager on request /villagers?

When make the request of villagers T-Bone is duplicated on result

It's the same data only difference is on 'appearances' property

https://www.diffchecker.com/9rNHHRif

image

{
    "name": "T-Bone",
    "url": "https://nookipedia.com/wiki/T-Bone",
    "alt_name": "",
    "title_color": "acc8cf",
    "text_color": "498992",
    "id": "bul05",
    "image_url": "https://dodo.ac/np/images/e/e0/T-Bone_NH.png",
    "species": "Bull",
    "personality": "Cranky",
    "gender": "Male",
    "birthday_month": "May",
    "birthday_day": "20",
    "sign": "Taurus",
    "quote": "Don't have a cow.",
    "phrase": "moocher",
    "clothing": "Hanten Jacket",
    "islander": false,
    "debut": "DNM",
    "prev_phrases": [],
    "nh_details": {
      "image_url": "https://dodo.ac/np/images/e/e0/T-Bone_NH.png",
      "photo_url": "https://dodo.ac/np/images/b/ba/T-Bone%27s_Poster_NH_Texture.png",
      "icon_url": "https://dodo.ac/np/images/1/16/T-Bone_NH_Villager_Icon.png",
      "quote": "Don't have a cow.",
      "sub-personality": "B",
      "catchphrase": "moocher",
      "clothing": "Hanten Jacket",
      "clothing_variation": "Dark Blue",
      "fav_styles": [
        "Cool",
        "Simple"
      ],
      "fav_colors": [
        "Blue",
        "Black"
      ],
      "hobby": "Education",
      "house_interior_url": "https://dodo.ac/np/images/7/7a/House_of_T-Bone_NH.png",
      "house_exterior_url": "https://dodo.ac/np/images/8/82/House_of_T-Bone_NH_Model.png",
      "house_wallpaper": "Arched-Window Wall",
      "house_flooring": "Arabesque Flooring",
      "house_music": "K.K. Steppe",
      "house_music_note": ""
    },
    "appearances": [
      "DNM",
      "AC",
      "E_PLUS",
      "NL",
      "WA",
      "NH",
      "HHD"
    ]
  },

Split app.py into multiple files

To better structure the app I'd propose to split it into multiple files.
Something like this for example:

app.py (app entrypoint)
nookipedia/__init__.py (app initialization/setup)
nookipedia/cargo.py (cargo handling)
nookipedia/db.py (database handling)
nookipedia/endpoints.py (api endpoints)
nookipedia/utility.py

Please sanitise some data

Can I make a request? There is an inconsistency in the time available values. In sea creatures, there are examples where the values are ; separated, and in bugs they're & separated.
An example is the Giant Isopod and Evening Cicada
Would we be able to make this consistent across the board? I mentioned in the wiki-tech room on discord the other day that it'd be good to have this time availability objectified, but atm i'm parsing the time string, which, as mentioned, is a bit inconsistent.
Thanks

Compress lists

Any field with a number should be compressed into a list the same way material1 through material6 are, and some similar fields

For example, in the future furniture endpoints, the buy columns could be compressed into one

It's mostly something that I personally haven't been actively implementing, but I've realized now that I should actively pursue the compression of lists

Maybe include it in the contribution.md file, just so that people know they should actively pursue it as well?

Add _pageName to query, remove url

On Nookipedia, each Cargo table has the following two columns:

  • A _pageName column that contains the article's name.
  • A url column (sometimes called something else) that contains a link to the article.

We want to deprecate the latter as it duplicates the pagename. In the API, we can update each endpoint's field variable to include _pageName=url, and then prepend https://nookipedia.com/wiki/ to it to create the URL.

.gitignore, venv, and requirements.txt to facilitate ease of development and deployment

This repository does not use a .gitignore to ensure that changes to config.ini and dashboard-config.cfg. While doing so may make necessary changes to these files require a force flag on git-add, this will provide benefit to those working on the project who just git add -A everything.

In addition, as a Python project, the use of a virtual environment is vital. For future users and developers, a virtual environment can be used in order for the rest of the system to be unaffected as well as to ensure that dependencies are met by simply doing a pip install -r requirements.txt.

Changes to the way the project is deployed will also mean changes in the README. I will be submitting a corresponding pull request in a while.

Set tag to empty string on ACNH item endpoints

On the wiki, we may soon remove the tag field from ACNH items, as this is purely used for sorting in-game, and is not a reliable indicator of anything useful. The function array is what actually holds useful functionality data.

Before the removal takes place on-wiki, we will need to:

  • update the ACNH item endpoints to remove tag from the query.
  • re-insert a tag field in the response body, with an empty string as the value (to ensure nothing breaks for existing users). This can be versioned.

Properly handle someone sending in both excludedetails and thumbsize

Currently, if someone sends in both excludedetails=true and thumbsize=##, the server responds with a 500 error as it will try to generate thumbnails based on non-existence image fields (since excludedetails results in only the required fields being queried).

API should be updated to properly account for this case by returning a 400 error indicating that one or the other should be provided, not both.

New Horizons fossils

To go alongside critters, we need an endpoint for New Horizons fossils.

Fossils currently have no NH info templates, nor any structured data; Template:NHFossilInfo + Cargo table needs to be created on the wiki, and then placed on all NH fossil pages.

Changes to `/nh/art` object

Something I've been mulling over is grouping constructs related to the real vs. the fake artwork into there own objects, something like this:

"has_fake": true,
"real_info": {
    "image_url": "",
    "texture_url": "",
    "description": "",
    "themes": []
},
"fake_info": {
    "image_url": "", // fake_image_url
    "texture_url": "", // fake_texture_url
    "description": "", // authenticity
    "themes": [] // Would use fake_theme, maybe more in the future
}

where fake_info would be null when has_fake is false.
This includes things added in #58, although I think they could be added separately, since it doesn't need to be versioned, and this change would be versioned to either 1.5.1 or 1.6.0

`/nh/fish` and `/nh/bugs`: `"time"` property is always empty

Problem

EDIT: this applies to /nh/bugs and /nh/bugs/{bug} too.

When querying the /nh/fish or /nh/fish/{fish} endpoints, seemingly with any params, there is no data for the time property.

Looking on the docs, there should be;

[
  {
    "url": "https://nookipedia.com/wiki/Cherry Salmon",
    "name": "Cherry Salmon",
    "number": 27,
    "image_url": "https://dodo.ac/np/images/d/db/Cherry_Salmon_NH_Icon.png",
    "render_url": "https://dodo.ac/np/images/c/c0/Cherry_Salmon_NH.png",
    "time": "4 PM – 9 AM", HERE
    "location": "River (clifftop)",
    "shadow_size": "Small",
    "rarity": "Uncommon",
    "total_catch": 100,
    "sell_nook": 1000,
    "sell_cj": 1500,
    "tank_width": 1,
    "tank_length": 1,
    "catchphrases": [],
    "north": {},
    "south": {}
  }
]

Example

Code

import fetch from "node-fetch";
import dotenv from "dotenv";
dotenv.config();

// retrieve data from api
const response = await fetch(`https://api.nookipedia.com/nh/fish`, {
  headers: {
    "X-API-KEY": process.env["NOOKIPEDIA_API_KEY"],
    "Accept-Version": "1.5.0",
    "content-type": "application/json",
  },
});
// get data as object
const allFishData = await response.json();
// print to console an array of { "fish name": "fish's time property" }
console.log(
    allFishData.map(
      (fish) => ({ [fish.name]: fish.time })
    )
  );

Expected

An array of data following the form;

[
  { Anchovy: "X AM - Y PM" },
  { Angelfish:"X AM - Y PM" },
  { Arapaima: "X AM - Y PM" },
  // ...etc
]

Actual

An array of data following the form;

[
  { Anchovy: undefined },
  { Angelfish: undefined },
  { Arapaima: undefined },
  // ...etc
]
Show data
[
  { Anchovy: undefined },
  { Angelfish: undefined },
  { Arapaima: undefined },
  { Arowana: undefined },
  { 'Barred Knifejaw': undefined },
  { Barreleye: undefined },
  { Betta: undefined },
  { Bitterling: undefined },
  { 'Black Bass': undefined },
  { Blowfish: undefined },
  { 'Blue Marlin': undefined },
  { Bluegill: undefined },
  { 'Butterfly Fish': undefined },
  { Carp: undefined },
  { Catfish: undefined },
  { Char: undefined },
  { 'Cherry Salmon': undefined },
  { 'Clown Fish': undefined },
  { Coelacanth: undefined },
  { Crawfish: undefined },
  { 'Crucian Carp': undefined },
  { Dab: undefined },
  { Dace: undefined },
  { Dorado: undefined },
  { 'Football Fish': undefined },
  { 'Freshwater Goby': undefined },
  { Frog: undefined },
  { Gar: undefined },
  { 'Giant Snakehead': undefined },
  { 'Giant Trevally': undefined },
  { 'Golden Trout': undefined },
  { Goldfish: undefined },
  { 'Great White Shark': undefined },
  { Guppy: undefined },
  { 'Hammerhead Shark': undefined },
  { 'Horse Mackerel': undefined },
  { Killifish: undefined },
  { 'King Salmon': undefined },
  { Koi: undefined },
  { Loach: undefined },
  { 'Mahi-Mahi': undefined },
  { 'Mitten Crab': undefined },
  { 'Moray Eel': undefined },
  { Napoleonfish: undefined },
  { 'Neon Tetra': undefined },
  { 'Nibble Fish': undefined },
  { Oarfish: undefined },
  { 'Ocean Sunfish': undefined },
  { 'Olive Flounder': undefined },
  { 'Pale Chub': undefined },
  { Pike: undefined },
  { Piranha: undefined },
  { 'Pond Smelt': undefined },
  { 'Pop-Eyed Goldfish': undefined },
  { 'Puffer Fish': undefined },
  { Rainbowfish: undefined },
  { 'Ranchu Goldfish': undefined },
  { Ray: undefined },
  { 'Red Snapper': undefined },
  { 'Ribbon Eel': undefined },
  { 'Saddled Bichir': undefined },
  { Salmon: undefined },
  { 'Saw Shark': undefined },
  { 'Sea Bass': undefined },
  { 'Sea Butterfly': undefined },
  { 'Sea Horse': undefined },
  { 'Snapping Turtle': undefined },
  { 'Soft-Shelled Turtle': undefined },
  { Squid: undefined },
  { Stringfish: undefined },
  { Sturgeon: undefined },
  { Suckerfish: undefined },
  { Surgeonfish: undefined },
  { Sweetfish: undefined },
  { Tadpole: undefined },
  { Tilapia: undefined },
  { Tuna: undefined },
  { 'Whale Shark': undefined },
  { 'Yellow Perch': undefined },
  { 'Zebra Turkeyfish': undefined }
]

What this means

The time property is not being set, or is being set to None/null/undefined by the API.

The part where I guess what's wrong and am probably off by a mile

I'd guess this is a remnant of a previous version of the API where instead of monthly time data for the hemispheres, it was just a single datapoint. Unless this was never a thing, then I'd guess I'm wrong.

Either that or it's just a mistake in the docs, an accident in the schema, something like that.

Add group_by to Cargo queries

On the wiki, Cargo is a bit finicky and can sometimes insert duplicate rows in a database table. As a result, the Nookipedia API sometimes returns duplicate objects.

We should consider adding group_by=<fields> to all our Cargo queries. Grouping by all fields will remove any duplicates in the query's return.

Villager text color

Villager's dialogue colors are now included to the villager table. E.g. the border like in Discord's bot message need match the title color. (like Bob's purple is a06fce)

Escape URLs in return bodies to account for question marks

For ACNH items with a ? in the name, our endpoints return a URL with an unescaped ?. This breaks the URL since ? is a reserved character for declaring URL parameters.

API should account for this and returned an escaped URL.

Example of current /nh/furniture response for ? Block:

{
  "url": "https://nookipedia.com/wiki/Item:?_Block_(New_Horizons)",
  "name": "? Block",
  "category": "Housewares",
  ...
}

url value should be https://nookipedia.com/wiki/Item:%3F_Block_(New_Horizons)

Include primary color(s)

Users have requested colors for critters and villagers (and any future items), primarily to decorate Discord embeds with. There are a couple solutions here:

  • Use a library to determine the predominate color of the item's image, and return it.
  • Utilize the in-game colors attached to each item (e.g. critters and villagers in New Horizons each have two hidden colors associated with them, which come into play for gifting).

`/meta/*` endpoints

/meta endpoints would give the user a way to programmatically monitor changes in the API's metadata for various purposes, such as checking the version, seeing what endpoints have been added/removed, if data structures have changed in endpoints, if previously missing/invalid data has been added/corrected. etc.

A happy side effect of this would be that the maintainers of this project would have an excuse to keep a digit changelog for the data, however vague it may be (eg, instead of "corrected clothing styles for [villager] - changed [erroneous] to [correct]" all you'd need is "corrected erroneous data").

Potential Structure

I propose that a URL param be sent on any GET request to /meta or /meta/*; date.
It would take the same form as the date field in /nh/events, so the validation code already exists. The reason I specify date is because the other three fields don't really apply here (hopefully explained below).

This parameter would determine the oldest date for updates to be fetched from, and the would be fetched from all days after that date, up to and including today (if any exist). You can of course also pass today to receive only today's updates.

The returned data from /meta would have the following structure or similar, and each of the top-level JSON keys would be the * in a potential /meta/* endpoint.

{
  "version": "<version string here>",
  "versions": [
    {
      "version": "<version string here>",
      "date": "<date here>"
    }
  ],
  "new": [
    {
      "name": "<name of the new endpoint here>",
      "date": "<date here>",
      "url": "<docs url here>",
      "description": "<maintainer's description here>"
    }
  ],
  "deprecated": [
    {
      "name": "<name of the removed/deprecated endpoint here>",
      "date": "<date here>",
      "description": "<maintainer's description here>"
    }
  ],
  "fixes": [
    {
      "name": "<name of the endpoint with fixed/updated data here>",
      "date": "<date here>",
      "url": "<docs url here>",
      "description": "<maintainer's description here>"
    }
  ],
  "structure": [
    {
      "name": "<name of the endpoint with data structure changes here>",
      "date": "<date here>",
      "url": "<docs url here>",
      "description": "<maintainer's description here>"
    }
  ]
}

If some of these things happen very infrequently, and it makes more sense to group them under a generic "updates" or "changelog" field, then that's absolutely a more sensible option.

Cool, but why?

Developers using this API for applications or services need to know when things change so they can change their application accordingly. Having a daily, weekly, or monthly poll for changes that are sent to their email can speed things up much more than reading a backlog or change logs or scanning the wiki-api-feed discord channel for updates amidst a stream of issues (like this one), comments, PRs, and whatever else may be enabled on the webhook.

For me, in the JS API Driver (which I've finally found enough time to work on!) I'm building for this API I would like to include a simple console.warn if they consumer is using something which may have changes they're unaware of. Also during development I want my console to yell at me about any changes so I can ensure my tests, types, and classes are still compatible.

Urgency

Nice to have

Endpoint for Events for the new API

Hello, I would like to see an endpoint for the events that occur in AC:NH in the new API. I am not sure if it is planned or not, but would love to know if it is in the to-do list!

As well as making a new AC:NH events endpoint for the new API, I would like to request if it is possible for invalid dates to return an invalid date error. For example on the old API, giving a date of September 31st would return the events on October 1. Giving an invalid date (like March 32nd) would return December 31st on a Wednesday.

Another request for the endpoint on the new API would be the ability to look up all the events that happen on a certain month, which would allow us to see seasonal events as well as villager birthdays that are happening during the month given.

[Meta] General cleanup of issues

A lot of the issues need to either be closed and/or labeled, that's pretty much all. Didn't want to comment on every issue that needed it, so made this issue instead

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.