Giter Club home page Giter Club logo

kegbot-server's Introduction

Kegbot Server

This is Kegbot Server, a backend and web interface for monitoring and managing kegged beverages.

Official repository: https://github.com/Kegbot/kegbot-server/

Quick start

Super quick start instructions:

$ docker-compose up
$ open http://localhost:8000/

For much more detail, see the complete Kegbot Server documentation.

Documentation and Help

Related Projects

  • Kegboard: Firmware and schematics for the Kegbot controller board.
  • Kegbot Android app: Kegtap, the Kegbot manager app for Android.

License

All code is offered under the MIT license, unless otherwise noted. Please see LICENSE.txt for the full license.

kegbot-server's People

Contributors

dependabot[bot] avatar geoffculp avatar jamesggraf avatar johnboiles avatar johnnyruz avatar jromer94 avatar kahlkevin avatar lcampbell avatar markrickert avatar markstubb avatar mattforscale avatar mik3y avatar patfreeman avatar pmppk avatar rasem avatar safarmer avatar sagnew avatar szechyjs avatar tannergifford avatar wangela 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

kegbot-server's Issues

Missing tables

I'm recieving several errors that tables do not exist. Looking at my database several of them do exist, ie: socialregistration_twitterprofile

Environment:


Request Method: GET
Request URL: http://kegbot.szechnet.com/account/connection/

Django Version: 1.4
Python Version: 2.7.3
Installed Applications:
('django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.humanize',
 'django.contrib.markup',
 'django.contrib.messages',
 'django.contrib.sessions',
 'django.contrib.sites',
 'django.contrib.staticfiles',
 'django_extensions',
 'bootstrapform',
 'imagekit',
 'pykeg.beerdb',
 'pykeg.connections',
 'pykeg.connections.foursquare',
 'pykeg.connections.twitter',
 'pykeg.connections.untappd',
 'pykeg.contrib.soundserver',
 'pykeg.core',
 'pykeg.web',
 'pykeg.web.api',
 'pykeg.web.account',
 'pykeg.web.charts',
 'pykeg.web.kegweb',
 'icanhaz',
 'registration',
 'socialregistration',
 'socialregistration.contrib.twitter',
 'socialregistration.contrib.facebook',
 'socialregistration.contrib.foursquare',
 'south',
 'django_nose',
 'sentry',
 'sentry.client',
 'djcelery',
 'djkombu',
 'raven.contrib.django',
 'sentry',
 'rjdj.djangotornado')
Installed Middleware:
('django.middleware.cache.UpdateCacheMiddleware',
 'django.middleware.gzip.GZipMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.middleware.transaction.TransactionMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'pykeg.web.middleware.KegbotSiteMiddleware',
 'pykeg.web.middleware.SiteActiveMiddleware',
 'django.middleware.doc.XViewMiddleware',
 'sentry.client.middleware.Sentry404CatchMiddleware',
 'django.middleware.cache.FetchFromCacheMiddleware')


Traceback:
File "/usr/local/lib/python2.7/dist-packages/Django-1.4-py2.7.egg/django/core/handlers/base.py" in get_response
  111.                         response = callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python2.7/dist-packages/Django-1.4-py2.7.egg/django/contrib/auth/decorators.py" in _wrapped_view
  20.                 return view_func(request, *args, **kwargs)
File "/home/ubuntu/kegbot/pykeg/src/pykeg/web/account/views.py" in connections
  62.     twitter_profile = sr_twitter_models.TwitterProfile.objects.get(user=user)
