Code Monkey home page Code Monkey logo

nintendoclients's People

Contributors

azillion avatar danielectra avatar epicusername12 avatar ioistired avatar ixaruz avatar jonbarrow avatar kinnay avatar lifehackerhansol avatar mcmi460 avatar mrexodia avatar nvnprogram avatar relm avatar tenda-gumi avatar thegreatrambler 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

nintendoclients's Issues

AC:NH credentials

Is there any method of getting the credentials required for the animal crossing script without rooting your Switch? (I have the new model and thus cannot root it)

Update Telemetry Page

https://github.com/kinnay/NintendoClients/wiki/Telemetry-Servers lists only receive for data telemetry - it now seems https://fw-api.lp1.nso.nintendo.net/v1/events is also used when enabled via sprofile, and events such as the following are sent:

{"type_name":"online_play","version":1,"occurred_at":1645484612,"application_id":"01006f8002326000"}

with {"message":"OK"} as a response.

Also, "telemetry" is misspelt a few times ^^

Obtain .btl file for MM2

According to this reddit post, three files are neccessary for a level on your savefile:

  • bcd (level data)
  • dat (replay? data)
  • btl (thumbnail data likely)

I am aware you cam download the bcd of any arbitrary level online. How could I aquire the other two and, if not, could I use the default provided by creating a new level in the MM2 editor? Thank you.

How to get smm2 stage data.

I want to get smm2 stage information, but there are no examples to get information from the server with switch platform.

I test example_mariokartdeluxe.py with login.

backend = backend.BackEndClient("switch.cfg")
backend.configure(SMM2.ACCESS_KEY, SMM2.NEX_VERSION, SMM2.CLIENT_VERSION)
backend.connect(HOST, PORT)
backend.login(USERNAME,auth_info=?)

and say
nintendo.nex.common.RMCError: Authentication::ValidationFailed (0x80680007)

What do i need to do?

Thank you for your reply.

Thread safety

The scheduler runs in a separate thread and there is no way to avoid that. However, when I wrote the PRUDP client (and other classes) I didn't pay attention to thread safety. I should probably check if this can cause issues.

Hang during call to device_token

During a call to dauth.device_token(keys) my code hangs at exactly this line. This code used to work a few weeks ago and I've updated the system and checked my keys file, but it inexplicably hangs here, not an error.

dauth = DAuthClient(keys)
dauth.set_certificate(cert, pkey)
dauth.set_system_version(SYSTEM_VERSION)
response = await dauth.device_token(dauth.BAAS)
device_token = response["device_auth_token"]

Question about PIA Protocol (NEX Game Server)

Hello, I have just read your repo on super mario 35 and the research you have done regarding how our consoles communicate with nintendo servers (and I would like to have your opinion on the pia (pear 2 pear) protocol ( when used for a connection to the NSO (Nintendo Switch Online))

if I understood correctly when our console connects to online on a game using the PIA protocol to play online

the console contacts the NEX server (Game Server) to request the available pools and attempt to connect to them

do you think it would be possible to recreate this protocol based on the research of the eagle server (an ips patch for change game server adress) to allow hacked consoles to communicate as if it were on the NSO without going through the nintendo servers

if possible this would be a major step forward especially if it does not depend on external hardware (compared to lan play)

Thank you in advance for your reply

Using `search_objects` to make a refined search of smm2 levels

I have been trying to implement as many functions as possible that return CourseInfo, but one method in particular seems like a good candidate for more specific searches. search_objects looks promising, but it returns a list of DataStoreMetaInfo which don't have any associated types. I'm wondering if I can change data_type in DataStoreSearchParam to some constant that maps to levels and then convert the resulting meta_binary in DataStoreMetaInfo to CourseInfo and if not whether a similar method can be put to use to get very particular searches.

[Wiki] Inconsistencies and corrections

Opening this issue just to keep track of any inaccuracies/issues I find in the wiki or new findings to be added to the wiki. Since I will be updating this issue every now and then I will keep it open

To start off it seems like on the 3DS NintendoLoginData in the Secure Protocol is actually named AccountExtraInfo. It contains the same data but just a different name in the AnyDataHolder

FollowingsLatestCourseSearchObject in DataStore (SMM) says it uses a DataStoreSearchParam and a <List>String in it's request but the data I have doesn't seem to quite match that? It seems like all the data matches up in DataStoreSearchParam except that it seems to lack the totalCountEnabled and dataTypes fields. I'm unsure if these are related to the NEX version or if it's a SMM-specific patch. If I omit these two fields then the data for FollowingsLatestCourseSearchObject matches up perfectly

And finally when again using SMM it looks like GetObjectInfos actually uses <List>DataStoreFileServerObjectInfo in the response but your wiki doesn't say that SMM patches that method? I have not checked any other games which use the DataStore protocol so I don't know if this is just the wiki being wrong in general or yet another SMM-specific patch

How do you extract the Switch's client certificate for MITM?

Hi, I'd like to MITM my Switch in order to try and figure out how some of these APIs work. I set up Charles, configured my Switch to proxy to it, and added a patch which disables certificate verification. It's working, sorta. I'm told I need my Switch's client certificate to get more detailed logging of requests. How do I get that? I tried using SimonMKWii's scripts but got a NameError. Then I tried using CertNXtractionPack but Charles refuses to read the resulting PFX file (I tested Firefox just in case it's a Charles error, no dice there either). Can you recommend a better way to get my Switch's client certificate?

