Giter Site home page Giter Site logo

libwallaby's Introduction

libkipr

Library for interfacing with KIPR Robot Controllers.

Documentation can be viewed at https://www.kipr.org/doc/index.html or by clicking the "Help" button in the KIPR Software Suite IDE.

CMake Options

Each of the following options may be specified when executing CMake by prefixing the option with -D (e.g., -Dwith_accel=OFF).

Modules

  • with_accel (default: ON) - Build accelerometer support.
  • with_analog (default: ON) - Build analog sensor support.
  • with_audio (default: ON) - Build audio support.
  • with_battery (default: ON) - Build battery support.
  • with_botball (default: ON) - Build botball support.
  • with_camera (default: ON) - Build camera support.
  • with_compass (default: ON) - Build compass support.
  • with_console (default: ON) - Build console support.
  • with_create (default: ON) - Build iRobot Create 2 support.
  • with_digital (default: ON) - Build digital sensor support.
  • with_graphics (default: ON) - Build graphics support (requires X11 development files, such as x11proto-dev on Debian/Ubuntu).
  • with_gyro (default: ON) - Build gyroscope support.
  • with_magneto (default: ON) - Build magnetometer support.
  • with_motor (default: ON) - Build motor support.
  • with_network (default: ON) - Build network support.
  • with_servo (default: ON) - Build servo support.
  • with_tello (default: ON) - Build Tello support.
  • with_thread (default: ON) - Build thread support.
  • with_time (default: ON) - Build time support.
  • with_wait_for (default: ON) - Build wait_for support.

Bindings

  • with_python_binding (default: ON) - Build Python binding (requires Python 3+ development files, such as libpython3.10-dev on Debian/Ubuntu).

Miscellaneous

  • with_documentation (default: ON) - Build documentation support (requires doxygen installed on system).
  • with_tests (default: ON) - Build tests.

Dummy Build

  • DUMMY (default: OFF) - Build a dummy build for use on computer

Cross-compiling to aarch64-linux-gnu (e.g., Wombat)

apt install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
cd libkipr
cmake -Bbuild -DCMAKE_TOOLCHAIN_FILE=$(pwd)/toolchain/arm-linux-gnueabihf.cmake .

Cross-compiling to JavaScript/WASM (e.g., Simulator)

Without Python Support

libkipr can be compiled to statically link to a C program that has been compiled to emscripten. The resulting libkipr.a should be used.

source emsdk/emsdk_env.sh
cd libkipr
emcmake cmake -Bbuild -Dwith_graphics=OFF -Dwith_camera=OFF -Dwith_tello=OFF -Dwith_python_binding=OFF .

With Python Support

libkipr can be compiled to dynamically link to a cpython that has been compiled to emscripten. The resulting kipr.wasm should be placed in cpython's virtual filesystem on the PYTHONPATH (see simulator for details).

source emsdk/emsdk_env.sh
cd libkipr
emcmake cmake -Bbuild -Dwith_graphics=OFF -Dwith_camera=OFF -Dwith_tello=OFF -DPYTHON_LIBRARY=$PYTHON_LIBRARY -DPYTHON_INCLUDE_DIR=$PYTHON_INCLUDE_DIR -Dwasm=ON .

where:

  • $PYTHON_LIBRARY is the libpythonVERSION.a file that has been compiled to emscripten-browser.
  • $PYTHON_INCLUDE_DIR is that python's include directory.

License

libkipr is licensed under the terms of the GPLv3 License.

Contributing

Want to Contribute? Start Here!: https://github.com/kipr/KIPR-Development-Toolkit

libwallaby's People

Contributors

bmcdorman avatar chrehall68 avatar edmyers avatar erinharrington-12 avatar eugenedmyers avatar justinmerrell avatar navzam avatar prithvirajkadiyala avatar ryanvade avatar sascha8a avatar schineaj23 avatar tcorbly avatar toberocat avatar zacharyprime avatar

