Giter Site home page Giter Site logo

harbaum / galagino Goto Github PK

View Code? Open in Web Editor NEW
316.0 18.0 21.0 31.71 MB

A Galaga, Pac-Man and Donkey Kong arcade emulator for the ESP32

C 86.13% C++ 5.94% Python 6.42% Shell 1.52%
arcade arduino emulator esp32 galaga donkey-kong pacman 8048 z80 digdug

galagino's People

Contributors

avatario34 avatar d0023r avatar harbaum avatar toastal avatar witnessmenow 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

galagino's Issues

Master reset

Currently the only way to "return" to the main menu is to hard reset the esp32. This requires to have the reset pin exposed.

Implement a "master reset" e.g. via pressing "coin" and "start" simultaneously.

redefinition of 'OpZ80_INL'

Apologies, I seem to be finding a few today.

When converting the galagino.ino into VSCode, then trying to compile, I get the message:

redefinition of 'OpZ80_INL'

Looking at the code, it's defined in emulation.h:

static inline byte OpZ80_INL(register word Addr) {
#ifndef SINGLE_MACHINE
static const unsigned char *rom_table[][3] = {
{ NONE, NONE, NONE },
#define ROM_ENDL ,
#else
static const unsigned char *rom_table[3] =
#define ROM_ENDL ;
#endif
#ifdef ENABLE_PACMAN
{ pacman_rom, NONE, NONE } ROM_ENDL
#endif
#ifdef ENABLE_GALAGA
{ galaga_rom_cpu1, galaga_rom_cpu2, galaga_rom_cpu3 } ROM_ENDL
#endif
#ifdef ENABLE_DKONG
{ dkong_rom_cpu1, NONE, NONE } ROM_ENDL
#endif
#ifdef ENABLE_FROGGER
{ frogger_rom_cpu1, frogger_rom_cpu2, NONE } ROM_ENDL
#endif
#ifdef ENABLE_DIGDUG
{ digdug_rom_cpu1, digdug_rom_cpu2, digdug_rom_cpu3 } ROM_ENDL
#endif
#ifndef SINGLE_MACHINE
};
return rom_table[machine][current_cpu][Addr];
#else
return rom_table[current_cpu][Addr];
#endif
}

and in z80.h:

static inline byte OpZ80_INL(register word Addr) {
#ifdef ENABLE_PACMAN
PACMAN_BEGIN
return pacman_rom[Addr];
PACMAN_END
#endif

#ifdef ENABLE_GALAGA
GALAGA_BEGIN
if(current_cpu == 1) return galaga_rom_cpu2[Addr];
else if(current_cpu == 2) return galaga_rom_cpu3[Addr];
return galaga_rom_cpu1[Addr];
GALAGA_END
#endif

#ifdef ENABLE_DKONG
DKONG_BEGIN
return dkong_rom_cpu1[Addr];
DKONG_END
#endif

#ifdef ENABLE_FROGGER
FROGGER_BEGIN
if(current_cpu == 0) return frogger_rom_cpu1[Addr];
else return frogger_rom_cpu2[Addr];
FROGGER_END
#endif
}

If I delete the version in z80.h (because it seems the less complete version, all games run except DigDug which starts playing and digs halfway through the screen, then crashes.

Skip self tests

Especially Galaga runs a self test for several seconds on startup. Pac-Man also does this but much shorter. Donkey Kong has no self test.

Patch Galaga and perhaps Pac-Man ROM to skip the self test.

Volume Settings

Hi,

is it possible to change the volume per software or do i have to use a potentiometer?
Great Project btw!

greets
Harry

CYD white background fix

Hi

Firstly, thanks for the amazing project. I have recently built a small arcade with this code and its amazing!

I also have a CYD2USB with a ST7789 display, however when I flashed I had a white background rather than black. I know from other projects I've used on this device that it can do that with this display.

I have managed to correct the issue, I'm hoping my below fixes can be added and hoping I dont need to submit a PR because I have no idea how to do that :)

So anyway my fixes involve both config.h and video.cpp.

In config.h I added this line to line 80:
// #define TFT_INV_OFF // some CYD screens need inversion off if you have a white background rather than black
Normal behaviour should probably be commented so it doesn't affect other ST7789 users.

In video.cpp I deleted line 104 and added:
#ifdef TFT_INV_OFF
0x20, 0, // INV OFF
#else
0x21, 0, // INV ON
#endif

I tested the line in config.h commented out and in and it had the correct effects on the display indicating the code is working e.g. white and black backgrounds.

Thanks

Watchdog reboots DigDug and Galaga

In "Dig Dug" and "Galaga" I get after some seconds:

`E (45312) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (45312) task_wdt: - IDLE (CPU 0)
E (45312) task_wdt: Tasks currently running:
E (45312) task_wdt: CPU 0: emulation task
E (45312) task_wdt: CPU 1: IDLE
E (45312) task_wdt: Aborting.

abort() was called at PC 0x400f1021 on core 0
Backtrace:0x40083aed:0x3ffbe8ec |<-CORRUPTED
ELF file SHA256: 0000000000000000
Rebooting...
`
The other games work great.

error: 'I2S_MODE_DAC_BUILT_IN' was not declared in this scope

While attempting to compile and build the Galagino package for a ESP32-2432S028R (aka, CYD or "Cheap Yellow Display") using the Arduino IDE under Windows 10, with the 2.0.14 version of the esp32 board library installed, the following error appears.

<path-to-repo>\galagino-main\galagino\galagino.ino: In function 'void audio_init()':
<path-to-repo>\galagino-main\galagino\galagino.ino:636:58: error: 'I2S_MODE_DAC_BUILT_IN' was not declared in this scope
     .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN),
                                                          ^~~~~~~~~~~~~~~~~~~~~