File "/usr/local/lib/python2.7/dist-packages/Django-1.4-py2.7.egg/django/db/models/manager.py" in get
  131.         return self.get_query_set().get(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/Django-1.4-py2.7.egg/django/db/models/query.py" in get
  361.         num = len(clone)
File "/usr/local/lib/python2.7/dist-packages/Django-1.4-py2.7.egg/django/db/models/query.py" in __len__
  85.                 self._result_cache = list(self.iterator())
File "/usr/local/lib/python2.7/dist-packages/Django-1.4-py2.7.egg/django/db/models/query.py" in iterator
  291.         for row in compiler.results_iter():
File "/usr/local/lib/python2.7/dist-packages/Django-1.4-py2.7.egg/django/db/models/sql/compiler.py" in results_iter
  763.         for rows in self.execute_sql(MULTI):
File "/usr/local/lib/python2.7/dist-packages/Django-1.4-py2.7.egg/django/db/models/sql/compiler.py" in execute_sql
  818.         cursor.execute(sql, params)
File "/usr/local/lib/python2.7/dist-packages/Django-1.4-py2.7.egg/django/db/backends/util.py" in execute
  40.             return self.cursor.execute(sql, params)
File "/usr/local/lib/python2.7/dist-packages/Django-1.4-py2.7.egg/django/db/backends/mysql/base.py" in execute
  114.             return self.cursor.execute(query, args)
File "/usr/lib/python2.7/dist-packages/MySQLdb/cursors.py" in execute
  174.             self.errorhandler(self, exc, value)
File "/usr/lib/python2.7/dist-packages/MySQLdb/connections.py" in defaulterrorhandler
  36.     raise errorclass, errorvalue

Exception Type: DatabaseError at /account/connection/
Exception Value: (1146, "Table 'kegbot.twitter_twitterprofile' doesn't exist")

This case seems like the table prefix is the only thing that is wrong 'twitter_' rather than 'socialregistration_'

I also get a similar error for untappd.

Exception Type: DatabaseError at /admin/untappd/useruntappdlink/
Exception Value: (1146, "Table 'kegbot.untappd_useruntappdlink' doesn't exist")

However, I do not see any tables in the database for untappd.

I have run kegbot-admin.py migrate several times and it always completes successfully.

kegweb: TemplateSyntaxError

Exception Type: TemplateSyntaxError at /
Exception Value: Caught NoReverseMatch while rendering: Reverse for 'pykeg.web.util.new_function' with arguments '(1L,)' and keyword arguments '{}' not found.

Full details: http://dpaste.com/602316/

kegadmin: Add manual "record a drink" form

I noticed when adding drinks from the Django admin interface, the stats are not all updated, only some. Even the recent activity isn't updated unless you regen stats.

[Edit 6/2013: previous subject: "Stats won't update if drinks are added manually"]

kegweb: units default to metric

On the first page view the units are displayed as their default (imperial) and the auto_units_metric cookie is set to false. However, after all following page views it gets changed to true and displays units in metric. When selecting the change to imperial in the footer it corrects the problem until the next page view, which will change it back to metric again.

kegweb: TemplateSyntaxError

Hi Mike,

I'm getting an error when trying to browse to my kegweb homepage. Do you think this error could be caused by something wrong in my local configuration?

Exception Type: TemplateSyntaxError at /
Exception Value: Caught NoReverseMatch while rendering: Reverse for 'kb-home' with arguments '(u'Default',)' and keyword arguments '{}' not found.

Full details : http://kegbot.homeip.net/

keg/drinker detail: paginate sessions

Rendering all sessions seriously bogs down the keg and drinker stats pages. Limit how many are shown, eg by loading the data via the web api, paginating the results, and rendering client-side.

core: error migrating auth token changes

I receive the following error while trying to migrate the recent changes...

File "/home/kegbot/kegbot/pykeg/src/pykeg/contrib/twitter/models.py", line 24, in
from pykeg.core import models as core_models
File "/home/kegbot/kegbot/pykeg/src/pykeg/core/models.py", line 36, in
from pykeg.core import stats
File "/home/kegbot/kegbot/pykeg/src/pykeg/core/stats.py", line 26, in
from pykeg.proto import models_pb2
File "/home/kegbot/kegbot/pykeg/src/pykeg/proto/models_pb2.py", line 1396, in
DESCRIPTOR.message_types_by_name['AuthenticationToken'] = _AUTHENTICATIONTOKEN
AttributeError: 'FileDescriptor' object has no attribute 'message_types_by_name'

kegadmin: token management

Allow direct [re-]assignment of a token from within kegadmin.

Allow new tokens to be created from within kegadmin.

TemplateSyntaxError at /account/

I am recieving an error when browsing to the kegweb account page. I also noticed that the login and logout pages cause the same error.

TemplateSyntaxError at /account/
TemplateSyntaxError at /accounts/logout/
TemplateSyntaxError at /accounts/login/

Caught AttributeError while rendering: 'NoneType' object has no attribute 'url'

Guest Pours

Since the start of the project guest pours always seem to be changing. When I have my kegbot running I get a decent number of guest pours, which I'm ok with, it just seems they need to be handled better. From what I can tell guest pours have no user assigned to the drink, there was a period where you were able to select a user to be the guest user if i recall correctly, as i have a decent chunk of drinks with the user set as guest rather than (none). The kegweb interface is really hit or miss when it comes to displaying guest pours, most of the time the drinker image is 404'd and empty, some of the links you can click and get actual pour and drinker stats, and some you cant. I'm sure this may have to do with using a database that has been used since the start. Perhaps some kind of migration is needed to clean it up and bring guest pours to a defined usage.

I like the idea of leaving the user null for guest drinks as it allows for easier changes down the road. I'd like the ability to have some kind of guest display options. A menu where: the guest display name can be changed, whether or not to display guest pours in kegweb recent activity (perhaps just collapse multiple pours to just one, to reduce an entire list of guest pours on home page), change the guest mugshot, and of course some guest related stats.

api: better listings

I'm trying to minimize the number of api call the kegbot app I am working on makes. The one issue I've found is when it comes to keg details. I have to make a call to /kegs first to collect keg id values then poll /gets/id for each keg in order to get the name of the beer in the keg. The other useful listing is users, however looks like you just implemented that one.

Crash in kegbot_core.py

I've seen a crash similar to this 3 times now. I grabbed the output this time. This is with code pulled and installed from git repo this morning.

2011-12-20 10:59:45,473 ERROR (service-thread) Uncaught exception in thread service-thread. Stack trace:
2011-12-20 10:59:45,502 ERROR (service-thread) File "/usr/local/lib/python2.7/dist-packages/kegbot-0.8.3-py2.7.egg/pykeg/core/util.py", line 113, in run
2011-12-20 10:59:45,503 ERROR (service-thread) self.ThreadMain()
2011-12-20 10:59:45,504 ERROR (service-thread)
2011-12-20 10:59:45,504 ERROR (service-thread) File "/usr/local/lib/python2.7/dist-packages/kegbot-0.8.3-py2.7.egg/pykeg/core/kb_threads.py", line 124, in ThreadMain
2011-12-20 10:59:45,505 ERROR (service-thread) self._Step(timeout=0.5)
2011-12-20 10:59:45,506 ERROR (service-thread)
2011-12-20 10:59:45,507 ERROR (service-thread) File "/usr/local/lib/python2.7/dist-packages/kegbot-0.8.3-py2.7.egg/pykeg/core/kb_threads.py", line 129, in _Step
2011-12-20 10:59:45,508 ERROR (service-thread) self._ProcessEvent(event)
2011-12-20 10:59:45,509 ERROR (service-thread)
2011-12-20 10:59:45,509 ERROR (service-thread) File "/usr/local/lib/python2.7/dist-packages/kegbot-0.8.3-py2.7.egg/pykeg/core/kb_threads.py", line 156, in _ProcessEvent
2011-12-20 10:59:45,510 ERROR (service-thread) cb(event)
2011-12-20 10:59:45,511 ERROR (service-thread)
2011-12-20 10:59:45,512 ERROR (service-thread) File "/usr/local/lib/python2.7/dist-packages/kegbot-0.8.3-py2.7.egg/pykeg/core/manager.py", line 462, in HandleFlowUpdateEvent
2011-12-20 10:59:45,513 ERROR (service-thread) self._HandleFlowEnded(event)
2011-12-20 10:59:45,513 ERROR (service-thread)
2011-12-20 10:59:45,515 ERROR (service-thread) File "/usr/local/lib/python2.7/dist-packages/kegbot-0.8.3-py2.7.egg/pykeg/core/manager.py", line 491, in _HandleFlowEnded
2011-12-20 10:59:45,515 ERROR (service-thread) spilled=spilled)
2011-12-20 10:59:45,516 ERROR (service-thread)
2011-12-20 10:59:45,517 ERROR (service-thread) File "/usr/local/lib/python2.7/dist-packages/kegbot-0.8.3-py2.7.egg/pykeg/core/backend.py", line 302, in RecordDrink
2011-12-20 10:59:45,518 ERROR (service-thread) duration=duration, auth_token=auth_token, spilled=spilled)
2011-12-20 10:59:45,518 ERROR (service-thread)
2011-12-20 10:59:45,519 ERROR (service-thread) File "/usr/local/lib/python2.7/dist-packages/kegbot-0.8.3-py2.7.egg/pykeg/web/api/krest.py", line 251, in RecordDrink
2011-12-20 10:59:45,520 ERROR (service-thread) return self.DoPOST(endpoint, models_pb2.Drink(), post_data=post_data)
2011-12-20 10:59:45,521 ERROR (service-thread)
2011-12-20 10:59:45,521 ERROR (service-thread) File "/usr/local/lib/python2.7/dist-packages/kegbot-0.8.3-py2.7.egg/pykeg/web/api/krest.py", line 173, in DoPOST
2011-12-20 10:59:45,522 ERROR (service-thread) return self._FetchResponse(endpoint, out_msg, params=params, post_data=post_data)
2011-12-20 10:59:45,523 ERROR (service-thread)
2011-12-20 10:59:45,524 ERROR (service-thread) File "/usr/local/lib/python2.7/dist-packages/kegbot-0.8.3-py2.7.egg/pykeg/web/api/krest.py", line 195, in _FetchResponse
2011-12-20 10:59:45,525 ERROR (service-thread) response_data = urlopen(url, data=encoded_post_data, timeout=FLAGS.krest_timeout).read()
2011-12-20 10:59:45,525 ERROR (service-thread)
2011-12-20 10:59:45,526 ERROR (service-thread) File "/usr/lib/python2.7/urllib2.py", line 126, in urlopen
2011-12-20 10:59:45,526 ERROR (service-thread) return _opener.open(url, data, timeout)
2011-12-20 10:59:45,527 ERROR (service-thread)
2011-12-20 10:59:45,527 ERROR (service-thread) File "/usr/lib/python2.7/urllib2.py", line 394, in open
2011-12-20 10:59:45,527 ERROR (service-thread) response = self._open(req, data)
2011-12-20 10:59:45,528 ERROR (service-thread)
2011-12-20 10:59:45,528 ERROR (service-thread) File "/usr/lib/python2.7/urllib2.py", line 412, in _open
2011-12-20 10:59:45,529 ERROR (service-thread) '_open', req)
2011-12-20 10:59:45,529 ERROR (service-thread)
2011-12-20 10:59:45,529 ERROR (service-thread) File "/usr/lib/python2.7/urllib2.py", line 372, in _call_chain
2011-12-20 10:59:45,530 ERROR (service-thread) result = func(*args)
2011-12-20 10:59:45,530 ERROR (service-thread)
2011-12-20 10:59:45,530 ERROR (service-thread) File "/usr/lib/python2.7/urllib2.py", line 1201, in http_open
2011-12-20 10:59:45,531 ERROR (service-thread) return self.do_open(httplib.HTTPConnection, req)
2011-12-20 10:59:45,531 ERROR (service-thread)
2011-12-20 10:59:45,531 ERROR (service-thread) File "/usr/lib/python2.7/urllib2.py", line 1174, in do_open
2011-12-20 10:59:45,531 ERROR (service-thread) r = h.getresponse(buffering=True)
2011-12-20 10:59:45,532 ERROR (service-thread)
2011-12-20 10:59:45,532 ERROR (service-thread) File "/usr/lib/python2.7/httplib.py", line 1027, in getresponse
2011-12-20 10:59:45,533 ERROR (service-thread) response.begin()
2011-12-20 10:59:45,533 ERROR (service-thread)
2011-12-20 10:59:45,534 ERROR (service-thread) File "/usr/lib/python2.7/httplib.py", line 407, in begin
2011-12-20 10:59:45,534 ERROR (service-thread) version, status, reason = self._read_status()
2011-12-20 10:59:45,535 ERROR (service-thread)
2011-12-20 10:59:45,535 ERROR (service-thread) File "/usr/lib/python2.7/httplib.py", line 365, in _read_status
2011-12-20 10:59:45,535 ERROR (service-thread) line = self.fp.readline()
2011-12-20 10:59:45,536 ERROR (service-thread)
2011-12-20 10:59:45,536 ERROR (service-thread) File "/usr/lib/python2.7/socket.py", line 447, in readline
2011-12-20 10:59:45,537 ERROR (service-thread) data = self._sock.recv(self._rbufsize)
2011-12-20 10:59:45,537 ERROR (service-thread)
2011-12-20 10:59:45,537 ERROR (service-thread) Error was: <class 'socket.timeout'>: timed out
2011-12-20 10:59:45,538 ERROR (service-thread) Exiting thread.
2011-12-20 10:59:46,533 ERROR (watchdog-thread) Thread service-thread died unexpectedly
2011-12-20 10:59:46,563 INFO (alarmmanager-thread) got quit event, quitting
2011-12-20 10:59:46,564 INFO (net-thread) got quit event, quitting
2011-12-20 10:59:46,564 INFO (eventhub-thread) got quit event, quitting
2011-12-20 10:59:46,565 INFO (watchdog-thread) got quit event, quitting
2011-12-20 10:59:46,565 INFO (heartbeat-thread) got quit event, quitting
2011-12-20 10:59:46,633 INFO (kegnet) Stopping server
2011-12-20 10:59:47,535 ERROR (main) Watchdog thread exited, quitting
2011-12-20 10:59:48,537 INFO (main) Stopping any remaining threads
2011-12-20 10:59:48,538 INFO (main) Stopping all service threads.
2011-12-20 10:59:48,538 INFO (main) All service threads stopped.
2011-12-20 10:59:48,538 INFO (main) Kegbot stopped.

