Giter VIP home page Giter VIP logo

anytask's People

Contributors

9omshitikov avatar annasvalova avatar antselevich avatar bcskda avatar bersdan avatar bibilov avatar dependabot-preview[bot] avatar dependabot[bot] avatar dimmo avatar gebetix avatar georgy-komarov avatar hariton27sy avatar hhell avatar holyprapor avatar houcha avatar itjune avatar kidig avatar klkvr avatar kopeicev avatar ksusonic avatar last-g avatar makhalin avatar mikhailyumanov avatar neychev avatar omrigan avatar shuternay avatar toplenboren avatar victorsamun avatar znick 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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

anytask's Issues

Добавить возможность изменения имени, e-mail-а и пароля

Как ни странно, но менять имя и e-mail менять может только администратор. Пароль менять можно, но только через функцию "забыл пароль".

Нужно сделать, чтобы в профиле можно было менять имя, email и пароль.

Важный моменты:

  1. Все ходы должны быть записаны. Можно писать в лог или сделать для этого табличку в БД (второе наверное лучше как ни странно).
  2. Должен быть какой-то тест с просьбой не злоупотреблять функцией изменения имени. Нужно указывать свое настоящие имя, а функция нужно только для исправления ошибок.
  3. При изменения пароля надо спрашивать старый пароль.

Upgrade bootstrap to recent version

Сейчас версия библиотеки какая-то очень старая - нужно её заменить на более свежую.

При этом могут посыпаться какие-то стили, это нужно протестировать и поправить если нужно.

Имеет смысл делать после #361

Сделать актуальную версию докер образа для production

Нормальный способ развернуть Джангу в прод описан тут. Используется nginx + gunicorn под systemd.

@znick что думаешь о таком стеке прода?

В целом можно будет сделать 2 контейнера - для разработки, и для прода. Это послужит базой для дальшейшей автоматизации (кубер или что-то ещё), там всё равно будет под капотом докер использоваться.

[epic] CI/CD

Делаем CI/CD для выкатки Anytask-а в тестинг и прод. Сейчас docker-образ собирается вручную на ноуте разработчика, надо это поправить.

  1. Упростить локальный запуск. Сделать docker-compose, который можно было бы просто запустить и разрабатываться.

  2. Прогонять тесты в Github Actions в докере на окружении приближеном в продакшену. Сейчас тесты запускаются с использованием sqlite.

  3. Сделать CI/CD сборку docker-образа в Github Actions: собирать docker-образ, пушить его в registry, выкатывать его сначала в тестинг, а потом в прод.

Тикеты:
#580
#581
#582
#583

Нотификации в Телеграм

Сейчас все нотификации отправляются в почту. Нужно сделать возможность отправлять нотификации в Телеграм.

Нужно продумать схему:

  1. Подружиться с ботом.
  2. Где-то сообщить свой логин (с верификацией).
  3. ...
  4. PROFIT

Выбор языка в профиле пользователя

В Anytask-е есть поддержка английского языка в базовом варианте.

https://github.com/znick/anytask/blob/master/anytask/settings_common.py#L56 (правда закомментирована).

Это работает так: Джанго смотрит на http заголово Accept-Languages: и выбирает более приоритетный из языков в заголовке: 'ru' или 'en'. Не всегда этот выбор правильный. Например, у меня в ОС стоит английский язык интерфейса, поэтому браузер, ориентируяся на эти настройки посылает Accept-Languages: en, ru (то есть en у меня более приоритетный). Но вот это совсем не значит, что я хочу видеть Anytask на Английском.

Проблема в том, что никакого способа вручную поменять язык локализации нет - можно только перенастроить браузер.

Нужно: сделать настройку языка в профиле пользователя и если она не выставлена, то оринтироваться на заголовок, а если выставлена, то тогда брать локаль из профиля. Впрочем вариант когда по умолчанию всегда русская локаль, а на английскую можно переключиться только вручную тоже сойдет.

[CI/CD] Унести cron-ы внутрь docker-а