<path-to-repo>\galagino-main\galagino\galagino.ino:636:58: note: suggested alternative: 'I2S_MODE_MASTER'
     .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN),
                                                          ^~~~~~~~~~~~~~~~~~~~~
                                                          I2S_MODE_MASTER
<path-to-repo>\galagino-main\galagino\galagino.ino:669:20: error: 'I2S_DAC_CHANNEL_RIGHT_EN' was not declared in this scope
   i2s_set_dac_mode(I2S_DAC_CHANNEL_RIGHT_EN);
                    ^~~~~~~~~~~~~~~~~~~~~~~~
<path-to-repo>\galagino-main\galagino\galagino.ino:669:20: note: suggested alternative: 'I2S_CHANNEL_FMT_RIGHT_LEFT'
   i2s_set_dac_mode(I2S_DAC_CHANNEL_RIGHT_EN);
                    ^~~~~~~~~~~~~~~~~~~~~~~~
                    I2S_CHANNEL_FMT_RIGHT_LEFT
<path-to-repo>\galagino-main\galagino\galagino.ino:669:3: error: 'i2s_set_dac_mode' was not declared in this scope
   i2s_set_dac_mode(I2S_DAC_CHANNEL_RIGHT_EN);
   ^~~~~~~~~~~~~~~~
<path-to-repo>\galagino-main\galagino\galagino.ino:669:3: note: suggested alternative: 'i2s_set_clk'
   i2s_set_dac_mode(I2S_DAC_CHANNEL_RIGHT_EN);
   ^~~~~~~~~~~~~~~~
   i2s_set_clk

exit status 1

Compilation error: 'I2S_MODE_DAC_BUILT_IN' was not declared in this scope

Attempting the changes suggested by the compiler trigger additional errors to appear in the compiler log.

Is there a workaround for this issue on this model of device?

Feature Request: Bluetooth Gamepad support

The ESP32 supports bluetooth.
May be it is possible to add bluetooth gamepad support, that would keep the device as cool as it is and would improve the playability a lot.

bug in cmapconv.py parse_colormap

There is a typo/oversight in the if statement that confirms the colormap data is valid. It does not affect the output, but I noticed it when looking at the code and wanted to point it out.