Scope of this repository

Currently, this repository implements everything that is required to access NEX services from a PC. Should it support other services as well? I've been thinking about this for a while.

First, some observations:

  • It's hardly possible to use NEX without talking to DAuth, AAuth and BaaS, so we have to implement those services anyway.
  • Some people do want to expand the scope of this repository (for example #85 and #87).

Also:

  • The wiki documents much more services than NEX: Pia, NPLN, AC:NH, just to name a few.
  • I've been working on LDN and NPLN in different repositories. I've also tried to implement Pia in this repository a few times, but was never able to get a fully working implementation because of its complexity.

I'm not against adding support for other services, but I also want to avoid feature creep. And:

  • The NEX implementation works quite well. I'm hesitant to implement something like Pia here, because its initial implementation will inevitably have problems. If it's in a different repository, I don't care. It can become more mature at its own pace. I just don't want to provide well-functioning services and half-broken services in the same repository.
  • Some services have a completely different design. It doesn't make sense to implement LDN or provide NPLN protobuf files in this repository.

I've been thinking about creating a github organization. This would have the following benefits:

  • All related repositories would be in one place, without unrelated repositories (example) filling the repository list.
  • As long as this repository is under my personal account, I want to be in control over the code that is committed. When it is moved to an organization, I might be less hesitant to add collaborators.

As far as I know, github automatically redirects the old repository when it is transferred to an organization, so existing links will remain intact.

If we do this, a few questions remain:

  • What would be the scope of the organization? Of course it would provide client code + documentation, but it might make sense to provide some server code as well?
  • How do we organize the code? Pia should probably get its own repository. Should we split the HTTP services into their own repository as well? They are independent from NEX after all. And what about generic code such as miis.py?
  • What would be a good name for the organization?

Just wanted to dump my thoughts here. If you want to share your opinion, leave a comment below.

ACNH: Patterns support

I would love to be able to upload an arbitrary image and get back a pattern share code programmatically. Similarly to be able to download a pattern given a share code or list all patterns created by a given creator code. Basically everything the in-game kiosk can do.

How to parse GBB game.bin

I was able to download game.bin by referring to gamebuilder.py. Thank you.
In the following line, the argument access_key was missing, so I added GBG.ACCESS_KEY.
It seems that the downloaded game.bin contains data such as jpeg and name. Is there a way to parse this?

param.data_id = code_to_data_id(GAME_CODE)

[Wiki] DataStore applicationIds

On the wiki I see you document DataStore Codes, so I was wondering if applicationIds might also be on the table for being properly documented? They are used a LOT in DataStore to get things like differing configuration settings, to changing what kind of data is sent with a response, to rating objects

For example in SMM:

  • If CustomRankingByDataId sends an applicationId of 300000000 then it expects user Mii data to be sent back, not course data
  • GetApplicationConfigString uses it to get different word black lists(?) (possibly for course names and Miiverse comments?)
  • GetApplicationConfig uses it to get different uint32 lists (unknown what they are for, but one seems to be a list of PIDs)
  • RateCustomRanking uses it heavily for rating objects with many different values

I have seen the following applicationIds used:

  • 0 (Unknown, seen in GetApplicationConfig and RateCustomRanking)
  • 1 (Unknown, seen in GetApplicationConfig)
  • 2 (Unknown, seen in GetApplicationConfig)
  • 10 (Unknown, seen in GetApplicationConfig)
  • 128 (Word black list? Seen in GetApplicationConfigString)
  • 129 (Word black list? Seen in GetApplicationConfigString)
  • 130 (Word black list? Seen in GetApplicationConfigString)
  • 2400 (Unknown, seen in RateCustomRanking)
  • 200000000 (Unknown, seen in RateCustomRanking)
  • 200002400 (Unknown, seen in RateCustomRanking)
  • 300000000 (Mii data? Seen in GetCustomRankingByDataId and RateCustomRanking)
  • 300002400 (Unknown, seen in RateCustomRanking)
  • 119700101 (Unknown, seen in RateCustomRanking)
  • 119702501 (Unknown, seen in RateCustomRanking)
  • 1497730516 (Unknown, seen in RateCustomRanking)
  • 1497732916 (Unknown, seen in RateCustomRanking)
  • 419700101 (Unknown, seen in RateCustomRanking)
  • 419702501 (Unknown, seen in RateCustomRanking)
  • 1797730516 (Unknown, seen in RateCustomRanking)
  • 1797732916 (Unknown, seen in RateCustomRanking)

Class documentation and tests

The wiki of this repository has almost 100 pages about the servers and protocols, but there is (aside from the example scripts) no documentation about the code. It would be nice to document the classes and their methods somewhere. Right now the only way to figure out the interfaces is to read the code, and it's not always clear which methods are supposed to be public or private. It would also be nice to have all the methods in one place, with clickable links if possible.

I don't have any experience with this. So far I have discovered Sphinx, MkDocs and pydoc. Seems like documentation is either written in markdown or docstrings. I think I'd prefer markdown because it's more flexible. Also, docstrings often increase the size of the code significantly, which might be harmful to its readability. On the other hand, docstrings are shown in python's help() function.

Possibly new information about PRUDPLite/Switch packets?

After reading up on PRUDPLite I attempted to look at my own traffic for research purposes. However none of the packets found in WireShark match that of the structure described here.

None of the packets in my dump have a 0x80 header, however many (if not all) seem to use 32 AB 98 64 as a header. This is true between both MK8D and Splatoon2. Could Nintendo have possibly changed the format? Or is this something different? There's no WebSocket data in the WireShark dumps and it doesn't appear to be going over TCP either. On a whim I also checked PRUDP V0 and V1 (not expecting anything), and unsurprisingly those also did not work.

MK8D WireShark dump 1: https://drive.google.com/open?id=1GLyehZHR7lHMqW61YT4lOZSqyj7Pixzp
MK8D WireShark dump 2 (full dump of race): https://drive.google.com/open?id=1B32NYEWweKr9ZQsmucwljo0VOMt6vjKm
Splatoon2 WireShark dump: https://drive.google.com/open?id=15yJRtBUCxfJDZ7f9WRfLl_hXaaqi5ArJ

Fix docs

Links are broken in the documentation.

  • Figure out what happened
  • Fix the docs

I'm guessing that it was caused by the release of mkdocs 1.2.

<message>Unlinked device</message>

i get Unlinked device when using donkey kong client. does anybody know why this happens?

INFO:anynet.http:Received HTTP response: 400
ERROR:nintendo.nnas:Account request returned status code 400

0110 Unlinked device

Mario Kart 8 Deluxe example script not working

Hi, I recently noticed that example_mariokartdeluxe.py doesn't seem to work anymore. Did they possibly disable the guest login?
The error I get is nintendo.nex.common.RMCError: RendezVous::InvalidUsername (0x80030064)

Automatic title version detection

Currently, the latest title version is hardcoded in games.py and must be updated manually whenever an update is released.

It would be nice if we could automate this. Maybe a bot can create a pull request whenever an update is released. I don't want to use my own client certificate though.

Maybe someone keeps a public database of Switch titles. If yes, check if it's good. Is it reasonably up to date?

Incorrect UserMessage structure on the wiki?

Today I was trying to get deliver_message to work properly for SmmServer and I ran into a strange issue.

Here is my log (I just added some debug prints):

[2022-08-20 15:42:38] INFO: MessageDeliveryServer.deliver_message()
[2022-08-20 15:42:38] INFO: DataHolder.decode, stream: 0e0042696e6172794d65737361676500a7000000a30000000000000000002a000000000000001a94357701000000000000000000000000000000000000000000000001000000010000010000006a0000006800000000030000000000000002540be46100470072006100730073007900200050006c00610069006e00730020002800450078007400720065006d0065006c0079002000450061007300790029000000000000305f304b306800002372e3580e235ab002818e880000
[2022-08-20 15:42:38] INFO: DataHolder.decode, name: BinaryMessage, stream: a7000000a30000000000000000002a000000000000001a94357701000000000000000000000000000000000000000000000001000000010000010000006a0000006800000000030000000000000002540be46100470072006100730073007900200050006c00610069006e00730020002800450078007400720065006d0065006c0079002000450061007300790029000000000000305f304b306800002372e3580e235ab002818e880000
[2022-08-20 15:42:38] INFO: DataHolder.decode, sub1: a30000000000000000002a000000000000001a94357701000000000000000000000000000000000000000000000001000000010000010000006a0000006800000000030000000000000002540be46100470072006100730073007900200050006c00610069006e00730020002800450078007400720065006d0065006c0079002000450061007300790029000000000000305f304b306800002372e3580e235ab002818e880000, stream: 
[2022-08-20 15:42:38] INFO: DataHolder.decode, sub2: 0000000000002a000000000000001a94357701000000000000000000000000000000000000000000000001000000010000010000006a0000006800000000030000000000000002540be46100470072006100730073007900200050006c00610069006e00730020002800450078007400720065006d0065006c0079002000450061007300790029000000000000305f304b306800002372e3580e235ab002818e880000, sub1: 
[2022-08-20 15:42:38] INFO: Structure.decode, hierarchy: [<class 'nintendo.nex.common.Data'>, <class '__main__.UserMessage'>, <class '__main__.BinaryMessage'>]
[2022-08-20 15:42:38] INFO: UserMessage.load stream: 000000001a94357701000000000000000000000000000000000000000000000001000000010000010000
[2022-08-20 15:42:38] INFO: BinaryMessage.load stream: 6800000000030000000000000002540be46100470072006100730073007900200050006c00610069006e00730020002800450078007400720065006d0065006c0079002000450061007300790029000000000000305f304b306800002372e3580e235ab002818e880000
[2022-08-20 15:42:38] INFO: message: {"binary_body": [0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 2, 84, 11, 228, 97, 0, 71, 0, 114, 0, 97, 0, 115, 0, 115, 0, 121, 0, 32, 0, 80, 0, 108, 0, 97, 0, 105, 0, 110, 0, 115, 0, 32, 0, 40, 0, 69, 0, 120, 0, 116, 0, 114, 0, 101, 0, 109, 0, 101, 0, 108, 0, 121, 0, 32, 0, 69, 0, 97, 0, 115, 0, 121, 0, 41, 0, 0, 0, 0, 0, 0, 48, 95, 48, 75, 48, 104, 0, 0, 35, 114, 227, 88, 14, 35, 90, 176, 2, 129, 142, 136, 0, 0], "flags": 0, "id": 0, "life_time": 0, "message_recipient": [1, 0, 0, 0, 1, 0, 0, 1, 0, 0], "parent_id": 2000000026, "pid_sender": 1, "reception_time": {"value": 0}, "sender": null, "subject": null}

Overall the structure makes sense. I figured out the following structure:

  • AnyDataHolder (name: BinaryMessage, length, length, Structure data)
  • Structure data: 00 00000000 00 2a000000 00000000 1a943577 01000000 0000000000000000 00000000 00000000 0000 0000 01000000 01000001 0000 006a 0000006800000000030000000000000002540be46100470072006100730073007900200050006c00610069006e00730020002800450078007400720065006d0065006c0079002000450061007300790029000000000000305f304b306800002372e3580e235ab002818e880000

This is composed of:

  • Data (has no members)
    • version: 00
    • length: 00000000
  • UserMessage
    • version: 00
    • length: 2a000000
    • m_uiID: 00000000
    • m_uiParentID: 1a943577 (this number occurs earlier in the logs so it makes sense)
    • m_pidSender: 01000000
    • m_receptiontime: 0000000000000000
    • m_uiLifeTime: 00000000
    • m_uiFlags: 00000000
    • m_strSubject: 0000 (null)
    • m_strSender: 0000 (null)
    • m_uiRecipientType: 01000000
    • m_principalId: 01000001
    • m_gatheringId: 0000 (there isn't enough data)
  • BinaryMessage
    • qbuffer: 006a 0000006800000000030000000000000002540be46100470072006100730073007900200050006c00610069006e00730020002800450078007400720065006d0065006c0079002000450061007300790029000000000000305f304b306800002372e3580e235ab002818e880000

It looks like there is something wrong with the MessageRecipient, perhaps the m_uiRecipientType is a Uint16?

That would make it:

0100 00000100 00010000

Which is type=1, principalId=65536, gatheringId=256 which seems more reasonable?

Update anyio version

Anyio recently reached version 2.0.0, with breaking changes. I fixed this by explicitly specifying the required anyio version in setup.py. However, I really want to update my code to be compatible with anyio 2.0.0 and higher at some point.

TLS verification?

As far as I can tell, the library uses TLS but ignores server certificates. Since N's certificates are self signed, is it possible we could supply our own TLS fingerprints for at least ToFU-based verification?

PRUDP port handling

PRUDP packets contain a source and destination port (just like regular TCP/UDP packets). These can be used to:

  • Establish multiple PRUDP connections using a single transport connection (e.g. using a single websocket connection)
  • Host multiple PRUDP servers at the same address (e.g. under the same websocket server)

My current implementation does not support this however. It always establishes a new transport connection for each PRUDP connection, and only one PRUDP server can be hosted at a given TCP/UDP port.

For completeness sake, it would be nice to properly implement PRUDP ports. Unfortunately, this is very difficult.

Rewrite scheduler to avoid polling

Currently, the scheduler loops through all sockets and timers every 20 milliseconds to check if they're ready. This is probably not scalable. Even if the performance impact is not as bad as it seems, it just feels bad to waste resources like that. Maybe we can use select?

Where is save 8000000000000010?

Sorry to keep asking questions, but I wasn't able to find save 8000000000000010 in goldleaf, only 8000000000000001 and 8000000000000011. Do you know where I could find and read it? Thank you.

Undocumented changes

There are a few differences between the source code of NintendoClients and the documentation which leads to certain undocumented differences

The ones which I have currently found deal with the type/flags and checksums

In https://github.com/Kinnay/NintendoClients/wiki/PRUDP-Protocol#v0-format it says that the "Type and flags" field is two bytes, however your source code shows a version which is one byte

https://github.com/Kinnay/NintendoClients/blob/a022b22d4d1bab16f6dd16f7679bd07546fd7e7b/nintendo/nex/prudp.py#L180-L183

Similarly the checksum is shown to only be one byte, but again your source code shows a version where there it is four bytes

https://github.com/Kinnay/NintendoClients/blob/a022b22d4d1bab16f6dd16f7679bd07546fd7e7b/nintendo/nex/prudp.py#L141-L160

From what I can tell these differing formats are not documented in the Wiki. There may be more as well, which I will leave here as comments if found, but at the moment I only have these 2

Use MM2 example without a digital download

I noticed that the MM2 example only uses the ticket in one place:

response = aauth.auth_digital(
	SMM2.TITLE_ID, SMM2.TITLE_VERSION,
	device_token, ticket
)

Is there an equivalent aauth.auth_gamecard to use with game cards? Thank you

Support 11.0.0

Should be as simple as adding the new user agent and system version digest to dauth.py, aauth.py and baas.py.

Add support for 12.1.0

See title. Dump the account sysmodule and check if anything has changed. Apparently there is a new master key.

Updated Wii U error codes

The error code documentation listed here https://github.com/Kinnay/NintendoClients/wiki/Wii-U-Error-Codes is very useful for understanding when to throw an error and why, however it remains very incomplete. On Wii U all the error codes and messages are stored in MSBT files. Using these we can get all known error codes and their messages

Attached is a complete list of all error codes and messages on the Wii U. While still incomplete, as not every error code has a message it seems, this is a substantial improvement

101-xxxx.md
102-xxxx.md
103-xxxx.md
104-xxxx.md
105-xxxx.md
106-xxxx.md
108-xxxx.md
109-xxxx.md
115-xxxx.md
118-xxxx.md
120-xxxx.md
124-xxxx.md
125-xxxx.md
126-xxxx.md
150-xxxx.md
151-xxxx.md
152-xxxx.md
155-xxxx.md
156-xxxx.md
157-xxxx.md
158-xxxx.md
161-xxxx.md
162-xxxx.md
165-xxxx.md
166-xxxx.md
167-xxxx.md
168-xxxx.md
199-xxxx.md
errors.md

Wii U 5.5.5 System Update

The new system version is X-Nintendo-System-Version | 0260 - this should be updated in the appropriate Wii U scripts

Nintendo 3DS PRUDP V1

Hi
I tried to create "server" for Metroid Prime FF to look into the packets just for fun.
But I have a problem with the packet signature in PRUDP V1.
The connection with the 3DS seems a little bit simpler as opposed to the Wii U. It just connects to nasc.nintendowifi.net, sends a request and gets a response that inlucdes an IP (Key named locator in the response) that is base64 encoded and a token that I have no idea how it is encoded. After it closes the connection to nasc it directly sends a SYN PRUDP V1 packet to the Game Server. The game seems to just accept my SYN packet from my server without a signature but the CONNECT packet that follows it will not accept. My CONNECT response is the exactly the same as the one from the real server, except the packet signature and the session ID. But the session ID seems to be a random number anyway so it shouldn't cause the game to not accept my packet.

I guess the 3DS doesn't use a secure key to calculate the signature because there is no such thing as a secure server, except it is hidden in the token from the nasc.
So the real problem I'm facing is how can I get the access key of Metroid Prime FF. Do you have any idea?

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.