Git Product home page Git Product logo

py-phias's Introduction

py-phias

Python application that can operate with FIAS (Russian Address Object DB)

Простое приложение для работы с БД ФИАС, используя БД PostgreSQL + Sphinxsearch. ГАР не поддерживается, только ФИАС в старом формате, последняя база от 31.08.2021

Пример работы

Swagger: github-pages

Содержание

Возможности

  1. API (выходной формат - JSON), основные функции которого:

    • Актуализация AOID, AOGUID.
    • Получение полного дерева адресного объекта по AOID.
    • Поиск адресного объекта по произвольной строке, выдает 10 самых релеватных результатов, может быть "мягким", с более широкими вариациями и исправлением опечаток (для подсказок), или "строгим" (к примеру, для автоматического импорта из внешних систем).
    • ВНИМАНИЕ: Поиск объекта только до улицы, по домам и квартирам не ищет! Поддержки нет и в рамках этого проекта не будет точно.
  2. Автоматическое развертывание базы ФИАС

    • Из директории с файлами XML, распакованными из архива с сайта ФНС (напр. AS_ADDROBJ_20160107_xxx.XML)
    • Из предподготовленных данных в формате CSV

Установка

ОС Linux, x86_64, Docker. Требования по "железу":

  • Диск: ~4Гб (БД + индексы + образы докера). Опционально сюда добавляется архив с базой (14Гб) + распакованная база (до 60Гб, но можно распаковывать не все файлы, ниже есть об этом).
  • RAM: 512Mb на Sphinx и примерно еще столько же на приложение + Postgres. 1Гб должно хватить минимально, в противном случае можно подтюнить sphinx.conf:5

Далее будет описана установка для Ubuntu 20.04 на VPS, но возможно использовать и другой дистрибутив.

Зависимости

Обязательна установка Docker, docker-compose. Можете по инструкции c офф. сайта, либо по такой:

sudo apt-get update
sudo apt-get install ca-certificates curl gnupg lsb-release
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin

Подготовка и скачивание компонентов ПО

Копируем на удаленный хост файлы из папки deploy: .env, docker-compose.yml, init.sh

Далее настраиваем файл .env (можно и не менять), пример:

DB_USER=admin
DB_PASS=devpass
DB_NAME=fias
DB_HOST=db
DB_PORT=5432
# директория, в которой будут хранится индексы сфинкса
SPHINX_VAR=/var/lib/sphinxsearch
# порт прослушки, важно, если SHPINX_LISTEN представляет собой TCP сокет, а не юникс
SPHINX_PORT=9312
# что слушает сфинкс, 'shpinx:9312' для TCP (где 'shpinx' - это имя контейнера) или '/temp/fias.sock'
# для юникс-сокета
SHPINX_LISTEN=/temp/fias.sock

Загрузка исходных данных

Есть 2 варианта загрузки:

  • Из распакованного архива с сайта ФНС.
  • Из предподготовленных данных в формате CSV.

Загрузка из распакованного архива с сайта ФНС

Идем в архив и качаем любую из ПОЛНАЯ БД ФИАС - XML, там будет архив под 12Гб. Его либо распаковываем на виртуалке и кладем файлы в ./data/source, либо качаем на свою машину, а файлы заливаем по SFTP. Заливать все файлы необходимости нет, нужны 2 таблицы: ADDROBJ и SOCRBASE, итого ls -la ./data/source после всех этих манимуляций должна выглядеть как-то так:

$ ls -la
drwxr-xr-x 1 user user          0 Jul 16 01:22 ./
drwxr-xr-x 1 user user          0 Jul 19 19:34 ../
-rw-r--r-- 1 user user 3882354436 Sep  1  2021 AS_ADDROBJ_20210901_34d43f4d-f8a9-4aff-a446-9696e9908011.XML
-rw-r--r-- 1 user user      39012 Sep  1  2021 AS_SOCRBASE_20210901_d242a252-db1f-4492-afd6-78af81f0588d.XML

Загрузка пред-подготовленных данных в формате CSV

Есть другой вариант, скачать уже подготовленные мной данные, это выгрузка от 31.08.2021 (последняя) в формате, который предварительно подготовлен и который поддерживается программой. Скачать можно с Яндекс Диска, заливать придется по SFTP, при этом распаковывать архив этот уже не надо; в таком случае папка будет как-то так выглядеть:

$ ls -la ./data/source
total 215616
drwxrwxr-x 2 user user      4096 Jul 19 22:45 .
drwxrwxr-x 3 user user      4096 Jul 19 22:37 ..
-rw-rw-r-- 1 user user 220779247 Jul 19 22:46 fias_csv_31_08_2021.zip