Сейчас cron-джобы Anytask-а запускаются с локальной машине следующим конфигом  😱:

0   4   *   *   *  root   flock -w 5 /tmp/anytask.cleanupregistration.lock docker exec anytask_app_1 /venv/bin/python manage.py cleanupregistration --settings=settings_docker >> /var/log/cron/cleanupregistration.log 2>&1
*/2 *   *   *   *  root   flock -w 5 /tmp/anytask.check_contest.lock docker exec anytask_app_1 /venv/bin/python manage.py check_contest --settings=settings_docker >> /var/log/cron/check_contest.log 2>&1
*/13 *   *   *   *  root  flock -w 5 /tmp/anytask.send_freezed_run_id_notify.lock docker exec anytask_app_1 /venv/bin/python manage.py send_freezed_run_id_notify  --settings=settings_docker >> /var/log/cron/send_freezed_run_id_notify.log 2>&1
*/5 *   *   *   *  root   flock -w 5 /tmp/anytask.send_notifications.lock docker exec anytask_app_1 /venv/bin/python manage.py send_notifications --settings=settings_docker >> /var/log/cron/send_notifications.log 2>&1
*/5 *   *   *   *  root   flock -w 5 /tmp/anytask.send_task_notifications.lock docker exec anytask_app_1 /venv/bin/python manage.py send_task_notifications --settings=settings_docker >> /var/log/cron/send_task_notifications.log 2>&1
*/5 *   *   *   *  root   flock -w 5 /tmp/anytask.send_mail_notifications.lock docker exec anytask_app_1 /venv/bin/python manage.py send_mail_notifications --settings=settings_docker >> /var/log/cron/send_mail_notifications.log 2>&1
0  */2   *   *   *  root  flock -w 30 /tmp/anytask.update_index.lock -c 'docker exec anytask_app_1 /venv/bin/python manage.py update_index -v2 --age=3 --settings=settings_docker >> /var/log/cron/update_index.partial.log 2>&1'
30  18   *   *   *  root  flock -w 30 /tmp/anytask.update_index.lock -c 'docker exec anytask_app_1 /venv/bin/python manage.py update_index -v2 --settings=settings_docker >> /var/log/cron/update_index.log 2>&1'
0   *   *   *   *  root   flock -w 5 /tmp/anytask.check_task_taken_expires.lock docker exec anytask_app_1 /venv/bin/python manage.py check_task_taken_expires --settings=settings_docker >> /var/log/cron/check_task_taken_expires.log 2>&1
17  0   *   *   *  root   flock -w 5 /tmp/anytask.s3migrate_issue_attachments.lock docker exec anytask_app_1 /venv/bin/python manage.py s3migrate_issue_attachments --settings=settings_docker --execute --rewrite-only-existing --delete-local-copies >> /var/log/cron/s3_migrate.log 2>&1

*/5  0   *   *   *  root cd /root/anytask && ./db-sync.sh >> /var/log/cron/sync.db.log 2>&1

Нужно унести это внутрь docker-compose

Вынеcти bootstrap на CDN

Сейчас bootstrap подтягивается из локальных (скопированных или добавленных через git submodules) файлов.

Нужно перевести их на какой-то Content Delivery Network, то есть чтобы он подгружался с глобального хранилища веб-библиотек.

Add 'edit message' feature

Добавить возможность редактировать текст отправленного сообщения в чате.
По-видимому, нужно позволять редактировать только текст сообщения, иначе у пользователя появится возможность заслать решение после дедлайна без штрафа.

[epic] Антиплагиат

Придумать систему антиплагиата.

Хочется, чтобы это была внешняя система, которая работает с Anytask-ом по API.

Нужно:

  1. Разобраться как устроено текущее API и понять что не хватает.
  2. Придумать общую идею как проверять на плагиат.

manage.py syncdb - заменить на актуальные команды

Кажется, что manage.py syncdb больше не работает. Однако, это то что содержится в readme. Поиск syncdb по репозиторию выдает еще 5 мест, где эта команда записана.