If I was more familiar with python I would take a crack at figuring it out, may look through the code later if I have time.

Thanks

-ray

kb_compress_temps - MultipleObjectsReturned

I'm getting the following error when trying to run kegbot-admin.py kb_compress_temps

pykeg.core.models.MultipleObjectsReturned: get() returned more than one ThermoSummaryLog -- it returned 2! Lookup parameters were {'date': datetime.datetime(2011, 4, 2, 0, 0), 'period': 'daily'}

Full details: http://dpaste.com/604220/

kegadmin: interface refresh issues

Steps to reproduce:

  1. Go to Admin->Taps
  2. Click Settings for a tap
  3. Make changes (or not)
  4. Click "Update Tap"
  5. Screen reloads, click "Settings" again.
  6. All form fields are blank.

Reloading the page manually and clicking settings again reloads the correct data into the form fields.

new stat: drinker affinities

New statistic to maintain: drinker affinities.

Each drinker has a map of {drinker -> counter}. For each session, for each other drinker in the session, update the counter for that drinker.

Result should be a rank of all co-drinkers by frequency.

celery tasks, twitter no tweet

Mike,

I'm running with the latest commits, and I noticed that the celery tasks for Twitter aren't being sent (Foursquare checkin is working).

Here's a log example:

http://dpaste.com/757781/