Stargazers

 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

libwallaby's Issues

Fix all compilation warnings

cc1: warning: command line option ‘-std=c++11’ is valid for C++/ObjC++ but not for C

This happens multiple times during the build process.
However, I hope that the cleanup crew project will solve this in the process.
If not, it should be addressed eventually. I'm not sure if the line needs to be removed or the compiler needs to stop treating those pieces as C (I believe the latter).

Camera live crashes botui

While testing the camera live view, BOTUI crashes when we try to go back.
This issues seems to be there after the merging of the pull request #106

Look into what resources are being consumed for the camera and what is being returned from the functions while calling any of the camera functions.

Add a range of TCP functionality for libwallaby

Here is a PR for the first attempt at doing this: #73

The KIPR-Update repository is now configured to install a managed mode configurator file. I plan to eventually add the ability to interact with that function to the wifi screen so that the Wombat can connect to wifi sources.

If we do that, TCP (or UDP/other) functionality will be a necessity so that we can add functions such as:

  • Allowing IDE use over the internet for virtual learning
  • Syncing multiple wombats to one shared network so that there aren't entire APs produced by every Wombat in a room
  • Connecting to a Unity Simulator (side project)
  • Communicating with another Wombat over TCP (ideally built into libwallaby)
  • Allowing the Wombat platform to be used for a broader range of tasks because there is a communication medium between the PC and the Wombat, for example, a browser based remote control robot.

It would also be nice if we could find a way to simplify the TCP connection process, similar to how the create_connect() handles complexity in the background.

Functions like:
TCP_connect(char* ip, char* port);
TCP_disconnect();
TCP_send(char* data);

Here is a link to the Unity Simulator:
https://github.com/Zacharyprime/RoboSim

Here is the TCP code for it:
https://github.com/Zacharyprime/RoboSim/blob/main/RoboSim/Assets/Scripts/Network.cs

(note: the sim is a unfinished, barely even started project as of writing this)

Check accelerometer consistency with libkovan

...particularly the scaling.

libwallaby currently uses a signed short for +/- 2G so we get about 2^12 per G.

A typical un-calibrated reading from the test program with the board flat on a table would look like:
ax: 359 ay: 244 az: -16595

Accessing the camera object

I'm trying to obtain the camera object. Would I need to include camera_c_p.cpp and then use DeviceSingleton::instance() ?

Once I have the object, how do I grab a frame?

Basic string/char* Warning

Warning 1:
/home/pi/dev/libwallaby/src/botball_c.cpp: In function ‘void wait_for_light(int)’:
/home/pi/dev/libwallaby/src/botball_c.cpp:123:56: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
g_printString("READING - ON = ",INSET,30,BLACK,2);

Warning 2:
/home/pi/dev/libwallaby/src/botball_c.cpp: In function ‘void wait_for_light(int)’:
/home/pi/dev/libwallaby/src/botball_c.cpp:123:56: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
g_printString("READING - ON = ",INSET,30,BLACK,2);
^

Update Doxygen

Doxygen and it's respective files are ancient in their implementation (like a lot of things).
We need to go through and bring everything up to the modern doxygen.

Additionally, we should check to make sure the page is actually being generated on build and not static files.
Cmake claims to be generating them, and it's told to do so in Cmakelists.txt but the way it acts about it is a little shady.
I've also had issues in the past with the documentation being generated.

After cleaning up we can standardize the commenting better.

nullptr/cmake issue

We made an update to the CMake configuration that enforces C++11 mode over C++0.
It also now uses CMAKE_CXX_STANDARD which was introduced in cmake 3.1; this also causes a minor inconvenience because we are still stuck on Debian Jessie, which is obsolete and cannot pull updated packages for cmake 3.1 without some finagling.

This was a step in the right direction, but it has caused some other problems with the standard changes between C++11 and C++0 mode.

I ran into this while working on a different issue. A temporary solution is to paste the old cmake C++11 handling back in.