Если этой команды уже нет, то стоит указать как быть теперь.

Error building docker image: MySQL-python

Hi,

I have launched a docker image build from anytask root folder:

sudo docker build -t anytask .

and got the following error. Could you please advise? It seems like MySQL-python is not compatible, and needs a different version to build?

Thanks in advance!

  Building wheel for MySQL-python (setup.py): started
  Building wheel for MySQL-python (setup.py): finished with status 'error'
  ERROR: Command errored out with exit status 1:
   command: /usr/local/bin/python -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-iX85KX/MySQL-python/setup.py'"'"'; __file__='"'"'/tmp/pip-install-iX85KX/MySQL-python/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' bdist_wheel -d /tmp/pip-wheel-KQwJkG --python-tag cp27
       cwd: /tmp/pip-install-iX85KX/MySQL-python/
  Complete output (38 lines):
  running bdist_wheel
  running build
  running build_py
  creating build
  creating build/lib.linux-x86_64-2.7
  copying _mysql_exceptions.py -> build/lib.linux-x86_64-2.7
  creating build/lib.linux-x86_64-2.7/MySQLdb
  copying MySQLdb/__init__.py -> build/lib.linux-x86_64-2.7/MySQLdb
  copying MySQLdb/converters.py -> build/lib.linux-x86_64-2.7/MySQLdb
  copying MySQLdb/connections.py -> build/lib.linux-x86_64-2.7/MySQLdb
  copying MySQLdb/cursors.py -> build/lib.linux-x86_64-2.7/MySQLdb
  copying MySQLdb/release.py -> build/lib.linux-x86_64-2.7/MySQLdb
  copying MySQLdb/times.py -> build/lib.linux-x86_64-2.7/MySQLdb
  creating build/lib.linux-x86_64-2.7/MySQLdb/constants
  copying MySQLdb/constants/__init__.py -> build/lib.linux-x86_64-2.7/MySQLdb/constants
  copying MySQLdb/constants/CR.py -> build/lib.linux-x86_64-2.7/MySQLdb/constants
  copying MySQLdb/constants/FIELD_TYPE.py -> build/lib.linux-x86_64-2.7/MySQLdb/constants
  copying MySQLdb/constants/ER.py -> build/lib.linux-x86_64-2.7/MySQLdb/constants
  copying MySQLdb/constants/FLAG.py -> build/lib.linux-x86_64-2.7/MySQLdb/constants
  copying MySQLdb/constants/REFRESH.py -> build/lib.linux-x86_64-2.7/MySQLdb/constants
  copying MySQLdb/constants/CLIENT.py -> build/lib.linux-x86_64-2.7/MySQLdb/constants
  running build_ext
  building '_mysql' extension
  creating build/temp.linux-x86_64-2.7
  gcc -pthread -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -Dversion_info=(1,2,5,'final',1) -D__version__=1.2.5 -I/usr/include/mariadb -I/usr/include/mariadb/mysql -I/usr/local/include/python2.7 -c _mysql.c -o build/temp.linux-x86_64-2.7/_mysql.o
  In file included from _mysql.c:44:
  /usr/include/mariadb/my_config.h:3:2: warning: #warning This file should not be included by clients, include only <mysql.h> [-Wcpp]
   #warning This file should not be included by clients, include only <mysql.h>
    ^~~~~~~
  In file included from _mysql.c:46:
  /usr/include/mariadb/mysql.h:440:3: warning: function declaration isn’t a prototype [-Wstrict-prototypes]
     MYSQL_CLIENT_PLUGIN_HEADER
     ^~~~~~~~~~~~~~~~~~~~~~~~~~
  _mysql.c: In function ‘_mysql_ConnectionObject_ping’:
  _mysql.c:2005:41: error: ‘MYSQL’ {aka ‘struct st_mysql’} has no member named ‘reconnect’
    if ( reconnect != -1 ) self->connection.reconnect = reconnect;
                                           ^
  error: command 'gcc' failed with exit status 1
  ----------------------------------------
  ERROR: Failed building wheel for MySQL-python