if ( c[0] < 0 or c[0] > 15 or c[0] < 0 or c[1] > 15 or

This should be revised as follows:

if ( c[0] < 0 or c[0] > 15 or c[1] < 0 or c[1] > 15 or

upload is not executed

Hey, when I want to upload the code via the Arduino IDE, the following error message always comes up. What can I do about it?`

/Users/benutzer/Desktop/galagino-main3/galagino/video.cpp:52:1: sorry, nicht implementiert: nicht-triviale designierte Initialisierer werden nicht unterstützt }; ^ /Users/benutzer/Desktop/galagino-main3/galagino/video.cpp:52:1: sorry, nicht implementiert: nicht-triviale designierte Initialisierer werden nicht unterstützt /Users/benutzer/Desktop/galagino-main3/galagino/video.cpp: Im Konstruktor 'Video::Video()': video.cpp:131:22: Fehler: 'SPI1_HOST' wurde in diesem Bereich nicht deklariert spi_bus_initialize(SPI1_HOST, &bus_cfg, SPI_DMA_CH_AUTO); ^ video.cpp:131:43: Fehler: 'SPI_DMA_CH_AUTO' wurde in diesem Bereich nicht deklariert spi_bus_initialize(SPI1_HOST, &bus_cfg, SPI_DMA_CH_AUTO); ^ In der Datei enthalten von /Users/benutzer/Documents/Arduino/libraries/FastLED/src/FastLED.h:75:0, von /Users/benutzer/Desktop/galagino-main3/galagino/leds.h:8, von /Users/benutzer/Desktop/galagino-main3/galagino/leds.cpp:7: /Users/benutzer/Documents/Arduino/libraries/FastLED/src/fastspi.h:157:23: Hinweis: #pragma-Nachricht: Keine Hardware-SPI-Pins definiert. Alle SPI-Zugriffe werden standardmäßig auf Bitbang-Ausgaben gesetzt # pragma-Nachricht "Keine Hardware-SPI-Pins definiert. Alle SPI-Zugriffe werden standardmäßig auf bitbanged-Ausgaben gesetzt" ^ In der Datei enthalten von /Users/benutzer/Documents/Arduino/libraries/FastLED/src/FastLED.h:75:0, von /Users/benutzer/Desktop/galagino-main3/galagino/leds.h:8, von /Users/benutzer/Desktop/galagino-main3/galagino/galagino.ino:14: /Users/benutzer/Documents/Arduino/libraries/FastLED/src/fastspi.h:157:23: Hinweis: #pragma-Nachricht: Keine Hardware-SPI-Pins definiert. Alle SPI-Zugriffe werden standardmäßig auf Bitbang-Ausgaben gesetzt # pragma-Nachricht "Keine Hardware-SPI-Pins definiert. Alle SPI-Zugriffe werden standardmäßig auf bitbanged-Ausgaben gesetzt" ^ /Users/benutzer/Desktop/galagino-main3/galagino/galagino.ino: In der Funktion 'void dkong_trigger_sound(char)': galagino:555:23: Fehler: keine Matching-Funktion für den Aufruf von 'random()' char rnd = random() % 3; ^ In der Datei enthalten von /var/folders/6c/04z3f_2j7kvd7nx0xxnjn3g40000gn/T/arduino_build_284766/sketch/galagino.ino.cpp:1:0: /Users/benutzer/Library/Arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/Arduino.h:121:6: Hinweis: Kandidat: long int random(long int, long int) lang zufällig (lang, lang); ^ /Users/benutzer/Library/Arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/Arduino.h:121:6: Hinweis: Der Kandidat erwartet 2 Argumente, 0 zur Verfügung gestellt In der Datei enthalten von /var/folders/6c/04z3f_2j7kvd7nx0xxnjn3g40000gn/T/arduino_build_284766/sketch/galagino.ino.cpp:1:0: /Users/benutzer/Library/Arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/Arduino.h:179:6: Hinweis: Kandidat: long int random(long int) lang zufällig (lang); ^ /Users/benutzer/Library/Arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/Arduino.h:179:6: Hinweis: Kandidat erwartet 1 Argument, 0 zur Verfügung gestellt /Users/benutzer/Desktop/galagino-main3/galagino/galagino.ino: In der Funktion 'void audio_init()': /Users/benutzer/Desktop/galagino-main3/galagino/galagino.ino:618:3: sorry, nicht implementiert: nicht-triviale designierte Initialisierer nicht unterstützt }; ^ /Users/benutzer/Desktop/galagino-main3/galagino/galagino.ino:618:3: sorry, nicht implementiert: nicht-triviale designierte Initialisierer nicht unterstützt /Users/benutzer/Desktop/galagino-main3/galagino/galagino.ino:618:3: sorry, nicht implementiert: nicht-triviale designierte Initialisierer nicht unterstützt /Users/benutzer/Desktop/galagino-main3/galagino/galagino.ino:618:3: sorry, nicht implementiert: nicht-triviale designierte Initialisierer nicht unterstützt Bibliothek FastLED in Version 3.6.0 im Ordner: /Users/benutzer/Documents/Arduino/libraries/FastLED wird verwendet Ausstiegsstatus 1 'SPI1_HOST' wurde in diesem Bereich nicht deklariert

driver/spi_master.h

Please upload the sound driver library.

galagino:12:10: fatal error: driver/i2s.h: No such file or directory
#include "driver/i2s.h"
^~~~~~~~~~~~~~
compilation terminated.
exit status 1

In file included from D:\galagino\galagino-main\galagino\galagino.ino:13:0:
video.h:7:10: fatal error: driver/spi_master.h: No such file or directory
#include <driver/spi_master.h>
^~~~~~~~~~~~~~~~~~~~~
compilation terminated.
exit status 1
driver/spi_master.h: No such file or directory

"machine" is undeclared when compiling

I have my conf file configured just for Galaga

// disable e.g. if roms are missing
// #define ENABLE_PACMAN
#define ENABLE_GALAGA
// #define ENABLE_DKONG
// #define ENABLE_FROGGER
// #define ENABLE_DIGDUG

Which defines SINGLE_MACHINE in the conf

And when I compile I get the following error

C:\Users\Brian\Documents\Code\galagino\galagino\emulation.h: In function 'OpZ80_INL':
emulation.h:238:20: error: 'machine' undeclared (first use in this function)
   return rom_table[machine][current_cpu][Addr];

It seems machine is only created if its not a single machine

From the main .ino

#ifndef SINGLE_MACHINE
signed char machine = MCH_MENU;   // start with menu
#endif

Gerber Files for cabling

Hello Mr. Harbaum, in your YouTube video https://www.youtube.com/watch?v=s7kZmB4fsLA you show circuit boards for the cabling from 42:30 onwards. I'm very interested in this. Prototype on breadboard is already running, joystick is also ready. Housing parts created with the 3D printer. The wiring is a horror because I'm currently unable to keep my hand as steady as I should for soldering. Can you please include the Gerber files in the project. Thank you ! Many greetings from the Wolfenbüttel district. Axel Ahlborn

Use DMA to transfer data to display

The pure data transfer to the display has a theoretical limit of 22428816/40000000 = 25,8 ms per frame. In the current implementation the transfer is blocking and all video and audio calculations need to take place in the remaining 7,5ms per 30Hz display frame.

Using DMA for the data transfer would allow to compute video and audio data while video data is being transferred. This would significantly relax the load on the esp32 core responsible for audio and video.

I2S_MODE_DAC_BUILT_IN was not declared in void audio_init

I've been trying/failing to compile/verify the .ino while I am waiting for my ESP32 to arrive.

Right now I've got an error in void audio_init() that I2S_MODE_DAC_BUILT_IN was not declared. Do I need a specific version of the ESP32 libraries? Can you provide which versions you are using?

On another note, I saw that the readme is now missing the section for using the other .py scripts, which I was able to find to get past the tileaddr.h error. While it did not mention the game logo python script, I was able to figure out the usage and run that command too.

Thank you and I look forward to building this project!

Did you ever see these failures?

Hi Till,

First, thanks for this wonderful project. I have ported it to my board with a WROVER and 320x480 pixel ILI9488 display. It works but with a few failures I am wondering if you can shed some light on (for example you saw this during your development).

  1. I get no sound. Nothing coming out of the DAC pins (25 & 26) even when viewed with an oscilloscope.
  2. The emulator (or at least parts of it) seem to freeze on occasion.
  • If I press COIN after it has displayed the attract screen for a while movement of the sprites stops and I can add no more coins but the starry background keeps moving. However if I hold COIN down through the startup then I immediate get a coin and can others and can start the play.
  • After a game it freezes after displaying the statistics. The statistics go away and the the entire game freezes (starry background freezes too).

I am compiling on Arduino 1.8.19 (Mac) with ESP Arduino package 2.0.6. I downloaded my ROMs from https://wowroms.com/en/roms/mame-0.139u1/download-galaga-namco-rev.-b/3699.html. All your python scripts seemed to work just fine on the Mac. Board is https://github.com/danjulio/gCore.

Changes I made include

  1. I display a background image instead of blanking the LCD as you can see to make use of the extra LCD real-estate (seems to work fine).
  2. I used different IO pins for the buttons (33, 34, 35, 36, 39) and used external 10k-ohm pull-ups (seems to work fine).
  3. I used the TFT_eSPI library to drive the LCD (80 MHz VSPI native pins). Seems to work fine and I did a little playing with your code to try out 60 Hz. Seems to work - starry background scrolls a lot faster - but didn't get an actual FPS yet.

I realize it is really hard to debug someone else's setup but just curious if you had seen any of these issues or had a pointer where I might go debugging.

Thanks, Dan

IMG_0293

Constant buzzing from speaker on GPIO26 (CYD). Can an external I2S amp be used?

HI,

Steller work on this, it's faultless!!

Except for the sound on my CYD display. It has an amp on pin 26, but all I hear is a buzzing sound?

To be honest I have not really ever had much luck with the sound on these boards.

So can an external I2S amp (MAX98357) be used, probably overkill for the sounds generated, but a least I will hear something less annoying than a buzzing!

:-)

Feature request - Use c button on nunchuck for coin/start

Thanks for this great project. I have compiled and installed on CYD and works great.
It seems I have an extra "c" button on the nintendo wii nunchuck which does not seem to be used.

I would love for it to allow to start the game and avoid using the boot button on the back of the board.

I will see if I can implement this feature...

Missing i2s libs in the sources

When trying to compile the galagino.ino I encounter an error message, that the file "driver/i2s.h" is missing. Due to the statement
#include "driver/i2s.h"
it has to be part of the project-files, but it isn't.

I tried to collect this and other missing files from espressif and place it in the respective subdirectory of the sourcefiles but this is a never-ending story.
Is there a simpler and safe soution in place?

Regards purehunter

Emulate Donkey Kong audio CPU

Currently Donkey Kong uses sampled audio and it's an ugly endeavor to find/create/convert matching sound bits . But on the real arcade machine most of the audio is actually generated by a program running in a intel 8049 compatible CPU.

Emulating the audio CPU itself would make Donkey Kong audio be "correct". At least for those sounds generated by the audio CPU. This means we have to implement a 8048 emulator as none matching this project seem to exist.

Entry for 1942 missing in conv_win.sh?

Hello,

super cool project, thanks for making it!

Have just realised that the following line seems to be missing in conv_win.sh for 1942:

python ./romconv.py _1942_rom_cpu1 ../roms/srb-03.m3 ../roms/srb-04.m4 ../galagino/1942_rom1.h

Thanks again, Christian

Feature request: more ROM options

Absolutely amazing! Awesome! I was looking for some fun projects with ESP32, and after some failures with other projects, I found this one, that works like a charm with great and very complete instructions. Instead of a cabinet, I 3D printed a console for it (I will release it on thingiverse as soon as I will reach the final version (no issues).

I was wondering: can you release other ROM packs with different games of the era? I wish make other consoles using the same hardware; actually I looked at the source code, but building a new ROM pack is beyond my skills, unfortunately.

I would love to see Gyruss in this pack, that was quite famous (at least in some part of Europe) and has an amazing music.
Other classic ROMs of the era with vertical display (IIRC), just as suggestion/example, could be Space Invaders, Phoenix, Xevious, Time Pilot, Quix, Q-Bert, Bomb Jack...

Higher quality reference image?

Hey there! I just found this project and it's REALLY cool! I can't wait to make little tiny arcade machines in my own home!

I was just wondering if you had a higher quality image of the reference breadboard, I'm having trouble figuring out what wires go where as I think the pins on my ESP32 are laid out differently compared to the example. Here is the ESP32 I'm using for reference.

https://www.aliexpress.us/item/3256805517875317.html?spm=a2g0o.order_list.order_list_main.17.7c8b1802ZVvMCu&gatewayAdapt=glo2usa

Thanks in advance!

  • Sulky

Combine coin and start button function

On a real arcade machine inserting a coin and starting a game are two different things. On the emulator inserting a virtual coin and starting always happen in a sequence.

Implement a automatic that is triggered by the start button and automatically inserts a coin before. The coin button can then be totally omitted.

May collide with #7

Galagino on TTGO T4

Hi,
progressing on the project.
All the python scripts succeeded on the roms but with compile of the project the galaga_starseed.h is throwing struct errors.
It was a bad sample_boom file, resolved with newly converted file.
Thank you

Master attract mode

All three games come with an "attract mode" where the game runs short game sequences to attract paying users. With the galagino menu these don't show up until one machine is selected in the menu.

Add a timer to implement a "master attract mode" where the esp32 randomly starts machines after some time into attract mode while it sits idle in the menu. This "master attract mode" ends once the user presses a button.

TypeError: object of type 'int' has no len()

PS C:\Software\Arcade\galagino-main\romconv> py ./cmapconv.py frogger_colormap ../roms/pr-91.6l ../galagino/frogger_cmap.h
Traceback (most recent call last):
File "C:\Software\Arcade\galagino-main\romconv\cmapconv.py", line 222, in
palette = parse_palette(sys.argv[2])
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Software\Arcade\galagino-main\romconv\cmapconv.py", line 39, in parse_palette
if len(c) == 3:
^^^^^^
TypeError: object of type 'int' has no len()

cmapconv.py returns an error when I try to run it. First I tried DigDug as it the new ROM, but also produces the same error when I try to convert an existing ROM.

I have tried py, python and python 3. Did I miss a setup step?

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.