It shouldn't be too difficult to fix, I'm mainly leaving this as a reminder so I can finish solving the first issue I was doing.

Example of one of the errors produced:

/home/pi/got2/libwallaby/src/digital_c.cpp:13:38: error: ‘nullptr’ was not declared in this scope
  return Private::digital_value(port, nullptr);
                                      ^
Determining the scope of groups...
/home/pi/got2/libwallaby/src/digital_c.cpp: In function ‘int get_digital_value(int)’:
/home/pi/got2/libwallaby/src/digital_c.cpp:23:39: error: ‘nullptr’ was not declared in this scope
  return (Private::digital_value(port, nullptr) ? 1 : 0);
                                       ^
Sorting lists...
/home/pi/got2/libwallaby/src/digital_c.cpp: In function ‘int get_digital_output(int)’:
/home/pi/got2/libwallaby/src/digital_c.cpp:33:40: error: ‘nullptr’ was not declared in this scope
  return (Private::digital_output(port, nullptr) ? 1 : 0);

Old Version:

# C++11
# http://www.guyrutenberg.com/2014/01/05/enabling-c11-c0x-in-cmake/
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
	add_definitions(--std=c++11)
elseif(COMPILER_SUPPORTS_CXX0X)
	add_definitions(--std=c++0x)
else()
	message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()

New Version:

# C++11
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

wait_for_light() May Make Motors and Servos Behave Strangely

When using the wait_for_light function from libwallaby, our motors and servos would sometimes behave very strangely (motors not moving at full speed, servos moving without instruction). It doesn't happen all the time, and we are unfortunately not sure how to reproduce it.

Bug Report: mrp not working

The discord user "Jammo2000" has reported that mrp is not functional.
He said he recreated the problem using the following code:

#include <kipr/wombat.h>

#define right_motor 1
#define left_motor 3
int main(){
    int i;
	for(i = 0;i<100;i++){
    	mrp(right_motor, 1000, -1000);
    	mrp(left_motor, 1000, 1000);
        bmd(right_motor);
        bmd(left_motor);
        msleep(1000);
        mrp(right_motor, 1000, 1000);
    	mrp(left_motor, 1000, -1000);
        bmd(right_motor);
        bmd(left_motor);
        msleep(1000);
    }
    return 0;
}

Quote from the user:
"So, the move_relative_position (mrp) function in the kipr library is broken. 5-10% of the time it simply fails to move the motor at all."

Pixel Toaster Warning

In file included from /home/pi/dev/libwallaby/src/pixeltoaster/PixelToaster.cpp:17:0:
/home/pi/dev/libwallaby/src/pixeltoaster/PixelToasterUnix.h: In member function ‘void PixelToaster::UnixDisplay::handleEvent(const XEvent&)’:
/home/pi/dev/libwallaby/src/pixeltoaster/PixelToasterUnix.h:353:30: warning: ‘KeySym XKeycodeToKeysym(Display*, KeyCode, int)’ is deprecated (declared at /usr/include/X11/Xlib.h:1699) [-Wdeprecated-declarations]
const KeySym keySym = ::XKeycodeToKeysym(display_, event.xkey.keycode, 0);
^
/home/pi/dev/libwallaby/src/pixeltoaster/PixelToasterUnix.h:353:78: warning: ‘KeySym XKeycodeToKeysym(Display*, KeyCode, int)’ is deprecated (declared at /usr/include/X11/Xlib.h:1699) [-Wdeprecated-declarations]
const KeySym keySym = ::XKeycodeToKeysym(display_, event.xkey.keycode, 0);
^
In file included from /home/pi/dev/libwallaby/src/pixeltoaster/PixelToaster.cpp:17:0:
/home/pi/dev/libwallaby/src/pixeltoaster/PixelToasterUnix.h: In member function ‘void PixelToaster::UnixDisplay::handleEvent(const XEvent&)’:
/home/pi/dev/libwallaby/src/pixeltoaster/PixelToasterUnix.h:353:30: warning: ‘KeySym XKeycodeToKeysym(Display*, KeyCode, int)’ is deprecated (declared at /usr/include/X11/Xlib.h:1699) [-Wdeprecated-declarations]
const KeySym keySym = ::XKeycodeToKeysym(display_, event.xkey.keycode, 0);
^
/home/pi/dev/libwallaby/src/pixeltoaster/PixelToasterUnix.h:353:78: warning: ‘KeySym XKeycodeToKeysym(Display*, KeyCode, int)’ is deprecated (declared at /usr/include/X11/Xlib.h:1699) [-Wdeprecated-declarations]
const KeySym keySym = ::XKeycodeToKeysym(display_, event.xkey.keycode, 0);