Популяция базы, индексирование и старт

Далее можно просто выполнить sudo ./init.sh, глянуть можно здесь (init.sh). После этого можно очистить исходники базы, они больше не нужны (sudo rm -rf ./data/source/*)

TLS-termination и NGINX

Тут много всего описано в интернете, конфиг nginx примерно такой:

upstream fias {
    server 127.0.0.1:8080 fail_timeout=0;
}

server {
    if ($host = fias.example.org) {
        return 301 https://$host$request_uri;
    }

    listen 80;
    listen [::]:80;
    server_name fias.example.org;

    location / {
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_redirect off;
      proxy_pass http://fias;
    }
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name fias.example.org;
    server_tokens off;
    client_max_body_size 1M;
    keepalive_timeout 5;

    # certs sent to the client in SERVER HELLO are concatenated in ssl_certificate
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;

    # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
    # ssl_dhparam /etc/ssl/certs/dhparam.pem;

    # modern configuration. tweak to your needs.
    ssl_protocols TLSv1.2;
    ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
    ssl_prefer_server_ciphers on;

    # HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
    add_header Strict-Transport-Security max-age=15768000;

    # OCSP Stapling ---
    # fetch OCSP records from URL in ssl_certificate and cache them
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4 valid=300s;

    location ^~ /.well-known/acme-challenge/ {
      alias /var/www/html;
    }

    location / {
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_set_header X-Forwarded-Proto https;
      proxy_redirect off;
      proxy_pass http://fias;
    }
    ssl_certificate /etc/letsencrypt/live/fias.example.org/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/fias.example.org/privkey.pem;
 # managed by Certbot
}

Тут важна больше всего опция proxy_set_header X-Forwarded-Proto https;, чтобы нормально отображался сваггер. Также, в docker-compose.yml потом можно поставить порты в app, чтобы слушало только localhost.

Api

После старта приложения по адресу: http://{ip}:8080/docs будет доступен Swagger с описанием и возможностью тестировать запросы на реальном окружении. Также его можно глянуть на github-pages, результаты отдавать не будет, естественно.

py-phias's People

Contributors

jar3b avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

py-phias's Issues

не заполняется БД

при первом запуске init.sh не может подключиться к БД
File "/usr/local/lib/python3.10/asyncio/selector_events.py", line 535, in _sock_connect_cb raise OSError(err, f'Connect call failed {address}') ConnectionRefusedError: [Errno 111] Connect call failed ('172.18.0.2', 5432) [Errno 111] Connect call failed ('172.18.0.2', 5432)
при последующих запусках
File "/usr/local/lib/python3.10/site-packages/asyncpg/connection.py", line 318, in execute return await self._protocol.query(query, timeout) File "asyncpg/protocol/protocol.pyx", line 338, in query asyncpg.exceptions.BadCopyFileFormatError: extra data after last expected column extra data after last expected column

Ошибка при создании базы

Помогите, что не так?
C:\Users\Artem\python-fias\fias-api>py manage.py -b create -s http
2021-02-16 17:29:38,922 Prepare to create DB structure...
2021-02-16 17:29:39,022 Done.
2021-02-16 17:29:39,252 POST https://fias.nalog.ru/WebServices/Public/DownloadService.asmx
2021-02-16 17:29:39,515 b'\r\n\r\n\r\n\r\n \r\n \r\n \r\n \r\n <title>\xd0\xa4\xd0\xb5\xd0\xb4\xd0\xb5\xd1\x80\xd0\xb0\xd0\xbb\xd1\x8c\xd0\xbd\xd0\xb0\xd1\x8f \xd0\xb8\xd0\xbd\xd1\x84\xd0\xbe\xd1\x80\xd0\xbc\xd0\xb0\xd1\x86\xd0\xb8\xd0\xbe\xd0\xbd\xd0\xbd\xd0\xb0\xd1\x8f \xd0\xb0\xd0\xb4\xd1\x80\xd0\xb5\xd1\x81\xd0\xbd\xd0\xb0\xd1\x8f \xd1\x81\xd0\xb8\xd1\x81\xd1\x82\xd0\xb5\xd0\xbc\xd0\xb0</title>\r\n\r\n \r\n \r\n \r\n <script src="/js/jquery-1.11.3.min.js"></script>\r\n <script src="/js/functions_2.js"></script>\r\n <script src="/js/jquery.cookie.js"></script>\r\n <script src="/js/radscripts.js"></script>\r\n <script src="/js/jquery.smslider.min.js"></script>\r\n <script src="/lib/kendo-ui/js/kendo.all.min.js"></script>\r\n <script src="/lib/kendo-ui/js/kendo.aspnetmvc.min.js"></script>\r\n <script src="/lib/kendo-ui/js/messages/kendo.messages.ru-RU.min.js"></script>\r\n <script src="/lib/kendo-ui/js/cultures/kendo.culture.ru.min.js"></script>\r\n <script src="/js/jquery.fias_file_service.js?fias_ver=21.2.12.1"></script>\r\n <script src="/js/jquery.fias_file_count.js?fias_ver=21.2.12.1"></script>\r\n\r\n <script src="/lib/polyfill/polyfill.min.js"></script>\r\n <script src="/lib/polyfill/es6-promise.min.js"></script>\r\n <script src="/lib/polyfill/ie_eventlistner_polyfill.js"></script>\r\n <script>window.allow_firefox_cadesplugin_async = 1;</script>\r\n <script src="/js/signature/jquery.gnivc.fias.signature.sync.min.js?fias_ver=21.2.12.1"></script>\r\n <script src="/js/signature/jquery.gnivc.fias.signature.async.min.js?fias_ver=21.2.12.1"></script>\r\n\r\n\r\n <script src="/js/site.min.js?fias_ver=21.2.12.1"></script>\r\n\r\n\r\n

\r\n \r\n
\r\n \r\n \r\n
\r\n

\r\n
\r\n \r\n\r\n
\r\n

\xd0\x9f\xd0\xa0\xd0\x9e\xd0\x98\xd0\x97\xd0\x9e\xd0\xa8\xd0\x81\xd0\x9b \xd0\xa2\xd0\x95\xd0\xa5\xd0\x9d\xd0\x98\xd0\xa7\xd0\x95\xd0\xa1\xd0\x9a\xd0\x98\xd0\x99 \xd0\xa1\xd0\x91\xd0\x9e\xd0\x99. \xd0\x9f\xd0\x9e\xd0\x9f\xd0\xa0\xd0\x9e\xd0\x91\xd0\xa3\xd0\x99\xd0\xa2\xd0\x95 \xd0\x9f\xd0\x9e\xd0\x92\xd0\xa2\xd0\x9e\xd0\xa0\xd0\x98\xd0\xa2\xd0\xac \xd0\x9f\xd0\x9e\xd0\x97\xd0\x94\xd0\x9d\xd0\x95\xd0\x95. \xd0\x92 \xd0\xa1\xd0\x9b\xd0\xa3\xd0\xa7\xd0\x90\xd0\x95, \xd0\x95\xd0\xa1\xd0\x9b\xd0\x98 \xd0\x9e\xd0\xa8\xd0\x98\xd0\x91\xd0\x9a\xd0\x90 \xd0\xa1\xd0\x9e\xd0\xa5\xd0\xa0\xd0\x90\xd0\x9d\xd0\x98\xd0\xa2\xd0\xa1\xd0\xaf - \xd0\x9e\xd0\x91\xd0\xa0\xd0\x90\xd0\xa2\xd0\x98\xd0\xa2\xd0\x95\xd0\xa1\xd0\xac \xd0\x92 \xd0\xa1\xd0\x9b\xd0\xa3\xd0\x96\xd0\x91\xd0\xa3 \xd0\xa2\xd0\x95\xd0\xa5\xd0\x9d\xd0\x98\xd0\xa7\xd0\x95\xd0\xa1\xd0\x9a\xd0\x9e\xd0\x99 \xd0\x9f\xd0\x9e\xd0\x94\xd0\x94\xd0\x95\xd0\xa0\xd0\x96\xd0\x9a\xd0\x98.

\r\n

\r\n n5001-ais1194-210216172938842
\r\n
\r\n \xd0\x9f\xd1\x80\xd0\xb8 \xd0\xbe\xd0\xb1\xd1\x80\xd0\xb0\xd1\x89\xd0\xb5\xd0\xbd\xd0\xb8\xd0\xb8 \xd0\xb2 \xd1\x81\xd0\xbb\xd1\x83\xd0\xb6\xd0\xb1\xd1\x83 \xd1\x82\xd0\xb5\xd1\x85\xd0\xbd\xd0\xb8\xd1\x87\xd0\xb5\xd1\x81\xd0\xba\xd0\xbe\xd0\xb9 \xd0\xbf\xd0\xbe\xd0\xb4\xd0\xb4\xd0\xb5\xd1\x80\xd0\xb6\xd0\xba\xd0\xb8, \xd0\xb4\xd0\xbb\xd1\x8f \xd1\x82\xd0\xbe\xd1\x87\xd0\xbd\xd0\xbe\xd0\xb3\xd0\xbe \xd0\xbe\xd0\xbf\xd1\x80\xd0\xb5\xd0\xb4\xd0\xb5\xd0\xbb\xd0\xb5\xd0\xbd\xd0\xb8\xd1\x8f \xd0\xbf\xd1\x80\xd0\xbe\xd0\xb1\xd0\xbb\xd0\xb5\xd0\xbc\xd1\x8b \xd0\xb2 \xd1\x81\xd0\xb8\xd1\x81\xd1\x82\xd0\xb5\xd0\xbc\xd0\xb5 \xd0\xa4\xd0\x98\xd0\x90\xd0\xa1 \xd0\xb8 \xd0\xb8\xd1\x81\xd0\xbf\xd1\x80\xd0\xb0\xd0\xb2\xd0\xbb\xd0\xb5\xd0\xbd\xd0\xb8\xd1\x8f \xd0\xb4\xd0\xb0\xd0\xbd\xd0\xbd\xd0\xbe\xd0\xb9 \xd0\xbe\xd1\x88\xd0\xb8\xd0\xb1\xd0\xba\xd0\xb8, \xd0\xbf\xd0\xbe\xd0\xb6\xd0\xb0\xd0\xbb\xd1\x83\xd0\xb9\xd1\x81\xd1\x82\xd0\xb0 \xd0\xbf\xd1\x80\xd0\xbe\xd0\xb8\xd0\xb7\xd0\xb2\xd0\xb5\xd0\xb4\xd0\xb8\xd1\x82\xd0\xb5 \xd1\x81\xd0\xbb\xd0\xb5\xd0\xb4\xd1\x83\xd1\x8e\xd1\x89\xd0\xb8\xd0\xb5 \xd0\xb4\xd0\xb5\xd0\xb9\xd1\x81\xd1\x82\xd0\xb2\xd0\xb8\xd1\x8f: \xd0\xbe\xd0\xbf\xd0\xb8\xd1\x88\xd0\xb8\xd1\x82\xd0\xb5 \xd0\xbf\xd0\xbe\xd1\x81\xd0\xbb\xd0\xb5\xd0\xb4\xd0\xbe\xd0\xb2\xd0\xb0\xd1\x82\xd0\xb5\xd0\xbb\xd1\x8c\xd0\xbd\xd0\xbe\xd1\x81\xd1\x82\xd1\x8c \xd0\xb2\xd1\x8b\xd0\xbf\xd0\xbe\xd0\xbb\xd0\xbd\xd1\x8f\xd0\xb5\xd0\xbc\xd1\x8b\xd1\x85 \xd0\x92\xd0\xb0\xd0\xbc\xd0\xb8 \xd0\xb4\xd0\xb5\xd0\xb9\xd1\x81\xd1\x82\xd0\xb2\xd0\xb8\xd0\xb9, \xd0\xbf\xd1\x80\xd0\xb8\xd0\xb2\xd0\xbe\xd0\xb4\xd1\x8f\xd1\x89\xd0\xb8\xd1\x85 \xd0\xba \xd0\xb4\xd0\xb0\xd0\xbd\xd0\xbd\xd0\xbe\xd0\xb9 \xd0\xbe\xd1\x88\xd0\xb8\xd0\xb1\xd0\xba\xd0\xb5; \xd0\xbf\xd1\x80\xd0\xb8\xd0\xbb\xd0\xbe\xd0\xb6\xd0\xb8\xd1\x82\xd0\xb5 \xd1\x81\xd0\xba\xd1\x80\xd0\xb8\xd0\xbd\xd1\x88\xd0\xbe\xd1\x82\xd1\x8b \xd1\x81\xd1\x82\xd1\x80\xd0\xb0\xd0\xbd\xd0\xb8\xd1\x86 \xd1\x81 \xd0\xb7\xd0\xb0\xd0\xbf\xd0\xbe\xd0\xbb\xd0\xbd\xd0\xb5\xd0\xbd\xd0\xbd\xd1\x8b\xd0\xbc\xd0\xb8 \xd0\xb4\xd0\xb0\xd0\xbd\xd0\xbd\xd1\x8b\xd0\xbc\xd0\xb8, \xd0\xb4\xd0\xbe \xd1\x82\xd0\xbe\xd0\xb3\xd0\xbe \xd0\xba\xd0\xb0\xd0\xba \xd0\x92\xd1\x8b \xd0\xbf\xd0\xbe\xd0\xbf\xd0\xb0\xd0\xbb\xd0\xb8 \xd0\xbd\xd0\xb0 \xd0\xb4\xd0\xb0\xd0\xbd\xd0\xbd\xd1\x83\xd1\x8e \xd1\x81\xd1\x82\xd1\x80\xd0\xb0\xd0\xbd\xd0\xb8\xd1\x86\xd1\x83; \xd0\xb4\xd0\xbe\xd0\xb1\xd0\xb0\xd0\xb2\xd1\x8c\xd1\x82\xd0\xb5 \xd0\xba \xd1\x81\xd0\xbe\xd0\xbe\xd0\xb1\xd1\x89\xd0\xb5\xd0\xbd\xd0\xb8\xd1\x8e \xd0\xbd\xd0\xbe\xd0\xbc\xd0\xb5\xd1\x80 \xd0\xb2\xd0\xbe\xd0\xb7\xd0\xbd\xd0\xb8\xd0\xba\xd1\x88\xd0\xb5\xd0\xb9 \xd0\xbe\xd1\x88\xd0\xb8\xd0\xb1\xd0\xba\xd0\xb8!\r\n

\r\n

\xd0\x92\xd0\xb5\xd1\x80\xd0\xbd\xd1\x83\xd1\x82\xd1\x8c\xd1\x81\xd1\x8f \xd0\xbd\xd0\xb0 \xd0\xb3\xd0\xbb\xd0\xb0\xd0\xb2\xd0\xbd\xd1\x83\xd1\x8e \xd1\x81\xd1\x82\xd1\x80\xd0\xb0\xd0\xbd\xd0\xb8\xd1\x86\xd1\x83.

\r\n\r\n
\r\n\r\n
\r\n
\r\n \r\n\r\n\r\n'
Traceback (most recent call last):
File "C:\Users\Artem\python-fias\fias-api\manage.py", line 141, in
main()
File "C:\Users\Artem\python-fias\fias-api\manage.py", line 128, in main
aoupdater.create(allowed_updates)
File "C:\Users\Artem\python-fias\fias-api\aore\updater\updater.py", line 111, in create
for update_entry in self.updalist_generator:
File "C:\Users\Artem\python-fias\fias-api\manage.py", line 52, in get_allowed_updates
all_versions = [x for x in imp.get_update_list()]
File "C:\Users\Artem\python-fias\fias-api\manage.py", line 52, in
all_versions = [x for x in imp.get_update_list()]
File "C:\Users\Artem\python-fias\fias-api\aore\updater\soapreceiver.py", line 14, in get_update_list
response = self.client.GetAllDownloadFileInfo()
File "C:\Program Files\Python39\lib\site-packages\pysimplesoap\client.py", line 175, in
return lambda *args, **kwargs: self.call(attr, *args, **kwargs)
File "C:\Program Files\Python39\lib\site-packages\pysimplesoap\client.py", line 257, in call
response = SimpleXMLElement(self.xml_response, namespace=self.namespace,
File "C:\Program Files\Python39\lib\site-packages\pysimplesoap\simplexml.py", line 56, in init
self.__document = xml.dom.minidom.parseString(text)
File "C:\Program Files\Python39\lib\xml\dom\minidom.py", line 1998, in parseString
return expatbuilder.parseString(string)
File "C:\Program Files\Python39\lib\xml\dom\expatbuilder.py", line 925, in parseString
return builder.parseString(string)
File "C:\Program Files\Python39\lib\xml\dom\expatbuilder.py", line 223, in parseString
parser.Parse(string, True)
xml.parsers.expat.ExpatError: mismatched tag: line 35, column 2

Что осталось?

  1. + Сделать запись версии (обновленной) в базу и чтение этой версии. (63f7827)
  2. -+ Сделать API (e249be2), ...
  3. + Сделать тестовое приложение (e249be2)

По релевантности

-Можно убрать стемминг с основы - отсечем словоформы, которые мы итак можем найти предварительно. Этот же стемминг добавить в малый индекс.
-Еще нужно сделать так, чтобы слово не бустило рейтинг, если оно несколько раз встретилось. Всякие там MAYBE не дают решения.
-Как вариант, смотреть где находится слово:

  1. Если рядом слово и сокращение - объединять
  2. Последнее слово искать ближе к концу (улицы там, пункты)

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.