Архивы для школ на главной странице

На странице уколы у нас есть архив для курсов
Например, https://anytask.org/school/mipt
image

Работает это так:
в модели есть галочка is_active:
https://github.com/znick/anytask/blob/master/anytask/courses/models.py#L100
которую админ выключает, когда надо переместить курс в архив. Никакой другой логики у нее нет - просто курс показывается на вкладке "архив", а не на основной, больше ничего не меняется.

Но у нас есть целые школы в которых давно не происходит активности. Нужно на главной странице добавить такую же вкладочку "Архив", добавить в модель School ( https://github.com/znick/anytask/blob/master/anytask/schools/models.py#L8 ) поле is_active и если школа не активна, то убирать ее в Архив на клавной странице.

[epic] speed & reliability

При разработке Anytask-а никто не задумывался про производительность. В итоге сейчас Anytask местами изрядно тормозит - на некоторых страницах это заметно невооруженным глазом.

  1. Сделать графики по времени обработки запросов и CPU.
  2. Поднять Sentry для обработки ошибок.
  3. Профилирование запросов и их частей.

Тикеты:
#584
#585

Add a README_EN.md file

Most of the community uses English, it would be good if a README.md file is added in that language

Улучшить обработку ошибок при отправки в RB невалидных текстовых файлов

Если отправить в issue невалидный (в сломаной текстовой кодировке) текстовый файл, то получим ошибку 500

Ошибка:

ERROR 2019-10-09 12:11:35,294 base 15612 139968382052288 Internal Server Error: /issue/upload/
Traceback (most recent call last):
  File "/usr/share/python/anytask/lib/python2.7/site-packages/django/core/handlers/base.py", line 113, in get_response
    response = callback(request, *callback_args, **callback_kwargs)
  File "/usr/share/python/anytask/lib/python2.7/site-packages/django/contrib/auth/decorators.py", line 25, in _wrapped_view
    return view_func(request, *args, **kwargs)
  File "/usr/share/python/anytask/lib/python2.7/site-packages/django/views/decorators/http.py", line 41, in inner
    return func(request, *args, **kwargs)
  File "/usr/share/python/anytask/lib/python2.7/site-packages/Anytask-0.0.0-py2.7.egg/anytask/issues/views.py", line 290, in upload
    issue.set_byname('comment', event_value, request.user)
  File "/usr/share/python/anytask/lib/python2.7/site-packages/Anytask-0.0.0-py2.7.egg/anytask/issues/models.py", line 279, in set_byname
    return self.set_field(field, value, author, from_contest)
  File "/usr/share/python/anytask/lib/python2.7/site-packages/Anytask-0.0.0-py2.7.egg/anytask/issues/models.py", line 347, in set_field
    review_request_id = anyrb.upload_review()
  File "/usr/share/python/anytask/lib/python2.7/site-packages/Anytask-0.0.0-py2.7.egg/anytask/anyrb/common.py", line 42, in upload_review
    file_content.append(line.decode('cp1251'))
  File "/usr/lib/python2.7/encodings/cp1251.py", line 15, in decode
    return codecs.charmap_decode(input,errors,decoding_table)
UnicodeDecodeError: 'charmap' codec can't decode byte 0x98 in position 0: character maps to <undefined>

Файлы для тесты в приложении.
README.txt
test.zip

Ошибка с языком

После развертывания debug-окружения везде на сайте пишет транслитом. Как выбрать нормальный русский язык?

[bug] Не работает обновления условий задач, подргуженных из Яндекс.Контеста

Ожидаемое поведение: при использовании задачи из Яндекс.Контеста можно внести изменения в условия или хотя бы выбрать язык.

Текущее поведение: условие не поддается изменениям. По нажатии Save and continue указывается, что результаты сохранены, но по факту они остаются неучтенными.

Migrations fail (postgresql)

Команда python manage.py syncdb --migrate --noinput --settings=settings_production падает с ошибкой DatabaseError: relation "mail_message" does not exist (бд postgresql 10)
Log
Содержимое settings_production.py

С базой sqlite3 ошибок не возникает.
Log

Пробовал python manage.py schemamigration users --auto.
В ответ Nothing seems to have changed.

Подключить licensed к actions

Есть такая штука, которая проверяет, что все зависимости имеют правильную лицензии: https://github.com/github/licensed

И есть ее адаптация, чтобы она запускалась в github actions и проверяла каждый PR: https://github.com/marketplace/actions/setup-github-licensed . Нужно подключить ее к этому репозитарию.

Статистика о курсе

Добавить статистику по проверке каждым из преподавателей/TA. Это полезно, если на курсе несколько проверяющих.

Можно еще какую-нибудь статистику по задачам: сколько студентов сдали, сколько начали и т.п.

Локальная beta

Написать скрипт, который бы разворачивал Anytask с нуля для разработческих целей.

Даешь ему пустой каталог, а он там virtualenv делает, все что нужно туда скачивает и, самое главное, заливает тестовый набор данных, чтобы anytask был не пустой.

Данные можно заливать либо прямо через Django код (создать объект модели User, Course, завести студентов, преподавателей и тп.). Либо завести это все вручную и сделать ./manage.py dump > ... Первый вариант более предпочтителен т.к. его будет проще поддерживать в будущем (когда модели будут меняться).

Также надо написать тест, который бы запускал этот скрипт и проверял, что все работает и не падает.

[epic] Деплой с помощью докера

Нужно уметь деплоить весь Anytask докером. В частности сам Anytask и RB. Также подумать что делать с БД для них.

Видимо должен быть отдельные docker-compose для Anytask-а и для RB в которых будет еще прописана и БД - можно для кадого приложению свой отдельный контейнер с БД.

Важно:

  1. Контейнеры должны собираться в github actions.
  2. Не забыть про костыль синхронизации аккаунтов.

Календарь дедлайнов

Нужно сделать URL по которому в специальном формате (ical?) должен отдаваться календарь дедлайнов для определенной курса/группы.

Нужно, чтобы этот URL можно было скормить сервисам вроде Google Calendar, Яндекс.Календарь или локальным программам календаряс (Calendar на MacOS или Outlook) и появился бы календарь с дедлайнами, который бы сам автоматически обновлялся.

Для удобства желательно сделать прямо кнопки "Добавить в Google Calendar", "Добавить в Яндекс.Календарь", ...

[epic] Доработка EasyCI

Это большой epic титкет, его нужно разбить на подзадачи.

EasyCI ( https://github.com/znick/anytask/tree/master/easyci) - это тот робот, который запускает тесты на присланные задачи. Сейчас он устроен супер просто: робот идет через API скачивает все комментарии с курса, потом строит очередь на проверку, запускает проверку по очереди и отправляет результат через API.

Нужные доработки

  1. Сейчас вся проверка делаются на одной машине (в 2 потока). Текущая архитектура не позволяет запускать проверки распределенно на нескольких машинах. Из-за этого результаты проверки приходится ждать довольно долго. Нужно сделать возможность запуска EasyCI распределенно на нескольких машинах
  2. API Anytask-а сейчас очень бедно - роботу приходится скачивать все-все комментарии потому что альтернативы нет. Хочется, чтобы Anytask умел дёргать произвольный URL и сообщать о событиях (e.g. добавился новый комментарий, изменилась оценка и т.п.). URL должен настраиваться в Настройках курса. Можно вдохновиться GitHub Webhooks.
    Правда, чтобы был профит EasyCI придется сделать полноценным web-сервисом со своим URL-ом.
  3. Прикрутить к EasyCI фронтенд, чтобы можно было смотреть, очередь проверки.

[epic] Вынос файлов пользователей в S3

Сейчас все файлы пользователей хранятся на жестком диске рядом с Anytask-ом. Цель: вынести их в S3, который предоставляется облачным провайдером (предположительно Digital Ocean или Яндекс.Облако).

Главное препядствие сейчас - это запускалка jupiter notebook, которая подразумевает, что имеет доступ к файлам прямо на диске. Нужно вынести ее в отдельный сервис:

  • принимает URL ноутбука и запускает его
  • делает это только от авторизованного пользователя в Anytask-е. Нужна возможность ограничивать такую возможность только для преподавателей.

Все это должно быть отделяемо от основого Anytask-а на отдельную машину и работать в docker или в Kuberneties. Адаптация готовых решений тоже подойдет (свой собственный jupiter cloud?)

Собственно сделать так, чтобы Anytask работал с файлами на S3 вместо локальных файлов: загружал туда файлы и выдавал на них ссылки кому надо. Также нужно продумать как загрузить в S3 все текущие файлы.

Правильная интеграция с Review Board

ReviewBoard - это система кодревью, которая используется в AnyTask
https://www.reviewboard.org/

A. Заапстримить патч

У нас есть свой собственный патч к RB:
https://github.com/gebetix/reviewboard ветка anytask-dev
Патч: reviewboard/reviewboard@master...gebetix:anytask-dev

Он нужен для обновления состава групп в Anytask-е (чтобы к ревьюшке имели доступы только преподаватели курса). К сожалению, в RB сейчас нет возможности делать это через API. Наш патч решает эту проблему, но он очень грязный и вряд ли его примут в таком виде. Такой функционал есть в веб-интерфейсе, но через API этого сделать нельзя.

B. Fixed/Drop

Далее, в текущем варианте Review Board настроен немного неправильно (?) и кнопки Fixed/Drop на комментарий появляются только у преподавателя, студенту они не видны. Нужно поправить конфигурацию, чтобы студент мог сам отмечать комментарии как «Fixed» или «Drop».

[test] Тест на создание пользователя

При переходе на python3.8 сломалась интеграция с django-registration и фамилии и имена вновь зарегистрированных пользователей не записывались в БД.

Коммит, который исправляет проблему:
f6fb3ae

Нужно покрыть эту функциональность тестом, а именно:

  1. Заполнять формочку на регистрацию.
  2. (желательно) Лоивть email и активировать аккаунт.
  3. Проверять, что все данные есть в БД.

Частично такой тест уже есть, но он не проверяет, что данные в базу записались и не проверяет, что аккаунт активируется:

def test_register_user(self):

А вот так можно "получать" почту в тесте:

change_password_url_match = self.RESET_LINK_RE.search(mail.outbox[0].body) # Find link in email

Django 1.11 warnings

https://pastebin.com/2DTMhWUQ

W001

?: (1_8.W001) The standalone TEMPLATE_* settings were deprecated in Django 1.8 and the TEMPLATES dictionary takes precedence. You must put the values of the following settings into your default TEMPLATES dict: TEMPLATE_DEBUG.

urls.W002

?: (urls.W002) Your URL pattern '/gradebook/$' [name='staff.views.get_gradebook'] has a regex beginning with a '/'. Remove this slash as it is unnecessary. If this pattern is targeted in an include(), ensure the include() pattern has a trailing '/'.

fields.W340

courses.Course.filename_extensions: (fields.W340) null has no effect on ManyToManyField.

[test] Тест на возможность заводить задачи с html-разметкой

При переходе на python3.8 сломалась отображение задач с html форматированием: вместо текста задачи в issue показывалась пустота.

Проблема была в несовместимости новой и старой версии парсера BeautifulSoap, который используется для фильтрации плохих запрещенных тегов. Фикс: c3aef60

Нужно написать тест, который проверяет, что task с html разметкой отображается нормально.

Подобные тесты можно подсмотреть:
https://github.com/znick/anytask/blob/master/anytask/tasks/tests.py
https://github.com/znick/anytask/blob/master/anytask/issues/tests.py

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.