This one will probably require some digging.

Camera not opening - Refactor

  • Camera doesn't open, just says "failed to open /dev/video0" when camera_open is called even though the camera is plugged in

"doc" folder is not gitignored

The doc folder that's generated is not gitignored, resulting in ~1000 changes that git tries to track after a build. Unless there's desire to have a version of the generated docs in source control, I think it makes sense to gitignore the folder.

camera_load_config()

camera_load_config() does not seem to be working, as it always returns 0 and does not load the requested configuration.

For our test conditions, we have a single color configuration file ("Canberra.conf") specified in the GUI that sets up a single channel (I am not sure where this is stored in the file system). This configuration file was not designated as the default (and no others were). camera_load_config() returns a zero (presumably indicating an error) - and any call to get_object_count(0) results in a printed error message that the "specified channel must be between 0 and some-large-number." This suggests that a configuration had not been set up.

Furthermore, when Canberra.conf is configured as the default configuration in the GUI, camera_load_config() still behaves the same, however get_object_count(0) does not fail.

//////////////////////////////////////////////////////////////////////////////////////////////////////

include <kipr/botball.h>

int main()

{
int res;

res = camera_open(LOW_RES);
printf("Open result: %d\n", res);

// Does not seem to work: always returns 0
res = camera_load_config("Canberra.conf");
printf("Configuration result: %d\n", res);

int object_count;
point2 p;

while(digital(1) == 0)
{
// Address buffering issue
res = camera_update();
res = camera_update();
res = camera_update();
res = camera_update();
printf("Update result: %d\n", res);

object_count = get_object_count(0);
printf("Number of objects %d \n",object_count);
if(object_count > 0){
  p = get_object_center(0,0);
  printf("Largest object: %d %d\n", p.x, p.y);
}

msleep(500);

}

camera_close();
printf("Done...\n");
msleep(500);
return 0;
}

Motor velocities are not capped to 1500

Motor functions like mav() and mtp() are not capped at a velocity of 1500. Similarly motor() is not capped at 100. You can pass any int velocity and it gets written.