Let me know if you need any thing else.
Cheers,
Geoff

session snapshot box looks ugly

The bootstrapified session snapshot box is just unpleasant: The gradient is loud; the rounded corners don't match its surroundings; the volume box doesn't fit its contents, which are off-center; the number of drinker images varies wildly; etc.

Need to re-think this and make it look nicer.

kegbot core error during pour

This is an odd one.

I can pour a drink from one tap with no issues. (drink registered, kegbot_core stays running), but when I pour a drink from my second tap kegbot_core stops with an error.

The kegbot_core log shows "2011-12-22 18:36:15,782 ERROR (service-thread) Error was: <class 'pykeg.web.api.krest.ServerError'>: Caused by: HTTP Error 500: INTERNAL SERVER ERROR"

The Senty message list shows a new error in pykeg.core.stats.RegisteredDrinkers -
AttributeError: 'RepeatedScalarFieldContainer' object has no attribute 'add'"
Location: /home/workbench/sandbox/kegbot-0.8.3/pykeg/src/pykeg/core/stats.py in RegisteredDrinkers, line 161

Thanks again for all the fixes, I know the risk I'm taking when running the tip of the tree.
Geoff

Django 1.4 requirements conflict

I'm finally getting around to updating my kegbot server, it was a couple of months out of date. I'm currently installing on a fresh install of Ubuntu 12.04 Server.