This initially caused problems in the simulator (see kipr/Simulator#88), and while we'll add a limit there, it feels like libwallaby should cap it for controllers too. I'm not sure how the controller currently behaves if you exceed 1500.

Graphics Library does not work

This has been an issue for a while, but I must have forgotten to submit one.

The graphics library that we use for wait_for_light and usually the starting light program (and can be used in programs but rarely is), currently crashes botui or doesn't work at all.

I have seen a screenshot of a Wombat Tim got to display a graphic, but I haven't been able to reproduce it on any other Wombat.
I'll add a comment if I/Tim get more context from the photo. For all I know it was a cropped image of a Wallaby.

It's most likely that the graphics library used some underlying graphics framework of the Wallaby that Raspberry Pis don't have.
If the image I saw was a real Wombat, then maybe it's a bug that got added moving the code over to the Pi during development phase.

Update Doxygen docs (add comments)

Doxygen doesn't generate documentation for all of the libwallaby functions.
We need to go through and make sure every function that is pulled by doxygen has a description and an example usage if applicable.

Get Tello working with Libwallaby

Eugene has already put work into this, it would be necessary to reach out to him, find his repo/branch, or have him comment on this issue to get the current progress of his work.

This discussion may be relevant, please take a look at Eugene's comments: kipr/botui#73

Fix/add Emscripten for JS support

This pull request was the first attempt at adding this functionality: #81

The commits made there are so far behind master at this point that I think it is likely to cause issues even if we resolved the merge conflicts.

Additionally, botball_c should just not be changed at all by the pull request as the modern version is much different.
The modern one also does not use graphics so the added #ifdef is not necessary (and is only necessary if that was added because of emscripten requirements).

For some reason the difference viewer did not show the correct version of the master's botball_c?
Probably due to the age of the branch and the evolution of that file.

I personally think it would be easier to just go through each commit made there, and reapply it with the context of the current master. However, someone with a better understanding of git or emscripten may be able to fix the old pull request.

It also seems to be bundled with other changes not relevant to emscripten, but I also don't know enough about emscripten to know that for sure. If the person solving this issue understands emscripten, take consideration when re-adding the changes.

No language bindings

Lack of bindings for python and java renders programs written in those languages incompatible with wallaby.

Compiling Dependencies

I am very new to compiling, so apologies if this may seem redundant, but what are said libraries in below error?

[ 39%] Linking CXX shared library libkipr.so
/usr/lib/gcc-cross/aarch64-linux-gnu/11/../../../../aarch64-linux-gnu/bin/ld: cannot find -lkj: No such file or directory
/usr/lib/gcc-cross/aarch64-linux-gnu/11/../../../../aarch64-linux-gnu/bin/ld: cannot find -lkj-async: No such file or directory
/usr/lib/gcc-cross/aarch64-linux-gnu/11/../../../../aarch64-linux-gnu/bin/ld: cannot find -lcapnp: No such file or directory
/usr/lib/gcc-cross/aarch64-linux-gnu/11/../../../../aarch64-linux-gnu/bin/ld: cannot find -lcapnp-rpc: No such file or directory
/usr/lib/gcc-cross/aarch64-linux-gnu/11/../../../../aarch64-linux-gnu/bin/ld: cannot find -lcreate3_common: No such file or directory
/usr/lib/gcc-cross/aarch64-linux-gnu/11/../../../../aarch64-linux-gnu/bin/ld: cannot find -lcreate3_client: No such file or directory
/usr/lib/gcc-cross/aarch64-linux-gnu/11/../../../../aarch64-linux-gnu/bin/ld: cannot find -lX11: No such file or directory
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/kipr.dir/build.make:250: libkipr.so] Error 1
make[1]: *** [CMakeFiles/Makefile2:1605: CMakeFiles/kipr.dir/all] Error 2
make: *** [Makefile:156: all] Error 2

These dependencies were not mentioned in the docs?
Any help appreciated. Thanks!

Implement confidence for HSV blobs

Currently, HSVChannelImpl objects all have a confidence of 1.0. We should implement a confidence value between 0.0 and 1.0 that is a function of the contour area and the bbox area.

Standardize formatting

Formatting is kinda inconsistent...

I suggest there be a standard ruleset. It could be explicitly put in the readme in a separate section marked 'formatting'.

Fake Issue

I'm making a github tutorial and this is a fake issue so I can get a screenshot.

Python shut_down_in doesn't appear to work on (some/many/all) Wombats

During the tournament I saw multiple teams whose shut_down_in in python was not functional. I ended up having them use sys.time() to keep track of their timing as a fix is probably going to take an hour or more of development time.

I tested it in C and it was functional so it might be an issue in compilation from python to C.

My rough guess is that shut_down_in utilizes pthread to keep track of time but I haven't gotten into the source code for it yet.

Add graphical wait_for_light back in

I created a ASCII lightbulb replacement for wait_for_light.

There is a ~2 second delay added from this which we had to account for at the tournament.

The graphical library now works on Wombat (afaik) so we should add back the old graphical version to prevent an advantage for Wallabies.

Set button functions do not work

set_a_button_text
set_b_button_text
set_c_button_text

These functions do not change the text on the buttons when running programs.

Add ROS functionality

I'm not sure exactly how we should do this, but at some point we need a way for libwallaby to be able to manage ROS.

Ideally it would be nice for libwallaby to manage a ROS network in a simple way.

But it could also be as simple as adding in ROS stuff directly like making a publisher or subscriber.

Create distance & angle counters overwritten

The set_create_distance and set_create_total_angle functions occasionally set the angle counters to extreme values.
When I run the code below, the create will turn back and forth for a while, but eventually it will either miss a rotation going counterclockwise or rotate clockwise forever. In both cases, the displayed value for get_create_total_angle will be around 18000. I'm not sure if it is the same value every time, but it's always in the same ballpark.

The issue is fairly rare, it usually takes a couple minutes of turning before I see it with the code below, but that is often enough to occur in about 1/4 of my runs.

A similar issue exists for set_create_distance, but I haven't looked into that one as much. The value the bug sets create_distance to is about 6000.

void create_turn_in_place(int degrees, int speed){
    int cached_angle;
    speed = abs(speed);
    set_create_total_angle(0);
    if(degrees>0){
        create_spin_CCW(speed);
        cached_angle = get_create_total_angle();
        while(cached_angle<degrees){
            cached_angle = get_create_total_angle();
            display_printf(0, 0, "%d    ", cached_angle);
            msleep(10);
        }
    }
    else{
        create_spin_CW(speed);
        cached_angle = get_create_total_angle();
        while(cached_angle>degrees){
            display_printf(0, 0, "%d     ", cached_angle);
            msleep(10);
            cached_angle = get_create_total_angle();
        }
    }
    create_stop();
}

int main(){
    create_connect();
    while(1){
        create_turn_in_place(180, 100);
        create_turn_in_place(-180, -100);
    }
}

Also, I've tried using these wrappers, but they didn't help. That might suggest that the bug is somewhere besides the actual set functions, but I'm not sure where else it could be.

void set_create_total_angle_fixed(int angle){
    do{
    	set_create_total_angle(angle);
    }while(get_create_total_angle()!=angle);
}
void set_create_distance_fixed(int dist){
    do{
    	set_create_distance(dist);
    }while(get_create_distance()!=dist);
}

Segmentation Fault when calling certain functions

This is on the refactor branch.

I get a segfault when trying to run a program containing a motor function.
It occurs when calling the function WombatDevice::transfer

(gdb) backtrace
#0  0x76a2852c in WombatDevice::transfer(unsigned char const*, unsigned char*, unsigned int) () from /lib/libkipr.so
kipr/libwallaby#1  0x76a28254 in WombatDevice::w8(unsigned char, unsigned char) ()
   from /lib/libkipr.so
kipr/libwallaby#2  0x76a26b4c in kipr::core::Platform::writeRegister8b(unsigned char, unsigned char) () from /lib/libkipr.so
kipr/libwallaby#3  0x76a4282c in kipr::motor::set_motor_mode(unsigned int, unsigned char) ()
   from /lib/libkipr.so
kipr/libwallaby#4  0x76a3eb20 in move_at_velocity () from /lib/libkipr.so
kipr/libwallaby#5  0x76a3eb60 in mav () from /lib/libkipr.so
kipr/libwallaby#6  0x76a3efbc in motor () from /lib/libkipr.so
kipr/libwallaby#7  0x000105c8 in main ()

This is the file those last functions are defined in.
https://github.com/kipr/libwallaby/blob/refactor/module/core/src/device/wombat/wombat_device.cpp

I thought maybe it could be something wrong with the STM32 since I had some troubles with that earlier.
But analog functions are working fine so the communication with STM32 is not broken.

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.