During the install the setup halts with the following error...

Installed /home/ubuntu/kegbot/pykeg/src
Processing dependencies for kegbot==0.9.0
error: Installed distribution Django 1.4 conflicts with requirement Django>=1.2,<1.4

Trying to run the shell I get the following error...

ubuntu@domU-12-31-39-02-25-CF:/etc/apache2/sites-available$ kegbot-admin.py shell
Traceback (most recent call last):
  File "/usr/local/bin/kegbot-admin.py", line 4, in <module>
    from pkg_resources import require; require('kegbot==0.9.0')
  File "/usr/lib/python2.7/dist-packages/pkg_resources.py", line 2711, in <module>
    parse_requirements(__requires__), Environment()
  File "/usr/lib/python2.7/dist-packages/pkg_resources.py", line 588, in resolve
    raise VersionConflict(dist,req) # XXX put more info here
pkg_resources.VersionConflict: (Django 1.4 (/usr/local/lib/python2.7/dist-packages/Django-1.4-py2.7.egg), Requirement.parse('Django>=1.2,<1.4'))

kegweb: recent activity list

In the recent activity list, each drink event is missing the drink size information. Also the url links to that drinker's page and the actual drink are not there anymore.

kegweb: template syntax error on tap admin

When selecting a tap in the tap admin page it results in a template syntax error.

http://dpaste.com/607116/

I'm assuming it has to do with the recent units changes, as the error is: Caught AttributeError while rendering: 'KegSize' object has no attribute 'Volume'

The error is also encountered while trying to view the KegSize entries in admin.

I noticed this Volume attribute was removed in commit: 97e8ab4

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.