Если вы когда-либо пробовали Go, вы знаете, что писать сервисы на Go очень просто. Нам нужно буквально несколько строк кода для того, чтобы можно было запустить http-сервис. Но что нужно добавить, если мы хотим приготовить такое приложение в продакшн? Давайте рассмотрим это на примере сервиса, который готов к запуску в Kubernetes.
Все шаги из этой статьи можно найти в одном теге, или вы можете следить за примерами статьи коммит за коммитом.
Шаг 1. Простейший сервис
Итак, у нас есть очень простое приложение:
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/home", func(w http.ResponseWriter, _ *http.Request) {
fmt.Fprint(w, "Hello! Your request was processed.")
},
)
http.ListenAndServe(":8000", nil)
}
Если мы хотим попробовать запустить его, команды go run main.go будет достаточно. С помощью curl мы можем проверить, как работает этот сервис: curl -i http://127.0.0.1:8000/home. Но когда мы запускаем это приложение, мы видим, что в терминале нет никакой информации о его состоянии.
Шаг 2. Добавляем логирование
Прежде всего, давайте добавим логирование для того, чтобы понимать, что происходит с сервисом, и для того, чтобы можно было журналировать ошибки или другие важные ситуации. В этом примере мы будем использовать простейший логер из стандартной библиотеки Go, но для настоящего сервиса, запущенного в продакшн, могут быть интересны более сложные решения, такие как glog или logrus.
Нам могут быть интересны 3 ситуации: когда сервис запускается, когда сервис готов обрабатывать запросы, и когда http.ListenAndServe возвращает ошибку. В результате получится что-то такое:
func main() {
log.Print("Starting the service...")
http.HandleFunc("/home", func(w http.ResponseWriter, _ *http.Request) {
fmt.Fprint(w, "Hello! Your request was processed.")
},
)
log.Print("The service is ready to listen and serve.")
log.Fatal(http.ListenAndServe(":8000", nil))
}
Уже лучше!
Шаг 3. Добавляем роутер
Для настоящего приложения мы, скорее всего, захотим использовать роутер для упрощения обработки разных URI, HTTP-методов или других правил. В стандартной библиотеке Go нет роутера, поэтому давайте попробуем gorilla/mux, который вполне совместим со стандартной библиотекой net/http.
Есть смысл вынести всё, связанное с роутингом, в отдельный пакет. Давайте вынесем инициализацию и задание правил роутинга, а также функции-обработчики в пакет handlers (полные изменения можно посмотреть здесь).
Добавим функцию Router, которая будет возвращать сконфигурированный роутер, и функцию home, которая будет обрабатывать правило для пути /home. Я предпочитаю разделять такие функции на отдельные файлы:
handlers/handlers.go:
package handlers
import (
"github.com/gorilla/mux"
)
// Router register necessary routes and returns an instance of a router.
func Router() *mux.Router {
r := mux.NewRouter()
r.HandleFunc("/home", home).Methods("GET")
return r
}
handlers/home.go:
package handlers
import (
"fmt"
"net/http"
)
// home is a simple HTTP handler function which writes a response.
func home(w http.ResponseWriter, _ *http.Request) {
fmt.Fprint(w, "Hello! Your request was processed.")
}
Кроме того, нам нужны небольшие изменения в файле main.go:
package main
import (
"log"
"net/http"
"github.com/rumyantseva/advent-2017/handlers"
)
// How to try it: go run main.go
func main() {
log.Print("Starting the service...")
router := handlers.Router()
log.Print("The service is ready to listen and serve.")
log.Fatal(http.ListenAndServe(":8000", router))
}
Шаг 4. Тесты
Самое время добавить несколько тестов. Для этого можно воспользоваться стандартным пакетом httptest. Для функции Router можно написать что-то такое:
package handlers
import (
"net/http"
"net/http/httptest"
"testing"
)
func TestRouter(t *testing.T) {
r := Router()
ts := httptest.NewServer(r)
defer ts.Close()
res, err := http.Get(ts.URL + "/home")
if err != nil {
t.Fatal(err)
}
if res.StatusCode != http.StatusOK {
t.Errorf("Status code for /home is wrong. Have: %d, want: %d.", res.StatusCode, http.StatusOK)
}
res, err = http.Post(ts.URL+"/home", "text/plain", nil)
if err != nil {
t.Fatal(err)
}
if res.StatusCode != http.StatusMethodNotAllowed {
t.Errorf("Status code for /home is wrong. Have: %d, want: %d.", res.StatusCode, http.StatusMethodNotAllowed)
}
res, err = http.Get(ts.URL + "/not-exists")
if err != nil {
t.Fatal(err)
}
if res.StatusCode != http.StatusNotFound {
t.Errorf("Status code for /home is wrong. Have: %d, want: %d.", res.StatusCode, http.StatusNotFound)
}
}
Здесь мы проверяем, что вызов метода GET для /home вернет код 200. А при попытке отправить POST ожидаемым ответом будет уже 405. И, наконец, для несуществующего пути мы ожидаем 404. Вообще, этот тест может быть несколько избыточным, ведь работа роутера и так уже покрыта тестами в рамках пакета gorilla/mux, так что здесь можно проверять даже меньшее количество кейсов.
Для функции home имеет смысл проверить уже не только код, но и тело ответа:
package handlers
import (
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"
)
func TestHome(t *testing.T) {
w := httptest.NewRecorder()
home(w, nil)
resp := w.Result()
if have, want := resp.StatusCode, http.StatusOK; have != want {
t.Errorf("Status code is wrong. Have: %d, want: %d.", have, want)
}
greeting, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
t.Fatal(err)
}
if have, want := string(greeting), "Hello! Your request was processed."; have != want {
t.Errorf("The greeting is wrong. Have: %s, want: %s.", have, want)
}
}
Запускаем go test и проверяем, что тесты работают:
$ go test -v ./...
? github.com/rumyantseva/advent-2017 [no test files]
=== RUN TestRouter
--- PASS: TestRouter (0.00s)
=== RUN TestHome
--- PASS: TestHome (0.00s)
PASS
ok github.com/rumyantseva/advent-2017/handlers 0.018s
Шаг 5. Конфигурирование
Следующий важный шаг — возможность задать конфигурацию сервиса. Сейчас при запуске сервис всегда слушает порт 8000, и возможность сконфигурировать это значение может быть полезной. Манифест двенадцатифакторных приложений, который представляет собой очень интересный подход к написанию сервисов, рекомендует нам хранить конфигурацию, основываясь на окружении. Итак, зададим конфиг для порта через переменную окружения:
package main
import (
"log"
"net/http"
"os"
"github.com/rumyantseva/advent-2017/handlers"
)
// How to try it: PORT=8000 go run main.go
func main() {
log.Print("Starting the service...")
port := os.Getenv("PORT")
if port == "" {
log.Fatal("Port is not set.")
}
r := handlers.Router()
log.Print("The service is ready to listen and serve.")
log.Fatal(http.ListenAndServe(":"+port, r))
}
В этом примере, если порт не задан, приложение сразу завершится с ошибкой. Нет смысла пытаться продолжать работу, если конфигурация задана некорректно.
Шаг 6. Makefile
Утилита make может быть весьма полезной, если вам приходится иметь дело с повторяющимися действиями. Давайте посмотрим, как можно использовать это в нашем проекте. Прямо сейчас у нас есть два повторяющихся действия: запуск тестов и компиляция и запуск сервиса. Добавим эти действия в Makefile, но вместо простого go run теперь будем использовать go build и после этого запускать скомпилированный бинарник, этот вариант лучше подходит, если в перспективе мы готовим приложение для продакшн:
APP?=advent
PORT?=8000
clean:
rm -f ${APP}
build: clean
go build -o ${APP}
run: build
PORT=${PORT} ./${APP}
test:
go test -v -race ./...
В этом примере мы вынесли имя бинарника в отдельную переменную APP, чтобы не повторять его несколько раз.
Кроме того, если мы хотим запускать приложение описанным образом, надо предварительно удалить старый бинарник (если он существует). Поэтому, при запуске make build сначала вызывается clean.
Шаг 7. Версионирование
Следующая практика, которую мы добавим в сервис — версионирование. Иногда полезно знать, какой конкретно билд и даже коммит мы используем в продакшн, и когда конкретно бинарник был собран.
Для того, чтобы хранить эту информацию, добавим новый пакет — version:
package version
var (
// BuildTime is a time label of the moment when the binary was built
BuildTime = "unset"
// Commit is a last commit hash at the moment when the binary was built
Commit = "unset"
// Release is a semantic version of current build
Release = "unset"
)
Мы можем логировать эти переменные, когда приложение запускается:
...
func main() {
log.Printf(
"Starting the service...\ncommit: %s, build time: %s, release: %s",
version.Commit, version.BuildTime, version.Release,
)
...
}
И также мы можем добавить их в home (не забудьте поправить тесты!):
package handlers
import (
"encoding/json"
"log"
"net/http"
"github.com/rumyantseva/advent-2017/version"
)
// home is a simple HTTP handler function which writes a response.
func home(w http.ResponseWriter, _ *http.Request) {
info := struct {
BuildTime string `json:"buildTime"`
Commit string `json:"commit"`
Release string `json:"release"`
}{
version.BuildTime, version.Commit, version.Release,
}
body, err := json.Marshal(info)
if err != nil {
log.Printf("Could not encode info data: %v", err)
http.Error(w, http.StatusText(http.StatusServiceUnavailable), http.StatusServiceUnavailable)
return
}
w.Header().Set("Content-Type", "application/json")
w.Write(body)
}
Будем использовать линкер для того, чтобы задать переменные BuildTime, Commit и Release во время компиляции.
Добавим новые переменные в Makefile:
RELEASE?=0.0.1
COMMIT?=$(shell git rev-parse --short HEAD)
BUILD_TIME?=$(shell date -u '+%Y-%m-%d_%H:%M:%S')
Здесь COMMIT и BUILD_TIME определены через заданные команды, а для RELEASE мы можем использовать, например, семантическое версионирование или просто инкрементные версии сборок.
Теперь перепишем цель build для того, чтобы можно было использовать значения этих переменных:
build: clean
go build \
-ldflags "-s -w -X ${PROJECT}/version.Release=${RELEASE} \
-X ${PROJECT}/version.Commit=${COMMIT} -X ${PROJECT}/version.BuildTime=${BUILD_TIME}" \
-o ${APP}
Мы также добавили в начало Makefile переменную PROJECT, чтобы не повторять одно и тоже несколько раз:
PROJECT?=github.com/rumyantseva/advent-2017
Все изменения, сделанные на этом шаге, можно найти здесь. Попробуйте make run для того, чтобы проверить, как это работает.
Шаг 8. Меньше зависимостей!
Есть одна вещь, которая мне не нравится в нашем коде: пакет handler зависит от пакета version. Поменять это легко: нам нужно сделать функцию home конфигурабельной:
// home returns a simple HTTP handler function which writes a response.
func home(buildTime, commit, release string) http.HandlerFunc {
return func(w http.ResponseWriter, _ *http.Request) {
...
}
}
И, опять же, не забудьте поправить тесты и внести се необходимые изменения.
Шаг 9. Хелсчеки
В случае запуска сервиса в Kubernetes обычно требуется добавить два хелсчека: liveness- и readiness-пробы. Цель liveness-пробы — дать понимание того, что сервис запустился. Если liveness-проба провалена, сервис будет перезапущен. Цель readiness-пробы — дать понимание того, что приложение готово к получению трафика. Если readiness-проба провалена, контейнер будет удален из балансировщиков нагрузки сервиса.
Для того чтобы определить liveness-пробу, можно написать простой хендлер, который всегда возвращает код 200:
// healthz is a liveness probe.
func healthz(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
}
Для readiness-пробы часто достаточно аналогичного решения, но иногда требуется дождаться некоторого события (например, готовности базы данных) для того, чтобы начать обрабатывать трафик:
// readyz is a readiness probe.
func readyz(isReady *atomic.Value) http.HandlerFunc {
return func(w http.ResponseWriter, _ *http.Request) {
if isReady == nil || !isReady.Load().(bool) {
http.Error(w, http.StatusText(http.StatusServiceUnavailable), http.StatusServiceUnavailable)
return
}
w.WriteHeader(http.StatusOK)
}
}
В этом примере мы возвращаем 200, только если переменная isReady задана и равна true.
Посмотрим, как это можно использовать:
func Router(buildTime, commit, release string) *mux.Router {
isReady := &atomic.Value{}
isReady.Store(false)
go func() {
log.Printf("Readyz probe is negative by default...")
time.Sleep(10 * time.Second)
isReady.Store(true)
log.Printf("Readyz probe is positive.")
}()
r := mux.NewRouter()
r.HandleFunc("/home", home(buildTime, commit, release)).Methods("GET")
r.HandleFunc("/healthz", healthz)
r.HandleFunc("/readyz", readyz(isReady))
return r
}
Здесь мы говорим, что приложение готово обрабатывать трафик через 10 секунд после запуска. Конечно, в реальной жизни нет никакого смысла ждать 10 секунд, но, может быть, вы захотите добавить сюда прогрев кеша или что-то еще в этом роде.
Как всегда, полные изменения можно найти на GitHub'е.
Примечание. Если приложению придёт слишком много трафика, оно начнет отвечать нестабильно. Например, liveness-проба может быть провалена из-за таймаутов, и контейнер будет перезагружен. По этой причине некоторые инженеры предпочитают не использовать liveness-пробы совсем. Лично я считаю, что лучше масштабировать ресурсы, если вы замечаете, что в сервис приходит все больше и больше запросов. Например, можно попробовать автоматическое масштабирование подов через HPA.
Шаг 10. Graceful shutdown
Когда сервису требуется остановка, хорошей практикой является не немедленный обрыв соединений, запросов и других операцией, но их корректная обработка. Go поддерживает "graceful shutdown" для http.Server, начиная с версии 1.8. Рассмотрим, как это можно использовать:
func main() {
...
r := handlers.Router(version.BuildTime, version.Commit, version.Release)
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM)
srv := &http.Server{
Addr: ":" + port,
Handler: r,
}
go func() {
log.Fatal(srv.ListenAndServe())
}()
log.Print("The service is ready to listen and serve.")
killSignal := <-interrupt
switch killSignal {
case os.Interrupt:
log.Print("Got SIGINT...")
case syscall.SIGTERM:
log.Print("Got SIGTERM...")
}
log.Print("The service is shutting down...")
srv.Shutdown(context.Background())
log.Print("Done")
}
В этом примере мы перехватываем системные сигналы SIGINT и SIGTERM и, если один из них пойман, останавливаем сервис правильно.
Примечание. Когда я писала этот код, я также пробовала перехватывать SIGKILL здесь. Я видела такой подход несколько раз в разных библиотеках и была уверена, что это работает. Но, как заметил Sandor Szücs, перехват SIGKILL невозможен. В случае SIGKILL приложение будет остановлено немедленно.
Шаг 11. Dockerfile
Наше приложение почти готово к запуску в Kubernetes, самое время контейнеризировать его.
Простейший Dockerfile, который нам понадобится, может выглядеть так:
FROM scratch
ENV PORT 8000
EXPOSE $PORT
COPY advent /
CMD ["/advent"]
Мы создаем минимально возможный контейнер, копируем туда бинарник и запускаем его (кроме того, мы не забыли пробросить переменную PORT).
Теперь немного изменим Makefile и добавим туда сборку образа и запуск контейнера. Здесь нам могут пригодиться две новые переменные: GOOS и GOARCH, которые мы будем использовать для кросс-компиляции в рамках цели build.
...
GOOS?=linux
GOARCH?=amd64
...
build: clean
CGO_ENABLED=0 GOOS=${GOOS} GOARCH=${GOARCH} go build \
-ldflags "-s -w -X ${PROJECT}/version.Release=${RELEASE} \
-X ${PROJECT}/version.Commit=${COMMIT} -X ${PROJECT}/version.BuildTime=${BUILD_TIME}" \
-o ${APP}
container: build
docker build -t $(APP):$(RELEASE) .
run: container
docker stop $(APP):$(RELEASE) || true && docker rm $(APP):$(RELEASE) || true
docker run --name ${APP} -p ${PORT}:${PORT} --rm \
-e "PORT=${PORT}" \
$(APP):$(RELEASE)
...
Итак, мы добавили цель container для сборки образа и поправили цель run так, чтобы вместо запуска бинарника теперь запускался контейнер. Все изменения доступны здесь.
Теперь можно попробовать запустить make run для проверки всего процесса.
Шаг 12. Управления зависимостями
В нашем проекте есть одна внешняя зависимость — github.com/gorilla/mux. И, значит, для приложения, действительно готового к продакшн, необходимо добавить управление зависимостями. Если мы используем утилиту dep, то всё, что нам требуется сделать — вызов команды dep init:
$ dep init
Using ^1.6.0 as constraint for direct dep github.com/gorilla/mux
Locking in v1.6.0 (7f08801) for direct dep github.com/gorilla/mux
Locking in v1.1 (1ea2538) for transitive dep github.com/gorilla/context
В результате были созданы файлы Gopkg.toml и Gopkg.lock и директория vendor, содержащая все используемые зависимости. Лично я предпочитаю пушить vendor в git, особенно для важных проектов.
Шаг 13. Kubernetes
И, наконец, финальный шаг: запускаем приложение в Kubernetes. Самый простой способ попробовать Kubernetes — установить и настроить на своем локальном окружении minikube.
Kubernetes скачивает образы из реестра (Docker registry). В нашем случае достаточно публичного реестра — Docker Hub. Нам понадобится еще одна переменная и еще одна команда в Makefile:
CONTAINER_IMAGE?=docker.io/webdeva/${APP}
...
container: build
docker build -t $(CONTAINER_IMAGE):$(RELEASE) .
...
push: container
docker push $(CONTAINER_IMAGE):$(RELEASE)
Здесь переменная CONTAINER_IMAGE задаёт репозиторий реестра, куда мы будем отправлять и откуда мы будем скачивать образы контейнеров. Как можно заметить, в данном примере в пути к реестру используется имя пользователя (webdeva). Если у вас нет аккаунта на hub.docker.com, самое время его завести и затем залогиниться с помощью команды docker login. После этого вы сможете отправлять образы в реестр.
Давайте попробуем make push:
$ make push
...
docker build -t docker.io/webdeva/advent:0.0.1 .
Sending build context to Docker daemon 5.25MB
...
Successfully built d3cc8f4121fe
Successfully tagged webdeva/advent:0.0.1
docker push docker.io/webdeva/advent:0.0.1
The push refers to a repository [docker.io/webdeva/advent]
ee1f0f98199f: Pushed
0.0.1: digest: sha256:fb3a25b19946787e291f32f45931ffd95a933100c7e55ab975e523a02810b04c size: 528
Работает! Теперь созданный образ можно найти в реестре.
Определим необходимые конфигурации (манифесты) для Kubernetes. Они представляют собой статические файлы в формате JSON или YAML, так что для подстановки "переменных" нам придется воспользоваться помощью утилиты sed. В этом примере мы рассмотрим три типа ресурсов: deployment, service и ingress.
Примечание. Проект helm решает задачу управления релизами конфигураций в Kubernetes в целом и рассматривает вопросы создания гибких конфигураций в частности. Так что, если простого sed недостаточно, есть смысл познакомиться с Helm.
Рассмотрим конфигурацию для deployment:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: {{ .ServiceName }}
labels:
app: {{ .ServiceName }}
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 50%
maxSurge: 1
template:
metadata:
labels:
app: {{ .ServiceName }}
spec:
containers:
- name: {{ .ServiceName }}
image: docker.io/webdeva/{{ .ServiceName }}:{{ .Release }}
imagePullPolicy: Always
ports:
- containerPort: 8000
livenessProbe:
httpGet:
path: /healthz
port: 8000
readinessProbe:
httpGet:
path: /readyz
port: 8000
resources:
limits:
cpu: 10m
memory: 30Mi
requests:
cpu: 10m
memory: 30Mi
terminationGracePeriodSeconds: 30
Вопросы конфигурирования Kubernetes лучше рассмотреть в рамках отдельной статьи, но, как можно заметить, кроме всего прочего здесь определяются реестр и образ контейнера, а также правила для liveness- и readiness-проб.
Типичная конфигурация для service выглядит проще:
apiVersion: v1
kind: Service
metadata:
name: {{ .ServiceName }}
labels:
app: {{ .ServiceName }}
spec:
ports:
- port: 80
targetPort: 8000
protocol: TCP
name: http
selector:
app: {{ .ServiceName }}
И, наконец, ingress. Здесь мы определяем конфигурацию ingress-контроллера, который поможет, например, получить доступ к сервису извне Kubernetes. Предположим, что мы хотим направлять запросы в сервис при обращению к домену advent.test (который в реальности, конечно, не существует):
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
ingress.kubernetes.io/rewrite-target: /
labels:
app: {{ .ServiceName }}
name: {{ .ServiceName }}
spec:
backend:
serviceName: {{ .ServiceName }}
servicePort: 80
rules:
- host: advent.test
http:
paths:
- path: /
backend:
serviceName: {{ .ServiceName }}
servicePort: 80
Для того чтобы проверить, как работает конфигурация, установим minikube, используя его официальную документацию. Кроме того, нам понадобится утилита kubectl для применения конфигураций и проверки сервиса.
Для запуска minikube, включения ingress и подготовки kubectl понадобятся следующие команды:
minikube start
minikube addons enable ingress
kubectl config use-context minikube
Теперь добавим в Makefile отдельную цель для установки сервиса в minikube:
minikube: push
for t in $(shell find ./kubernetes/advent -type f -name "*.yaml"); do \
cat $$t | \
gsed -E "s/\{\{(\s*)\.Release(\s*)\}\}/$(RELEASE)/g" | \
gsed -E "s/\{\{(\s*)\.ServiceName(\s*)\}\}/$(APP)/g"; \
echo ---; \
done > tmp.yaml
kubectl apply -f tmp.yaml
Эти команды "компилируют" все *.yaml-конфигурации в один файл, заменяют "переменные" Release и ServiceName реальными значениями (я использую gsed вместо обычного sed) и запускают kubectl apply для установки приложения в Kubernetes.
Проверим, как применились конфигурации:
$ kubectl get deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
advent 3 3 3 3 1d
$ kubectl get service
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
advent 10.109.133.147 <none> 80/TCP 1d
$ kubectl get ingress
NAME HOSTS ADDRESS PORTS AGE
advent advent.test 192.168.64.2 80 1d
Теперь попробуем отправить запрос к сервису через заданный домен. Прежде всего, нам нужно добавить домен advent.test в локальный файл /etc/hosts (для Windows --%SystemRoot%\System32\drivers\etc\hosts):
echo "$(minikube ip) advent.test" | sudo tee -a /etc/hosts
И теперь можно проверять работу сервиса:
curl -i http://advent.test/home
HTTP/1.1 200 OK
Server: nginx/1.13.6
Date: Sun, 10 Dec 2017 20:40:37 GMT
Content-Type: application/json
Content-Length: 72
Connection: keep-alive
Vary: Accept-Encoding
{"buildTime":"2017-12-10_11:29:59","commit":"020a181","release":"0.0.5"}%
Ура, работает!
<!doctype html>
<html lang="ru" class="no-js no-touch ">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="yandex-verification" content="3019a35aeda6b45d" />
<script type="text/javascript">
var html = document.getElementsByTagName('html')[0];
html.className = html.className.replace('no-js', '');
window.React = {};
window.metrics = [];
window.TEST_ENV = false;
window.isSuperuser = false;
window.isStaff = false;
window.isHeadTeacher = false;
</script>
<script type="text/javascript">
window.DEBUG_COUNTERS = true;
var yaParams = {
'course_title': 'b',
'ab': 'b',
'features': JSON.parse('{"category-catalog-redirect": true, "landing-price-mode-switcher": true, "register-instead-of-start-test": true, "main-page-redesign": true, "subscription_genus_basic": true, "adblender": true, "greenlight": true, "phone": true, "professions": true, "course_enrol": true, "new_lessons_page": true, "jivosite": false, "course-page-single-screen": true, "right-price": false, "course_page_header_footer_new": true, "submit-application": false, "prof_dev_certificate": false, "assessment-react": true, "new-events-calendar": true, "new-pre-assessment-screen": true, "recommended_courses": true, "tinkoff_payment": true, "payment-page-3-front-refactor": true, "installment-calculator": true, "boomstream-player": true, "finsystems": true, "new-reviews": true}')
};
</script>
<!-- MindBox JavaScript SDK --->
<script>
mindbox = window.mindbox || function() { mindbox.queue.push(arguments); };
mindbox.queue = mindbox.queue || [];
mindbox('create');
</script>
<script src="https://api.mindbox.ru/scripts/v1/tracker.js" async></script>
<!-- End MindBox JavaScript SDK --->
<!-- Yandex.Metrika counter -->
<script type="text/javascript">
(function (ids) {
function yamInit(d, w, c, id) {
(w[c] = w[c] || []).push(function () {
try {
const metrika = new Ya.Metrika2({
id: id,
params: window.yaParams || {},
clickmap: true,
trackLinks: true,
accurateTrackBounce: true,
webvisor: true
});
w.yaMetriks.push(metrika);
w['yaCounter' + id] = metrika;
} catch (e) {
}
});
var n = d.getElementsByTagName('script')[0],
s = d.createElement('script'),
f = function () {
n.parentNode.insertBefore(s, n);
};
s.type = 'text/javascript';
s.async = true;
s.src = 'https://mc.yandex.ru/metrika/tag.js';
if (w.opera == '[object Opera]') {
d.addEventListener('DOMContentLoaded', f, false);
} else {
f();
}
}
window['yaMetriks'] = [];
(Array.isArray(ids) ? ids : [ids]).forEach(id => {
if (id) {
yamInit(document, window, 'yandex_metrika_callbacks2', id)
}
})
})([34531570, 82755226, 93715742])
</script>
<!-- /Yandex.Metrika counter -->
<script type="text/javascript" id="advcakeAsync">
(function (a) {
var b = a.createElement('script');
b.async = 1;
b.src = '//0gs25f.ru/';
a = a.getElementsByTagName('script')[0];
a.parentNode.insertBefore(b, a)
})(document);
window.advcake_data = window.advcake_data || [];
</script>
<script>
!(function (w, d, t) {
w.TiktokAnalyticsObject = t;
var ttq = (w[t] = w[t] || []);
(ttq.methods = [
'page',
'track',
'identify',
'instances',
'debug',
'on',
'off',
'once',
'ready',
'alias',
'group',
'enableCookie',
'disableCookie'
]),
(ttq.setAndDefer = function (t, e) {
t[e] = function () {
t.push([e].concat(Array.prototype.slice.call(arguments, 0)));
};
});
for (var i = 0; i < ttq.methods.length; i++)
ttq.setAndDefer(ttq, ttq.methods[i]);
(ttq.instance = function (t) {
for (var e = ttq._i[t] || [], n = 0; n < ttq.methods.length; n++)
ttq.setAndDefer(e, ttq.methods[n]);
return e;
}),
(ttq.load = function (e, n) {
var i = 'https://analytics.tiktok.com/i18n/pixel/events.js';
(ttq._i = ttq._i || {}),
(ttq._i[e] = []),
(ttq._i[e]._u = i),
(ttq._t = ttq._t || {}),
(ttq._t[e] = +new Date()),
(ttq._o = ttq._o || {}),
(ttq._o[e] = n || {});
var o = document.createElement('script');
(o.type = 'text/javascript'),
(o.async = !0),
(o.src = i + '?sdkid=' + e + '&lib=' + t);
var a = document.getElementsByTagName('script')[0];
a.parentNode.insertBefore(o, a);
});
ttq.load("C4IDL5C17T561FR1EMKG");
ttq.page();
})(window, document, 'ttq');
</script>
<script>
window.vkAsyncInit = function () {
VK.Retargeting.Init("VK-RTRG-410987-bLXUv");
VK.Retargeting.Hit();
}
</script>
<script src="//vk.com/js/api/openapi.js?159" async></script>
<noscript>
<img src="https://vk.com/rtrg?p=VK-RTRG-410987-bLXUv"
style="position:fixed; left:-999px;" alt="" />
</noscript>
<!-- rick.ai/q -->
<script type="text/javascript">
(function(e) {
var t = e.createElement("script");
t.src = "https://store-b2b.ru/tag.js?id=wsse7xcbtr07r1";
t.type = "module";
t.async = true;
t.crossorigin = "anonymous";
e.head.appendChild(t)
})(document)
</script>
<script type="text/javascript" nomodule src="https://store-b2b.ru/tag.js?id=wsse7xcbtr07r1&nomodule"></script>
<!-- end rick.ai/q -->
<script type="text/javascript">
!(function (n, e, t, r, a, s) {
function i(n, r) {
const a = e.createElement(t),
s = e.getElementsByTagName(t)[0];
(a.async = 1),
(a.src = n),
(a.onerror = r),
s.parentNode.insertBefore(a, s);
}
(n.SalesNinja = ['init', 'start', 'onPersonalization', 'reachGoal'].reduce(
(e, t) => {
return (
(e[t] = function () {
const e = Array.prototype.slice.call(arguments);
e.unshift(t), n[r].apply(0, e);
}),
e
);
},
{ k: r, ready: !1 }
)),
(n[r] = function () {
let e,
t,
a = new Promise((n, r) => {
(e = n), (t = r);
});
return (
(n[r].r = n[r].r || []).push({ s: e, f: t }),
(n[r].c = n[r].c || []).push(arguments),
a
);
}),
i(a, () => {
i(s);
});
})(
window,
document,
'script',
'ninja',
'https://cdn.sales-ninja.me/userBundle.js',
'https://bundle.sales-ninja.me/userBundle.js'
);
ninja('init', 'c20cc0ff-6d2f-42ac-9b66-1103c735a13a');
ninja('start');
</script>
<script type="text/javascript">
window.TMR_PIXEL_ID = 3316675;
var _tmr = window._tmr || (window._tmr = []);
_tmr.push({id: "3316675", type: "pageView", start: (new Date()).getTime()});
(function (d, w, id) {
if (d.getElementById(id)) return;
var ts = d.createElement("script"); ts.type = "text/javascript"; ts.async = true; ts.id = id;
ts.src = "https://top-fwz1.mail.ru/js/code.js";
var f = function () {var s = d.getElementsByTagName("script")[0]; s.parentNode.insertBefore(ts, s);};
if (w.opera == "[object Opera]") { d.addEventListener("DOMContentLoaded", f, false); } else { f(); }
})(document, window, "tmr-code");
</script>
<noscript>
<div>
<img src="https://top-fwz1.mail.ru/counter?id=3316675;js=na"
style="position:absolute;left:-9999px;" alt="Top.Mail.Ru" />
</div>
</noscript>
<!-- Pixel Tag Code -->
<script type="text/javascript">
(function (t, l, g, r, m) {
t[g] ||
((g = t[g] =
function () {
g.run ? g.run.apply(g, arguments) : g.queue.push(arguments);
}),
(g.queue = []),
(t = l.createElement(r)),
(t.async = !0),
(t.src = m),
(l = l.getElementsByTagName(r)[0]),
l.parentNode.insertBefore(t, l));
})(window, document, 'tgp', 'script', 'https://telegram.org/js/pixel.js');
tgp('init', '4bxSybss');
</script>
<!-- End Pixel Tag Code -->
<!-- GTM is no more -->
<link rel="canonical" href="https://otus.ru/nest/post/1389/"/>
<link rel="amphtml" href="https://otus.ru/nest/post/1389/?amp"/>
<title>Пишем сервис на Go для Kubernetes | OTUS</title>
<meta property="og:type" content="website"/>
<meta property="og:url" content="https://otus.ru/nest/post/1389/"/>
<meta property="og:title" content="Пишем сервис на Go для Kubernetes | OTUS">
<meta property="og:description" content="Пишем сервис на Go для Kubernetes в OTUS, только интересные посты!">
<meta name="description" content="Пишем сервис на Go для Kubernetes в OTUS, только интересные посты!">
<meta property="og:site_name" content="Otus">
<meta property="fb:app_id" content="486413851704844"/>
<meta property="og:image" content="/static/img/favicons/android-chrome-537x240.jpg?nocache">
<meta property="og:image:width" content="537">
<meta property="og:image:height" content="240">
<link href="/static/img/favicons/android-chrome-537x240.jpg" rel="image_src"/>
<meta property="vk:image" content="/static/img/favicons/android-chrome-537x240.jpg">
<link href="/static/img/favicons/apple-touch-icon.png" rel="apple-touch-icon"/>
<link href="/static/img/favicons/apple-touch-icon-57x57.png" sizes="57x57" rel="apple-touch-icon"/>
<link href="/static/img/favicons/apple-touch-icon-60x60.png" sizes="60x60" rel="apple-touch-icon"/>
<link href="/static/img/favicons/apple-touch-icon-72x72.png" sizes="72x72" rel="apple-touch-icon"/>
<link href="/static/img/favicons/apple-touch-icon-76x76.png" sizes="76x76" rel="apple-touch-icon"/>
<link href="/static/img/favicons/apple-touch-icon-114x114.png" sizes="114x114" rel="apple-touch-icon"/>
<link href="/static/img/favicons/apple-touch-icon-120x120.png" sizes="120x120" rel="apple-touch-icon"/>
<link href="/static/img/favicons/apple-touch-icon-144x144.png" sizes="144x144" rel="apple-touch-icon"/>
<link href="/static/img/favicons/apple-touch-icon-152x152.png" sizes="152x152" rel="apple-touch-icon"/>
<link href="/static/img/favicons/apple-touch-icon-180x180.png" sizes="180x180" rel="apple-touch-icon"/>
<link type="image/png" href="/static/img/favicons/favicon-32x32.png" sizes="32x32" rel="icon"/>
<link type="image/png" href="/static/img/favicons/favicon-16x16.png" sizes="16x16" rel="icon"/>
<link type="image/x-icon" href="/static/img/favicons/favicon.ico" rel="shortcut icon"/>
<link rel="mask-icon" href="/static/img/favicons/safari-pinned-tab.svg" color="#000000"/>
<meta name="msapplication-TileColor" content="#ffffff">
<meta name="msapplication-TileImage" content="/static/img/favicons/mstile-144x144.png">
<meta name="theme-color" content="#FFFFFF"/>
<link rel="manifest" href="/manifest.json" crossorigin="use-credentials">
<meta name="sw" content="https://otus.ru/static/js/service-worker.8ed2b.js"/>
<meta name="csrf" id="meta-csrf" content="ZIfZ8joK9HE52VNXgIHlgScQsoeumcxOIPvRlRpT4Ovcd2wQ9nDHrj5NelH97Lt9"/>
<meta name="auth" content="false"/>
<meta name="phone_confirmed" content="false"/>
<meta name="next" content='{"value": "/nest/post/1389/"}'/>
<link href="https://otus.ru/static/css/vendor.react.dd7f4.css" rel="stylesheet" />
<link href="https://otus.ru/static/css/vendor.common.5ac2f.css" rel="stylesheet" />
<link href="https://otus.ru/static/css/otus-react:header-search.37c7a.css" rel="stylesheet" />
<link href="https://otus.ru/static/css/fonts.211eb.css" rel="stylesheet" />
<link href="https://otus.ru/static/css/otus-icons.e3e2d.css" rel="stylesheet" />
<link href="https://otus.ru/static/css/vendor.common.5ac2f.css" rel="stylesheet" />
<link href="https://otus.ru/static/css/vendor.otus-scss.59b5e.css" rel="stylesheet" />
<link href="https://otus.ru/static/css/otus-scss.2de41.css" rel="stylesheet" />
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Organization",
"name": "Otus",
"url": "https://otus.ru",
"logo": "https://otus.ru/__new_static__/img/meta-image.png",
"sameAs": [
"https://vk.com/otusru",
"https://t.me/Otusjava"
]
}
</script>
</head>
<body class=" body-header3">
<script type="application/ld+json">
{
"@context" : "http://schema.org",
"@type" : "Organization",
"name" : "OTUS",
"url" : "https://otus.ru",
"logo": "https://otus.ru/static/img/favicons/apple-touch-icon-180x180.png",
"sameAs": [
"",
"https://www.youtube.com/channel/UCetgtvy93o3i3CvyGXKFU3g",
"https://www.instagram.com/otus.ru/"
],
"contactPoint": [
{
"@type": "ContactPoint",
"telephone": "+7-499-938-92-02",
"contactType": "customer service",
"areaServed": "RU"
}
]
}
</script>
<!-- TODO FIXME DRY -->>
<script
src="https://smartcaptcha.yandexcloud.net/captcha.js?render=onload&onload=smartCaptchaInit"
defer
></script>
<script>
function smartCaptchaInit() {
const sitekey = 'ysc1_cM9ClhSx0kwuG9QxSMfFmxHnC1gsW7Axbyddkmzref6982c0';
const test = false;
if (!window.smartCaptcha || !sitekey) {
return;
}
const widgetId = window.smartCaptcha.render('captcha-container', {
sitekey,
invisible: true,
test,
hideShield: true,
});
}
</script>
<div id="captcha-container"></div>
<script src="https://otus.ru/js-18n"></script>
<script>
window.texts = {
companyEmail: "help@otus.ru",
separateQuestionCount: " из "
}
window.language = 'ru-ru'
window.config = {
isEnablePhoneConfirm: true
}
</script>
<script src="https://otus.ru/js-18n"></script>
<script>
window.texts = {
companyEmail: "help@otus.ru",
separateQuestionCount: " из "
}
window.language = 'ru-ru'
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BlogPosting",
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https://otus.ru/nest/post/1389/"
},
"headline": "Пишем сервис на Go для Kubernetes",
"image": "",
"author": {
"@type": "Person",
"name": "Елена Граховац",
"url": "https://otus.ru/profile/67150/"
},
"publisher": {
"@type": "Organization",
"name": "OTUS",
"logo": {
"@type": "ImageObject",
"url": "https://otus.ru/static/img/favicons/apple-touch-icon-180x180.png"
}
},
"datePublished": "2020-05-06T15:11:17.938283+03:00",
"dateModified": "2023-12-18T18:17:38.469953+03:00"
}
</script>
<div class="body-wrapper">
<div class="body body_header3 drawer body_not-subscribed drawer--right blog-drawer ">
<div class="before-header-ui">
<div class="before-header-ui__ellipse1"></div>
<div class="before-header-ui__ellipse2"></div>
<div class="before-header-ui__container">
<div class="before-header-ui__img before-header-ui__img_sales"></div>
<div class="before-header-ui__content">
<div class="before-header-ui__title hide-phone">Курсы по нейросетям со скидкой до 30%</div>
<div class="before-header-ui__title show-phone">Курсы по нейросетям со скидкой до 30%</div>
</div>
<a href="https://otus.ru/catalog/courses?categories=neural_networks&utm_source=internal&utm_medium=free&utm_campaign=otus&utm_term=chank&utm_content=sla_sale_20-02-2026-10-04-2026" rel="nofollow noreferrer noopener" target="_blank" class="before-header-ui__button">Выбрать курс</a>
</div>
</div>
<header class="header3 js-header3">
<div class="header3__container">
<a class="header3__logo" href="/">
<img
class="header3__logo-img"
src="/static/img/logos/logo-2022-without-text.svg"
width="82"
height="42"
alt="Logo"
/>
</a>
<nav class="header3__nav">
<div id="headerSearch" class="header3__nav-item header3__nav-item-search">
<div class="header-search-icon">
<svg
class="header-search-icon__icon"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle
cx="11.767"
cy="11.767"
r="8.989"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
></circle>
<path
d="M18.018 18.485 21.542 22"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
></path>
</svg>
</div>
</div>
<div data-name="learning" class="header3__nav-item js-header3-popup-trigger header3__nav-item_only-desktop header3__nav-item_with-hover " >
<span title="Обучение" class="header3__nav-item-arrow-title">Обучение</span>
<div class="header3__nav-item-arrow-container js-header3-popup-arrow">
<svg
width="10"
height="5"
viewBox="0 0 10 5"
fill="none"
xmlns="http://www.w3.org/2000/svg"
class="header3__nav-item-arrow"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M1.10067 0.378818C1.29593 0.183556 1.61251 0.183555 1.80778 0.378818L5.00023 3.57127L8.19272 0.378777C8.38798 0.183515 8.70457 0.183515 8.89983 0.378777C9.09509 0.574039 9.09509 0.890622 8.89983 1.08588L5.3643 4.62142C5.26426 4.72146 5.13237 4.77024 5.00127 4.76777C4.8695 4.77079 4.73676 4.72202 4.6362 4.62146L1.10067 1.08592C0.905408 0.890663 0.905408 0.57408 1.10067 0.378818Z"
fill="currentColor"
></path>
</svg>
</div>
</div>
<div class="header3__nav-item-popup-wrapper js-header3-popup" data-name="learning" style="display: none;">
<div class="header3__nav-item-popup-container js-header3-popup-container">
<div class="header3__nav-item-popup-content">
<div class="header3__nav-column">
<div>
<p class="header3__nav-section-title ">Направления</p>
<div class="header3__nav-section-items header3__nav-section-items_learning header3__nav-section-items_learning_rows-8">
<a
class="header3__nav-section-item"
href="/categories/programming/"
>
Программирование (117)
</a>
<a
class="header3__nav-section-item"
href="/categories/architecture/"
>
Архитектура (17)
</a>
<a
class="header3__nav-section-item"
href="/categories/data-science/"
>
Data Science (27)
</a>
<a
class="header3__nav-section-item"
href="/categories/operations/"
>
Инфраструктура (58)
</a>
<a
class="header3__nav-section-item"
href="/categories/gamedev/"
>
GameDev (10)
</a>
<a
class="header3__nav-section-item"
href="/categories/information-security-courses/"
>
Безопасность (15)
</a>
<a
class="header3__nav-section-item"
href="/categories/marketing-business/"
>
Управление (46)
</a>
<a
class="header3__nav-section-item"
href="/categories/analytics/"
>
Аналитика и анализ (25)
</a>
<a
class="header3__nav-section-item"
href="/categories/business-product/"
>
Бизнес и продукт в IT (26)
</a>
<a
class="header3__nav-section-item"
href="/categories/import-substitution/"
>
Импортозамещение (15)
</a>
<a
class="header3__nav-section-item"
href="/categories/testing/"
>
Тестирование (12)
</a>
<a
class="header3__nav-section-item"
href="/categories/neural_networks/"
>
Нейросети (9)
</a>
<a
class="header3__nav-section-item"
href="/categories/it-bez-programmirovanija/"
>
IT без программирования (19)
</a>
<a
class="header3__nav-section-item"
href="/categories/corporate/"
>
Корпоративные курсы (27)
</a>
</div>
</div>
</div>
<div class="header3__nav-column">
<div>
<p class="header3__nav-section-title ">События</p>
<div class="header3__nav-section-items ">
<a
class="header3__nav-section-item"
href="/lessons/calendar/2026/"
>
Календарь запуска курсов
</a>
<a
class="header3__nav-section-item"
href="/events/near/"
>
Календарь мероприятий
</a>
</div>
</div>
<div>
<p class="header3__nav-section-title ">Другое</p>
<div class="header3__nav-section-items ">
<a
class="header3__nav-section-item"
href="/categories/spec/"
>
Специализации (13)
</a>
<a
class="header3__nav-section-item"
href="/categories/online/"
>
Подготовительные курсы (14)
</a>
<a
class="header3__nav-section-item header3__nav-section-item_bold"
href="/subscription"
>
Подписка на курсы
</a>
<a
class="header3__nav-section-item"
href="/tests"
>
Проверьте свои знания
</a>
</div>
</div>
</div>
<div class="header3__nav-column">
<div>
<p class="header3__nav-section-title header3__nav-section-items-recommendation-title">OTUS рекомендует</p>
<div class="header3__nav-section-items header3__nav-section-items_not-items header3__nav-section-items-recommendation">
<a
href="/lessons/ai-dlya-analitiki-i-raboty-s-dannymi/"
class="header3__card-recommendation"
>
<div
class="header3__card-recommendation-background"
style="background: linear-gradient( 90deg,#0A4489, #00316B);"
></div>
<div class="header3__card-recommendation-header">
<div class="header3__card-recommendation-header-photo-wrapper" style="background: linear-gradient( 90deg,#0A4489, #00316B);">
<img
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODAiIGhlaWdodD0iODAiIHZpZXdCb3g9IjAgMCA4MCA4MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoCiAgICAgICAgZD0iTTM1LjAwNDcgNDUuODcyNUMzNS4wMDQ3IDQ2LjkzMDYgMzYuMTA5IDQ3LjU3NTcgMzYuOTYwMyA0Ny4wMTQ5TDQ0LjYyOTIgNDEuOTYzMUM0NS4wMDI5IDQxLjcxNjkgNDUuMjI5OSA0MS4yODUyIDQ1LjIyOTkgNDAuODIwN1YyNi43NDg5QzQ1LjIyOTkgMjYuNzQ4OSA0Ny43ODYyIDI2Ljc0ODkgNTQuMTc3IDIyLjcwNzRDNTcuMzAxMiAyMC43MzE4IDU4Ljg5OCAxOC43NTYxIDU5LjcxNDMgMTcuMjUyNUM2MC4yNDY1IDE2LjI3MjEgNTkuMjUxMSAxNS41NTg4IDU4LjI5NjUgMTYuMDcyM0M1NS4zMjkyIDE3LjY2ODQgNDkuMzkxOCAyMC4wMTMyIDQwLjExNzMgMjAuMDEzMkMzMC44NDI4IDIwLjAxMzIgMjQuOTA1NCAxNy42Njg0IDIxLjkzODEgMTYuMDcyM0MyMC45ODM1IDE1LjU1ODggMTkuOTg4MSAxNi4yNzIxIDIwLjUyMDMgMTcuMjUyNUMyMS4zMzY2IDE4Ljc1NjEgMjIuOTMzNCAyMC43MzE4IDI2LjA1NzcgMjIuNzA3NEMzMi40NDg0IDI2Ljc0ODkgMzUuMDA0NyAyNi43NDg5IDM1LjAwNDcgMjYuNzQ4OVY0NS44NzI1WiIKICAgICAgICBmaWxsPSJ3aGl0ZSIgLz4KICAgIDxlbGxpcHNlIGN4PSIyNi45NTM1IiBjeT0iMzUuNTUyNiIgcng9IjMuOTQ5MTQiIHJ5PSI0LjA4NTMyIiBmaWxsPSJ3aGl0ZSIgLz4KICAgIDxlbGxpcHNlIGN4PSI1My4yODEyIiBjeT0iMzUuNTUyNiIgcng9IjMuOTQ5MTQiIHJ5PSI0LjA4NTMyIiBmaWxsPSJ3aGl0ZSIgLz4KICAgIDxwYXRoCiAgICAgICAgZD0iTTI1LjYzNzIgNTkuNjM1QzI1LjYzNzIgNTguNzk2MSAyNi4yMjY2IDU4LjExNiAyNi45NTM2IDU4LjExNkMyNy42ODA2IDU4LjExNiAyOC4yNyA1OC43OTYxIDI4LjI3IDU5LjYzNVY2Mi4wNDRDMjguMjcgNjIuNDQ2OSAyOC4xMzEzIDYyLjgzMzMgMjcuODg0NCA2My4xMTgxQzI3LjM3MDMgNjMuNzExNCAyNi41MzY4IDYzLjcxMTQgMjYuMDIyOCA2My4xMTgxQzI1Ljc3NTkgNjIuODMzMyAyNS42MzcyIDYyLjQ0NjkgMjUuNjM3MiA2Mi4wNDRWNTkuNjM1WiIKICAgICAgICBmaWxsPSJ3aGl0ZSIgLz4KICAgIDxwYXRoCiAgICAgICAgZD0iTTQ0LjA2NjUgNTkuNjM1QzQ0LjA2NjUgNTguNzk2MSA0NC42NTU5IDU4LjExNiA0NS4zODI5IDU4LjExNkM0Ni4xMDk5IDU4LjExNiA0Ni42OTkzIDU4Ljc5NjEgNDYuNjk5MyA1OS42MzVWNjIuMDQ0QzQ2LjY5OTMgNjIuNDQ2OSA0Ni41NjA2IDYyLjgzMzMgNDYuMzEzOCA2My4xMTgxQzQ1Ljc5OTcgNjMuNzExNCA0NC45NjYyIDYzLjcxMTQgNDQuNDUyMSA2My4xMTgxQzQ0LjIwNTIgNjIuODMzMyA0NC4wNjY1IDYyLjQ0NjkgNDQuMDY2NSA2Mi4wNDRWNTkuNjM1WiIKICAgICAgICBmaWxsPSJ3aGl0ZSIgLz4KICAgIDxwYXRoCiAgICAgICAgZD0iTTI5LjU4NjQgNTkuNjM1QzI5LjU4NjQgNTguNzk2MSAzMC4xNzU3IDU4LjExNiAzMC45MDI3IDU4LjExNkMzMS42Mjk4IDU4LjExNiAzMi4yMTkxIDU4Ljc5NjEgMzIuMjE5MSA1OS42MzVWNjIuMDQ0QzMyLjIxOTEgNjIuNDQ2OSAzMi4wODA0IDYyLjgzMzMgMzEuODMzNiA2My4xMTgxQzMxLjMxOTUgNjMuNzExNCAzMC40ODYgNjMuNzExNCAyOS45NzE5IDYzLjExODFDMjkuNzI1IDYyLjgzMzMgMjkuNTg2NCA2Mi40NDY5IDI5LjU4NjQgNjIuMDQ0VjU5LjYzNVoiCiAgICAgICAgZmlsbD0id2hpdGUiIC8+CiAgICA8cGF0aAogICAgICAgIGQ9Ik00OC4wMTU3IDU5LjYzNUM0OC4wMTU3IDU4Ljc5NjEgNDguNjA1MSA1OC4xMTYgNDkuMzMyMSA1OC4xMTZDNTAuMDU5MSA1OC4xMTYgNTAuNjQ4NSA1OC43OTYxIDUwLjY0ODUgNTkuNjM1VjYyLjA0NEM1MC42NDg1IDYyLjQ0NjkgNTAuNTA5OCA2Mi44MzMzIDUwLjI2MjkgNjMuMTE4MUM0OS43NDg4IDYzLjcxMTQgNDguOTE1MyA2My43MTE0IDQ4LjQwMTIgNjMuMTE4MUM0OC4xNTQ0IDYyLjgzMzMgNDguMDE1NyA2Mi40NDY5IDQ4LjAxNTcgNjIuMDQ0VjU5LjYzNVoiCiAgICAgICAgZmlsbD0id2hpdGUiIC8+CiAgICA8cGF0aAogICAgICAgIGQ9Ik0zMy41MzU1IDU5LjYzNUMzMy41MzU1IDU4Ljc5NjEgMzQuMTI0OSA1OC4xMTYgMzQuODUxOSA1OC4xMTZDMzUuNTc4OSA1OC4xMTYgMzYuMTY4MyA1OC43OTYxIDM2LjE2ODMgNTkuNjM1VjYyLjA0NEMzNi4xNjgzIDYyLjQ0NjkgMzYuMDI5NiA2Mi44MzMzIDM1Ljc4MjcgNjMuMTE4MUMzNS4yNjg2IDYzLjcxMTQgMzQuNDM1MSA2My43MTE0IDMzLjkyMTEgNjMuMTE4MUMzMy42NzQyIDYyLjgzMzMgMzMuNTM1NSA2Mi40NDY5IDMzLjUzNTUgNjIuMDQ0VjU5LjYzNVoiCiAgICAgICAgZmlsbD0id2hpdGUiIC8+CiAgICA8cGF0aAogICAgICAgIGQ9Ik01MS45NjQ4IDU5LjYzNUM1MS45NjQ4IDU4Ljc5NjEgNTIuNTU0MiA1OC4xMTYgNTMuMjgxMiA1OC4xMTZDNTQuMDA4MiA1OC4xMTYgNTQuNTk3NiA1OC43OTYxIDU0LjU5NzYgNTkuNjM1VjYyLjA0NEM1NC41OTc2IDYyLjQ0NjkgNTQuNDU4OSA2Mi44MzMzIDU0LjIxMiA2My4xMTgxQzUzLjY5OCA2My43MTE0IDUyLjg2NDUgNjMuNzExNCA1Mi4zNTA0IDYzLjExODFDNTIuMTAzNSA2Mi44MzMzIDUxLjk2NDggNjIuNDQ2OSA1MS45NjQ4IDYyLjA0NFY1OS42MzVaIgogICAgICAgIGZpbGw9IndoaXRlIiAvPgo8L3N2Zz4="
class="header3__card-recommendation-header-photo header3__card-recommendation-header-photo_default"
/>
<img
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODAiIGhlaWdodD0iODAiIHZpZXdCb3g9IjAgMCA4MCA4MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxtYXNrIGlkPSJhIiBmaWxsPSIjZmZmIj4KICAgICAgICA8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIKICAgICAgICAgICAgZD0iTTAgMTJDMCA1LjM3MyA1LjM3MyAwIDEyIDBoNTZjNi42MjcgMCAxMiA1LjM3MyAxMiAxMnY1NmMwIDYuNjI3LTUuMzczIDEyLTEyIDEySDEyQzUuMzczIDgwIDAgNzQuNjI3IDAgNjhWMTJabTM1LjAwNSAzMy44NzNjMCAxLjA1OCAxLjEwNCAxLjcwMyAxLjk1NSAxLjE0Mmw3LjY3LTUuMDUyYy4zNzMtLjI0Ni42LS42NzguNi0xLjE0MlYyNi43NDlzMi41NTYgMCA4Ljk0Ny00LjA0MmMzLjEyNC0xLjk3NSA0LjcyMS0zLjk1MSA1LjUzNy01LjQ1NC41MzMtLjk4MS0uNDYzLTEuNjk0LTEuNDE3LTEuMTgtMi45NjggMS41OTUtOC45MDUgMy45NC0xOC4xOCAzLjk0LTkuMjc0IDAtMTUuMjEyLTIuMzQ1LTE4LjE3OS0zLjk0LS45NTQtLjUxNC0xLjk1LjE5OS0xLjQxOCAxLjE4LjgxNyAxLjUwMyAyLjQxMyAzLjQ3OSA1LjUzOCA1LjQ1NCA2LjM5IDQuMDQyIDguOTQ3IDQuMDQyIDguOTQ3IDQuMDQydjE5LjEyNFptLTguMDUxLTYuMjM1YzIuMTggMCAzLjk0OS0xLjgzIDMuOTQ5LTQuMDg1IDAtMi4yNTctMS43NjgtNC4wODYtMy45NS00LjA4Ni0yLjE4IDAtMy45NDkgMS44My0zLjk0OSA0LjA4NiAwIDIuMjU2IDEuNzY4IDQuMDg1IDMuOTUgNC4wODVabTMwLjI3Ni00LjA4NWMwIDIuMjU2LTEuNzY4IDQuMDg1LTMuOTQ5IDQuMDg1LTIuMTggMC0zLjk0OS0xLjgzLTMuOTQ5LTQuMDg1IDAtMi4yNTcgMS43NjgtNC4wODYgMy45NS00LjA4NiAyLjE4IDAgMy45NDggMS44MyAzLjk0OCA0LjA4NlpNMjYuOTU0IDU4LjExNmMtLjcyNyAwLTEuMzE3LjY4LTEuMzE3IDEuNTE5djIuNDA5YzAgLjQwMy4xMzkuNzkuMzg2IDEuMDc0LjUxNC41OTMgMS4zNDcuNTkzIDEuODYxIDAgLjI0Ny0uMjg1LjM4Ni0uNjcxLjM4Ni0xLjA3NHYtMi40MDljMC0uODM5LS41OS0xLjUxOS0xLjMxNy0xLjUxOVptMTguNDI5IDBjLS43MjcgMC0xLjMxNy42OC0xLjMxNyAxLjUxOXYyLjQwOWMwIC40MDMuMTQuNzkuMzg2IDEuMDc0LjUxNC41OTMgMS4zNDguNTkzIDEuODYyIDAgLjI0Ny0uMjg1LjM4NS0uNjcxLjM4NS0xLjA3NHYtMi40MDljMC0uODM5LS41OS0xLjUxOS0xLjMxNi0xLjUxOVptLTE1Ljc5NyAxLjUxOWMwLS44MzkuNTktMS41MTkgMS4zMTctMS41MTlzMS4zMTYuNjggMS4zMTYgMS41MTl2Mi40MDljMCAuNDAzLS4xMzkuNzktLjM4NiAxLjA3NC0uNTE0LjU5My0xLjM0Ny41OTMtMS44NjEgMGExLjY0NSAxLjY0NSAwIDAgMS0uMzg2LTEuMDc0di0yLjQwOVptMTkuNzQ2LTEuNTE5Yy0uNzI3IDAtMS4zMTYuNjgtMS4zMTYgMS41MTl2Mi40MDljMCAuNDAzLjEzOC43OS4zODUgMS4wNzQuNTE0LjU5MyAxLjM0OC41OTMgMS44NjIgMCAuMjQ3LS4yODUuMzg1LS42NzEuMzg1LTEuMDc0di0yLjQwOWMwLS44MzktLjU4OS0xLjUxOS0xLjMxNi0xLjUxOVptLTE1Ljc5NyAxLjUxOWMwLS44MzkuNTktMS41MTkgMS4zMTctMS41MTlzMS4zMTYuNjggMS4zMTYgMS41MTl2Mi40MDljMCAuNDAzLS4xMzkuNzktLjM4NSAxLjA3NC0uNTE0LjU5My0xLjM0OC41OTMtMS44NjIgMGExLjY0NSAxLjY0NSAwIDAgMS0uMzg2LTEuMDc0di0yLjQwOVptMTkuNzQ2LTEuNTE5Yy0uNzI3IDAtMS4zMTYuNjgtMS4zMTYgMS41MTl2Mi40MDljMCAuNDAzLjEzOC43OS4zODUgMS4wNzQuNTE0LjU5MyAxLjM0OC41OTMgMS44NjIgMCAuMjQ3LS4yODUuMzg2LS42NzEuMzg2LTEuMDc0di0yLjQwOWMwLS44MzktLjU5LTEuNTE5LTEuMzE3LTEuNTE5WiIgLz4KICAgIDwvbWFzaz4KICAgIDxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIgogICAgICAgIGQ9Ik0wIDEyQzAgNS4zNzMgNS4zNzMgMCAxMiAwaDU2YzYuNjI3IDAgMTIgNS4zNzMgMTIgMTJ2NTZjMCA2LjYyNy01LjM3MyAxMi0xMiAxMkgxMkM1LjM3MyA4MCAwIDc0LjYyNyAwIDY4VjEyWm0zNS4wMDUgMzMuODczYzAgMS4wNTggMS4xMDQgMS43MDMgMS45NTUgMS4xNDJsNy42Ny01LjA1MmMuMzczLS4yNDYuNi0uNjc4LjYtMS4xNDJWMjYuNzQ5czIuNTU2IDAgOC45NDctNC4wNDJjMy4xMjQtMS45NzUgNC43MjEtMy45NTEgNS41MzctNS40NTQuNTMzLS45ODEtLjQ2My0xLjY5NC0xLjQxNy0xLjE4LTIuOTY4IDEuNTk1LTguOTA1IDMuOTQtMTguMTggMy45NC05LjI3NCAwLTE1LjIxMi0yLjM0NS0xOC4xNzktMy45NC0uOTU0LS41MTQtMS45NS4xOTktMS40MTggMS4xOC44MTcgMS41MDMgMi40MTMgMy40NzkgNS41MzggNS40NTQgNi4zOSA0LjA0MiA4Ljk0NyA0LjA0MiA4Ljk0NyA0LjA0MnYxOS4xMjRabS04LjA1MS02LjIzNWMyLjE4IDAgMy45NDktMS44MyAzLjk0OS00LjA4NSAwLTIuMjU3LTEuNzY4LTQuMDg2LTMuOTUtNC4wODYtMi4xOCAwLTMuOTQ5IDEuODMtMy45NDkgNC4wODYgMCAyLjI1NiAxLjc2OCA0LjA4NSAzLjk1IDQuMDg1Wm0zMC4yNzYtNC4wODVjMCAyLjI1Ni0xLjc2OCA0LjA4NS0zLjk0OSA0LjA4NS0yLjE4IDAtMy45NDktMS44My0zLjk0OS00LjA4NSAwLTIuMjU3IDEuNzY4LTQuMDg2IDMuOTUtNC4wODYgMi4xOCAwIDMuOTQ4IDEuODMgMy45NDggNC4wODZaTTI2Ljk1NCA1OC4xMTZjLS43MjcgMC0xLjMxNy42OC0xLjMxNyAxLjUxOXYyLjQwOWMwIC40MDMuMTM5Ljc5LjM4NiAxLjA3NC41MTQuNTkzIDEuMzQ3LjU5MyAxLjg2MSAwIC4yNDctLjI4NS4zODYtLjY3MS4zODYtMS4wNzR2LTIuNDA5YzAtLjgzOS0uNTktMS41MTktMS4zMTctMS41MTlabTE4LjQyOSAwYy0uNzI3IDAtMS4zMTcuNjgtMS4zMTcgMS41MTl2Mi40MDljMCAuNDAzLjE0Ljc5LjM4NiAxLjA3NC41MTQuNTkzIDEuMzQ4LjU5MyAxLjg2MiAwIC4yNDctLjI4NS4zODUtLjY3MS4zODUtMS4wNzR2LTIuNDA5YzAtLjgzOS0uNTktMS41MTktMS4zMTYtMS41MTlabS0xNS43OTcgMS41MTljMC0uODM5LjU5LTEuNTE5IDEuMzE3LTEuNTE5czEuMzE2LjY4IDEuMzE2IDEuNTE5djIuNDA5YzAgLjQwMy0uMTM5Ljc5LS4zODYgMS4wNzQtLjUxNC41OTMtMS4zNDcuNTkzLTEuODYxIDBhMS42NDUgMS42NDUgMCAwIDEtLjM4Ni0xLjA3NHYtMi40MDlabTE5Ljc0Ni0xLjUxOWMtLjcyNyAwLTEuMzE2LjY4LTEuMzE2IDEuNTE5djIuNDA5YzAgLjQwMy4xMzguNzkuMzg1IDEuMDc0LjUxNC41OTMgMS4zNDguNTkzIDEuODYyIDAgLjI0Ny0uMjg1LjM4NS0uNjcxLjM4NS0xLjA3NHYtMi40MDljMC0uODM5LS41ODktMS41MTktMS4zMTYtMS41MTlabS0xNS43OTcgMS41MTljMC0uODM5LjU5LTEuNTE5IDEuMzE3LTEuNTE5czEuMzE2LjY4IDEuMzE2IDEuNTE5djIuNDA5YzAgLjQwMy0uMTM5Ljc5LS4zODUgMS4wNzQtLjUxNC41OTMtMS4zNDguNTkzLTEuODYyIDBhMS42NDUgMS42NDUgMCAwIDEtLjM4Ni0xLjA3NHYtMi40MDlabTE5Ljc0Ni0xLjUxOWMtLjcyNyAwLTEuMzE2LjY4LTEuMzE2IDEuNTE5djIuNDA5YzAgLjQwMy4xMzguNzkuMzg1IDEuMDc0LjUxNC41OTMgMS4zNDguNTkzIDEuODYyIDAgLjI0Ny0uMjg1LjM4Ni0uNjcxLjM4Ni0xLjA3NHYtMi40MDljMC0uODM5LS41OS0xLjUxOS0xLjMxNy0xLjUxOVoiCiAgICAgICAgZmlsbD0iI2ZmZiIgLz4KICAgIDxwYXRoCiAgICAgICAgZD0ibTM2Ljk2IDQ3LjAxNSAxLjEgMS42Ny0xLjEtMS42N1ptNy42Ny01LjA1MiAxLjEgMS42Ny0xLjEtMS42N1ptLjYtMTUuMjE0di0yaC0ydjJoMlptOC45NDctNC4wNDIgMS4wNjkgMS42OS0xLjA2OS0xLjY5Wm01LjUzNy01LjQ1NCAxLjc1OC45NTQtMS43NTgtLjk1NFptLTEuNDE3LTEuMTguOTQ3IDEuNzYtLjk0Ny0xLjc2Wm0tMzYuMzU5IDAtLjk0NyAxLjc2Ljk0Ny0xLjc2Wm0tMS40MTggMS4xOCAxLjc1OC0uOTU1LTEuNzU4Ljk1NVptNS41MzggNS40NTQtMS4wNyAxLjY5IDEuMDctMS42OVptOC45NDcgNC4wNDJoMnYtMmgtMnYyWm0tOC45ODIgMzYuMzcgMS41MTEtMS4zMS0xLjUxMSAxLjMxWm0xLjg2MSAwIDEuNTEyIDEuMzA5LTEuNTEyLTEuMzFabTE2LjU2OCAwLTEuNTExIDEuMzA5IDEuNTExLTEuMzFabTEuODYyIDAgMS41MTEgMS4zMDktMS41MTEtMS4zMVptLTE0LjQ4IDAtMS41MTItMS4zMSAxLjUxMiAxLjMxWm0tMS44NjIgMCAxLjUxMS0xLjMxLTEuNTExIDEuMzFabTE4LjQzIDAtMS41MTIgMS4zMDkgMS41MTEtMS4zMVptMS44NiAwIDEuNTEyIDEuMzA5LTEuNTExLTEuMzFabS0xNC40OCAwIDEuNTEyIDEuMzA5LTEuNTExLTEuMzFabS0xLjg2MSAwLTEuNTExIDEuMzA5IDEuNTExLTEuMzFabTE4LjQzIDAgMS41MS0xLjMxLTEuNTEgMS4zMVptMS44NjEgMCAxLjUxMSAxLjMwOS0xLjUxMS0xLjMxWk0xMi0yQzQuMjY4LTItMiA0LjI2OC0yIDEyaDRDMiA2LjQ3NyA2LjQ3NyAyIDEyIDJ2LTRabTU2IDBIMTJ2NGg1NnYtNFptMTQgMTRjMC03LjczMi02LjI2OC0xNC0xNC0xNHY0YzUuNTIzIDAgMTAgNC40NzcgMTAgMTBoNFptMCA1NlYxMmgtNHY1Nmg0Wk02OCA4MmM3LjczMiAwIDE0LTYuMjY4IDE0LTE0aC00YzAgNS41MjMtNC40NzcgMTAtMTAgMTB2NFptLTU2IDBoNTZ2LTRIMTJ2NFpNLTIgNjhjMCA3LjczMiA2LjI2OCAxNCAxNCAxNHYtNEM2LjQ3NyA3OCAyIDczLjUyMyAyIDY4aC00Wm0wLTU2djU2aDRWMTJoLTRabTM3Ljg2IDMzLjM0NWEuNzkxLjc5MSAwIDAgMSAuODEyLS4wMjEuNjU2LjY1NiAwIDAgMSAuMzMzLjU0OWgtNGMwIDIuNDU0IDIuNzE0IDQuMzU1IDUuMDU1IDIuODEybC0yLjItMy4zNFptNy42NjktNS4wNTItNy42NjkgNS4wNTIgMi4yIDMuMzQgNy42Ny01LjA1Mi0yLjIwMS0zLjM0Wm0tLjI5OS41MjhjMC0uMTc4LjA4Ni0uMzg4LjI5OS0uNTI4bDIuMiAzLjM0YTMuMzY1IDMuMzY1IDAgMCAwIDEuNTAxLTIuODEyaC00Wm0wLTE0LjA3MlY0MC44Mmg0VjI2Ljc0OWgtNFptOS44NzgtNS43MzJjLTMuMDk3IDEuOTU5LTUuMTk3IDIuODk1LTYuNDY0IDMuMzRhOC44NDUgOC44NDUgMCAwIDEtMS4yOC4zNjIgMi40MiAyLjQyIDAgMCAxLS4yMDMuMDMxSDQ1LjE5bC4wMTgtLjAwMWguMDJjLjAwMSAwIC4wMDMgMCAuMDAzIDJzLjAwMiAyIC4wMDMgMmguMDU0YTMuMTk2IDMuMTk2IDAgMCAwIC4yNTYtLjAxN2MuMTQ0LS4wMTQuMzI3LS4wMzguNTUyLS4wOC40NS0uMDg0IDEuMDY5LS4yMzggMS44NzUtLjUyMSAxLjYxLS41NjYgMy45ODItMS42NSA3LjI3Ni0zLjczM2wtMi4xMzgtMy4zODFabTQuODQ5LTQuNzE5Yy0uNjM3IDEuMTczLTEuOTgzIDIuOTA2LTQuODQ5IDQuNzE5bDIuMTM4IDMuMzhjMy4zODItMi4xMzggNS4yMy00LjM1NiA2LjIyNi02LjE5bC0zLjUxNS0xLjkwOVptMS4yODcgMS41MzZjLS4xMDYuMDU2LS40OTQuMTczLS45MTYtLjE1OGExLjIzMyAxLjIzMyAwIDAgMS0uNDQ4LS43Ni45ODUuOTg1IDAgMCAxIC4wNzctLjYxOGwzLjUxNSAxLjkwOWMuMzA4LS41NjguNDcyLTEuMjQ4LjM1MS0xLjk2YTIuNzY4IDIuNzY4IDAgMCAwLTEuMDI1LTEuNzE4Yy0xLjAyNi0uODA1LTIuMzg4LS43ODgtMy40NDktLjIxOGwxLjg5NSAzLjUyM1ptLTE5LjEyNyA0LjE4YzkuNjI4IDAgMTUuODg5LTIuNDM4IDE5LjEyNy00LjE4bC0xLjg5NS0zLjUyM2MtMi42OTYgMS40NS04LjMxIDMuNzAyLTE3LjIzMiAzLjcwMnY0Wm0tMTkuMTI2LTQuMThjMy4yMzggMS43NDIgOS40OTkgNC4xOCAxOS4xMjYgNC4xOHYtNGMtOC45MjEgMC0xNC41MzUtMi4yNTMtMTcuMjMxLTMuNzAzbC0xLjg5NSAzLjUyM1ptMS4yODctMS41MzZjLjA0Mi4wNzguMTMxLjMuMDc3LjYxOWExLjIzMiAxLjIzMiAwIDAgMS0uNDQ5Ljc1OWMtLjQyMi4zMy0uODEuMjE1LS45MTUuMTU4bDEuODk1LTMuNTIzYy0xLjA2LS41Ny0yLjQyNC0uNTg3LTMuNDQ5LjIxOGEyLjc2OCAyLjc2OCAwIDAgMC0xLjAyNiAxLjcxOWMtLjEyLjcxMS4wNDMgMS4zOTEuMzUyIDEuOTU5bDMuNTE1LTEuOTA5Wm00Ljg0OSA0LjcxOWMtMi44NjctMS44MTMtNC4yMTItMy41NDYtNC44NDktNC43MTlsLTMuNTE1IDEuOTA5Yy45OTUgMS44MzQgMi44NDQgNC4wNTIgNi4yMjYgNi4xOWwyLjEzOC0zLjM4Wm03Ljg3OCA1LjczMmMwLTIgLjAwMS0yIC4wMDMtMkgzNS4wNDdsLjAyNS4wMDFoLjAwMWEyLjQyIDIuNDIgMCAwIDEtLjIwMi0uMDMgOC44NTIgOC44NTIgMCAwIDEtMS4yOC0uMzYzYy0xLjI2Ny0uNDQ1LTMuMzY3LTEuMzgxLTYuNDY0LTMuMzRsLTIuMTM4IDMuMzhjMy4yOTMgMi4wODQgNS42NjYgMy4xNjggNy4yNzYgMy43MzQuODA2LjI4MyAxLjQyNS40MzcgMS44NzUuNTJhNi4zNTYgNi4zNTYgMCAwIDAgLjczNy4wOTVsLjA3MS4wMDJoLjA1NGMuMDAxIDAgLjAwMyAwIC4wMDMtMlptMiAxOS4xMjRWMjYuNzQ5aC00djE5LjEyNGg0Wm0tOC4xMDItMTAuMzJjMCAxLjIxNi0uOTM2IDIuMDg1LTEuOTUgMi4wODV2NGMzLjM1IDAgNS45NS0yLjc4OSA1Ljk1LTYuMDg1aC00Wm0tMS45NS0yLjA4NmMxLjAxNCAwIDEuOTUuODcgMS45NSAyLjA4Nmg0YzAtMy4yOTctMi42LTYuMDg2LTUuOTUtNi4wODZ2NFptLTEuOTQ5IDIuMDg2YzAtMS4yMTYuOTM2LTIuMDg2IDEuOTUtMi4wODZ2LTRjLTMuMzUgMC01Ljk1IDIuNzktNS45NSA2LjA4Nmg0Wm0xLjk1IDIuMDg1Yy0xLjAxNCAwLTEuOTUtLjg3LTEuOTUtMi4wODVoLTRjMCAzLjI5NiAyLjYgNi4wODUgNS45NSA2LjA4NXYtNFptMjYuMzI3IDRjMy4zNSAwIDUuOTUtMi43ODkgNS45NS02LjA4NWgtNGMwIDEuMjE2LS45MzcgMi4wODUtMS45NSAyLjA4NXY0Wm0tNS45NDktNi4wODVjMCAzLjI5NiAyLjYgNi4wODUgNS45NSA2LjA4NXYtNGMtMS4wMTQgMC0xLjk1LS44Ny0xLjk1LTIuMDg1aC00Wm01Ljk1LTYuMDg2Yy0zLjM1IDAtNS45NSAyLjc5LTUuOTUgNi4wODZoNGMwLTEuMjE2LjkzNi0yLjA4NiAxLjk1LTIuMDg2di00Wm01Ljk0OCA2LjA4NmMwLTMuMjk3LTIuNi02LjA4Ni01Ljk0OS02LjA4NnY0YzEuMDEzIDAgMS45NS44NyAxLjk1IDIuMDg2aDRaTTI3LjYzNyA1OS42MzVhLjM3LjM3IDAgMCAxLS4xMDMuMjM2Ljc3NC43NzQgMCAwIDEtLjU4LjI0NXYtNGMtMi4wOTEgMC0zLjMxNyAxLjg1NC0zLjMxNyAzLjUxOWg0Wm0wIDIuNDA5di0yLjQwOWgtNHYyLjQwOWg0Wm0tLjEwMy0uMjM2YS40NS40NSAwIDAgMSAuMDg2LjE0Mi4yNzcuMjc3IDAgMCAxIC4wMTcuMDk0aC00YzAgLjg0OC4yOSAxLjcxLjg3NCAyLjM4NGwzLjAyMy0yLjYyWm0tMS4xNjEgMGEuNzc2Ljc3NiAwIDAgMSAuNTgtLjI0NWMuMjcgMCAuNDc2LjEyNC41ODEuMjQ1bC0zLjAyMyAyLjYyYzEuMzEyIDEuNTEzIDMuNTczIDEuNTEzIDQuODg1IDBsLTMuMDIzLTIuNjJabS0uMTAzLjIzNmMwLS4wMjcuMDA0LS4wNTguMDE3LS4wOTRhLjQ1LjQ1IDAgMCAxIC4wODYtLjE0MmwzLjAyMyAyLjYyYTMuNjQ0IDMuNjQ0IDAgMCAwIC44NzQtMi4zODRoLTRabTAtMi40MDl2Mi40MDloNHYtMi40MDloLTRabS42ODMuNDgxYy0uMjkgMC0uNDktLjE0LS41OC0uMjQ1YS4zNy4zNyAwIDAgMS0uMTAzLS4yMzZoNGMwLTEuNjY1LTEuMjI2LTMuNTE5LTMuMzE3LTMuNTE5djRabTE5LjExMy0uNDgxYS4zNy4zNyAwIDAgMS0uMTAyLjIzNi43NzQuNzc0IDAgMCAxLS41ODEuMjQ1di00Yy0yLjA5MSAwLTMuMzE3IDEuODU0LTMuMzE3IDMuNTE5aDRabTAgMi40MDl2LTIuNDA5aC00djIuNDA5aDRabS0uMTAyLS4yMzZhLjQ1LjQ1IDAgMCAxIC4wODUuMTQyLjI3Ny4yNzcgMCAwIDEgLjAxNy4wOTRoLTRjMCAuODQ4LjI5IDEuNzEuODc1IDIuMzg0bDMuMDIzLTIuNjJabS0xLjE2MiAwYS43NzUuNzc1IDAgMCAxIC41OC0uMjQ1Yy4yNzEgMCAuNDc3LjEyNC41ODIuMjQ1bC0zLjAyMyAyLjYyYzEuMzExIDEuNTEzIDMuNTczIDEuNTEzIDQuODg0IDBsLTMuMDIzLTIuNjJabS0uMTAzLjIzNmMwLS4wMjcuMDA1LS4wNTguMDE4LS4wOTRhLjQ1LjQ1IDAgMCAxIC4wODUtLjE0MmwzLjAyMyAyLjYyYTMuNjQ1IDMuNjQ1IDAgMCAwIC44NzQtMi4zODRoLTRabTAtMi40MDl2Mi40MDloNHYtMi40MDloLTRabS42ODQuNDgxYy0uMjkgMC0uNDktLjE0LS41OC0uMjQ1YS4zNjkuMzY5IDAgMCAxLS4xMDQtLjIzNmg0YzAtMS42NjUtMS4yMjUtMy41MTktMy4zMTYtMy41MTl2NFptLTE0LjQ4LTRjLTIuMDkxIDAtMy4zMTcgMS44NTQtMy4zMTcgMy41MTloNGEuMzcuMzcgMCAwIDEtLjEwMy4yMzYuNzc0Ljc3NCAwIDAgMS0uNTguMjQ1di00Wm0zLjMxNiAzLjUxOWMwLTEuNjY1LTEuMjI1LTMuNTE5LTMuMzE2LTMuNTE5djRjLS4yOSAwLS40OS0uMTQtLjU4LS4yNDVhLjM3LjM3IDAgMCAxLS4xMDQtLjIzNmg0Wm0wIDIuNDA5di0yLjQwOWgtNHYyLjQwOWg0Wm0tLjg3NCAyLjM4NGEzLjY0NCAzLjY0NCAwIDAgMCAuODc0LTIuMzg0aC00YzAtLjAyNy4wMDUtLjA1OC4wMTctLjA5NGEuNDUuNDUgMCAwIDEgLjA4Ni0uMTQybDMuMDIzIDIuNjJabS00Ljg4NSAwYzEuMzEyIDEuNTEzIDMuNTczIDEuNTEzIDQuODg1IDBsLTMuMDIzLTIuNjJhLjc3NS43NzUgMCAwIDEgLjU4LS4yNDVjLjI3IDAgLjQ3Ni4xMjQuNTgxLjI0NWwtMy4wMjMgMi42MlptLS44NzQtMi4zODRjMCAuODQ4LjI5IDEuNzEuODc0IDIuMzg0bDMuMDIzLTIuNjJhLjQ1LjQ1IDAgMCAxIC4wODYuMTQyLjI3Ny4yNzcgMCAwIDEgLjAxNy4wOTRoLTRabTAtMi40MDl2Mi40MDloNHYtMi40MDloLTRabTIyLjQzIDBhLjM3LjM3IDAgMCAxLS4xMDMuMjM2Ljc3NC43NzQgMCAwIDEtLjU4MS4yNDV2LTRjLTIuMDkgMC0zLjMxNiAxLjg1NC0zLjMxNiAzLjUxOWg0Wm0wIDIuNDA5di0yLjQwOWgtNHYyLjQwOWg0Wm0tLjEwMy0uMjM2YS40NTMuNDUzIDAgMCAxIC4wODUuMTQyLjI3Ny4yNzcgMCAwIDEgLjAxOC4wOTRoLTRjMCAuODQ4LjI5IDEuNzEuODc0IDIuMzg0bDMuMDIzLTIuNjJabS0xLjE2MiAwYS43NzYuNzc2IDAgMCAxIC41ODEtLjI0NWMuMjcgMCAuNDc2LjEyNC41OC4yNDVsLTMuMDIyIDIuNjJjMS4zMTEgMS41MTMgMy41NzMgMS41MTMgNC44ODQgMGwtMy4wMjMtMi42MlptLS4xMDMuMjM2YzAtLjAyNy4wMDUtLjA1OC4wMTgtLjA5NGEuNDUuNDUgMCAwIDEgLjA4NS0uMTQybDMuMDIzIDIuNjJhMy42NDQgMy42NDQgMCAwIDAgLjg3NC0yLjM4NGgtNFptMC0yLjQwOXYyLjQwOWg0di0yLjQwOWgtNFptLjY4NC40ODFjLS4yOSAwLS40OS0uMTQtLjU4LS4yNDVhLjM3LjM3IDAgMCAxLS4xMDQtLjIzNmg0YzAtMS42NjUtMS4yMjUtMy41MTktMy4zMTYtMy41MTl2NFptLTE0LjQ4LTRjLTIuMDkxIDAtMy4zMTYgMS44NTQtMy4zMTYgMy41MTloNGEuMzcuMzcgMCAwIDEtLjEwNC4yMzYuNzc0Ljc3NCAwIDAgMS0uNTguMjQ1di00Wm0zLjMxNiAzLjUxOWMwLTEuNjY1LTEuMjI1LTMuNTE5LTMuMzE2LTMuNTE5djRjLS4yOSAwLS40OS0uMTQtLjU4LS4yNDVhLjM3LjM3IDAgMCAxLS4xMDQtLjIzNmg0Wm0wIDIuNDA5di0yLjQwOWgtNHYyLjQwOWg0Wm0tLjg3NCAyLjM4NGEzLjY0NCAzLjY0NCAwIDAgMCAuODc0LTIuMzg0aC00YzAtLjAyNy4wMDUtLjA1OC4wMTgtLjA5NGEuNDUuNDUgMCAwIDEgLjA4NS0uMTQybDMuMDIzIDIuNjJabS00Ljg4NCAwYzEuMzExIDEuNTEzIDMuNTczIDEuNTEzIDQuODg0IDBsLTMuMDIzLTIuNjJhLjc3Ni43NzYgMCAwIDEgLjU4LS4yNDVjLjI3MSAwIC40NzcuMTI0LjU4MS4yNDVsLTMuMDIyIDIuNjJabS0uODc0LTIuMzg0YzAgLjg0OC4yODkgMS43MS44NzQgMi4zODRsMy4wMjMtMi42MmEuNDUzLjQ1MyAwIDAgMSAuMDg1LjE0Mi4yNzcuMjc3IDAgMCAxIC4wMTcuMDk0aC00Wm0wLTIuNDA5djIuNDA5aDR2LTIuNDA5aC00Wm0yMi40MjkgMGEuMzcuMzcgMCAwIDEtLjEwMy4yMzYuNzc0Ljc3NCAwIDAgMS0uNTguMjQ1di00Yy0yLjA5MiAwLTMuMzE3IDEuODU0LTMuMzE3IDMuNTE5aDRabTAgMi40MDl2LTIuNDA5aC00djIuNDA5aDRabS0uMTAzLS4yMzZhLjQ1LjQ1IDAgMCAxIC4wODUuMTQyLjI3Ny4yNzcgMCAwIDEgLjAxOC4wOTRoLTRjMCAuODQ4LjI5IDEuNzEuODc0IDIuMzg0bDMuMDIzLTIuNjJabS0xLjE2MiAwYS43NzYuNzc2IDAgMCAxIC41ODEtLjI0NWMuMjcgMCAuNDc2LjEyNC41OC4yNDVsLTMuMDIyIDIuNjJjMS4zMTIgMS41MTMgMy41NzMgMS41MTMgNC44ODUgMGwtMy4wMjMtMi42MlptLS4xMDIuMjM2YzAtLjAyNy4wMDQtLjA1OC4wMTctLjA5NGEuNDU1LjQ1NSAwIDAgMSAuMDg1LS4xNDJsMy4wMjMgMi42MmEzLjY0NSAzLjY0NSAwIDAgMCAuODc1LTIuMzg0aC00Wm0wLTIuNDA5djIuNDA5aDR2LTIuNDA5aC00Wm0uNjgzLjQ4MWMtLjI5IDAtLjQ5LS4xNC0uNTgtLjI0NWEuMzcuMzcgMCAwIDEtLjEwMy0uMjM2aDRjMC0xLjY2NS0xLjIyNi0zLjUxOS0zLjMxNy0zLjUxOXY0WiIKICAgICAgICBmaWxsPSIjZmZmIiBtYXNrPSJ1cmwoI2EpIiAvPgo8L3N2Zz4="
class="header3__card-recommendation-header-photo header3__card-recommendation-header-photo_default_inverted"
/>
</div>
<div class="header3__card-recommendation-header-content">
<div class="header3__card-recommendation-header-content-tag">
Курс
</div>
<div class="header3__card-recommendation-header-sub">
<span
class="header3__card-recommendation-header-sub-chunk header3__card-recommendation-header-sub-chunk_green"
>
Скидка 20000 ₽
</span>
</div>
</div>
</div>
<h6 class="header3__card-recommendation-title">
AI для аналитики и работы с данными
</h6>
<div class="header3__card-recommendation-footer">
12 марта
, 2026
· 2 месяца
</div>
</a>
</div>
</div>
</div>
</div>
<svg
class="header3__nav-item-popup-figure"
viewBox="0 0 600 600"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M125.573 140.619C131.659 71.6017 210.245 34.9562 267.027 74.6573L553.942 275.262C610.723 314.962 603.117 401.233 540.247 430.55L222.58 578.681C159.71 607.997 88.7344 558.37 94.8204 489.355L125.573 140.619Z"
stroke="#eaeaea"
class="header3__nav-item-popup-figure-spinner"
></path>
<path
d="M148.472 246.647C133.624 191.005 184.615 140.013 240.257 154.862L519.856 229.476C575.498 244.325 594.059 313.877 553.266 354.67L348.281 559.656C307.488 600.449 237.935 581.888 223.087 526.246L148.472 246.647Z"
fill="url(#paint0_linear-learning)"
></path>
<defs>
<linearGradient
id="paint0_linear-learning"
x1="128.696"
y1="395.739"
x2="443.538"
y2="180.173"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#f9f9f9"></stop>
<stop offset="1" stop-color="#EBEBEB"></stop>
</linearGradient>
</defs>
</svg>
</div>
</div>
<div data-name="info" class="header3__nav-item js-header3-popup-trigger header3__nav-item_only-desktop header3__nav-item_with-hover " >
<span title="Информация" class="header3__nav-item-arrow-title">Информация</span>
<div class="header3__nav-item-arrow-container js-header3-popup-arrow">
<svg
width="10"
height="5"
viewBox="0 0 10 5"
fill="none"
xmlns="http://www.w3.org/2000/svg"
class="header3__nav-item-arrow"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M1.10067 0.378818C1.29593 0.183556 1.61251 0.183555 1.80778 0.378818L5.00023 3.57127L8.19272 0.378777C8.38798 0.183515 8.70457 0.183515 8.89983 0.378777C9.09509 0.574039 9.09509 0.890622 8.89983 1.08588L5.3643 4.62142C5.26426 4.72146 5.13237 4.77024 5.00127 4.76777C4.8695 4.77079 4.73676 4.72202 4.6362 4.62146L1.10067 1.08592C0.905408 0.890663 0.905408 0.57408 1.10067 0.378818Z"
fill="currentColor"
></path>
</svg>
</div>
</div>
<div class="header3__nav-item-popup-wrapper js-header3-popup" data-name="info" style="display: none;">
<div class="header3__nav-item-popup-container js-header3-popup-container">
<div class="header3__nav-item-popup-content">
<div class="header3__nav-column">
<div>
<p class="header3__nav-section-title ">OTUS</p>
<div class="header3__nav-section-items ">
<a
class="header3__nav-section-item"
href="/about"
>
О компании
</a>
<a
class="header3__nav-section-item"
href="/smi/"
>
СМИ о нас
</a>
<a
class="header3__nav-section-item js-stats"
href="/journal/"
target="_blank"
rel="noreferrer nofollow"
data-event="header;click_otus_journal"
data-goal="click_otus_journal"
>
OTUS Журнал
</a>
<a
class="header3__nav-section-item"
href="https://direct.otus.ru/"
target="_blank"
rel="noreferrer nofollow"
>
OTUS Директ
</a>
<a
class="header3__nav-section-item"
href="/legal/common/"
>
Сведения об образовательной организации
</a>
<a
class="header3__nav-section-item"
href="/contacts/"
>
Контактная информация
</a>
</div>
</div>
</div>
<div class="header3__nav-column">
<div>
<p class="header3__nav-section-title ">Студентам</p>
<div class="header3__nav-section-items ">
<a
class="header3__nav-section-item"
href="/reviews"
>
Отзывы
</a>
<a
class="header3__nav-section-item"
target="_blank"
href="https://landing.otus.ru/about-otus"
>
Как выбрать курс
</a>
<a
class="header3__nav-section-item"
target="_blank"
href="https://landing.otus.ru/gallery"
>
Истории выпускников
</a>
<a
class="header3__nav-section-item"
href="/instructors/"
>
Наши преподаватели
</a>
<a
class="header3__nav-section-item"
href="/employers/all/"
>
Наши партнеры
</a>
<a
class="header3__nav-section-item"
href="/about/loyalty/"
>
Программа лояльности
</a>
<a
class="header3__nav-section-item"
href="/faq/"
>
Вопросы и ответы
</a>
</div>
</div>
</div>
<div class="header3__nav-column">
<div>
<p class="header3__nav-section-title ">Преподавателям</p>
<div class="header3__nav-section-items ">
<a
class="header3__nav-section-item"
href="/teach/"
>
Стать преподавателем
</a>
<a
class="header3__nav-section-item"
href="/instructors/"
>
Наши преподаватели
</a>
<a
class="header3__nav-section-item"
href="/nest/dlja-prepodavatelej/"
>
База знаний
</a>
</div>
</div>
</div>
<div class="header3__nav-column header3__nav-column_space-between">
<div>
<p class="header3__nav-section-title header3__nav-section-items-recommendation-title">OTUS рекомендует</p>
<div class="header3__nav-section-items header3__nav-section-items_not-items header3__nav-section-items-recommendation">
<a
href="/lessons/ai-dlya-analitiki-i-raboty-s-dannymi/"
class="header3__card-recommendation"
>
<div
class="header3__card-recommendation-background"
style="background: linear-gradient( 90deg,#0A4489, #00316B);"
></div>
<div class="header3__card-recommendation-header">
<div class="header3__card-recommendation-header-photo-wrapper" style="background: linear-gradient( 90deg,#0A4489, #00316B);">
<img
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODAiIGhlaWdodD0iODAiIHZpZXdCb3g9IjAgMCA4MCA4MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoCiAgICAgICAgZD0iTTM1LjAwNDcgNDUuODcyNUMzNS4wMDQ3IDQ2LjkzMDYgMzYuMTA5IDQ3LjU3NTcgMzYuOTYwMyA0Ny4wMTQ5TDQ0LjYyOTIgNDEuOTYzMUM0NS4wMDI5IDQxLjcxNjkgNDUuMjI5OSA0MS4yODUyIDQ1LjIyOTkgNDAuODIwN1YyNi43NDg5QzQ1LjIyOTkgMjYuNzQ4OSA0Ny43ODYyIDI2Ljc0ODkgNTQuMTc3IDIyLjcwNzRDNTcuMzAxMiAyMC43MzE4IDU4Ljg5OCAxOC43NTYxIDU5LjcxNDMgMTcuMjUyNUM2MC4yNDY1IDE2LjI3MjEgNTkuMjUxMSAxNS41NTg4IDU4LjI5NjUgMTYuMDcyM0M1NS4zMjkyIDE3LjY2ODQgNDkuMzkxOCAyMC4wMTMyIDQwLjExNzMgMjAuMDEzMkMzMC44NDI4IDIwLjAxMzIgMjQuOTA1NCAxNy42Njg0IDIxLjkzODEgMTYuMDcyM0MyMC45ODM1IDE1LjU1ODggMTkuOTg4MSAxNi4yNzIxIDIwLjUyMDMgMTcuMjUyNUMyMS4zMzY2IDE4Ljc1NjEgMjIuOTMzNCAyMC43MzE4IDI2LjA1NzcgMjIuNzA3NEMzMi40NDg0IDI2Ljc0ODkgMzUuMDA0NyAyNi43NDg5IDM1LjAwNDcgMjYuNzQ4OVY0NS44NzI1WiIKICAgICAgICBmaWxsPSJ3aGl0ZSIgLz4KICAgIDxlbGxpcHNlIGN4PSIyNi45NTM1IiBjeT0iMzUuNTUyNiIgcng9IjMuOTQ5MTQiIHJ5PSI0LjA4NTMyIiBmaWxsPSJ3aGl0ZSIgLz4KICAgIDxlbGxpcHNlIGN4PSI1My4yODEyIiBjeT0iMzUuNTUyNiIgcng9IjMuOTQ5MTQiIHJ5PSI0LjA4NTMyIiBmaWxsPSJ3aGl0ZSIgLz4KICAgIDxwYXRoCiAgICAgICAgZD0iTTI1LjYzNzIgNTkuNjM1QzI1LjYzNzIgNTguNzk2MSAyNi4yMjY2IDU4LjExNiAyNi45NTM2IDU4LjExNkMyNy42ODA2IDU4LjExNiAyOC4yNyA1OC43OTYxIDI4LjI3IDU5LjYzNVY2Mi4wNDRDMjguMjcgNjIuNDQ2OSAyOC4xMzEzIDYyLjgzMzMgMjcuODg0NCA2My4xMTgxQzI3LjM3MDMgNjMuNzExNCAyNi41MzY4IDYzLjcxMTQgMjYuMDIyOCA2My4xMTgxQzI1Ljc3NTkgNjIuODMzMyAyNS42MzcyIDYyLjQ0NjkgMjUuNjM3MiA2Mi4wNDRWNTkuNjM1WiIKICAgICAgICBmaWxsPSJ3aGl0ZSIgLz4KICAgIDxwYXRoCiAgICAgICAgZD0iTTQ0LjA2NjUgNTkuNjM1QzQ0LjA2NjUgNTguNzk2MSA0NC42NTU5IDU4LjExNiA0NS4zODI5IDU4LjExNkM0Ni4xMDk5IDU4LjExNiA0Ni42OTkzIDU4Ljc5NjEgNDYuNjk5MyA1OS42MzVWNjIuMDQ0QzQ2LjY5OTMgNjIuNDQ2OSA0Ni41NjA2IDYyLjgzMzMgNDYuMzEzOCA2My4xMTgxQzQ1Ljc5OTcgNjMuNzExNCA0NC45NjYyIDYzLjcxMTQgNDQuNDUyMSA2My4xMTgxQzQ0LjIwNTIgNjIuODMzMyA0NC4wNjY1IDYyLjQ0NjkgNDQuMDY2NSA2Mi4wNDRWNTkuNjM1WiIKICAgICAgICBmaWxsPSJ3aGl0ZSIgLz4KICAgIDxwYXRoCiAgICAgICAgZD0iTTI5LjU4NjQgNTkuNjM1QzI5LjU4NjQgNTguNzk2MSAzMC4xNzU3IDU4LjExNiAzMC45MDI3IDU4LjExNkMzMS42Mjk4IDU4LjExNiAzMi4yMTkxIDU4Ljc5NjEgMzIuMjE5MSA1OS42MzVWNjIuMDQ0QzMyLjIxOTEgNjIuNDQ2OSAzMi4wODA0IDYyLjgzMzMgMzEuODMzNiA2My4xMTgxQzMxLjMxOTUgNjMuNzExNCAzMC40ODYgNjMuNzExNCAyOS45NzE5IDYzLjExODFDMjkuNzI1IDYyLjgzMzMgMjkuNTg2NCA2Mi40NDY5IDI5LjU4NjQgNjIuMDQ0VjU5LjYzNVoiCiAgICAgICAgZmlsbD0id2hpdGUiIC8+CiAgICA8cGF0aAogICAgICAgIGQ9Ik00OC4wMTU3IDU5LjYzNUM0OC4wMTU3IDU4Ljc5NjEgNDguNjA1MSA1OC4xMTYgNDkuMzMyMSA1OC4xMTZDNTAuMDU5MSA1OC4xMTYgNTAuNjQ4NSA1OC43OTYxIDUwLjY0ODUgNTkuNjM1VjYyLjA0NEM1MC42NDg1IDYyLjQ0NjkgNTAuNTA5OCA2Mi44MzMzIDUwLjI2MjkgNjMuMTE4MUM0OS43NDg4IDYzLjcxMTQgNDguOTE1MyA2My43MTE0IDQ4LjQwMTIgNjMuMTE4MUM0OC4xNTQ0IDYyLjgzMzMgNDguMDE1NyA2Mi40NDY5IDQ4LjAxNTcgNjIuMDQ0VjU5LjYzNVoiCiAgICAgICAgZmlsbD0id2hpdGUiIC8+CiAgICA8cGF0aAogICAgICAgIGQ9Ik0zMy41MzU1IDU5LjYzNUMzMy41MzU1IDU4Ljc5NjEgMzQuMTI0OSA1OC4xMTYgMzQuODUxOSA1OC4xMTZDMzUuNTc4OSA1OC4xMTYgMzYuMTY4MyA1OC43OTYxIDM2LjE2ODMgNTkuNjM1VjYyLjA0NEMzNi4xNjgzIDYyLjQ0NjkgMzYuMDI5NiA2Mi44MzMzIDM1Ljc4MjcgNjMuMTE4MUMzNS4yNjg2IDYzLjcxMTQgMzQuNDM1MSA2My43MTE0IDMzLjkyMTEgNjMuMTE4MUMzMy42NzQyIDYyLjgzMzMgMzMuNTM1NSA2Mi40NDY5IDMzLjUzNTUgNjIuMDQ0VjU5LjYzNVoiCiAgICAgICAgZmlsbD0id2hpdGUiIC8+CiAgICA8cGF0aAogICAgICAgIGQ9Ik01MS45NjQ4IDU5LjYzNUM1MS45NjQ4IDU4Ljc5NjEgNTIuNTU0MiA1OC4xMTYgNTMuMjgxMiA1OC4xMTZDNTQuMDA4MiA1OC4xMTYgNTQuNTk3NiA1OC43OTYxIDU0LjU5NzYgNTkuNjM1VjYyLjA0NEM1NC41OTc2IDYyLjQ0NjkgNTQuNDU4OSA2Mi44MzMzIDU0LjIxMiA2My4xMTgxQzUzLjY5OCA2My43MTE0IDUyLjg2NDUgNjMuNzExNCA1Mi4zNTA0IDYzLjExODFDNTIuMTAzNSA2Mi44MzMzIDUxLjk2NDggNjIuNDQ2OSA1MS45NjQ4IDYyLjA0NFY1OS42MzVaIgogICAgICAgIGZpbGw9IndoaXRlIiAvPgo8L3N2Zz4="
class="header3__card-recommendation-header-photo header3__card-recommendation-header-photo_default"
/>
<img
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODAiIGhlaWdodD0iODAiIHZpZXdCb3g9IjAgMCA4MCA4MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxtYXNrIGlkPSJhIiBmaWxsPSIjZmZmIj4KICAgICAgICA8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIKICAgICAgICAgICAgZD0iTTAgMTJDMCA1LjM3MyA1LjM3MyAwIDEyIDBoNTZjNi42MjcgMCAxMiA1LjM3MyAxMiAxMnY1NmMwIDYuNjI3LTUuMzczIDEyLTEyIDEySDEyQzUuMzczIDgwIDAgNzQuNjI3IDAgNjhWMTJabTM1LjAwNSAzMy44NzNjMCAxLjA1OCAxLjEwNCAxLjcwMyAxLjk1NSAxLjE0Mmw3LjY3LTUuMDUyYy4zNzMtLjI0Ni42LS42NzguNi0xLjE0MlYyNi43NDlzMi41NTYgMCA4Ljk0Ny00LjA0MmMzLjEyNC0xLjk3NSA0LjcyMS0zLjk1MSA1LjUzNy01LjQ1NC41MzMtLjk4MS0uNDYzLTEuNjk0LTEuNDE3LTEuMTgtMi45NjggMS41OTUtOC45MDUgMy45NC0xOC4xOCAzLjk0LTkuMjc0IDAtMTUuMjEyLTIuMzQ1LTE4LjE3OS0zLjk0LS45NTQtLjUxNC0xLjk1LjE5OS0xLjQxOCAxLjE4LjgxNyAxLjUwMyAyLjQxMyAzLjQ3OSA1LjUzOCA1LjQ1NCA2LjM5IDQuMDQyIDguOTQ3IDQuMDQyIDguOTQ3IDQuMDQydjE5LjEyNFptLTguMDUxLTYuMjM1YzIuMTggMCAzLjk0OS0xLjgzIDMuOTQ5LTQuMDg1IDAtMi4yNTctMS43NjgtNC4wODYtMy45NS00LjA4Ni0yLjE4IDAtMy45NDkgMS44My0zLjk0OSA0LjA4NiAwIDIuMjU2IDEuNzY4IDQuMDg1IDMuOTUgNC4wODVabTMwLjI3Ni00LjA4NWMwIDIuMjU2LTEuNzY4IDQuMDg1LTMuOTQ5IDQuMDg1LTIuMTggMC0zLjk0OS0xLjgzLTMuOTQ5LTQuMDg1IDAtMi4yNTcgMS43NjgtNC4wODYgMy45NS00LjA4NiAyLjE4IDAgMy45NDggMS44MyAzLjk0OCA0LjA4NlpNMjYuOTU0IDU4LjExNmMtLjcyNyAwLTEuMzE3LjY4LTEuMzE3IDEuNTE5djIuNDA5YzAgLjQwMy4xMzkuNzkuMzg2IDEuMDc0LjUxNC41OTMgMS4zNDcuNTkzIDEuODYxIDAgLjI0Ny0uMjg1LjM4Ni0uNjcxLjM4Ni0xLjA3NHYtMi40MDljMC0uODM5LS41OS0xLjUxOS0xLjMxNy0xLjUxOVptMTguNDI5IDBjLS43MjcgMC0xLjMxNy42OC0xLjMxNyAxLjUxOXYyLjQwOWMwIC40MDMuMTQuNzkuMzg2IDEuMDc0LjUxNC41OTMgMS4zNDguNTkzIDEuODYyIDAgLjI0Ny0uMjg1LjM4NS0uNjcxLjM4NS0xLjA3NHYtMi40MDljMC0uODM5LS41OS0xLjUxOS0xLjMxNi0xLjUxOVptLTE1Ljc5NyAxLjUxOWMwLS44MzkuNTktMS41MTkgMS4zMTctMS41MTlzMS4zMTYuNjggMS4zMTYgMS41MTl2Mi40MDljMCAuNDAzLS4xMzkuNzktLjM4NiAxLjA3NC0uNTE0LjU5My0xLjM0Ny41OTMtMS44NjEgMGExLjY0NSAxLjY0NSAwIDAgMS0uMzg2LTEuMDc0di0yLjQwOVptMTkuNzQ2LTEuNTE5Yy0uNzI3IDAtMS4zMTYuNjgtMS4zMTYgMS41MTl2Mi40MDljMCAuNDAzLjEzOC43OS4zODUgMS4wNzQuNTE0LjU5MyAxLjM0OC41OTMgMS44NjIgMCAuMjQ3LS4yODUuMzg1LS42NzEuMzg1LTEuMDc0di0yLjQwOWMwLS44MzktLjU4OS0xLjUxOS0xLjMxNi0xLjUxOVptLTE1Ljc5NyAxLjUxOWMwLS44MzkuNTktMS41MTkgMS4zMTctMS41MTlzMS4zMTYuNjggMS4zMTYgMS41MTl2Mi40MDljMCAuNDAzLS4xMzkuNzktLjM4NSAxLjA3NC0uNTE0LjU5My0xLjM0OC41OTMtMS44NjIgMGExLjY0NSAxLjY0NSAwIDAgMS0uMzg2LTEuMDc0di0yLjQwOVptMTkuNzQ2LTEuNTE5Yy0uNzI3IDAtMS4zMTYuNjgtMS4zMTYgMS41MTl2Mi40MDljMCAuNDAzLjEzOC43OS4zODUgMS4wNzQuNTE0LjU5MyAxLjM0OC41OTMgMS44NjIgMCAuMjQ3LS4yODUuMzg2LS42NzEuMzg2LTEuMDc0di0yLjQwOWMwLS44MzktLjU5LTEuNTE5LTEuMzE3LTEuNTE5WiIgLz4KICAgIDwvbWFzaz4KICAgIDxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIgogICAgICAgIGQ9Ik0wIDEyQzAgNS4zNzMgNS4zNzMgMCAxMiAwaDU2YzYuNjI3IDAgMTIgNS4zNzMgMTIgMTJ2NTZjMCA2LjYyNy01LjM3MyAxMi0xMiAxMkgxMkM1LjM3MyA4MCAwIDc0LjYyNyAwIDY4VjEyWm0zNS4wMDUgMzMuODczYzAgMS4wNTggMS4xMDQgMS43MDMgMS45NTUgMS4xNDJsNy42Ny01LjA1MmMuMzczLS4yNDYuNi0uNjc4LjYtMS4xNDJWMjYuNzQ5czIuNTU2IDAgOC45NDctNC4wNDJjMy4xMjQtMS45NzUgNC43MjEtMy45NTEgNS41MzctNS40NTQuNTMzLS45ODEtLjQ2My0xLjY5NC0xLjQxNy0xLjE4LTIuOTY4IDEuNTk1LTguOTA1IDMuOTQtMTguMTggMy45NC05LjI3NCAwLTE1LjIxMi0yLjM0NS0xOC4xNzktMy45NC0uOTU0LS41MTQtMS45NS4xOTktMS40MTggMS4xOC44MTcgMS41MDMgMi40MTMgMy40NzkgNS41MzggNS40NTQgNi4zOSA0LjA0MiA4Ljk0NyA0LjA0MiA4Ljk0NyA0LjA0MnYxOS4xMjRabS04LjA1MS02LjIzNWMyLjE4IDAgMy45NDktMS44MyAzLjk0OS00LjA4NSAwLTIuMjU3LTEuNzY4LTQuMDg2LTMuOTUtNC4wODYtMi4xOCAwLTMuOTQ5IDEuODMtMy45NDkgNC4wODYgMCAyLjI1NiAxLjc2OCA0LjA4NSAzLjk1IDQuMDg1Wm0zMC4yNzYtNC4wODVjMCAyLjI1Ni0xLjc2OCA0LjA4NS0zLjk0OSA0LjA4NS0yLjE4IDAtMy45NDktMS44My0zLjk0OS00LjA4NSAwLTIuMjU3IDEuNzY4LTQuMDg2IDMuOTUtNC4wODYgMi4xOCAwIDMuOTQ4IDEuODMgMy45NDggNC4wODZaTTI2Ljk1NCA1OC4xMTZjLS43MjcgMC0xLjMxNy42OC0xLjMxNyAxLjUxOXYyLjQwOWMwIC40MDMuMTM5Ljc5LjM4NiAxLjA3NC41MTQuNTkzIDEuMzQ3LjU5MyAxLjg2MSAwIC4yNDctLjI4NS4zODYtLjY3MS4zODYtMS4wNzR2LTIuNDA5YzAtLjgzOS0uNTktMS41MTktMS4zMTctMS41MTlabTE4LjQyOSAwYy0uNzI3IDAtMS4zMTcuNjgtMS4zMTcgMS41MTl2Mi40MDljMCAuNDAzLjE0Ljc5LjM4NiAxLjA3NC41MTQuNTkzIDEuMzQ4LjU5MyAxLjg2MiAwIC4yNDctLjI4NS4zODUtLjY3MS4zODUtMS4wNzR2LTIuNDA5YzAtLjgzOS0uNTktMS41MTktMS4zMTYtMS41MTlabS0xNS43OTcgMS41MTljMC0uODM5LjU5LTEuNTE5IDEuMzE3LTEuNTE5czEuMzE2LjY4IDEuMzE2IDEuNTE5djIuNDA5YzAgLjQwMy0uMTM5Ljc5LS4zODYgMS4wNzQtLjUxNC41OTMtMS4zNDcuNTkzLTEuODYxIDBhMS42NDUgMS42NDUgMCAwIDEtLjM4Ni0xLjA3NHYtMi40MDlabTE5Ljc0Ni0xLjUxOWMtLjcyNyAwLTEuMzE2LjY4LTEuMzE2IDEuNTE5djIuNDA5YzAgLjQwMy4xMzguNzkuMzg1IDEuMDc0LjUxNC41OTMgMS4zNDguNTkzIDEuODYyIDAgLjI0Ny0uMjg1LjM4NS0uNjcxLjM4NS0xLjA3NHYtMi40MDljMC0uODM5LS41ODktMS41MTktMS4zMTYtMS41MTlabS0xNS43OTcgMS41MTljMC0uODM5LjU5LTEuNTE5IDEuMzE3LTEuNTE5czEuMzE2LjY4IDEuMzE2IDEuNTE5djIuNDA5YzAgLjQwMy0uMTM5Ljc5LS4zODUgMS4wNzQtLjUxNC41OTMtMS4zNDguNTkzLTEuODYyIDBhMS42NDUgMS42NDUgMCAwIDEtLjM4Ni0xLjA3NHYtMi40MDlabTE5Ljc0Ni0xLjUxOWMtLjcyNyAwLTEuMzE2LjY4LTEuMzE2IDEuNTE5djIuNDA5YzAgLjQwMy4xMzguNzkuMzg1IDEuMDc0LjUxNC41OTMgMS4zNDguNTkzIDEuODYyIDAgLjI0Ny0uMjg1LjM4Ni0uNjcxLjM4Ni0xLjA3NHYtMi40MDljMC0uODM5LS41OS0xLjUxOS0xLjMxNy0xLjUxOVoiCiAgICAgICAgZmlsbD0iI2ZmZiIgLz4KICAgIDxwYXRoCiAgICAgICAgZD0ibTM2Ljk2IDQ3LjAxNSAxLjEgMS42Ny0xLjEtMS42N1ptNy42Ny01LjA1MiAxLjEgMS42Ny0xLjEtMS42N1ptLjYtMTUuMjE0di0yaC0ydjJoMlptOC45NDctNC4wNDIgMS4wNjkgMS42OS0xLjA2OS0xLjY5Wm01LjUzNy01LjQ1NCAxLjc1OC45NTQtMS43NTgtLjk1NFptLTEuNDE3LTEuMTguOTQ3IDEuNzYtLjk0Ny0xLjc2Wm0tMzYuMzU5IDAtLjk0NyAxLjc2Ljk0Ny0xLjc2Wm0tMS40MTggMS4xOCAxLjc1OC0uOTU1LTEuNzU4Ljk1NVptNS41MzggNS40NTQtMS4wNyAxLjY5IDEuMDctMS42OVptOC45NDcgNC4wNDJoMnYtMmgtMnYyWm0tOC45ODIgMzYuMzcgMS41MTEtMS4zMS0xLjUxMSAxLjMxWm0xLjg2MSAwIDEuNTEyIDEuMzA5LTEuNTEyLTEuMzFabTE2LjU2OCAwLTEuNTExIDEuMzA5IDEuNTExLTEuMzFabTEuODYyIDAgMS41MTEgMS4zMDktMS41MTEtMS4zMVptLTE0LjQ4IDAtMS41MTItMS4zMSAxLjUxMiAxLjMxWm0tMS44NjIgMCAxLjUxMS0xLjMxLTEuNTExIDEuMzFabTE4LjQzIDAtMS41MTIgMS4zMDkgMS41MTEtMS4zMVptMS44NiAwIDEuNTEyIDEuMzA5LTEuNTExLTEuMzFabS0xNC40OCAwIDEuNTEyIDEuMzA5LTEuNTExLTEuMzFabS0xLjg2MSAwLTEuNTExIDEuMzA5IDEuNTExLTEuMzFabTE4LjQzIDAgMS41MS0xLjMxLTEuNTEgMS4zMVptMS44NjEgMCAxLjUxMSAxLjMwOS0xLjUxMS0xLjMxWk0xMi0yQzQuMjY4LTItMiA0LjI2OC0yIDEyaDRDMiA2LjQ3NyA2LjQ3NyAyIDEyIDJ2LTRabTU2IDBIMTJ2NGg1NnYtNFptMTQgMTRjMC03LjczMi02LjI2OC0xNC0xNC0xNHY0YzUuNTIzIDAgMTAgNC40NzcgMTAgMTBoNFptMCA1NlYxMmgtNHY1Nmg0Wk02OCA4MmM3LjczMiAwIDE0LTYuMjY4IDE0LTE0aC00YzAgNS41MjMtNC40NzcgMTAtMTAgMTB2NFptLTU2IDBoNTZ2LTRIMTJ2NFpNLTIgNjhjMCA3LjczMiA2LjI2OCAxNCAxNCAxNHYtNEM2LjQ3NyA3OCAyIDczLjUyMyAyIDY4aC00Wm0wLTU2djU2aDRWMTJoLTRabTM3Ljg2IDMzLjM0NWEuNzkxLjc5MSAwIDAgMSAuODEyLS4wMjEuNjU2LjY1NiAwIDAgMSAuMzMzLjU0OWgtNGMwIDIuNDU0IDIuNzE0IDQuMzU1IDUuMDU1IDIuODEybC0yLjItMy4zNFptNy42NjktNS4wNTItNy42NjkgNS4wNTIgMi4yIDMuMzQgNy42Ny01LjA1Mi0yLjIwMS0zLjM0Wm0tLjI5OS41MjhjMC0uMTc4LjA4Ni0uMzg4LjI5OS0uNTI4bDIuMiAzLjM0YTMuMzY1IDMuMzY1IDAgMCAwIDEuNTAxLTIuODEyaC00Wm0wLTE0LjA3MlY0MC44Mmg0VjI2Ljc0OWgtNFptOS44NzgtNS43MzJjLTMuMDk3IDEuOTU5LTUuMTk3IDIuODk1LTYuNDY0IDMuMzRhOC44NDUgOC44NDUgMCAwIDEtMS4yOC4zNjIgMi40MiAyLjQyIDAgMCAxLS4yMDMuMDMxSDQ1LjE5bC4wMTgtLjAwMWguMDJjLjAwMSAwIC4wMDMgMCAuMDAzIDJzLjAwMiAyIC4wMDMgMmguMDU0YTMuMTk2IDMuMTk2IDAgMCAwIC4yNTYtLjAxN2MuMTQ0LS4wMTQuMzI3LS4wMzguNTUyLS4wOC40NS0uMDg0IDEuMDY5LS4yMzggMS44NzUtLjUyMSAxLjYxLS41NjYgMy45ODItMS42NSA3LjI3Ni0zLjczM2wtMi4xMzgtMy4zODFabTQuODQ5LTQuNzE5Yy0uNjM3IDEuMTczLTEuOTgzIDIuOTA2LTQuODQ5IDQuNzE5bDIuMTM4IDMuMzhjMy4zODItMi4xMzggNS4yMy00LjM1NiA2LjIyNi02LjE5bC0zLjUxNS0xLjkwOVptMS4yODcgMS41MzZjLS4xMDYuMDU2LS40OTQuMTczLS45MTYtLjE1OGExLjIzMyAxLjIzMyAwIDAgMS0uNDQ4LS43Ni45ODUuOTg1IDAgMCAxIC4wNzctLjYxOGwzLjUxNSAxLjkwOWMuMzA4LS41NjguNDcyLTEuMjQ4LjM1MS0xLjk2YTIuNzY4IDIuNzY4IDAgMCAwLTEuMDI1LTEuNzE4Yy0xLjAyNi0uODA1LTIuMzg4LS43ODgtMy40NDktLjIxOGwxLjg5NSAzLjUyM1ptLTE5LjEyNyA0LjE4YzkuNjI4IDAgMTUuODg5LTIuNDM4IDE5LjEyNy00LjE4bC0xLjg5NS0zLjUyM2MtMi42OTYgMS40NS04LjMxIDMuNzAyLTE3LjIzMiAzLjcwMnY0Wm0tMTkuMTI2LTQuMThjMy4yMzggMS43NDIgOS40OTkgNC4xOCAxOS4xMjYgNC4xOHYtNGMtOC45MjEgMC0xNC41MzUtMi4yNTMtMTcuMjMxLTMuNzAzbC0xLjg5NSAzLjUyM1ptMS4yODctMS41MzZjLjA0Mi4wNzguMTMxLjMuMDc3LjYxOWExLjIzMiAxLjIzMiAwIDAgMS0uNDQ5Ljc1OWMtLjQyMi4zMy0uODEuMjE1LS45MTUuMTU4bDEuODk1LTMuNTIzYy0xLjA2LS41Ny0yLjQyNC0uNTg3LTMuNDQ5LjIxOGEyLjc2OCAyLjc2OCAwIDAgMC0xLjAyNiAxLjcxOWMtLjEyLjcxMS4wNDMgMS4zOTEuMzUyIDEuOTU5bDMuNTE1LTEuOTA5Wm00Ljg0OSA0LjcxOWMtMi44NjctMS44MTMtNC4yMTItMy41NDYtNC44NDktNC43MTlsLTMuNTE1IDEuOTA5Yy45OTUgMS44MzQgMi44NDQgNC4wNTIgNi4yMjYgNi4xOWwyLjEzOC0zLjM4Wm03Ljg3OCA1LjczMmMwLTIgLjAwMS0yIC4wMDMtMkgzNS4wNDdsLjAyNS4wMDFoLjAwMWEyLjQyIDIuNDIgMCAwIDEtLjIwMi0uMDMgOC44NTIgOC44NTIgMCAwIDEtMS4yOC0uMzYzYy0xLjI2Ny0uNDQ1LTMuMzY3LTEuMzgxLTYuNDY0LTMuMzRsLTIuMTM4IDMuMzhjMy4yOTMgMi4wODQgNS42NjYgMy4xNjggNy4yNzYgMy43MzQuODA2LjI4MyAxLjQyNS40MzcgMS44NzUuNTJhNi4zNTYgNi4zNTYgMCAwIDAgLjczNy4wOTVsLjA3MS4wMDJoLjA1NGMuMDAxIDAgLjAwMyAwIC4wMDMtMlptMiAxOS4xMjRWMjYuNzQ5aC00djE5LjEyNGg0Wm0tOC4xMDItMTAuMzJjMCAxLjIxNi0uOTM2IDIuMDg1LTEuOTUgMi4wODV2NGMzLjM1IDAgNS45NS0yLjc4OSA1Ljk1LTYuMDg1aC00Wm0tMS45NS0yLjA4NmMxLjAxNCAwIDEuOTUuODcgMS45NSAyLjA4Nmg0YzAtMy4yOTctMi42LTYuMDg2LTUuOTUtNi4wODZ2NFptLTEuOTQ5IDIuMDg2YzAtMS4yMTYuOTM2LTIuMDg2IDEuOTUtMi4wODZ2LTRjLTMuMzUgMC01Ljk1IDIuNzktNS45NSA2LjA4Nmg0Wm0xLjk1IDIuMDg1Yy0xLjAxNCAwLTEuOTUtLjg3LTEuOTUtMi4wODVoLTRjMCAzLjI5NiAyLjYgNi4wODUgNS45NSA2LjA4NXYtNFptMjYuMzI3IDRjMy4zNSAwIDUuOTUtMi43ODkgNS45NS02LjA4NWgtNGMwIDEuMjE2LS45MzcgMi4wODUtMS45NSAyLjA4NXY0Wm0tNS45NDktNi4wODVjMCAzLjI5NiAyLjYgNi4wODUgNS45NSA2LjA4NXYtNGMtMS4wMTQgMC0xLjk1LS44Ny0xLjk1LTIuMDg1aC00Wm01Ljk1LTYuMDg2Yy0zLjM1IDAtNS45NSAyLjc5LTUuOTUgNi4wODZoNGMwLTEuMjE2LjkzNi0yLjA4NiAxLjk1LTIuMDg2di00Wm01Ljk0OCA2LjA4NmMwLTMuMjk3LTIuNi02LjA4Ni01Ljk0OS02LjA4NnY0YzEuMDEzIDAgMS45NS44NyAxLjk1IDIuMDg2aDRaTTI3LjYzNyA1OS42MzVhLjM3LjM3IDAgMCAxLS4xMDMuMjM2Ljc3NC43NzQgMCAwIDEtLjU4LjI0NXYtNGMtMi4wOTEgMC0zLjMxNyAxLjg1NC0zLjMxNyAzLjUxOWg0Wm0wIDIuNDA5di0yLjQwOWgtNHYyLjQwOWg0Wm0tLjEwMy0uMjM2YS40NS40NSAwIDAgMSAuMDg2LjE0Mi4yNzcuMjc3IDAgMCAxIC4wMTcuMDk0aC00YzAgLjg0OC4yOSAxLjcxLjg3NCAyLjM4NGwzLjAyMy0yLjYyWm0tMS4xNjEgMGEuNzc2Ljc3NiAwIDAgMSAuNTgtLjI0NWMuMjcgMCAuNDc2LjEyNC41ODEuMjQ1bC0zLjAyMyAyLjYyYzEuMzEyIDEuNTEzIDMuNTczIDEuNTEzIDQuODg1IDBsLTMuMDIzLTIuNjJabS0uMTAzLjIzNmMwLS4wMjcuMDA0LS4wNTguMDE3LS4wOTRhLjQ1LjQ1IDAgMCAxIC4wODYtLjE0MmwzLjAyMyAyLjYyYTMuNjQ0IDMuNjQ0IDAgMCAwIC44NzQtMi4zODRoLTRabTAtMi40MDl2Mi40MDloNHYtMi40MDloLTRabS42ODMuNDgxYy0uMjkgMC0uNDktLjE0LS41OC0uMjQ1YS4zNy4zNyAwIDAgMS0uMTAzLS4yMzZoNGMwLTEuNjY1LTEuMjI2LTMuNTE5LTMuMzE3LTMuNTE5djRabTE5LjExMy0uNDgxYS4zNy4zNyAwIDAgMS0uMTAyLjIzNi43NzQuNzc0IDAgMCAxLS41ODEuMjQ1di00Yy0yLjA5MSAwLTMuMzE3IDEuODU0LTMuMzE3IDMuNTE5aDRabTAgMi40MDl2LTIuNDA5aC00djIuNDA5aDRabS0uMTAyLS4yMzZhLjQ1LjQ1IDAgMCAxIC4wODUuMTQyLjI3Ny4yNzcgMCAwIDEgLjAxNy4wOTRoLTRjMCAuODQ4LjI5IDEuNzEuODc1IDIuMzg0bDMuMDIzLTIuNjJabS0xLjE2MiAwYS43NzUuNzc1IDAgMCAxIC41OC0uMjQ1Yy4yNzEgMCAuNDc3LjEyNC41ODIuMjQ1bC0zLjAyMyAyLjYyYzEuMzExIDEuNTEzIDMuNTczIDEuNTEzIDQuODg0IDBsLTMuMDIzLTIuNjJabS0uMTAzLjIzNmMwLS4wMjcuMDA1LS4wNTguMDE4LS4wOTRhLjQ1LjQ1IDAgMCAxIC4wODUtLjE0MmwzLjAyMyAyLjYyYTMuNjQ1IDMuNjQ1IDAgMCAwIC44NzQtMi4zODRoLTRabTAtMi40MDl2Mi40MDloNHYtMi40MDloLTRabS42ODQuNDgxYy0uMjkgMC0uNDktLjE0LS41OC0uMjQ1YS4zNjkuMzY5IDAgMCAxLS4xMDQtLjIzNmg0YzAtMS42NjUtMS4yMjUtMy41MTktMy4zMTYtMy41MTl2NFptLTE0LjQ4LTRjLTIuMDkxIDAtMy4zMTcgMS44NTQtMy4zMTcgMy41MTloNGEuMzcuMzcgMCAwIDEtLjEwMy4yMzYuNzc0Ljc3NCAwIDAgMS0uNTguMjQ1di00Wm0zLjMxNiAzLjUxOWMwLTEuNjY1LTEuMjI1LTMuNTE5LTMuMzE2LTMuNTE5djRjLS4yOSAwLS40OS0uMTQtLjU4LS4yNDVhLjM3LjM3IDAgMCAxLS4xMDQtLjIzNmg0Wm0wIDIuNDA5di0yLjQwOWgtNHYyLjQwOWg0Wm0tLjg3NCAyLjM4NGEzLjY0NCAzLjY0NCAwIDAgMCAuODc0LTIuMzg0aC00YzAtLjAyNy4wMDUtLjA1OC4wMTctLjA5NGEuNDUuNDUgMCAwIDEgLjA4Ni0uMTQybDMuMDIzIDIuNjJabS00Ljg4NSAwYzEuMzEyIDEuNTEzIDMuNTczIDEuNTEzIDQuODg1IDBsLTMuMDIzLTIuNjJhLjc3NS43NzUgMCAwIDEgLjU4LS4yNDVjLjI3IDAgLjQ3Ni4xMjQuNTgxLjI0NWwtMy4wMjMgMi42MlptLS44NzQtMi4zODRjMCAuODQ4LjI5IDEuNzEuODc0IDIuMzg0bDMuMDIzLTIuNjJhLjQ1LjQ1IDAgMCAxIC4wODYuMTQyLjI3Ny4yNzcgMCAwIDEgLjAxNy4wOTRoLTRabTAtMi40MDl2Mi40MDloNHYtMi40MDloLTRabTIyLjQzIDBhLjM3LjM3IDAgMCAxLS4xMDMuMjM2Ljc3NC43NzQgMCAwIDEtLjU4MS4yNDV2LTRjLTIuMDkgMC0zLjMxNiAxLjg1NC0zLjMxNiAzLjUxOWg0Wm0wIDIuNDA5di0yLjQwOWgtNHYyLjQwOWg0Wm0tLjEwMy0uMjM2YS40NTMuNDUzIDAgMCAxIC4wODUuMTQyLjI3Ny4yNzcgMCAwIDEgLjAxOC4wOTRoLTRjMCAuODQ4LjI5IDEuNzEuODc0IDIuMzg0bDMuMDIzLTIuNjJabS0xLjE2MiAwYS43NzYuNzc2IDAgMCAxIC41ODEtLjI0NWMuMjcgMCAuNDc2LjEyNC41OC4yNDVsLTMuMDIyIDIuNjJjMS4zMTEgMS41MTMgMy41NzMgMS41MTMgNC44ODQgMGwtMy4wMjMtMi42MlptLS4xMDMuMjM2YzAtLjAyNy4wMDUtLjA1OC4wMTgtLjA5NGEuNDUuNDUgMCAwIDEgLjA4NS0uMTQybDMuMDIzIDIuNjJhMy42NDQgMy42NDQgMCAwIDAgLjg3NC0yLjM4NGgtNFptMC0yLjQwOXYyLjQwOWg0di0yLjQwOWgtNFptLjY4NC40ODFjLS4yOSAwLS40OS0uMTQtLjU4LS4yNDVhLjM3LjM3IDAgMCAxLS4xMDQtLjIzNmg0YzAtMS42NjUtMS4yMjUtMy41MTktMy4zMTYtMy41MTl2NFptLTE0LjQ4LTRjLTIuMDkxIDAtMy4zMTYgMS44NTQtMy4zMTYgMy41MTloNGEuMzcuMzcgMCAwIDEtLjEwNC4yMzYuNzc0Ljc3NCAwIDAgMS0uNTguMjQ1di00Wm0zLjMxNiAzLjUxOWMwLTEuNjY1LTEuMjI1LTMuNTE5LTMuMzE2LTMuNTE5djRjLS4yOSAwLS40OS0uMTQtLjU4LS4yNDVhLjM3LjM3IDAgMCAxLS4xMDQtLjIzNmg0Wm0wIDIuNDA5di0yLjQwOWgtNHYyLjQwOWg0Wm0tLjg3NCAyLjM4NGEzLjY0NCAzLjY0NCAwIDAgMCAuODc0LTIuMzg0aC00YzAtLjAyNy4wMDUtLjA1OC4wMTgtLjA5NGEuNDUuNDUgMCAwIDEgLjA4NS0uMTQybDMuMDIzIDIuNjJabS00Ljg4NCAwYzEuMzExIDEuNTEzIDMuNTczIDEuNTEzIDQuODg0IDBsLTMuMDIzLTIuNjJhLjc3Ni43NzYgMCAwIDEgLjU4LS4yNDVjLjI3MSAwIC40NzcuMTI0LjU4MS4yNDVsLTMuMDIyIDIuNjJabS0uODc0LTIuMzg0YzAgLjg0OC4yODkgMS43MS44NzQgMi4zODRsMy4wMjMtMi42MmEuNDUzLjQ1MyAwIDAgMSAuMDg1LjE0Mi4yNzcuMjc3IDAgMCAxIC4wMTcuMDk0aC00Wm0wLTIuNDA5djIuNDA5aDR2LTIuNDA5aC00Wm0yMi40MjkgMGEuMzcuMzcgMCAwIDEtLjEwMy4yMzYuNzc0Ljc3NCAwIDAgMS0uNTguMjQ1di00Yy0yLjA5MiAwLTMuMzE3IDEuODU0LTMuMzE3IDMuNTE5aDRabTAgMi40MDl2LTIuNDA5aC00djIuNDA5aDRabS0uMTAzLS4yMzZhLjQ1LjQ1IDAgMCAxIC4wODUuMTQyLjI3Ny4yNzcgMCAwIDEgLjAxOC4wOTRoLTRjMCAuODQ4LjI5IDEuNzEuODc0IDIuMzg0bDMuMDIzLTIuNjJabS0xLjE2MiAwYS43NzYuNzc2IDAgMCAxIC41ODEtLjI0NWMuMjcgMCAuNDc2LjEyNC41OC4yNDVsLTMuMDIyIDIuNjJjMS4zMTIgMS41MTMgMy41NzMgMS41MTMgNC44ODUgMGwtMy4wMjMtMi42MlptLS4xMDIuMjM2YzAtLjAyNy4wMDQtLjA1OC4wMTctLjA5NGEuNDU1LjQ1NSAwIDAgMSAuMDg1LS4xNDJsMy4wMjMgMi42MmEzLjY0NSAzLjY0NSAwIDAgMCAuODc1LTIuMzg0aC00Wm0wLTIuNDA5djIuNDA5aDR2LTIuNDA5aC00Wm0uNjgzLjQ4MWMtLjI5IDAtLjQ5LS4xNC0uNTgtLjI0NWEuMzcuMzcgMCAwIDEtLjEwMy0uMjM2aDRjMC0xLjY2NS0xLjIyNi0zLjUxOS0zLjMxNy0zLjUxOXY0WiIKICAgICAgICBmaWxsPSIjZmZmIiBtYXNrPSJ1cmwoI2EpIiAvPgo8L3N2Zz4="
class="header3__card-recommendation-header-photo header3__card-recommendation-header-photo_default_inverted"
/>
</div>
<div class="header3__card-recommendation-header-content">
<div class="header3__card-recommendation-header-content-tag">
Курс
</div>
<div class="header3__card-recommendation-header-sub">
<span
class="header3__card-recommendation-header-sub-chunk header3__card-recommendation-header-sub-chunk_green"
>
Скидка 20000 ₽
</span>
</div>
</div>
</div>
<h6 class="header3__card-recommendation-title">
AI для аналитики и работы с данными
</h6>
<div class="header3__card-recommendation-footer">
12 марта
, 2026
· 2 месяца
</div>
</a>
</div>
</div>
<div>
<p class="header3__nav-section-title ">Ответим на ваши вопросы</p>
<div class="header3__nav-section-items ">
<a
class="header3__nav-section-item header3__nav-section-item_phone"
rel="noopener noreferrer"
href="tel:+7 499 938-92-02"
>
<svg
class="header3__phone-icon"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M14.352 2.75a7.971 7.971 0 0 1 7.041 7.032M14.352 6.293a4.426 4.426 0 0 1 3.5 3.5"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
></path>
<path
clip-rule="evenodd"
d="M7.7 16.299C.803 9.4 1.783 6.241 2.51 5.223c.094-.164 2.396-3.611 4.865-1.589 6.126 5.045-1.63 4.332 3.514 9.477 5.146 5.144 4.431-2.611 9.477 3.514 2.022 2.469-1.425 4.771-1.588 4.864-1.018.728-4.178 1.709-11.078-5.19Z"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
></path>
</svg>
+7 499 938-92-02
</a>
</div>
</div>
</div>
</div>
<svg
class="header3__nav-item-popup-figure"
viewBox="0 0 600 600"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M125.573 140.619C131.659 71.6017 210.245 34.9562 267.027 74.6573L553.942 275.262C610.723 314.962 603.117 401.233 540.247 430.55L222.58 578.681C159.71 607.997 88.7344 558.37 94.8204 489.355L125.573 140.619Z"
stroke="#eaeaea"
class="header3__nav-item-popup-figure-spinner"
></path>
<path
d="M148.472 246.647C133.624 191.005 184.615 140.013 240.257 154.862L519.856 229.476C575.498 244.325 594.059 313.877 553.266 354.67L348.281 559.656C307.488 600.449 237.935 581.888 223.087 526.246L148.472 246.647Z"
fill="url(#paint0_linear-info)"
></path>
<defs>
<linearGradient
id="paint0_linear-info"
x1="128.696"
y1="395.739"
x2="443.538"
y2="180.173"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#f9f9f9"></stop>
<stop offset="1" stop-color="#EBEBEB"></stop>
</linearGradient>
</defs>
</svg>
</div>
</div>
<a class="header3__nav-item header3__nav-item-b2b header3__nav-item_with-hover" href="/b2b">
Компаниям
</a>
</nav>
<div class="header3__nav header3__nav_right">
<div data-name="" class="header3__nav-item js-header3-popup-trigger js-open-modal-reg header3__button-sign-up-container" >
<button class="header3__button-sign-up">
<svg class="header3__button-sign-up-icon" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
clip-rule="evenodd"
d="M9.922 21.808c-3.814 0-7.072-.577-7.072-2.887s3.237-4.41 7.072-4.41c3.814 0 7.072 2.08 7.072 4.39 0 2.308-3.237 2.907-7.072 2.907ZM9.922 11.216A4.534 4.534 0 1 0 5.39 6.683a4.518 4.518 0 0 0 4.501 4.533h.032Z"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
></path>
<path
d="M19.131 8.13v4.01M21.178 10.134h-4.09"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
></path>
</svg>
Зарегистрироваться
</button>
</div>
<div data-name="" class="header3__nav-item js-header3-popup-trigger js-open-modal-login header3__button-sign-in-container" data-modal-id="new-log-reg">
<button class="header3__button-sign-in">
Войти
</button>
</div>
<div class="header3__hamburger">
<button data-name="hamburger" class="header3__hamburger-button js-header3-popup-trigger">
<svg
class="header3__hamburger-icon js-header3-popup-trigger-icon-default"
width="28"
height="22"
viewBox="0 0 28 22"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M2.15999 0.119995C1.09961 0.119995 0.23999 0.979576 0.23999 2.04C0.23999 3.10035 1.09961 3.96 2.15999 3.96H25.84C26.9004 3.96 27.76 3.10035 27.76 2.04C27.76 0.979576 26.9004 0.119995 25.84 0.119995H2.15999ZM2.15999 9.08C1.09961 9.08 0.23999 9.93957 0.23999 11C0.23999 12.0604 1.09961 12.92 2.15999 12.92H25.84C26.9004 12.92 27.76 12.0604 27.76 11C27.76 9.93957 26.9004 9.08 25.84 9.08H2.15999ZM2.15999 18.04C1.09961 18.04 0.23999 18.8996 0.23999 19.96C0.23999 21.0204 1.09961 21.88 2.15999 21.88H25.84C26.9004 21.88 27.76 21.0204 27.76 19.96C27.76 18.8996 26.9004 18.04 25.84 18.04H2.15999Z"
fill="currentColor"
></path>
</svg>
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
class="header3__hamburger-icon-close js-header3-popup-trigger-icon-close"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M12 0.75C11.3096 0.75 10.75 1.30964 10.75 2V10.75L2 10.75C1.30964 10.75 0.75 11.3096 0.75 12C0.75 12.6904 1.30964 13.25 2 13.25L10.75 13.25L10.75 22C10.75 22.6904 11.3096 23.25 12 23.25C12.6904 23.25 13.25 22.6904 13.25 22L13.25 13.25L22 13.25C22.6904 13.25 23.25 12.6904 23.25 12C23.25 11.3096 22.6904 10.75 22 10.75L13.25 10.75V2C13.25 1.30964 12.6904 0.75 12 0.75Z"
fill="currentColor"
></path>
</svg>
</button>
<div
data-name="hamburger"
data-only-click="true"
class="header3__nav-item-popup-wrapper js-header3-popup"
style="display: none;"
>
<div
class="header3__nav-item-popup-container js-header3-popup-container"
>
<svg
class="header3__nav-item-popup-figure"
viewBox="0 0 600 600"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M125.573 140.619C131.659 71.6017 210.245 34.9562 267.027 74.6573L553.942 275.262C610.723 314.962 603.117 401.233 540.247 430.55L222.58 578.681C159.71 607.997 88.7344 558.37 94.8204 489.355L125.573 140.619Z"
stroke="#eaeaea"
class="header3__nav-item-popup-figure-spinner"
></path>
<path
d="M148.472 246.647C133.624 191.005 184.615 140.013 240.257 154.862L519.856 229.476C575.498 244.325 594.059 313.877 553.266 354.67L348.281 559.656C307.488 600.449 237.935 581.888 223.087 526.246L148.472 246.647Z"
fill="url(#paint0_linear-hamburger)"
></path>
<defs>
<linearGradient
id="paint0_linear-hamburger"
x1="128.696"
y1="395.739"
x2="443.538"
y2="180.173"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#f9f9f9"></stop>
<stop offset="1" stop-color="#EBEBEB"></stop>
</linearGradient>
</defs>
</svg>
<div class="header3__nav-item-popup-content header3__hamburger-tabs">
<ul>
<li
class="header3__hamburger-tabs-tab header3__hamburger-tabs-tab_active"
>
Обучение
</li>
<li class="header3__hamburger-tabs-tab">
Информация
</li>
<li data-url="/b2b" class="header3__hamburger-tabs-tab header3__hamburger-tabs-tab_link">
Компаниям
</li>
</ul>
<div class="header3__hamburger-tabs-tab-content-wrapper">
<div
class="header3__hamburger-tabs-tab-content header3__hamburger-tabs-tab-learning header3__hamburger-tabs-tab-content_active"
>
<div class="header3__nav-column">
<div>
<p class="header3__nav-section-title ">Направления</p>
<div class="header3__nav-section-items header3__nav-section-items_learning header3__nav-section-items_learning_rows-8">
<a
class="header3__nav-section-item"
href="/categories/programming/"
>
Программирование (117)
</a>
<a
class="header3__nav-section-item"
href="/categories/architecture/"
>
Архитектура (17)
</a>
<a
class="header3__nav-section-item"
href="/categories/data-science/"
>
Data Science (27)
</a>
<a
class="header3__nav-section-item"
href="/categories/operations/"
>
Инфраструктура (58)
</a>
<a
class="header3__nav-section-item"
href="/categories/gamedev/"
>
GameDev (10)
</a>
<a
class="header3__nav-section-item"
href="/categories/information-security-courses/"
>
Безопасность (15)
</a>
<a
class="header3__nav-section-item"
href="/categories/marketing-business/"
>
Управление (46)
</a>
<a
class="header3__nav-section-item"
href="/categories/analytics/"
>
Аналитика и анализ (25)
</a>
<a
class="header3__nav-section-item"
href="/categories/business-product/"
>
Бизнес и продукт в IT (26)
</a>
<a
class="header3__nav-section-item"
href="/categories/import-substitution/"
>
Импортозамещение (15)
</a>
<a
class="header3__nav-section-item"
href="/categories/testing/"
>
Тестирование (12)
</a>
<a
class="header3__nav-section-item"
href="/categories/neural_networks/"
>
Нейросети (9)
</a>
<a
class="header3__nav-section-item"
href="/categories/it-bez-programmirovanija/"
>
IT без программирования (19)
</a>
<a
class="header3__nav-section-item"
href="/categories/corporate/"
>
Корпоративные курсы (27)
</a>
</div>
</div>
</div>
<div class="header3__nav-column">
<div>
<p class="header3__nav-section-title ">События</p>
<div class="header3__nav-section-items ">
<a
class="header3__nav-section-item"
href="/lessons/calendar/2026/"
>
Календарь запуска курсов
</a>
<a
class="header3__nav-section-item"
href="/events/near/"
>
Календарь мероприятий
</a>
</div>
</div>
<div>
<p class="header3__nav-section-title ">Другое</p>
<div class="header3__nav-section-items ">
<a
class="header3__nav-section-item"
href="/categories/spec/"
>
Специализации (13)
</a>
<a
class="header3__nav-section-item"
href="/categories/online/"
>
Подготовительные курсы (14)
</a>
<a
class="header3__nav-section-item header3__nav-section-item_bold"
href="/subscription"
>
Подписка на курсы
</a>
<a
class="header3__nav-section-item"
href="/tests"
>
Проверьте свои знания
</a>
</div>
</div>
</div>
<div class="header3__nav-column">
<div>
<p class="header3__nav-section-title header3__nav-section-items-recommendation-title">OTUS рекомендует</p>
<div class="header3__nav-section-items header3__nav-section-items_not-items header3__nav-section-items-recommendation">
<a
href="/lessons/ai-dlya-analitiki-i-raboty-s-dannymi/"
class="header3__card-recommendation"
>
<div
class="header3__card-recommendation-background"
style="background: linear-gradient( 90deg,#0A4489, #00316B);"
></div>
<div class="header3__card-recommendation-header">
<div class="header3__card-recommendation-header-photo-wrapper" style="background: linear-gradient( 90deg,#0A4489, #00316B);">
<img
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODAiIGhlaWdodD0iODAiIHZpZXdCb3g9IjAgMCA4MCA4MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoCiAgICAgICAgZD0iTTM1LjAwNDcgNDUuODcyNUMzNS4wMDQ3IDQ2LjkzMDYgMzYuMTA5IDQ3LjU3NTcgMzYuOTYwMyA0Ny4wMTQ5TDQ0LjYyOTIgNDEuOTYzMUM0NS4wMDI5IDQxLjcxNjkgNDUuMjI5OSA0MS4yODUyIDQ1LjIyOTkgNDAuODIwN1YyNi43NDg5QzQ1LjIyOTkgMjYuNzQ4OSA0Ny43ODYyIDI2Ljc0ODkgNTQuMTc3IDIyLjcwNzRDNTcuMzAxMiAyMC43MzE4IDU4Ljg5OCAxOC43NTYxIDU5LjcxNDMgMTcuMjUyNUM2MC4yNDY1IDE2LjI3MjEgNTkuMjUxMSAxNS41NTg4IDU4LjI5NjUgMTYuMDcyM0M1NS4zMjkyIDE3LjY2ODQgNDkuMzkxOCAyMC4wMTMyIDQwLjExNzMgMjAuMDEzMkMzMC44NDI4IDIwLjAxMzIgMjQuOTA1NCAxNy42Njg0IDIxLjkzODEgMTYuMDcyM0MyMC45ODM1IDE1LjU1ODggMTkuOTg4MSAxNi4yNzIxIDIwLjUyMDMgMTcuMjUyNUMyMS4zMzY2IDE4Ljc1NjEgMjIuOTMzNCAyMC43MzE4IDI2LjA1NzcgMjIuNzA3NEMzMi40NDg0IDI2Ljc0ODkgMzUuMDA0NyAyNi43NDg5IDM1LjAwNDcgMjYuNzQ4OVY0NS44NzI1WiIKICAgICAgICBmaWxsPSJ3aGl0ZSIgLz4KICAgIDxlbGxpcHNlIGN4PSIyNi45NTM1IiBjeT0iMzUuNTUyNiIgcng9IjMuOTQ5MTQiIHJ5PSI0LjA4NTMyIiBmaWxsPSJ3aGl0ZSIgLz4KICAgIDxlbGxpcHNlIGN4PSI1My4yODEyIiBjeT0iMzUuNTUyNiIgcng9IjMuOTQ5MTQiIHJ5PSI0LjA4NTMyIiBmaWxsPSJ3aGl0ZSIgLz4KICAgIDxwYXRoCiAgICAgICAgZD0iTTI1LjYzNzIgNTkuNjM1QzI1LjYzNzIgNTguNzk2MSAyNi4yMjY2IDU4LjExNiAyNi45NTM2IDU4LjExNkMyNy42ODA2IDU4LjExNiAyOC4yNyA1OC43OTYxIDI4LjI3IDU5LjYzNVY2Mi4wNDRDMjguMjcgNjIuNDQ2OSAyOC4xMzEzIDYyLjgzMzMgMjcuODg0NCA2My4xMTgxQzI3LjM3MDMgNjMuNzExNCAyNi41MzY4IDYzLjcxMTQgMjYuMDIyOCA2My4xMTgxQzI1Ljc3NTkgNjIuODMzMyAyNS42MzcyIDYyLjQ0NjkgMjUuNjM3MiA2Mi4wNDRWNTkuNjM1WiIKICAgICAgICBmaWxsPSJ3aGl0ZSIgLz4KICAgIDxwYXRoCiAgICAgICAgZD0iTTQ0LjA2NjUgNTkuNjM1QzQ0LjA2NjUgNTguNzk2MSA0NC42NTU5IDU4LjExNiA0NS4zODI5IDU4LjExNkM0Ni4xMDk5IDU4LjExNiA0Ni42OTkzIDU4Ljc5NjEgNDYuNjk5MyA1OS42MzVWNjIuMDQ0QzQ2LjY5OTMgNjIuNDQ2OSA0Ni41NjA2IDYyLjgzMzMgNDYuMzEzOCA2My4xMTgxQzQ1Ljc5OTcgNjMuNzExNCA0NC45NjYyIDYzLjcxMTQgNDQuNDUyMSA2My4xMTgxQzQ0LjIwNTIgNjIuODMzMyA0NC4wNjY1IDYyLjQ0NjkgNDQuMDY2NSA2Mi4wNDRWNTkuNjM1WiIKICAgICAgICBmaWxsPSJ3aGl0ZSIgLz4KICAgIDxwYXRoCiAgICAgICAgZD0iTTI5LjU4NjQgNTkuNjM1QzI5LjU4NjQgNTguNzk2MSAzMC4xNzU3IDU4LjExNiAzMC45MDI3IDU4LjExNkMzMS42Mjk4IDU4LjExNiAzMi4yMTkxIDU4Ljc5NjEgMzIuMjE5MSA1OS42MzVWNjIuMDQ0QzMyLjIxOTEgNjIuNDQ2OSAzMi4wODA0IDYyLjgzMzMgMzEuODMzNiA2My4xMTgxQzMxLjMxOTUgNjMuNzExNCAzMC40ODYgNjMuNzExNCAyOS45NzE5IDYzLjExODFDMjkuNzI1IDYyLjgzMzMgMjkuNTg2NCA2Mi40NDY5IDI5LjU4NjQgNjIuMDQ0VjU5LjYzNVoiCiAgICAgICAgZmlsbD0id2hpdGUiIC8+CiAgICA8cGF0aAogICAgICAgIGQ9Ik00OC4wMTU3IDU5LjYzNUM0OC4wMTU3IDU4Ljc5NjEgNDguNjA1MSA1OC4xMTYgNDkuMzMyMSA1OC4xMTZDNTAuMDU5MSA1OC4xMTYgNTAuNjQ4NSA1OC43OTYxIDUwLjY0ODUgNTkuNjM1VjYyLjA0NEM1MC42NDg1IDYyLjQ0NjkgNTAuNTA5OCA2Mi44MzMzIDUwLjI2MjkgNjMuMTE4MUM0OS43NDg4IDYzLjcxMTQgNDguOTE1MyA2My43MTE0IDQ4LjQwMTIgNjMuMTE4MUM0OC4xNTQ0IDYyLjgzMzMgNDguMDE1NyA2Mi40NDY5IDQ4LjAxNTcgNjIuMDQ0VjU5LjYzNVoiCiAgICAgICAgZmlsbD0id2hpdGUiIC8+CiAgICA8cGF0aAogICAgICAgIGQ9Ik0zMy41MzU1IDU5LjYzNUMzMy41MzU1IDU4Ljc5NjEgMzQuMTI0OSA1OC4xMTYgMzQuODUxOSA1OC4xMTZDMzUuNTc4OSA1OC4xMTYgMzYuMTY4MyA1OC43OTYxIDM2LjE2ODMgNTkuNjM1VjYyLjA0NEMzNi4xNjgzIDYyLjQ0NjkgMzYuMDI5NiA2Mi44MzMzIDM1Ljc4MjcgNjMuMTE4MUMzNS4yNjg2IDYzLjcxMTQgMzQuNDM1MSA2My43MTE0IDMzLjkyMTEgNjMuMTE4MUMzMy42NzQyIDYyLjgzMzMgMzMuNTM1NSA2Mi40NDY5IDMzLjUzNTUgNjIuMDQ0VjU5LjYzNVoiCiAgICAgICAgZmlsbD0id2hpdGUiIC8+CiAgICA8cGF0aAogICAgICAgIGQ9Ik01MS45NjQ4IDU5LjYzNUM1MS45NjQ4IDU4Ljc5NjEgNTIuNTU0MiA1OC4xMTYgNTMuMjgxMiA1OC4xMTZDNTQuMDA4MiA1OC4xMTYgNTQuNTk3NiA1OC43OTYxIDU0LjU5NzYgNTkuNjM1VjYyLjA0NEM1NC41OTc2IDYyLjQ0NjkgNTQuNDU4OSA2Mi44MzMzIDU0LjIxMiA2My4xMTgxQzUzLjY5OCA2My43MTE0IDUyLjg2NDUgNjMuNzExNCA1Mi4zNTA0IDYzLjExODFDNTIuMTAzNSA2Mi44MzMzIDUxLjk2NDggNjIuNDQ2OSA1MS45NjQ4IDYyLjA0NFY1OS42MzVaIgogICAgICAgIGZpbGw9IndoaXRlIiAvPgo8L3N2Zz4="
class="header3__card-recommendation-header-photo header3__card-recommendation-header-photo_default"
/>
<img
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODAiIGhlaWdodD0iODAiIHZpZXdCb3g9IjAgMCA4MCA4MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxtYXNrIGlkPSJhIiBmaWxsPSIjZmZmIj4KICAgICAgICA8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIKICAgICAgICAgICAgZD0iTTAgMTJDMCA1LjM3MyA1LjM3MyAwIDEyIDBoNTZjNi42MjcgMCAxMiA1LjM3MyAxMiAxMnY1NmMwIDYuNjI3LTUuMzczIDEyLTEyIDEySDEyQzUuMzczIDgwIDAgNzQuNjI3IDAgNjhWMTJabTM1LjAwNSAzMy44NzNjMCAxLjA1OCAxLjEwNCAxLjcwMyAxLjk1NSAxLjE0Mmw3LjY3LTUuMDUyYy4zNzMtLjI0Ni42LS42NzguNi0xLjE0MlYyNi43NDlzMi41NTYgMCA4Ljk0Ny00LjA0MmMzLjEyNC0xLjk3NSA0LjcyMS0zLjk1MSA1LjUzNy01LjQ1NC41MzMtLjk4MS0uNDYzLTEuNjk0LTEuNDE3LTEuMTgtMi45NjggMS41OTUtOC45MDUgMy45NC0xOC4xOCAzLjk0LTkuMjc0IDAtMTUuMjEyLTIuMzQ1LTE4LjE3OS0zLjk0LS45NTQtLjUxNC0xLjk1LjE5OS0xLjQxOCAxLjE4LjgxNyAxLjUwMyAyLjQxMyAzLjQ3OSA1LjUzOCA1LjQ1NCA2LjM5IDQuMDQyIDguOTQ3IDQuMDQyIDguOTQ3IDQuMDQydjE5LjEyNFptLTguMDUxLTYuMjM1YzIuMTggMCAzLjk0OS0xLjgzIDMuOTQ5LTQuMDg1IDAtMi4yNTctMS43NjgtNC4wODYtMy45NS00LjA4Ni0yLjE4IDAtMy45NDkgMS44My0zLjk0OSA0LjA4NiAwIDIuMjU2IDEuNzY4IDQuMDg1IDMuOTUgNC4wODVabTMwLjI3Ni00LjA4NWMwIDIuMjU2LTEuNzY4IDQuMDg1LTMuOTQ5IDQuMDg1LTIuMTggMC0zLjk0OS0xLjgzLTMuOTQ5LTQuMDg1IDAtMi4yNTcgMS43NjgtNC4wODYgMy45NS00LjA4NiAyLjE4IDAgMy45NDggMS44MyAzLjk0OCA0LjA4NlpNMjYuOTU0IDU4LjExNmMtLjcyNyAwLTEuMzE3LjY4LTEuMzE3IDEuNTE5djIuNDA5YzAgLjQwMy4xMzkuNzkuMzg2IDEuMDc0LjUxNC41OTMgMS4zNDcuNTkzIDEuODYxIDAgLjI0Ny0uMjg1LjM4Ni0uNjcxLjM4Ni0xLjA3NHYtMi40MDljMC0uODM5LS41OS0xLjUxOS0xLjMxNy0xLjUxOVptMTguNDI5IDBjLS43MjcgMC0xLjMxNy42OC0xLjMxNyAxLjUxOXYyLjQwOWMwIC40MDMuMTQuNzkuMzg2IDEuMDc0LjUxNC41OTMgMS4zNDguNTkzIDEuODYyIDAgLjI0Ny0uMjg1LjM4NS0uNjcxLjM4NS0xLjA3NHYtMi40MDljMC0uODM5LS41OS0xLjUxOS0xLjMxNi0xLjUxOVptLTE1Ljc5NyAxLjUxOWMwLS44MzkuNTktMS41MTkgMS4zMTctMS41MTlzMS4zMTYuNjggMS4zMTYgMS41MTl2Mi40MDljMCAuNDAzLS4xMzkuNzktLjM4NiAxLjA3NC0uNTE0LjU5My0xLjM0Ny41OTMtMS44NjEgMGExLjY0NSAxLjY0NSAwIDAgMS0uMzg2LTEuMDc0di0yLjQwOVptMTkuNzQ2LTEuNTE5Yy0uNzI3IDAtMS4zMTYuNjgtMS4zMTYgMS41MTl2Mi40MDljMCAuNDAzLjEzOC43OS4zODUgMS4wNzQuNTE0LjU5MyAxLjM0OC41OTMgMS44NjIgMCAuMjQ3LS4yODUuMzg1LS42NzEuMzg1LTEuMDc0di0yLjQwOWMwLS44MzktLjU4OS0xLjUxOS0xLjMxNi0xLjUxOVptLTE1Ljc5NyAxLjUxOWMwLS44MzkuNTktMS41MTkgMS4zMTctMS41MTlzMS4zMTYuNjggMS4zMTYgMS41MTl2Mi40MDljMCAuNDAzLS4xMzkuNzktLjM4NSAxLjA3NC0uNTE0LjU5My0xLjM0OC41OTMtMS44NjIgMGExLjY0NSAxLjY0NSAwIDAgMS0uMzg2LTEuMDc0di0yLjQwOVptMTkuNzQ2LTEuNTE5Yy0uNzI3IDAtMS4zMTYuNjgtMS4zMTYgMS41MTl2Mi40MDljMCAuNDAzLjEzOC43OS4zODUgMS4wNzQuNTE0LjU5MyAxLjM0OC41OTMgMS44NjIgMCAuMjQ3LS4yODUuMzg2LS42NzEuMzg2LTEuMDc0di0yLjQwOWMwLS44MzktLjU5LTEuNTE5LTEuMzE3LTEuNTE5WiIgLz4KICAgIDwvbWFzaz4KICAgIDxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIgogICAgICAgIGQ9Ik0wIDEyQzAgNS4zNzMgNS4zNzMgMCAxMiAwaDU2YzYuNjI3IDAgMTIgNS4zNzMgMTIgMTJ2NTZjMCA2LjYyNy01LjM3MyAxMi0xMiAxMkgxMkM1LjM3MyA4MCAwIDc0LjYyNyAwIDY4VjEyWm0zNS4wMDUgMzMuODczYzAgMS4wNTggMS4xMDQgMS43MDMgMS45NTUgMS4xNDJsNy42Ny01LjA1MmMuMzczLS4yNDYuNi0uNjc4LjYtMS4xNDJWMjYuNzQ5czIuNTU2IDAgOC45NDctNC4wNDJjMy4xMjQtMS45NzUgNC43MjEtMy45NTEgNS41MzctNS40NTQuNTMzLS45ODEtLjQ2My0xLjY5NC0xLjQxNy0xLjE4LTIuOTY4IDEuNTk1LTguOTA1IDMuOTQtMTguMTggMy45NC05LjI3NCAwLTE1LjIxMi0yLjM0NS0xOC4xNzktMy45NC0uOTU0LS41MTQtMS45NS4xOTktMS40MTggMS4xOC44MTcgMS41MDMgMi40MTMgMy40NzkgNS41MzggNS40NTQgNi4zOSA0LjA0MiA4Ljk0NyA0LjA0MiA4Ljk0NyA0LjA0MnYxOS4xMjRabS04LjA1MS02LjIzNWMyLjE4IDAgMy45NDktMS44MyAzLjk0OS00LjA4NSAwLTIuMjU3LTEuNzY4LTQuMDg2LTMuOTUtNC4wODYtMi4xOCAwLTMuOTQ5IDEuODMtMy45NDkgNC4wODYgMCAyLjI1NiAxLjc2OCA0LjA4NSAzLjk1IDQuMDg1Wm0zMC4yNzYtNC4wODVjMCAyLjI1Ni0xLjc2OCA0LjA4NS0zLjk0OSA0LjA4NS0yLjE4IDAtMy45NDktMS44My0zLjk0OS00LjA4NSAwLTIuMjU3IDEuNzY4LTQuMDg2IDMuOTUtNC4wODYgMi4xOCAwIDMuOTQ4IDEuODMgMy45NDggNC4wODZaTTI2Ljk1NCA1OC4xMTZjLS43MjcgMC0xLjMxNy42OC0xLjMxNyAxLjUxOXYyLjQwOWMwIC40MDMuMTM5Ljc5LjM4NiAxLjA3NC41MTQuNTkzIDEuMzQ3LjU5MyAxLjg2MSAwIC4yNDctLjI4NS4zODYtLjY3MS4zODYtMS4wNzR2LTIuNDA5YzAtLjgzOS0uNTktMS41MTktMS4zMTctMS41MTlabTE4LjQyOSAwYy0uNzI3IDAtMS4zMTcuNjgtMS4zMTcgMS41MTl2Mi40MDljMCAuNDAzLjE0Ljc5LjM4NiAxLjA3NC41MTQuNTkzIDEuMzQ4LjU5MyAxLjg2MiAwIC4yNDctLjI4NS4zODUtLjY3MS4zODUtMS4wNzR2LTIuNDA5YzAtLjgzOS0uNTktMS41MTktMS4zMTYtMS41MTlabS0xNS43OTcgMS41MTljMC0uODM5LjU5LTEuNTE5IDEuMzE3LTEuNTE5czEuMzE2LjY4IDEuMzE2IDEuNTE5djIuNDA5YzAgLjQwMy0uMTM5Ljc5LS4zODYgMS4wNzQtLjUxNC41OTMtMS4zNDcuNTkzLTEuODYxIDBhMS42NDUgMS42NDUgMCAwIDEtLjM4Ni0xLjA3NHYtMi40MDlabTE5Ljc0Ni0xLjUxOWMtLjcyNyAwLTEuMzE2LjY4LTEuMzE2IDEuNTE5djIuNDA5YzAgLjQwMy4xMzguNzkuMzg1IDEuMDc0LjUxNC41OTMgMS4zNDguNTkzIDEuODYyIDAgLjI0Ny0uMjg1LjM4NS0uNjcxLjM4NS0xLjA3NHYtMi40MDljMC0uODM5LS41ODktMS41MTktMS4zMTYtMS41MTlabS0xNS43OTcgMS41MTljMC0uODM5LjU5LTEuNTE5IDEuMzE3LTEuNTE5czEuMzE2LjY4IDEuMzE2IDEuNTE5djIuNDA5YzAgLjQwMy0uMTM5Ljc5LS4zODUgMS4wNzQtLjUxNC41OTMtMS4zNDguNTkzLTEuODYyIDBhMS42NDUgMS42NDUgMCAwIDEtLjM4Ni0xLjA3NHYtMi40MDlabTE5Ljc0Ni0xLjUxOWMtLjcyNyAwLTEuMzE2LjY4LTEuMzE2IDEuNTE5djIuNDA5YzAgLjQwMy4xMzguNzkuMzg1IDEuMDc0LjUxNC41OTMgMS4zNDguNTkzIDEuODYyIDAgLjI0Ny0uMjg1LjM4Ni0uNjcxLjM4Ni0xLjA3NHYtMi40MDljMC0uODM5LS41OS0xLjUxOS0xLjMxNy0xLjUxOVoiCiAgICAgICAgZmlsbD0iI2ZmZiIgLz4KICAgIDxwYXRoCiAgICAgICAgZD0ibTM2Ljk2IDQ3LjAxNSAxLjEgMS42Ny0xLjEtMS42N1ptNy42Ny01LjA1MiAxLjEgMS42Ny0xLjEtMS42N1ptLjYtMTUuMjE0di0yaC0ydjJoMlptOC45NDctNC4wNDIgMS4wNjkgMS42OS0xLjA2OS0xLjY5Wm01LjUzNy01LjQ1NCAxLjc1OC45NTQtMS43NTgtLjk1NFptLTEuNDE3LTEuMTguOTQ3IDEuNzYtLjk0Ny0xLjc2Wm0tMzYuMzU5IDAtLjk0NyAxLjc2Ljk0Ny0xLjc2Wm0tMS40MTggMS4xOCAxLjc1OC0uOTU1LTEuNzU4Ljk1NVptNS41MzggNS40NTQtMS4wNyAxLjY5IDEuMDctMS42OVptOC45NDcgNC4wNDJoMnYtMmgtMnYyWm0tOC45ODIgMzYuMzcgMS41MTEtMS4zMS0xLjUxMSAxLjMxWm0xLjg2MSAwIDEuNTEyIDEuMzA5LTEuNTEyLTEuMzFabTE2LjU2OCAwLTEuNTExIDEuMzA5IDEuNTExLTEuMzFabTEuODYyIDAgMS41MTEgMS4zMDktMS41MTEtMS4zMVptLTE0LjQ4IDAtMS41MTItMS4zMSAxLjUxMiAxLjMxWm0tMS44NjIgMCAxLjUxMS0xLjMxLTEuNTExIDEuMzFabTE4LjQzIDAtMS41MTIgMS4zMDkgMS41MTEtMS4zMVptMS44NiAwIDEuNTEyIDEuMzA5LTEuNTExLTEuMzFabS0xNC40OCAwIDEuNTEyIDEuMzA5LTEuNTExLTEuMzFabS0xLjg2MSAwLTEuNTExIDEuMzA5IDEuNTExLTEuMzFabTE4LjQzIDAgMS41MS0xLjMxLTEuNTEgMS4zMVptMS44NjEgMCAxLjUxMSAxLjMwOS0xLjUxMS0xLjMxWk0xMi0yQzQuMjY4LTItMiA0LjI2OC0yIDEyaDRDMiA2LjQ3NyA2LjQ3NyAyIDEyIDJ2LTRabTU2IDBIMTJ2NGg1NnYtNFptMTQgMTRjMC03LjczMi02LjI2OC0xNC0xNC0xNHY0YzUuNTIzIDAgMTAgNC40NzcgMTAgMTBoNFptMCA1NlYxMmgtNHY1Nmg0Wk02OCA4MmM3LjczMiAwIDE0LTYuMjY4IDE0LTE0aC00YzAgNS41MjMtNC40NzcgMTAtMTAgMTB2NFptLTU2IDBoNTZ2LTRIMTJ2NFpNLTIgNjhjMCA3LjczMiA2LjI2OCAxNCAxNCAxNHYtNEM2LjQ3NyA3OCAyIDczLjUyMyAyIDY4aC00Wm0wLTU2djU2aDRWMTJoLTRabTM3Ljg2IDMzLjM0NWEuNzkxLjc5MSAwIDAgMSAuODEyLS4wMjEuNjU2LjY1NiAwIDAgMSAuMzMzLjU0OWgtNGMwIDIuNDU0IDIuNzE0IDQuMzU1IDUuMDU1IDIuODEybC0yLjItMy4zNFptNy42NjktNS4wNTItNy42NjkgNS4wNTIgMi4yIDMuMzQgNy42Ny01LjA1Mi0yLjIwMS0zLjM0Wm0tLjI5OS41MjhjMC0uMTc4LjA4Ni0uMzg4LjI5OS0uNTI4bDIuMiAzLjM0YTMuMzY1IDMuMzY1IDAgMCAwIDEuNTAxLTIuODEyaC00Wm0wLTE0LjA3MlY0MC44Mmg0VjI2Ljc0OWgtNFptOS44NzgtNS43MzJjLTMuMDk3IDEuOTU5LTUuMTk3IDIuODk1LTYuNDY0IDMuMzRhOC44NDUgOC44NDUgMCAwIDEtMS4yOC4zNjIgMi40MiAyLjQyIDAgMCAxLS4yMDMuMDMxSDQ1LjE5bC4wMTgtLjAwMWguMDJjLjAwMSAwIC4wMDMgMCAuMDAzIDJzLjAwMiAyIC4wMDMgMmguMDU0YTMuMTk2IDMuMTk2IDAgMCAwIC4yNTYtLjAxN2MuMTQ0LS4wMTQuMzI3LS4wMzguNTUyLS4wOC40NS0uMDg0IDEuMDY5LS4yMzggMS44NzUtLjUyMSAxLjYxLS41NjYgMy45ODItMS42NSA3LjI3Ni0zLjczM2wtMi4xMzgtMy4zODFabTQuODQ5LTQuNzE5Yy0uNjM3IDEuMTczLTEuOTgzIDIuOTA2LTQuODQ5IDQuNzE5bDIuMTM4IDMuMzhjMy4zODItMi4xMzggNS4yMy00LjM1NiA2LjIyNi02LjE5bC0zLjUxNS0xLjkwOVptMS4yODcgMS41MzZjLS4xMDYuMDU2LS40OTQuMTczLS45MTYtLjE1OGExLjIzMyAxLjIzMyAwIDAgMS0uNDQ4LS43Ni45ODUuOTg1IDAgMCAxIC4wNzctLjYxOGwzLjUxNSAxLjkwOWMuMzA4LS41NjguNDcyLTEuMjQ4LjM1MS0xLjk2YTIuNzY4IDIuNzY4IDAgMCAwLTEuMDI1LTEuNzE4Yy0xLjAyNi0uODA1LTIuMzg4LS43ODgtMy40NDktLjIxOGwxLjg5NSAzLjUyM1ptLTE5LjEyNyA0LjE4YzkuNjI4IDAgMTUuODg5LTIuNDM4IDE5LjEyNy00LjE4bC0xLjg5NS0zLjUyM2MtMi42OTYgMS40NS04LjMxIDMuNzAyLTE3LjIzMiAzLjcwMnY0Wm0tMTkuMTI2LTQuMThjMy4yMzggMS43NDIgOS40OTkgNC4xOCAxOS4xMjYgNC4xOHYtNGMtOC45MjEgMC0xNC41MzUtMi4yNTMtMTcuMjMxLTMuNzAzbC0xLjg5NSAzLjUyM1ptMS4yODctMS41MzZjLjA0Mi4wNzguMTMxLjMuMDc3LjYxOWExLjIzMiAxLjIzMiAwIDAgMS0uNDQ5Ljc1OWMtLjQyMi4zMy0uODEuMjE1LS45MTUuMTU4bDEuODk1LTMuNTIzYy0xLjA2LS41Ny0yLjQyNC0uNTg3LTMuNDQ5LjIxOGEyLjc2OCAyLjc2OCAwIDAgMC0xLjAyNiAxLjcxOWMtLjEyLjcxMS4wNDMgMS4zOTEuMzUyIDEuOTU5bDMuNTE1LTEuOTA5Wm00Ljg0OSA0LjcxOWMtMi44NjctMS44MTMtNC4yMTItMy41NDYtNC44NDktNC43MTlsLTMuNTE1IDEuOTA5Yy45OTUgMS44MzQgMi44NDQgNC4wNTIgNi4yMjYgNi4xOWwyLjEzOC0zLjM4Wm03Ljg3OCA1LjczMmMwLTIgLjAwMS0yIC4wMDMtMkgzNS4wNDdsLjAyNS4wMDFoLjAwMWEyLjQyIDIuNDIgMCAwIDEtLjIwMi0uMDMgOC44NTIgOC44NTIgMCAwIDEtMS4yOC0uMzYzYy0xLjI2Ny0uNDQ1LTMuMzY3LTEuMzgxLTYuNDY0LTMuMzRsLTIuMTM4IDMuMzhjMy4yOTMgMi4wODQgNS42NjYgMy4xNjggNy4yNzYgMy43MzQuODA2LjI4MyAxLjQyNS40MzcgMS44NzUuNTJhNi4zNTYgNi4zNTYgMCAwIDAgLjczNy4wOTVsLjA3MS4wMDJoLjA1NGMuMDAxIDAgLjAwMyAwIC4wMDMtMlptMiAxOS4xMjRWMjYuNzQ5aC00djE5LjEyNGg0Wm0tOC4xMDItMTAuMzJjMCAxLjIxNi0uOTM2IDIuMDg1LTEuOTUgMi4wODV2NGMzLjM1IDAgNS45NS0yLjc4OSA1Ljk1LTYuMDg1aC00Wm0tMS45NS0yLjA4NmMxLjAxNCAwIDEuOTUuODcgMS45NSAyLjA4Nmg0YzAtMy4yOTctMi42LTYuMDg2LTUuOTUtNi4wODZ2NFptLTEuOTQ5IDIuMDg2YzAtMS4yMTYuOTM2LTIuMDg2IDEuOTUtMi4wODZ2LTRjLTMuMzUgMC01Ljk1IDIuNzktNS45NSA2LjA4Nmg0Wm0xLjk1IDIuMDg1Yy0xLjAxNCAwLTEuOTUtLjg3LTEuOTUtMi4wODVoLTRjMCAzLjI5NiAyLjYgNi4wODUgNS45NSA2LjA4NXYtNFptMjYuMzI3IDRjMy4zNSAwIDUuOTUtMi43ODkgNS45NS02LjA4NWgtNGMwIDEuMjE2LS45MzcgMi4wODUtMS45NSAyLjA4NXY0Wm0tNS45NDktNi4wODVjMCAzLjI5NiAyLjYgNi4wODUgNS45NSA2LjA4NXYtNGMtMS4wMTQgMC0xLjk1LS44Ny0xLjk1LTIuMDg1aC00Wm01Ljk1LTYuMDg2Yy0zLjM1IDAtNS45NSAyLjc5LTUuOTUgNi4wODZoNGMwLTEuMjE2LjkzNi0yLjA4NiAxLjk1LTIuMDg2di00Wm01Ljk0OCA2LjA4NmMwLTMuMjk3LTIuNi02LjA4Ni01Ljk0OS02LjA4NnY0YzEuMDEzIDAgMS45NS44NyAxLjk1IDIuMDg2aDRaTTI3LjYzNyA1OS42MzVhLjM3LjM3IDAgMCAxLS4xMDMuMjM2Ljc3NC43NzQgMCAwIDEtLjU4LjI0NXYtNGMtMi4wOTEgMC0zLjMxNyAxLjg1NC0zLjMxNyAzLjUxOWg0Wm0wIDIuNDA5di0yLjQwOWgtNHYyLjQwOWg0Wm0tLjEwMy0uMjM2YS40NS40NSAwIDAgMSAuMDg2LjE0Mi4yNzcuMjc3IDAgMCAxIC4wMTcuMDk0aC00YzAgLjg0OC4yOSAxLjcxLjg3NCAyLjM4NGwzLjAyMy0yLjYyWm0tMS4xNjEgMGEuNzc2Ljc3NiAwIDAgMSAuNTgtLjI0NWMuMjcgMCAuNDc2LjEyNC41ODEuMjQ1bC0zLjAyMyAyLjYyYzEuMzEyIDEuNTEzIDMuNTczIDEuNTEzIDQuODg1IDBsLTMuMDIzLTIuNjJabS0uMTAzLjIzNmMwLS4wMjcuMDA0LS4wNTguMDE3LS4wOTRhLjQ1LjQ1IDAgMCAxIC4wODYtLjE0MmwzLjAyMyAyLjYyYTMuNjQ0IDMuNjQ0IDAgMCAwIC44NzQtMi4zODRoLTRabTAtMi40MDl2Mi40MDloNHYtMi40MDloLTRabS42ODMuNDgxYy0uMjkgMC0uNDktLjE0LS41OC0uMjQ1YS4zNy4zNyAwIDAgMS0uMTAzLS4yMzZoNGMwLTEuNjY1LTEuMjI2LTMuNTE5LTMuMzE3LTMuNTE5djRabTE5LjExMy0uNDgxYS4zNy4zNyAwIDAgMS0uMTAyLjIzNi43NzQuNzc0IDAgMCAxLS41ODEuMjQ1di00Yy0yLjA5MSAwLTMuMzE3IDEuODU0LTMuMzE3IDMuNTE5aDRabTAgMi40MDl2LTIuNDA5aC00djIuNDA5aDRabS0uMTAyLS4yMzZhLjQ1LjQ1IDAgMCAxIC4wODUuMTQyLjI3Ny4yNzcgMCAwIDEgLjAxNy4wOTRoLTRjMCAuODQ4LjI5IDEuNzEuODc1IDIuMzg0bDMuMDIzLTIuNjJabS0xLjE2MiAwYS43NzUuNzc1IDAgMCAxIC41OC0uMjQ1Yy4yNzEgMCAuNDc3LjEyNC41ODIuMjQ1bC0zLjAyMyAyLjYyYzEuMzExIDEuNTEzIDMuNTczIDEuNTEzIDQuODg0IDBsLTMuMDIzLTIuNjJabS0uMTAzLjIzNmMwLS4wMjcuMDA1LS4wNTguMDE4LS4wOTRhLjQ1LjQ1IDAgMCAxIC4wODUtLjE0MmwzLjAyMyAyLjYyYTMuNjQ1IDMuNjQ1IDAgMCAwIC44NzQtMi4zODRoLTRabTAtMi40MDl2Mi40MDloNHYtMi40MDloLTRabS42ODQuNDgxYy0uMjkgMC0uNDktLjE0LS41OC0uMjQ1YS4zNjkuMzY5IDAgMCAxLS4xMDQtLjIzNmg0YzAtMS42NjUtMS4yMjUtMy41MTktMy4zMTYtMy41MTl2NFptLTE0LjQ4LTRjLTIuMDkxIDAtMy4zMTcgMS44NTQtMy4zMTcgMy41MTloNGEuMzcuMzcgMCAwIDEtLjEwMy4yMzYuNzc0Ljc3NCAwIDAgMS0uNTguMjQ1di00Wm0zLjMxNiAzLjUxOWMwLTEuNjY1LTEuMjI1LTMuNTE5LTMuMzE2LTMuNTE5djRjLS4yOSAwLS40OS0uMTQtLjU4LS4yNDVhLjM3LjM3IDAgMCAxLS4xMDQtLjIzNmg0Wm0wIDIuNDA5di0yLjQwOWgtNHYyLjQwOWg0Wm0tLjg3NCAyLjM4NGEzLjY0NCAzLjY0NCAwIDAgMCAuODc0LTIuMzg0aC00YzAtLjAyNy4wMDUtLjA1OC4wMTctLjA5NGEuNDUuNDUgMCAwIDEgLjA4Ni0uMTQybDMuMDIzIDIuNjJabS00Ljg4NSAwYzEuMzEyIDEuNTEzIDMuNTczIDEuNTEzIDQuODg1IDBsLTMuMDIzLTIuNjJhLjc3NS43NzUgMCAwIDEgLjU4LS4yNDVjLjI3IDAgLjQ3Ni4xMjQuNTgxLjI0NWwtMy4wMjMgMi42MlptLS44NzQtMi4zODRjMCAuODQ4LjI5IDEuNzEuODc0IDIuMzg0bDMuMDIzLTIuNjJhLjQ1LjQ1IDAgMCAxIC4wODYuMTQyLjI3Ny4yNzcgMCAwIDEgLjAxNy4wOTRoLTRabTAtMi40MDl2Mi40MDloNHYtMi40MDloLTRabTIyLjQzIDBhLjM3LjM3IDAgMCAxLS4xMDMuMjM2Ljc3NC43NzQgMCAwIDEtLjU4MS4yNDV2LTRjLTIuMDkgMC0zLjMxNiAxLjg1NC0zLjMxNiAzLjUxOWg0Wm0wIDIuNDA5di0yLjQwOWgtNHYyLjQwOWg0Wm0tLjEwMy0uMjM2YS40NTMuNDUzIDAgMCAxIC4wODUuMTQyLjI3Ny4yNzcgMCAwIDEgLjAxOC4wOTRoLTRjMCAuODQ4LjI5IDEuNzEuODc0IDIuMzg0bDMuMDIzLTIuNjJabS0xLjE2MiAwYS43NzYuNzc2IDAgMCAxIC41ODEtLjI0NWMuMjcgMCAuNDc2LjEyNC41OC4yNDVsLTMuMDIyIDIuNjJjMS4zMTEgMS41MTMgMy41NzMgMS41MTMgNC44ODQgMGwtMy4wMjMtMi42MlptLS4xMDMuMjM2YzAtLjAyNy4wMDUtLjA1OC4wMTgtLjA5NGEuNDUuNDUgMCAwIDEgLjA4NS0uMTQybDMuMDIzIDIuNjJhMy42NDQgMy42NDQgMCAwIDAgLjg3NC0yLjM4NGgtNFptMC0yLjQwOXYyLjQwOWg0di0yLjQwOWgtNFptLjY4NC40ODFjLS4yOSAwLS40OS0uMTQtLjU4LS4yNDVhLjM3LjM3IDAgMCAxLS4xMDQtLjIzNmg0YzAtMS42NjUtMS4yMjUtMy41MTktMy4zMTYtMy41MTl2NFptLTE0LjQ4LTRjLTIuMDkxIDAtMy4zMTYgMS44NTQtMy4zMTYgMy41MTloNGEuMzcuMzcgMCAwIDEtLjEwNC4yMzYuNzc0Ljc3NCAwIDAgMS0uNTguMjQ1di00Wm0zLjMxNiAzLjUxOWMwLTEuNjY1LTEuMjI1LTMuNTE5LTMuMzE2LTMuNTE5djRjLS4yOSAwLS40OS0uMTQtLjU4LS4yNDVhLjM3LjM3IDAgMCAxLS4xMDQtLjIzNmg0Wm0wIDIuNDA5di0yLjQwOWgtNHYyLjQwOWg0Wm0tLjg3NCAyLjM4NGEzLjY0NCAzLjY0NCAwIDAgMCAuODc0LTIuMzg0aC00YzAtLjAyNy4wMDUtLjA1OC4wMTgtLjA5NGEuNDUuNDUgMCAwIDEgLjA4NS0uMTQybDMuMDIzIDIuNjJabS00Ljg4NCAwYzEuMzExIDEuNTEzIDMuNTczIDEuNTEzIDQuODg0IDBsLTMuMDIzLTIuNjJhLjc3Ni43NzYgMCAwIDEgLjU4LS4yNDVjLjI3MSAwIC40NzcuMTI0LjU4MS4yNDVsLTMuMDIyIDIuNjJabS0uODc0LTIuMzg0YzAgLjg0OC4yODkgMS43MS44NzQgMi4zODRsMy4wMjMtMi42MmEuNDUzLjQ1MyAwIDAgMSAuMDg1LjE0Mi4yNzcuMjc3IDAgMCAxIC4wMTcuMDk0aC00Wm0wLTIuNDA5djIuNDA5aDR2LTIuNDA5aC00Wm0yMi40MjkgMGEuMzcuMzcgMCAwIDEtLjEwMy4yMzYuNzc0Ljc3NCAwIDAgMS0uNTguMjQ1di00Yy0yLjA5MiAwLTMuMzE3IDEuODU0LTMuMzE3IDMuNTE5aDRabTAgMi40MDl2LTIuNDA5aC00djIuNDA5aDRabS0uMTAzLS4yMzZhLjQ1LjQ1IDAgMCAxIC4wODUuMTQyLjI3Ny4yNzcgMCAwIDEgLjAxOC4wOTRoLTRjMCAuODQ4LjI5IDEuNzEuODc0IDIuMzg0bDMuMDIzLTIuNjJabS0xLjE2MiAwYS43NzYuNzc2IDAgMCAxIC41ODEtLjI0NWMuMjcgMCAuNDc2LjEyNC41OC4yNDVsLTMuMDIyIDIuNjJjMS4zMTIgMS41MTMgMy41NzMgMS41MTMgNC44ODUgMGwtMy4wMjMtMi42MlptLS4xMDIuMjM2YzAtLjAyNy4wMDQtLjA1OC4wMTctLjA5NGEuNDU1LjQ1NSAwIDAgMSAuMDg1LS4xNDJsMy4wMjMgMi42MmEzLjY0NSAzLjY0NSAwIDAgMCAuODc1LTIuMzg0aC00Wm0wLTIuNDA5djIuNDA5aDR2LTIuNDA5aC00Wm0uNjgzLjQ4MWMtLjI5IDAtLjQ5LS4xNC0uNTgtLjI0NWEuMzcuMzcgMCAwIDEtLjEwMy0uMjM2aDRjMC0xLjY2NS0xLjIyNi0zLjUxOS0zLjMxNy0zLjUxOXY0WiIKICAgICAgICBmaWxsPSIjZmZmIiBtYXNrPSJ1cmwoI2EpIiAvPgo8L3N2Zz4="
class="header3__card-recommendation-header-photo header3__card-recommendation-header-photo_default_inverted"
/>
</div>
<div class="header3__card-recommendation-header-content">
<div class="header3__card-recommendation-header-content-tag">
Курс
</div>
<div class="header3__card-recommendation-header-sub">
<span
class="header3__card-recommendation-header-sub-chunk header3__card-recommendation-header-sub-chunk_green"
>
Скидка 20000 ₽
</span>
</div>
</div>
</div>
<h6 class="header3__card-recommendation-title">
AI для аналитики и работы с данными
</h6>
<div class="header3__card-recommendation-footer">
12 марта
, 2026
· 2 месяца
</div>
</a>
</div>
</div>
</div>
</div>
<div class="header3__hamburger-tabs-tab-content">
<div class="header3__nav-column">
<div>
<p class="header3__nav-section-title ">OTUS</p>
<div class="header3__nav-section-items ">
<a
class="header3__nav-section-item"
href="/about"
>
О компании
</a>
<a
class="header3__nav-section-item"
href="/smi/"
>
СМИ о нас
</a>
<a
class="header3__nav-section-item js-stats"
href="/journal/"
target="_blank"
rel="noreferrer nofollow"
data-event="header;click_otus_journal"
data-goal="click_otus_journal"
>
OTUS Журнал
</a>
<a
class="header3__nav-section-item"
href="https://direct.otus.ru/"
target="_blank"
rel="noreferrer nofollow"
>
OTUS Директ
</a>
<a
class="header3__nav-section-item"
href="/legal/common/"
>
Сведения об образовательной организации
</a>
<a
class="header3__nav-section-item"
href="/contacts/"
>
Контактная информация
</a>
</div>
</div>
</div>
<div class="header3__nav-column">
<div>
<p class="header3__nav-section-title ">Студентам</p>
<div class="header3__nav-section-items ">
<a
class="header3__nav-section-item"
href="/reviews"
>
Отзывы
</a>
<a
class="header3__nav-section-item"
target="_blank"
href="https://landing.otus.ru/about-otus"
>
Как выбрать курс
</a>
<a
class="header3__nav-section-item"
target="_blank"
href="https://landing.otus.ru/gallery"
>
Истории выпускников
</a>
<a
class="header3__nav-section-item"
href="/instructors/"
>
Наши преподаватели
</a>
<a
class="header3__nav-section-item"
href="/employers/all/"
>
Наши партнеры
</a>
<a
class="header3__nav-section-item"
href="/about/loyalty/"
>
Программа лояльности
</a>
<a
class="header3__nav-section-item"
href="/faq/"
>
Вопросы и ответы
</a>
</div>
</div>
</div>
<div class="header3__nav-column">
<div>
<p class="header3__nav-section-title ">Преподавателям</p>
<div class="header3__nav-section-items ">
<a
class="header3__nav-section-item"
href="/teach/"
>
Стать преподавателем
</a>
<a
class="header3__nav-section-item"
href="/instructors/"
>
Наши преподаватели
</a>
<a
class="header3__nav-section-item"
href="/nest/dlja-prepodavatelej/"
>
База знаний
</a>
</div>
</div>
</div>
<div class="header3__nav-column header3__nav-column_space-between">
<div>
<p class="header3__nav-section-title header3__nav-section-items-recommendation-title">OTUS рекомендует</p>
<div class="header3__nav-section-items header3__nav-section-items_not-items header3__nav-section-items-recommendation">
<a
href="/lessons/ai-dlya-analitiki-i-raboty-s-dannymi/"
class="header3__card-recommendation"
>
<div
class="header3__card-recommendation-background"
style="background: linear-gradient( 90deg,#0A4489, #00316B);"
></div>
<div class="header3__card-recommendation-header">
<div class="header3__card-recommendation-header-photo-wrapper" style="background: linear-gradient( 90deg,#0A4489, #00316B);">
<img
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODAiIGhlaWdodD0iODAiIHZpZXdCb3g9IjAgMCA4MCA4MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoCiAgICAgICAgZD0iTTM1LjAwNDcgNDUuODcyNUMzNS4wMDQ3IDQ2LjkzMDYgMzYuMTA5IDQ3LjU3NTcgMzYuOTYwMyA0Ny4wMTQ5TDQ0LjYyOTIgNDEuOTYzMUM0NS4wMDI5IDQxLjcxNjkgNDUuMjI5OSA0MS4yODUyIDQ1LjIyOTkgNDAuODIwN1YyNi43NDg5QzQ1LjIyOTkgMjYuNzQ4OSA0Ny43ODYyIDI2Ljc0ODkgNTQuMTc3IDIyLjcwNzRDNTcuMzAxMiAyMC43MzE4IDU4Ljg5OCAxOC43NTYxIDU5LjcxNDMgMTcuMjUyNUM2MC4yNDY1IDE2LjI3MjEgNTkuMjUxMSAxNS41NTg4IDU4LjI5NjUgMTYuMDcyM0M1NS4zMjkyIDE3LjY2ODQgNDkuMzkxOCAyMC4wMTMyIDQwLjExNzMgMjAuMDEzMkMzMC44NDI4IDIwLjAxMzIgMjQuOTA1NCAxNy42Njg0IDIxLjkzODEgMTYuMDcyM0MyMC45ODM1IDE1LjU1ODggMTkuOTg4MSAxNi4yNzIxIDIwLjUyMDMgMTcuMjUyNUMyMS4zMzY2IDE4Ljc1NjEgMjIuOTMzNCAyMC43MzE4IDI2LjA1NzcgMjIuNzA3NEMzMi40NDg0IDI2Ljc0ODkgMzUuMDA0NyAyNi43NDg5IDM1LjAwNDcgMjYuNzQ4OVY0NS44NzI1WiIKICAgICAgICBmaWxsPSJ3aGl0ZSIgLz4KICAgIDxlbGxpcHNlIGN4PSIyNi45NTM1IiBjeT0iMzUuNTUyNiIgcng9IjMuOTQ5MTQiIHJ5PSI0LjA4NTMyIiBmaWxsPSJ3aGl0ZSIgLz4KICAgIDxlbGxpcHNlIGN4PSI1My4yODEyIiBjeT0iMzUuNTUyNiIgcng9IjMuOTQ5MTQiIHJ5PSI0LjA4NTMyIiBmaWxsPSJ3aGl0ZSIgLz4KICAgIDxwYXRoCiAgICAgICAgZD0iTTI1LjYzNzIgNTkuNjM1QzI1LjYzNzIgNTguNzk2MSAyNi4yMjY2IDU4LjExNiAyNi45NTM2IDU4LjExNkMyNy42ODA2IDU4LjExNiAyOC4yNyA1OC43OTYxIDI4LjI3IDU5LjYzNVY2Mi4wNDRDMjguMjcgNjIuNDQ2OSAyOC4xMzEzIDYyLjgzMzMgMjcuODg0NCA2My4xMTgxQzI3LjM3MDMgNjMuNzExNCAyNi41MzY4IDYzLjcxMTQgMjYuMDIyOCA2My4xMTgxQzI1Ljc3NTkgNjIuODMzMyAyNS42MzcyIDYyLjQ0NjkgMjUuNjM3MiA2Mi4wNDRWNTkuNjM1WiIKICAgICAgICBmaWxsPSJ3aGl0ZSIgLz4KICAgIDxwYXRoCiAgICAgICAgZD0iTTQ0LjA2NjUgNTkuNjM1QzQ0LjA2NjUgNTguNzk2MSA0NC42NTU5IDU4LjExNiA0NS4zODI5IDU4LjExNkM0Ni4xMDk5IDU4LjExNiA0Ni42OTkzIDU4Ljc5NjEgNDYuNjk5MyA1OS42MzVWNjIuMDQ0QzQ2LjY5OTMgNjIuNDQ2OSA0Ni41NjA2IDYyLjgzMzMgNDYuMzEzOCA2My4xMTgxQzQ1Ljc5OTcgNjMuNzExNCA0NC45NjYyIDYzLjcxMTQgNDQuNDUyMSA2My4xMTgxQzQ0LjIwNTIgNjIuODMzMyA0NC4wNjY1IDYyLjQ0NjkgNDQuMDY2NSA2Mi4wNDRWNTkuNjM1WiIKICAgICAgICBmaWxsPSJ3aGl0ZSIgLz4KICAgIDxwYXRoCiAgICAgICAgZD0iTTI5LjU4NjQgNTkuNjM1QzI5LjU4NjQgNTguNzk2MSAzMC4xNzU3IDU4LjExNiAzMC45MDI3IDU4LjExNkMzMS42Mjk4IDU4LjExNiAzMi4yMTkxIDU4Ljc5NjEgMzIuMjE5MSA1OS42MzVWNjIuMDQ0QzMyLjIxOTEgNjIuNDQ2OSAzMi4wODA0IDYyLjgzMzMgMzEuODMzNiA2My4xMTgxQzMxLjMxOTUgNjMuNzExNCAzMC40ODYgNjMuNzExNCAyOS45NzE5IDYzLjExODFDMjkuNzI1IDYyLjgzMzMgMjkuNTg2NCA2Mi40NDY5IDI5LjU4NjQgNjIuMDQ0VjU5LjYzNVoiCiAgICAgICAgZmlsbD0id2hpdGUiIC8+CiAgICA8cGF0aAogICAgICAgIGQ9Ik00OC4wMTU3IDU5LjYzNUM0OC4wMTU3IDU4Ljc5NjEgNDguNjA1MSA1OC4xMTYgNDkuMzMyMSA1OC4xMTZDNTAuMDU5MSA1OC4xMTYgNTAuNjQ4NSA1OC43OTYxIDUwLjY0ODUgNTkuNjM1VjYyLjA0NEM1MC42NDg1IDYyLjQ0NjkgNTAuNTA5OCA2Mi44MzMzIDUwLjI2MjkgNjMuMTE4MUM0OS43NDg4IDYzLjcxMTQgNDguOTE1MyA2My43MTE0IDQ4LjQwMTIgNjMuMTE4MUM0OC4xNTQ0IDYyLjgzMzMgNDguMDE1NyA2Mi40NDY5IDQ4LjAxNTcgNjIuMDQ0VjU5LjYzNVoiCiAgICAgICAgZmlsbD0id2hpdGUiIC8+CiAgICA8cGF0aAogICAgICAgIGQ9Ik0zMy41MzU1IDU5LjYzNUMzMy41MzU1IDU4Ljc5NjEgMzQuMTI0OSA1OC4xMTYgMzQuODUxOSA1OC4xMTZDMzUuNTc4OSA1OC4xMTYgMzYuMTY4MyA1OC43OTYxIDM2LjE2ODMgNTkuNjM1VjYyLjA0NEMzNi4xNjgzIDYyLjQ0NjkgMzYuMDI5NiA2Mi44MzMzIDM1Ljc4MjcgNjMuMTE4MUMzNS4yNjg2IDYzLjcxMTQgMzQuNDM1MSA2My43MTE0IDMzLjkyMTEgNjMuMTE4MUMzMy42NzQyIDYyLjgzMzMgMzMuNTM1NSA2Mi40NDY5IDMzLjUzNTUgNjIuMDQ0VjU5LjYzNVoiCiAgICAgICAgZmlsbD0id2hpdGUiIC8+CiAgICA8cGF0aAogICAgICAgIGQ9Ik01MS45NjQ4IDU5LjYzNUM1MS45NjQ4IDU4Ljc5NjEgNTIuNTU0MiA1OC4xMTYgNTMuMjgxMiA1OC4xMTZDNTQuMDA4MiA1OC4xMTYgNTQuNTk3NiA1OC43OTYxIDU0LjU5NzYgNTkuNjM1VjYyLjA0NEM1NC41OTc2IDYyLjQ0NjkgNTQuNDU4OSA2Mi44MzMzIDU0LjIxMiA2My4xMTgxQzUzLjY5OCA2My43MTE0IDUyLjg2NDUgNjMuNzExNCA1Mi4zNTA0IDYzLjExODFDNTIuMTAzNSA2Mi44MzMzIDUxLjk2NDggNjIuNDQ2OSA1MS45NjQ4IDYyLjA0NFY1OS42MzVaIgogICAgICAgIGZpbGw9IndoaXRlIiAvPgo8L3N2Zz4="
class="header3__card-recommendation-header-photo header3__card-recommendation-header-photo_default"
/>
<img
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODAiIGhlaWdodD0iODAiIHZpZXdCb3g9IjAgMCA4MCA4MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxtYXNrIGlkPSJhIiBmaWxsPSIjZmZmIj4KICAgICAgICA8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIKICAgICAgICAgICAgZD0iTTAgMTJDMCA1LjM3MyA1LjM3MyAwIDEyIDBoNTZjNi42MjcgMCAxMiA1LjM3MyAxMiAxMnY1NmMwIDYuNjI3LTUuMzczIDEyLTEyIDEySDEyQzUuMzczIDgwIDAgNzQuNjI3IDAgNjhWMTJabTM1LjAwNSAzMy44NzNjMCAxLjA1OCAxLjEwNCAxLjcwMyAxLjk1NSAxLjE0Mmw3LjY3LTUuMDUyYy4zNzMtLjI0Ni42LS42NzguNi0xLjE0MlYyNi43NDlzMi41NTYgMCA4Ljk0Ny00LjA0MmMzLjEyNC0xLjk3NSA0LjcyMS0zLjk1MSA1LjUzNy01LjQ1NC41MzMtLjk4MS0uNDYzLTEuNjk0LTEuNDE3LTEuMTgtMi45NjggMS41OTUtOC45MDUgMy45NC0xOC4xOCAzLjk0LTkuMjc0IDAtMTUuMjEyLTIuMzQ1LTE4LjE3OS0zLjk0LS45NTQtLjUxNC0xLjk1LjE5OS0xLjQxOCAxLjE4LjgxNyAxLjUwMyAyLjQxMyAzLjQ3OSA1LjUzOCA1LjQ1NCA2LjM5IDQuMDQyIDguOTQ3IDQuMDQyIDguOTQ3IDQuMDQydjE5LjEyNFptLTguMDUxLTYuMjM1YzIuMTggMCAzLjk0OS0xLjgzIDMuOTQ5LTQuMDg1IDAtMi4yNTctMS43NjgtNC4wODYtMy45NS00LjA4Ni0yLjE4IDAtMy45NDkgMS44My0zLjk0OSA0LjA4NiAwIDIuMjU2IDEuNzY4IDQuMDg1IDMuOTUgNC4wODVabTMwLjI3Ni00LjA4NWMwIDIuMjU2LTEuNzY4IDQuMDg1LTMuOTQ5IDQuMDg1LTIuMTggMC0zLjk0OS0xLjgzLTMuOTQ5LTQuMDg1IDAtMi4yNTcgMS43NjgtNC4wODYgMy45NS00LjA4NiAyLjE4IDAgMy45NDggMS44MyAzLjk0OCA0LjA4NlpNMjYuOTU0IDU4LjExNmMtLjcyNyAwLTEuMzE3LjY4LTEuMzE3IDEuNTE5djIuNDA5YzAgLjQwMy4xMzkuNzkuMzg2IDEuMDc0LjUxNC41OTMgMS4zNDcuNTkzIDEuODYxIDAgLjI0Ny0uMjg1LjM4Ni0uNjcxLjM4Ni0xLjA3NHYtMi40MDljMC0uODM5LS41OS0xLjUxOS0xLjMxNy0xLjUxOVptMTguNDI5IDBjLS43MjcgMC0xLjMxNy42OC0xLjMxNyAxLjUxOXYyLjQwOWMwIC40MDMuMTQuNzkuMzg2IDEuMDc0LjUxNC41OTMgMS4zNDguNTkzIDEuODYyIDAgLjI0Ny0uMjg1LjM4NS0uNjcxLjM4NS0xLjA3NHYtMi40MDljMC0uODM5LS41OS0xLjUxOS0xLjMxNi0xLjUxOVptLTE1Ljc5NyAxLjUxOWMwLS44MzkuNTktMS41MTkgMS4zMTctMS41MTlzMS4zMTYuNjggMS4zMTYgMS41MTl2Mi40MDljMCAuNDAzLS4xMzkuNzktLjM4NiAxLjA3NC0uNTE0LjU5My0xLjM0Ny41OTMtMS44NjEgMGExLjY0NSAxLjY0NSAwIDAgMS0uMzg2LTEuMDc0di0yLjQwOVptMTkuNzQ2LTEuNTE5Yy0uNzI3IDAtMS4zMTYuNjgtMS4zMTYgMS41MTl2Mi40MDljMCAuNDAzLjEzOC43OS4zODUgMS4wNzQuNTE0LjU5MyAxLjM0OC41OTMgMS44NjIgMCAuMjQ3LS4yODUuMzg1LS42NzEuMzg1LTEuMDc0di0yLjQwOWMwLS44MzktLjU4OS0xLjUxOS0xLjMxNi0xLjUxOVptLTE1Ljc5NyAxLjUxOWMwLS44MzkuNTktMS41MTkgMS4zMTctMS41MTlzMS4zMTYuNjggMS4zMTYgMS41MTl2Mi40MDljMCAuNDAzLS4xMzkuNzktLjM4NSAxLjA3NC0uNTE0LjU5My0xLjM0OC41OTMtMS44NjIgMGExLjY0NSAxLjY0NSAwIDAgMS0uMzg2LTEuMDc0di0yLjQwOVptMTkuNzQ2LTEuNTE5Yy0uNzI3IDAtMS4zMTYuNjgtMS4zMTYgMS41MTl2Mi40MDljMCAuNDAzLjEzOC43OS4zODUgMS4wNzQuNTE0LjU5MyAxLjM0OC41OTMgMS44NjIgMCAuMjQ3LS4yODUuMzg2LS42NzEuMzg2LTEuMDc0di0yLjQwOWMwLS44MzktLjU5LTEuNTE5LTEuMzE3LTEuNTE5WiIgLz4KICAgIDwvbWFzaz4KICAgIDxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIgogICAgICAgIGQ9Ik0wIDEyQzAgNS4zNzMgNS4zNzMgMCAxMiAwaDU2YzYuNjI3IDAgMTIgNS4zNzMgMTIgMTJ2NTZjMCA2LjYyNy01LjM3MyAxMi0xMiAxMkgxMkM1LjM3MyA4MCAwIDc0LjYyNyAwIDY4VjEyWm0zNS4wMDUgMzMuODczYzAgMS4wNTggMS4xMDQgMS43MDMgMS45NTUgMS4xNDJsNy42Ny01LjA1MmMuMzczLS4yNDYuNi0uNjc4LjYtMS4xNDJWMjYuNzQ5czIuNTU2IDAgOC45NDctNC4wNDJjMy4xMjQtMS45NzUgNC43MjEtMy45NTEgNS41MzctNS40NTQuNTMzLS45ODEtLjQ2My0xLjY5NC0xLjQxNy0xLjE4LTIuOTY4IDEuNTk1LTguOTA1IDMuOTQtMTguMTggMy45NC05LjI3NCAwLTE1LjIxMi0yLjM0NS0xOC4xNzktMy45NC0uOTU0LS41MTQtMS45NS4xOTktMS40MTggMS4xOC44MTcgMS41MDMgMi40MTMgMy40NzkgNS41MzggNS40NTQgNi4zOSA0LjA0MiA4Ljk0NyA0LjA0MiA4Ljk0NyA0LjA0MnYxOS4xMjRabS04LjA1MS02LjIzNWMyLjE4IDAgMy45NDktMS44MyAzLjk0OS00LjA4NSAwLTIuMjU3LTEuNzY4LTQuMDg2LTMuOTUtNC4wODYtMi4xOCAwLTMuOTQ5IDEuODMtMy45NDkgNC4wODYgMCAyLjI1NiAxLjc2OCA0LjA4NSAzLjk1IDQuMDg1Wm0zMC4yNzYtNC4wODVjMCAyLjI1Ni0xLjc2OCA0LjA4NS0zLjk0OSA0LjA4NS0yLjE4IDAtMy45NDktMS44My0zLjk0OS00LjA4NSAwLTIuMjU3IDEuNzY4LTQuMDg2IDMuOTUtNC4wODYgMi4xOCAwIDMuOTQ4IDEuODMgMy45NDggNC4wODZaTTI2Ljk1NCA1OC4xMTZjLS43MjcgMC0xLjMxNy42OC0xLjMxNyAxLjUxOXYyLjQwOWMwIC40MDMuMTM5Ljc5LjM4NiAxLjA3NC41MTQuNTkzIDEuMzQ3LjU5MyAxLjg2MSAwIC4yNDctLjI4NS4zODYtLjY3MS4zODYtMS4wNzR2LTIuNDA5YzAtLjgzOS0uNTktMS41MTktMS4zMTctMS41MTlabTE4LjQyOSAwYy0uNzI3IDAtMS4zMTcuNjgtMS4zMTcgMS41MTl2Mi40MDljMCAuNDAzLjE0Ljc5LjM4NiAxLjA3NC41MTQuNTkzIDEuMzQ4LjU5MyAxLjg2MiAwIC4yNDctLjI4NS4zODUtLjY3MS4zODUtMS4wNzR2LTIuNDA5YzAtLjgzOS0uNTktMS41MTktMS4zMTYtMS41MTlabS0xNS43OTcgMS41MTljMC0uODM5LjU5LTEuNTE5IDEuMzE3LTEuNTE5czEuMzE2LjY4IDEuMzE2IDEuNTE5djIuNDA5YzAgLjQwMy0uMTM5Ljc5LS4zODYgMS4wNzQtLjUxNC41OTMtMS4zNDcuNTkzLTEuODYxIDBhMS42NDUgMS42NDUgMCAwIDEtLjM4Ni0xLjA3NHYtMi40MDlabTE5Ljc0Ni0xLjUxOWMtLjcyNyAwLTEuMzE2LjY4LTEuMzE2IDEuNTE5djIuNDA5YzAgLjQwMy4xMzguNzkuMzg1IDEuMDc0LjUxNC41OTMgMS4zNDguNTkzIDEuODYyIDAgLjI0Ny0uMjg1LjM4NS0uNjcxLjM4NS0xLjA3NHYtMi40MDljMC0uODM5LS41ODktMS41MTktMS4zMTYtMS41MTlabS0xNS43OTcgMS41MTljMC0uODM5LjU5LTEuNTE5IDEuMzE3LTEuNTE5czEuMzE2LjY4IDEuMzE2IDEuNTE5djIuNDA5YzAgLjQwMy0uMTM5Ljc5LS4zODUgMS4wNzQtLjUxNC41OTMtMS4zNDguNTkzLTEuODYyIDBhMS42NDUgMS42NDUgMCAwIDEtLjM4Ni0xLjA3NHYtMi40MDlabTE5Ljc0Ni0xLjUxOWMtLjcyNyAwLTEuMzE2LjY4LTEuMzE2IDEuNTE5djIuNDA5YzAgLjQwMy4xMzguNzkuMzg1IDEuMDc0LjUxNC41OTMgMS4zNDguNTkzIDEuODYyIDAgLjI0Ny0uMjg1LjM4Ni0uNjcxLjM4Ni0xLjA3NHYtMi40MDljMC0uODM5LS41OS0xLjUxOS0xLjMxNy0xLjUxOVoiCiAgICAgICAgZmlsbD0iI2ZmZiIgLz4KICAgIDxwYXRoCiAgICAgICAgZD0ibTM2Ljk2IDQ3LjAxNSAxLjEgMS42Ny0xLjEtMS42N1ptNy42Ny01LjA1MiAxLjEgMS42Ny0xLjEtMS42N1ptLjYtMTUuMjE0di0yaC0ydjJoMlptOC45NDctNC4wNDIgMS4wNjkgMS42OS0xLjA2OS0xLjY5Wm01LjUzNy01LjQ1NCAxLjc1OC45NTQtMS43NTgtLjk1NFptLTEuNDE3LTEuMTguOTQ3IDEuNzYtLjk0Ny0xLjc2Wm0tMzYuMzU5IDAtLjk0NyAxLjc2Ljk0Ny0xLjc2Wm0tMS40MTggMS4xOCAxLjc1OC0uOTU1LTEuNzU4Ljk1NVptNS41MzggNS40NTQtMS4wNyAxLjY5IDEuMDctMS42OVptOC45NDcgNC4wNDJoMnYtMmgtMnYyWm0tOC45ODIgMzYuMzcgMS41MTEtMS4zMS0xLjUxMSAxLjMxWm0xLjg2MSAwIDEuNTEyIDEuMzA5LTEuNTEyLTEuMzFabTE2LjU2OCAwLTEuNTExIDEuMzA5IDEuNTExLTEuMzFabTEuODYyIDAgMS41MTEgMS4zMDktMS41MTEtMS4zMVptLTE0LjQ4IDAtMS41MTItMS4zMSAxLjUxMiAxLjMxWm0tMS44NjIgMCAxLjUxMS0xLjMxLTEuNTExIDEuMzFabTE4LjQzIDAtMS41MTIgMS4zMDkgMS41MTEtMS4zMVptMS44NiAwIDEuNTEyIDEuMzA5LTEuNTExLTEuMzFabS0xNC40OCAwIDEuNTEyIDEuMzA5LTEuNTExLTEuMzFabS0xLjg2MSAwLTEuNTExIDEuMzA5IDEuNTExLTEuMzFabTE4LjQzIDAgMS41MS0xLjMxLTEuNTEgMS4zMVptMS44NjEgMCAxLjUxMSAxLjMwOS0xLjUxMS0xLjMxWk0xMi0yQzQuMjY4LTItMiA0LjI2OC0yIDEyaDRDMiA2LjQ3NyA2LjQ3NyAyIDEyIDJ2LTRabTU2IDBIMTJ2NGg1NnYtNFptMTQgMTRjMC03LjczMi02LjI2OC0xNC0xNC0xNHY0YzUuNTIzIDAgMTAgNC40NzcgMTAgMTBoNFptMCA1NlYxMmgtNHY1Nmg0Wk02OCA4MmM3LjczMiAwIDE0LTYuMjY4IDE0LTE0aC00YzAgNS41MjMtNC40NzcgMTAtMTAgMTB2NFptLTU2IDBoNTZ2LTRIMTJ2NFpNLTIgNjhjMCA3LjczMiA2LjI2OCAxNCAxNCAxNHYtNEM2LjQ3NyA3OCAyIDczLjUyMyAyIDY4aC00Wm0wLTU2djU2aDRWMTJoLTRabTM3Ljg2IDMzLjM0NWEuNzkxLjc5MSAwIDAgMSAuODEyLS4wMjEuNjU2LjY1NiAwIDAgMSAuMzMzLjU0OWgtNGMwIDIuNDU0IDIuNzE0IDQuMzU1IDUuMDU1IDIuODEybC0yLjItMy4zNFptNy42NjktNS4wNTItNy42NjkgNS4wNTIgMi4yIDMuMzQgNy42Ny01LjA1Mi0yLjIwMS0zLjM0Wm0tLjI5OS41MjhjMC0uMTc4LjA4Ni0uMzg4LjI5OS0uNTI4bDIuMiAzLjM0YTMuMzY1IDMuMzY1IDAgMCAwIDEuNTAxLTIuODEyaC00Wm0wLTE0LjA3MlY0MC44Mmg0VjI2Ljc0OWgtNFptOS44NzgtNS43MzJjLTMuMDk3IDEuOTU5LTUuMTk3IDIuODk1LTYuNDY0IDMuMzRhOC44NDUgOC44NDUgMCAwIDEtMS4yOC4zNjIgMi40MiAyLjQyIDAgMCAxLS4yMDMuMDMxSDQ1LjE5bC4wMTgtLjAwMWguMDJjLjAwMSAwIC4wMDMgMCAuMDAzIDJzLjAwMiAyIC4wMDMgMmguMDU0YTMuMTk2IDMuMTk2IDAgMCAwIC4yNTYtLjAxN2MuMTQ0LS4wMTQuMzI3LS4wMzguNTUyLS4wOC40NS0uMDg0IDEuMDY5LS4yMzggMS44NzUtLjUyMSAxLjYxLS41NjYgMy45ODItMS42NSA3LjI3Ni0zLjczM2wtMi4xMzgtMy4zODFabTQuODQ5LTQuNzE5Yy0uNjM3IDEuMTczLTEuOTgzIDIuOTA2LTQuODQ5IDQuNzE5bDIuMTM4IDMuMzhjMy4zODItMi4xMzggNS4yMy00LjM1NiA2LjIyNi02LjE5bC0zLjUxNS0xLjkwOVptMS4yODcgMS41MzZjLS4xMDYuMDU2LS40OTQuMTczLS45MTYtLjE1OGExLjIzMyAxLjIzMyAwIDAgMS0uNDQ4LS43Ni45ODUuOTg1IDAgMCAxIC4wNzctLjYxOGwzLjUxNSAxLjkwOWMuMzA4LS41NjguNDcyLTEuMjQ4LjM1MS0xLjk2YTIuNzY4IDIuNzY4IDAgMCAwLTEuMDI1LTEuNzE4Yy0xLjAyNi0uODA1LTIuMzg4LS43ODgtMy40NDktLjIxOGwxLjg5NSAzLjUyM1ptLTE5LjEyNyA0LjE4YzkuNjI4IDAgMTUuODg5LTIuNDM4IDE5LjEyNy00LjE4bC0xLjg5NS0zLjUyM2MtMi42OTYgMS40NS04LjMxIDMuNzAyLTE3LjIzMiAzLjcwMnY0Wm0tMTkuMTI2LTQuMThjMy4yMzggMS43NDIgOS40OTkgNC4xOCAxOS4xMjYgNC4xOHYtNGMtOC45MjEgMC0xNC41MzUtMi4yNTMtMTcuMjMxLTMuNzAzbC0xLjg5NSAzLjUyM1ptMS4yODctMS41MzZjLjA0Mi4wNzguMTMxLjMuMDc3LjYxOWExLjIzMiAxLjIzMiAwIDAgMS0uNDQ5Ljc1OWMtLjQyMi4zMy0uODEuMjE1LS45MTUuMTU4bDEuODk1LTMuNTIzYy0xLjA2LS41Ny0yLjQyNC0uNTg3LTMuNDQ5LjIxOGEyLjc2OCAyLjc2OCAwIDAgMC0xLjAyNiAxLjcxOWMtLjEyLjcxMS4wNDMgMS4zOTEuMzUyIDEuOTU5bDMuNTE1LTEuOTA5Wm00Ljg0OSA0LjcxOWMtMi44NjctMS44MTMtNC4yMTItMy41NDYtNC44NDktNC43MTlsLTMuNTE1IDEuOTA5Yy45OTUgMS44MzQgMi44NDQgNC4wNTIgNi4yMjYgNi4xOWwyLjEzOC0zLjM4Wm03Ljg3OCA1LjczMmMwLTIgLjAwMS0yIC4wMDMtMkgzNS4wNDdsLjAyNS4wMDFoLjAwMWEyLjQyIDIuNDIgMCAwIDEtLjIwMi0uMDMgOC44NTIgOC44NTIgMCAwIDEtMS4yOC0uMzYzYy0xLjI2Ny0uNDQ1LTMuMzY3LTEuMzgxLTYuNDY0LTMuMzRsLTIuMTM4IDMuMzhjMy4yOTMgMi4wODQgNS42NjYgMy4xNjggNy4yNzYgMy43MzQuODA2LjI4MyAxLjQyNS40MzcgMS44NzUuNTJhNi4zNTYgNi4zNTYgMCAwIDAgLjczNy4wOTVsLjA3MS4wMDJoLjA1NGMuMDAxIDAgLjAwMyAwIC4wMDMtMlptMiAxOS4xMjRWMjYuNzQ5aC00djE5LjEyNGg0Wm0tOC4xMDItMTAuMzJjMCAxLjIxNi0uOTM2IDIuMDg1LTEuOTUgMi4wODV2NGMzLjM1IDAgNS45NS0yLjc4OSA1Ljk1LTYuMDg1aC00Wm0tMS45NS0yLjA4NmMxLjAxNCAwIDEuOTUuODcgMS45NSAyLjA4Nmg0YzAtMy4yOTctMi42LTYuMDg2LTUuOTUtNi4wODZ2NFptLTEuOTQ5IDIuMDg2YzAtMS4yMTYuOTM2LTIuMDg2IDEuOTUtMi4wODZ2LTRjLTMuMzUgMC01Ljk1IDIuNzktNS45NSA2LjA4Nmg0Wm0xLjk1IDIuMDg1Yy0xLjAxNCAwLTEuOTUtLjg3LTEuOTUtMi4wODVoLTRjMCAzLjI5NiAyLjYgNi4wODUgNS45NSA2LjA4NXYtNFptMjYuMzI3IDRjMy4zNSAwIDUuOTUtMi43ODkgNS45NS02LjA4NWgtNGMwIDEuMjE2LS45MzcgMi4wODUtMS45NSAyLjA4NXY0Wm0tNS45NDktNi4wODVjMCAzLjI5NiAyLjYgNi4wODUgNS45NSA2LjA4NXYtNGMtMS4wMTQgMC0xLjk1LS44Ny0xLjk1LTIuMDg1aC00Wm01Ljk1LTYuMDg2Yy0zLjM1IDAtNS45NSAyLjc5LTUuOTUgNi4wODZoNGMwLTEuMjE2LjkzNi0yLjA4NiAxLjk1LTIuMDg2di00Wm01Ljk0OCA2LjA4NmMwLTMuMjk3LTIuNi02LjA4Ni01Ljk0OS02LjA4NnY0YzEuMDEzIDAgMS45NS44NyAxLjk1IDIuMDg2aDRaTTI3LjYzNyA1OS42MzVhLjM3LjM3IDAgMCAxLS4xMDMuMjM2Ljc3NC43NzQgMCAwIDEtLjU4LjI0NXYtNGMtMi4wOTEgMC0zLjMxNyAxLjg1NC0zLjMxNyAzLjUxOWg0Wm0wIDIuNDA5di0yLjQwOWgtNHYyLjQwOWg0Wm0tLjEwMy0uMjM2YS40NS40NSAwIDAgMSAuMDg2LjE0Mi4yNzcuMjc3IDAgMCAxIC4wMTcuMDk0aC00YzAgLjg0OC4yOSAxLjcxLjg3NCAyLjM4NGwzLjAyMy0yLjYyWm0tMS4xNjEgMGEuNzc2Ljc3NiAwIDAgMSAuNTgtLjI0NWMuMjcgMCAuNDc2LjEyNC41ODEuMjQ1bC0zLjAyMyAyLjYyYzEuMzEyIDEuNTEzIDMuNTczIDEuNTEzIDQuODg1IDBsLTMuMDIzLTIuNjJabS0uMTAzLjIzNmMwLS4wMjcuMDA0LS4wNTguMDE3LS4wOTRhLjQ1LjQ1IDAgMCAxIC4wODYtLjE0MmwzLjAyMyAyLjYyYTMuNjQ0IDMuNjQ0IDAgMCAwIC44NzQtMi4zODRoLTRabTAtMi40MDl2Mi40MDloNHYtMi40MDloLTRabS42ODMuNDgxYy0uMjkgMC0uNDktLjE0LS41OC0uMjQ1YS4zNy4zNyAwIDAgMS0uMTAzLS4yMzZoNGMwLTEuNjY1LTEuMjI2LTMuNTE5LTMuMzE3LTMuNTE5djRabTE5LjExMy0uNDgxYS4zNy4zNyAwIDAgMS0uMTAyLjIzNi43NzQuNzc0IDAgMCAxLS41ODEuMjQ1di00Yy0yLjA5MSAwLTMuMzE3IDEuODU0LTMuMzE3IDMuNTE5aDRabTAgMi40MDl2LTIuNDA5aC00djIuNDA5aDRabS0uMTAyLS4yMzZhLjQ1LjQ1IDAgMCAxIC4wODUuMTQyLjI3Ny4yNzcgMCAwIDEgLjAxNy4wOTRoLTRjMCAuODQ4LjI5IDEuNzEuODc1IDIuMzg0bDMuMDIzLTIuNjJabS0xLjE2MiAwYS43NzUuNzc1IDAgMCAxIC41OC0uMjQ1Yy4yNzEgMCAuNDc3LjEyNC41ODIuMjQ1bC0zLjAyMyAyLjYyYzEuMzExIDEuNTEzIDMuNTczIDEuNTEzIDQuODg0IDBsLTMuMDIzLTIuNjJabS0uMTAzLjIzNmMwLS4wMjcuMDA1LS4wNTguMDE4LS4wOTRhLjQ1LjQ1IDAgMCAxIC4wODUtLjE0MmwzLjAyMyAyLjYyYTMuNjQ1IDMuNjQ1IDAgMCAwIC44NzQtMi4zODRoLTRabTAtMi40MDl2Mi40MDloNHYtMi40MDloLTRabS42ODQuNDgxYy0uMjkgMC0uNDktLjE0LS41OC0uMjQ1YS4zNjkuMzY5IDAgMCAxLS4xMDQtLjIzNmg0YzAtMS42NjUtMS4yMjUtMy41MTktMy4zMTYtMy41MTl2NFptLTE0LjQ4LTRjLTIuMDkxIDAtMy4zMTcgMS44NTQtMy4zMTcgMy41MTloNGEuMzcuMzcgMCAwIDEtLjEwMy4yMzYuNzc0Ljc3NCAwIDAgMS0uNTguMjQ1di00Wm0zLjMxNiAzLjUxOWMwLTEuNjY1LTEuMjI1LTMuNTE5LTMuMzE2LTMuNTE5djRjLS4yOSAwLS40OS0uMTQtLjU4LS4yNDVhLjM3LjM3IDAgMCAxLS4xMDQtLjIzNmg0Wm0wIDIuNDA5di0yLjQwOWgtNHYyLjQwOWg0Wm0tLjg3NCAyLjM4NGEzLjY0NCAzLjY0NCAwIDAgMCAuODc0LTIuMzg0aC00YzAtLjAyNy4wMDUtLjA1OC4wMTctLjA5NGEuNDUuNDUgMCAwIDEgLjA4Ni0uMTQybDMuMDIzIDIuNjJabS00Ljg4NSAwYzEuMzEyIDEuNTEzIDMuNTczIDEuNTEzIDQuODg1IDBsLTMuMDIzLTIuNjJhLjc3NS43NzUgMCAwIDEgLjU4LS4yNDVjLjI3IDAgLjQ3Ni4xMjQuNTgxLjI0NWwtMy4wMjMgMi42MlptLS44NzQtMi4zODRjMCAuODQ4LjI5IDEuNzEuODc0IDIuMzg0bDMuMDIzLTIuNjJhLjQ1LjQ1IDAgMCAxIC4wODYuMTQyLjI3Ny4yNzcgMCAwIDEgLjAxNy4wOTRoLTRabTAtMi40MDl2Mi40MDloNHYtMi40MDloLTRabTIyLjQzIDBhLjM3LjM3IDAgMCAxLS4xMDMuMjM2Ljc3NC43NzQgMCAwIDEtLjU4MS4yNDV2LTRjLTIuMDkgMC0zLjMxNiAxLjg1NC0zLjMxNiAzLjUxOWg0Wm0wIDIuNDA5di0yLjQwOWgtNHYyLjQwOWg0Wm0tLjEwMy0uMjM2YS40NTMuNDUzIDAgMCAxIC4wODUuMTQyLjI3Ny4yNzcgMCAwIDEgLjAxOC4wOTRoLTRjMCAuODQ4LjI5IDEuNzEuODc0IDIuMzg0bDMuMDIzLTIuNjJabS0xLjE2MiAwYS43NzYuNzc2IDAgMCAxIC41ODEtLjI0NWMuMjcgMCAuNDc2LjEyNC41OC4yNDVsLTMuMDIyIDIuNjJjMS4zMTEgMS41MTMgMy41NzMgMS41MTMgNC44ODQgMGwtMy4wMjMtMi42MlptLS4xMDMuMjM2YzAtLjAyNy4wMDUtLjA1OC4wMTgtLjA5NGEuNDUuNDUgMCAwIDEgLjA4NS0uMTQybDMuMDIzIDIuNjJhMy42NDQgMy42NDQgMCAwIDAgLjg3NC0yLjM4NGgtNFptMC0yLjQwOXYyLjQwOWg0di0yLjQwOWgtNFptLjY4NC40ODFjLS4yOSAwLS40OS0uMTQtLjU4LS4yNDVhLjM3LjM3IDAgMCAxLS4xMDQtLjIzNmg0YzAtMS42NjUtMS4yMjUtMy41MTktMy4zMTYtMy41MTl2NFptLTE0LjQ4LTRjLTIuMDkxIDAtMy4zMTYgMS44NTQtMy4zMTYgMy41MTloNGEuMzcuMzcgMCAwIDEtLjEwNC4yMzYuNzc0Ljc3NCAwIDAgMS0uNTguMjQ1di00Wm0zLjMxNiAzLjUxOWMwLTEuNjY1LTEuMjI1LTMuNTE5LTMuMzE2LTMuNTE5djRjLS4yOSAwLS40OS0uMTQtLjU4LS4yNDVhLjM3LjM3IDAgMCAxLS4xMDQtLjIzNmg0Wm0wIDIuNDA5di0yLjQwOWgtNHYyLjQwOWg0Wm0tLjg3NCAyLjM4NGEzLjY0NCAzLjY0NCAwIDAgMCAuODc0LTIuMzg0aC00YzAtLjAyNy4wMDUtLjA1OC4wMTgtLjA5NGEuNDUuNDUgMCAwIDEgLjA4NS0uMTQybDMuMDIzIDIuNjJabS00Ljg4NCAwYzEuMzExIDEuNTEzIDMuNTczIDEuNTEzIDQuODg0IDBsLTMuMDIzLTIuNjJhLjc3Ni43NzYgMCAwIDEgLjU4LS4yNDVjLjI3MSAwIC40NzcuMTI0LjU4MS4yNDVsLTMuMDIyIDIuNjJabS0uODc0LTIuMzg0YzAgLjg0OC4yODkgMS43MS44NzQgMi4zODRsMy4wMjMtMi42MmEuNDUzLjQ1MyAwIDAgMSAuMDg1LjE0Mi4yNzcuMjc3IDAgMCAxIC4wMTcuMDk0aC00Wm0wLTIuNDA5djIuNDA5aDR2LTIuNDA5aC00Wm0yMi40MjkgMGEuMzcuMzcgMCAwIDEtLjEwMy4yMzYuNzc0Ljc3NCAwIDAgMS0uNTguMjQ1di00Yy0yLjA5MiAwLTMuMzE3IDEuODU0LTMuMzE3IDMuNTE5aDRabTAgMi40MDl2LTIuNDA5aC00djIuNDA5aDRabS0uMTAzLS4yMzZhLjQ1LjQ1IDAgMCAxIC4wODUuMTQyLjI3Ny4yNzcgMCAwIDEgLjAxOC4wOTRoLTRjMCAuODQ4LjI5IDEuNzEuODc0IDIuMzg0bDMuMDIzLTIuNjJabS0xLjE2MiAwYS43NzYuNzc2IDAgMCAxIC41ODEtLjI0NWMuMjcgMCAuNDc2LjEyNC41OC4yNDVsLTMuMDIyIDIuNjJjMS4zMTIgMS41MTMgMy41NzMgMS41MTMgNC44ODUgMGwtMy4wMjMtMi42MlptLS4xMDIuMjM2YzAtLjAyNy4wMDQtLjA1OC4wMTctLjA5NGEuNDU1LjQ1NSAwIDAgMSAuMDg1LS4xNDJsMy4wMjMgMi42MmEzLjY0NSAzLjY0NSAwIDAgMCAuODc1LTIuMzg0aC00Wm0wLTIuNDA5djIuNDA5aDR2LTIuNDA5aC00Wm0uNjgzLjQ4MWMtLjI5IDAtLjQ5LS4xNC0uNTgtLjI0NWEuMzcuMzcgMCAwIDEtLjEwMy0uMjM2aDRjMC0xLjY2NS0xLjIyNi0zLjUxOS0zLjMxNy0zLjUxOXY0WiIKICAgICAgICBmaWxsPSIjZmZmIiBtYXNrPSJ1cmwoI2EpIiAvPgo8L3N2Zz4="
class="header3__card-recommendation-header-photo header3__card-recommendation-header-photo_default_inverted"
/>
</div>
<div class="header3__card-recommendation-header-content">
<div class="header3__card-recommendation-header-content-tag">
Курс
</div>
<div class="header3__card-recommendation-header-sub">
<span
class="header3__card-recommendation-header-sub-chunk header3__card-recommendation-header-sub-chunk_green"
>
Скидка 20000 ₽
</span>
</div>
</div>
</div>
<h6 class="header3__card-recommendation-title">
AI для аналитики и работы с данными
</h6>
<div class="header3__card-recommendation-footer">
12 марта
, 2026
· 2 месяца
</div>
</a>
</div>
</div>
<div>
<p class="header3__nav-section-title ">Ответим на ваши вопросы</p>
<div class="header3__nav-section-items ">
<a
class="header3__nav-section-item header3__nav-section-item_phone"
rel="noopener noreferrer"
href="tel:+7 499 938-92-02"
>
<svg
class="header3__phone-icon"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M14.352 2.75a7.971 7.971 0 0 1 7.041 7.032M14.352 6.293a4.426 4.426 0 0 1 3.5 3.5"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
></path>
<path
clip-rule="evenodd"
d="M7.7 16.299C.803 9.4 1.783 6.241 2.51 5.223c.094-.164 2.396-3.611 4.865-1.589 6.126 5.045-1.63 4.332 3.514 9.477 5.146 5.144 4.431-2.611 9.477 3.514 2.022 2.469-1.425 4.771-1.588 4.864-1.018.728-4.178 1.709-11.078-5.19Z"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
></path>
</svg>
+7 499 938-92-02
</a>
</div>
</div>
</div>
</div>
</div>
<div class="header3__hamburger-pagination">
<div
class="header3__hamburger-pagination-button header3__hamburger-pagination-button_prev"
>
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M19.75 11.726h-15M13.7 5.701l6.05 6.024-6.05 6.025"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
></path>
</svg>
</div>
<div class="header3__hamburger-pagination-items"></div>
<div
class="header3__hamburger-pagination-button header3__hamburger-pagination-button_next"
>
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M19.75 11.726h-15M13.7 5.701l6.05 6.024-6.05 6.025"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
></path>
</svg>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</header>
<div class="blog js-blog">
<div class="blog__nav-wrapper">
<div class="nav nav_blue nav_mobile-fix">
<div class="nav__scroll">
<div class="container container-relative container-overflow-auto">
<div class="nav__items nav__float-left">
<a href="/nest/" class="nav__item" title="Блоги">Блоги</a>
<a href="/nest/posts/" class="nav__item nav__item_divider nav__item_divider-pad" title="Посты">
Посты
</a>
<a href="/nest/best/" class="nav__item nav__item_divider"
title="Лучшие">
Лучшие
</a>
<a href="/nest/users/" class="nav__item" title="Участники">Участники</a>
<div class="nav__item show-md">
<form action="/nest/search/" method="get" class="inline-block search js-search">
<div class="search__box js-search-box search__box_close">
<input autocomplete="off"
name="q"
placeholder="Поиск блогов, постов, текста в постах"
class="search__input input"
/>
<i class="ic ic-close search__box-close js-cancel"></i>
<button class="button button_gray2 search__box-button">
<i class="ic ic-search-black search__icon"></i>Найти
</button>
</div>
<div class="search__button js-open-search">
<i class="ic ic-search search__icon"></i>Поиск
</div>
</form>
<form action="/nest/post/add/" method="get" class="js-form-need-auth inline-block">
<input type="hidden" name="blog" value="115"/>
</form>
</div>
</div>
<div class="nav__items nav__float-right hide-md">
<div class="nav__item vertical-middle">
<form action="/nest/search/" method="get" class="inline-block search js-search">
<div class="search__box js-search-box search__box_close">
<input autocomplete="off"
name="q"
placeholder="Поиск блогов, постов, текста в постах"
class="search__input input"
/>
<i class="ic ic-close search__box-close js-cancel"></i>
<button class="button button_gray2 search__box-button">
<i class="ic ic-search-black search__icon"></i>Найти
</button>
</div>
<div class="search__button js-open-search">
<i class="ic ic-search search__icon"></i>Поиск
</div>
</form>
<form action="/nest/post/add/" method="get" class="js-form-need-auth inline-block">
<input type="hidden" name="blog" value="115"/>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="blog__content">
<div class="container">
<div class="container__row container__row_gutter-24">
<div class="container__col container__col_8 container__col_md-12">
<div class="blog-post">
<div class="blog__tile blog-post__tile">
<article class="blog-post-content">
<div class="post-info">
<a href="/profile/67150/">
<div class="post-info__avatar ic ic-blog-default-avatar" style="background-image: url(https://cdn.otus.ru/media/public/a5/6c/avatar-67150-a56c90.png);"></div>
<div class="post-info__author">Елена Граховац</div>
</a>
<div class="post-info__time">06.05.20 в 12:11</div>
</div>
<h1 class="blog__h1">Пишем сервис на Go для Kubernetes</h1>
<div class="post-info">
<div class="post-info__blogs">
<a href="/nest/go/" class="post-info__blog" title="Golang" >Golang</a> →
<a href="/nest/go-art/" class="post-info__blog" title="Полезные материалы по Go" >Полезные материалы по Go</a>
</div>
<div class="post-info__tags">
Теги: go golang kubernetes k8s microservices 12factor
</div>
</div>
<div class="blog-post-text blog-post-text_markdown markdown">
<p><img alt="otus_Posts_19may_VK_1000x700_1-20219-c02499.jpg" src="https://cdn.otus.ru/media/public/c0/24/otus_Posts_19may_VK_1000x700_1-20219-c02499.jpg"></p>
<p>Если вы когда-либо пробовали Go, вы знаете, что писать сервисы на Go очень просто. Нам нужно буквально <a href="https://github.com/rumyantseva/advent-2017/commit/76864ab0587dd9a599752ed090f618749b6bfe0c">несколько строк кода</a> для того, чтобы можно было запустить http-сервис. Но что нужно добавить, если мы хотим приготовить такое приложение в продакшн? Давайте рассмотрим это на примере сервиса, который готов к запуску в Kubernetes. <cut></cut></p>
<p>Все шаги из этой статьи можно найти <a href="https://github.com/rumyantseva/advent-2017/tree/all-steps">в одном теге</a>, или вы можете следить за примерами статьи <a href="https://github.com/rumyantseva/advent-2017/commits/master">коммит за коммитом</a>.</p>
<h2>Шаг 1. Простейший сервис</h2>
<p>Итак, у нас есть очень простое приложение:</p>
<pre><div class="codehilite"><pre><span></span>package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/home", func(w http.ResponseWriter, _ *http.Request) {
fmt.Fprint(w, "Hello! Your request was processed.")
},
)
http.ListenAndServe(":8000", nil)
}
</pre></div>
</pre>
<p>Если мы хотим попробовать запустить его, команды <em>go run main.go</em> будет достаточно. С помощью curl мы можем проверить, как работает этот сервис: <em>curl -i http://127.0.0.1:8000/home</em>. Но когда мы запускаем это приложение, мы видим, что в терминале нет никакой информации о его состоянии.</p>
<h2>Шаг 2. Добавляем логирование</h2>
<p>Прежде всего, давайте добавим логирование для того, чтобы понимать, что происходит с сервисом, и для того, чтобы можно было журналировать ошибки или другие важные ситуации. В этом примере мы будем использовать простейший логер из стандартной библиотеки Go, но для настоящего сервиса, запущенного в продакшн, могут быть интересны более сложные решения, такие как <a href="https://github.com/golang/glog">glog</a> или <a href="https://github.com/sirupsen/logrus">logrus</a>.</p>
<p>Нам могут быть интересны 3 ситуации: когда сервис запускается, когда сервис готов обрабатывать запросы, и когда http.ListenAndServe возвращает ошибку. В результате получится что-то <a href="https://github.com/rumyantseva/advent-2017/commit/65689d282be7e6a7ec38ec254605811fd3bef784">такое</a>:</p>
<pre><div class="codehilite"><pre><span></span>func main() {
log.Print("Starting the service...")
http.HandleFunc("/home", func(w http.ResponseWriter, _ *http.Request) {
fmt.Fprint(w, "Hello! Your request was processed.")
},
)
log.Print("The service is ready to listen and serve.")
log.Fatal(http.ListenAndServe(":8000", nil))
}
</pre></div>
</pre>
<p>Уже лучше!</p>
<h2>Шаг 3. Добавляем роутер</h2>
<p>Для настоящего приложения мы, скорее всего, захотим использовать роутер для упрощения обработки разных URI, HTTP-методов или других правил. В стандартной библиотеке Go нет роутера, поэтому давайте попробуем <a href="https://github.com/gorilla/mux">gorilla/mux</a>, который вполне совместим со стандартной библиотекой net/http.</p>
<p>Есть смысл вынести всё, связанное с роутингом, в отдельный пакет. Давайте вынесем инициализацию и задание правил роутинга, а также функции-обработчики в пакет handlers (полные изменения можно посмотреть <a href="https://github.com/rumyantseva/advent-2017/commit/1a61e7952e227e33eaab81404d7bff9278244080">здесь</a>).</p>
<p>Добавим функцию Router, которая будет возвращать сконфигурированный роутер, и функцию home, которая будет обрабатывать правило для пути /home. Я предпочитаю разделять такие функции на отдельные файлы:</p>
<p>handlers/handlers.go:</p>
<pre><div class="codehilite"><pre><span></span>package handlers
import (
"github.com/gorilla/mux"
)
// Router register necessary routes and returns an instance of a router.
func Router() *mux.Router {
r := mux.NewRouter()
r.HandleFunc("/home", home).Methods("GET")
return r
}
</pre></div>
</pre>
<p>handlers/home.go:</p>
<pre><div class="codehilite"><pre><span></span>package handlers
import (
"fmt"
"net/http"
)
// home is a simple HTTP handler function which writes a response.
func home(w http.ResponseWriter, _ *http.Request) {
fmt.Fprint(w, "Hello! Your request was processed.")
}
</pre></div>
</pre>
<p>Кроме того, нам нужны небольшие изменения в файле main.go:</p>
<pre><div class="codehilite"><pre><span></span>package main
import (
"log"
"net/http"
"github.com/rumyantseva/advent-2017/handlers"
)
// How to try it: go run main.go
func main() {
log.Print("Starting the service...")
router := handlers.Router()
log.Print("The service is ready to listen and serve.")
log.Fatal(http.ListenAndServe(":8000", router))
}
</pre></div>
</pre>
<h2>Шаг 4. Тесты</h2>
<p>Самое время добавить несколько тестов. Для этого можно воспользоваться стандартным пакетом httptest. Для функции Router можно написать что-то такое:</p>
<pre><div class="codehilite"><pre><span></span>package handlers
import (
"net/http"
"net/http/httptest"
"testing"
)
func TestRouter(t *testing.T) {
r := Router()
ts := httptest.NewServer(r)
defer ts.Close()
res, err := http.Get(ts.URL + "/home")
if err != nil {
t.Fatal(err)
}
if res.StatusCode != http.StatusOK {
t.Errorf("Status code for /home is wrong. Have: %d, want: %d.", res.StatusCode, http.StatusOK)
}
res, err = http.Post(ts.URL+"/home", "text/plain", nil)
if err != nil {
t.Fatal(err)
}
if res.StatusCode != http.StatusMethodNotAllowed {
t.Errorf("Status code for /home is wrong. Have: %d, want: %d.", res.StatusCode, http.StatusMethodNotAllowed)
}
res, err = http.Get(ts.URL + "/not-exists")
if err != nil {
t.Fatal(err)
}
if res.StatusCode != http.StatusNotFound {
t.Errorf("Status code for /home is wrong. Have: %d, want: %d.", res.StatusCode, http.StatusNotFound)
}
}
</pre></div>
</pre>
<p>Здесь мы проверяем, что вызов метода GET для /home вернет код 200. А при попытке отправить POST ожидаемым ответом будет уже 405. И, наконец, для несуществующего пути мы ожидаем 404. Вообще, этот тест может быть несколько избыточным, ведь работа роутера и так уже покрыта тестами в рамках пакета gorilla/mux, так что здесь можно проверять даже меньшее количество кейсов.</p>
<p>Для функции home имеет смысл проверить уже не только код, но и тело ответа:</p>
<pre><div class="codehilite"><pre><span></span>package handlers
import (
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"
)
func TestHome(t *testing.T) {
w := httptest.NewRecorder()
home(w, nil)
resp := w.Result()
if have, want := resp.StatusCode, http.StatusOK; have != want {
t.Errorf("Status code is wrong. Have: %d, want: %d.", have, want)
}
greeting, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
t.Fatal(err)
}
if have, want := string(greeting), "Hello! Your request was processed."; have != want {
t.Errorf("The greeting is wrong. Have: %s, want: %s.", have, want)
}
}
</pre></div>
</pre>
<p>Запускаем go test и проверяем, что тесты работают:</p>
<pre><div class="codehilite"><pre><span></span>$ go test -v ./...
? github.com/rumyantseva/advent-2017 [no test files]
=== RUN TestRouter
--- PASS: TestRouter (0.00s)
=== RUN TestHome
--- PASS: TestHome (0.00s)
PASS
ok github.com/rumyantseva/advent-2017/handlers 0.018s
</pre></div>
</pre>
<h2>Шаг 5. Конфигурирование</h2>
<p>Следующий важный шаг — возможность задать конфигурацию сервиса. Сейчас при запуске сервис всегда слушает порт 8000, и возможность сконфигурировать это значение может быть полезной. Манифест двенадцатифакторных приложений, который представляет собой очень интересный подход к написанию сервисов, рекомендует нам хранить конфигурацию, основываясь на окружении. Итак, зададим конфиг для порта через переменную окружения:</p>
<pre><div class="codehilite"><pre><span></span>package main
import (
"log"
"net/http"
"os"
"github.com/rumyantseva/advent-2017/handlers"
)
// How to try it: PORT=8000 go run main.go
func main() {
log.Print("Starting the service...")
port := os.Getenv("PORT")
if port == "" {
log.Fatal("Port is not set.")
}
r := handlers.Router()
log.Print("The service is ready to listen and serve.")
log.Fatal(http.ListenAndServe(":"+port, r))
}
</pre></div>
</pre>
<p>В этом примере, если порт не задан, приложение сразу завершится с ошибкой. Нет смысла пытаться продолжать работу, если конфигурация задана некорректно.</p>
<h2>Шаг 6. Makefile</h2>
<p>Утилита make может быть весьма полезной, если вам приходится иметь дело с повторяющимися действиями. Давайте посмотрим, как можно использовать это в нашем проекте. Прямо сейчас у нас есть два повторяющихся действия: запуск тестов и компиляция и запуск сервиса. Добавим эти действия в Makefile, но вместо простого go run теперь будем использовать go build и после этого запускать скомпилированный бинарник, этот вариант лучше подходит, если в перспективе мы готовим приложение для продакшн:</p>
<pre><div class="codehilite"><pre><span></span>APP?=advent
PORT?=8000
clean:
rm -f ${APP}
build: clean
go build -o ${APP}
run: build
PORT=${PORT} ./${APP}
test:
go test -v -race ./...
</pre></div>
</pre>
<p>В этом примере мы вынесли имя бинарника в отдельную переменную APP, чтобы не повторять его несколько раз.</p>
<p>Кроме того, если мы хотим запускать приложение описанным образом, надо предварительно удалить старый бинарник (если он существует). Поэтому, при запуске make build сначала вызывается clean.</p>
<h2>Шаг 7. Версионирование</h2>
<p>Следующая практика, которую мы добавим в сервис — версионирование. Иногда полезно знать, какой конкретно билд и даже коммит мы используем в продакшн, и когда конкретно бинарник был собран.</p>
<p>Для того, чтобы хранить эту информацию, добавим новый пакет — version:</p>
<pre><div class="codehilite"><pre><span></span>package version
var (
// BuildTime is a time label of the moment when the binary was built
BuildTime = "unset"
// Commit is a last commit hash at the moment when the binary was built
Commit = "unset"
// Release is a semantic version of current build
Release = "unset"
)
</pre></div>
</pre>
<p>Мы можем логировать эти переменные, когда приложение запускается:</p>
<pre><div class="codehilite"><pre><span></span>...
func main() {
log.Printf(
"Starting the service...\ncommit: %s, build time: %s, release: %s",
version.Commit, version.BuildTime, version.Release,
)
...
}
</pre></div>
</pre>
<p>И также мы можем добавить их в home (не забудьте поправить тесты!):</p>
<pre><div class="codehilite"><pre><span></span>package handlers
import (
"encoding/json"
"log"
"net/http"
"github.com/rumyantseva/advent-2017/version"
)
// home is a simple HTTP handler function which writes a response.
func home(w http.ResponseWriter, _ *http.Request) {
info := struct {
BuildTime string <span class="sb">`json:"buildTime"`</span>
Commit string <span class="sb">`json:"commit"`</span>
Release string <span class="sb">`json:"release"`</span>
}{
version.BuildTime, version.Commit, version.Release,
}
body, err := json.Marshal(info)
if err != nil {
log.Printf("Could not encode info data: %v", err)
http.Error(w, http.StatusText(http.StatusServiceUnavailable), http.StatusServiceUnavailable)
return
}
w.Header().Set("Content-Type", "application/json")
w.Write(body)
}
</pre></div>
</pre>
<p>Будем использовать линкер для того, чтобы задать переменные BuildTime, Commit и Release во время компиляции.</p>
<p>Добавим новые переменные в Makefile:</p>
<pre><div class="codehilite"><pre><span></span>RELEASE?=0.0.1
COMMIT?=$(shell git rev-parse --short HEAD)
BUILD_TIME?=$(shell date -u '+%Y-%m-%d_%H:%M:%S')
</pre></div>
</pre>
<p>Здесь COMMIT и BUILD_TIME определены через заданные команды, а для RELEASE мы можем использовать, например, семантическое версионирование или просто инкрементные версии сборок.</p>
<p>Теперь перепишем цель build для того, чтобы можно было использовать значения этих переменных:</p>
<pre><div class="codehilite"><pre><span></span>build: clean
go build \
-ldflags "-s -w -X ${PROJECT}/version.Release=${RELEASE} \
-X ${PROJECT}/version.Commit=${COMMIT} -X ${PROJECT}/version.BuildTime=${BUILD_TIME}" \
-o ${APP}
</pre></div>
</pre>
<p>Мы также добавили в начало Makefile переменную PROJECT, чтобы не повторять одно и тоже несколько раз:</p>
<pre><div class="codehilite"><pre><span></span>PROJECT?=github.com/rumyantseva/advent-2017
</pre></div>
</pre>
<p>Все изменения, сделанные на этом шаге, можно найти <a href="https://github.com/rumyantseva/advent-2017/commit/eaa4ff224b32fb343f5eac2a1204cc3806a22efd">здесь</a>. Попробуйте make run для того, чтобы проверить, как это работает.</p>
<h2>Шаг 8. Меньше зависимостей!</h2>
<p>Есть одна вещь, которая мне не нравится в нашем коде: пакет handler зависит от пакета version. Поменять это легко: нам нужно сделать функцию home конфигурабельной:</p>
<pre><div class="codehilite"><pre><span></span>// home returns a simple HTTP handler function which writes a response.
func home(buildTime, commit, release string) http.HandlerFunc {
return func(w http.ResponseWriter, _ *http.Request) {
...
}
}
</pre></div>
</pre>
<p>И, опять же, не забудьте поправить тесты и внести <a href="https://github.com/rumyantseva/advent-2017/commit/e73b996f8522b736c150e53db059cf041c7c3e64">се необходимые изменения</a>.</p>
<h2>Шаг 9. Хелсчеки</h2>
<p>В случае запуска сервиса в Kubernetes обычно требуется добавить два хелсчека: liveness- и readiness-пробы. Цель liveness-пробы — дать понимание того, что сервис запустился. Если liveness-проба провалена, сервис будет перезапущен. Цель readiness-пробы — дать понимание того, что приложение готово к получению трафика. Если readiness-проба провалена, контейнер будет удален из балансировщиков нагрузки сервиса.</p>
<p>Для того чтобы определить liveness-пробу, можно написать простой хендлер, который всегда возвращает код 200:</p>
<pre><div class="codehilite"><pre><span></span>// healthz is a liveness probe.
func healthz(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
}
</pre></div>
</pre>
<p>Для readiness-пробы часто достаточно аналогичного решения, но иногда требуется дождаться некоторого события (например, готовности базы данных) для того, чтобы начать обрабатывать трафик:</p>
<pre><div class="codehilite"><pre><span></span>// readyz is a readiness probe.
func readyz(isReady <span class="ge">*atomic.Value) http.HandlerFunc {</span>
<span class="ge"> return func(w http.ResponseWriter, _</span> *http.Request) {
if isReady == nil || !isReady.Load().(bool) {
http.Error(w, http.StatusText(http.StatusServiceUnavailable), http.StatusServiceUnavailable)
return
}
w.WriteHeader(http.StatusOK)
}
}
</pre></div>
</pre>
<p>В этом примере мы возвращаем 200, только если переменная isReady задана и равна true.</p>
<p>Посмотрим, как это можно использовать:</p>
<pre><div class="codehilite"><pre><span></span>func Router(buildTime, commit, release string) <span class="ge">*mux.Router {</span>
<span class="ge"> isReady := &atomic.Value{}</span>
<span class="ge"> isReady.Store(false)</span>
<span class="ge"> go func() {</span>
<span class="ge"> log.Printf("Readyz probe is negative by default...")</span>
<span class="ge"> time.Sleep(10 *</span> time.Second)
isReady.Store(true)
log.Printf("Readyz probe is positive.")
}()
r := mux.NewRouter()
r.HandleFunc("/home", home(buildTime, commit, release)).Methods("GET")
r.HandleFunc("/healthz", healthz)
r.HandleFunc("/readyz", readyz(isReady))
return r
}
</pre></div>
</pre>
<p>Здесь мы говорим, что приложение готово обрабатывать трафик через 10 секунд после запуска. Конечно, в реальной жизни нет никакого смысла ждать 10 секунд, но, может быть, вы захотите добавить сюда прогрев кеша или что-то еще в этом роде.</p>
<p>Как всегда, полные изменения можно найти на <a href="https://github.com/rumyantseva/advent-2017/commit/e73b996f8522b736c150e53db059cf041c7c3e64">GitHub'е</a>.</p>
<p><em>Примечание</em>. Если приложению придёт слишком много трафика, оно начнет отвечать нестабильно. Например, liveness-проба может быть провалена из-за таймаутов, и контейнер будет перезагружен. По этой причине некоторые инженеры предпочитают не использовать liveness-пробы совсем. Лично я считаю, что лучше масштабировать ресурсы, если вы замечаете, что в сервис приходит все больше и больше запросов. Например, можно попробовать <a href="https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/">автоматическое масштабирование подов через HPA</a>.</p>
<h2>Шаг 10. Graceful shutdown</h2>
<p>Когда сервису требуется остановка, хорошей практикой является не немедленный обрыв соединений, запросов и других операцией, но их корректная обработка. Go поддерживает "graceful shutdown" для http.Server, начиная с версии 1.8. Рассмотрим, как это можно использовать:</p>
<pre><div class="codehilite"><pre><span></span>func main() {
...
r := handlers.Router(version.BuildTime, version.Commit, version.Release)
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM)
srv := &http.Server{
Addr: ":" + port,
Handler: r,
}
go func() {
log.Fatal(srv.ListenAndServe())
}()
log.Print("The service is ready to listen and serve.")
killSignal := <-interrupt
switch killSignal {
case os.Interrupt:
log.Print("Got SIGINT...")
case syscall.SIGTERM:
log.Print("Got SIGTERM...")
}
log.Print("The service is shutting down...")
srv.Shutdown(context.Background())
log.Print("Done")
}
</pre></div>
</pre>
<p>В этом примере мы перехватываем системные сигналы SIGINT и SIGTERM и, если один из них пойман, останавливаем сервис правильно.</p>
<p><em>Примечание</em>. Когда я писала этот код, я также пробовала перехватывать SIGKILL здесь. Я видела такой подход несколько раз в разных библиотеках и была уверена, что это работает. Но, как <a href="https://twitter.com/sszuecs/status/941582509565005824">заметил</a> Sandor Szücs, перехват SIGKILL невозможен. В случае SIGKILL приложение будет остановлено немедленно.</p>
<h2>Шаг 11. Dockerfile</h2>
<p>Наше приложение почти готово к запуску в Kubernetes, самое время контейнеризировать его.</p>
<p>Простейший Dockerfile, который нам понадобится, может выглядеть так:</p>
<pre><div class="codehilite"><pre><span></span>FROM scratch
ENV PORT 8000
EXPOSE $PORT
COPY advent /
CMD ["/advent"]
</pre></div>
</pre>
<p>Мы создаем минимально возможный контейнер, копируем туда бинарник и запускаем его (кроме того, мы не забыли пробросить переменную PORT).</p>
<p>Теперь немного изменим Makefile и добавим туда сборку образа и запуск контейнера. Здесь нам могут пригодиться две новые переменные: GOOS и GOARCH, которые мы будем использовать для кросс-компиляции в рамках цели build.</p>
<pre><div class="codehilite"><pre><span></span>...
GOOS?=linux
GOARCH?=amd64
...
build: clean
CGO_ENABLED=0 GOOS=${GOOS} GOARCH=${GOARCH} go build \
-ldflags "-s -w -X ${PROJECT}/version.Release=${RELEASE} \
-X ${PROJECT}/version.Commit=${COMMIT} -X ${PROJECT}/version.BuildTime=${BUILD_TIME}" \
-o ${APP}
container: build
docker build -t $(APP):$(RELEASE) .
run: container
docker stop $(APP):$(RELEASE) || true && docker rm $(APP):$(RELEASE) || true
docker run --name ${APP} -p ${PORT}:${PORT} --rm \
-e "PORT=${PORT}" \
$(APP):$(RELEASE)
...
</pre></div>
</pre>
<p>Итак, мы добавили цель container для сборки образа и поправили цель run так, чтобы вместо запуска бинарника теперь запускался контейнер. Все изменения доступны <a href="https://github.com/rumyantseva/advent-2017/commit/909fef6d585c85c5e16b5b0e4fdbdf080893b679">здесь</a>.</p>
<p>Теперь можно попробовать запустить make run для проверки всего процесса.</p>
<h2>Шаг 12. Управления зависимостями</h2>
<p>В нашем проекте есть одна внешняя зависимость — github.com/gorilla/mux. И, значит, для приложения, действительно готового к продакшн, необходимо добавить <a href="https://github.com/rumyantseva/advent-2017/commit/7ffa56a78400367e5d633521dee816b767d7d05d">управление зависимостями</a>. Если мы используем утилиту <a href="https://github.com/golang/dep">dep</a>, то всё, что нам требуется сделать — вызов команды dep init:</p>
<pre><div class="codehilite"><pre><span></span>$ dep init
Using ^1.6.0 as constraint for direct dep github.com/gorilla/mux
Locking in v1.6.0 (7f08801) for direct dep github.com/gorilla/mux
Locking in v1.1 (1ea2538) for transitive dep github.com/gorilla/context
</pre></div>
</pre>
<p>В результате были созданы файлы Gopkg.toml и Gopkg.lock и директория vendor, содержащая все используемые зависимости. Лично я предпочитаю пушить vendor в git, особенно для важных проектов.</p>
<h2>Шаг 13. Kubernetes</h2>
<p>И, наконец, финальный шаг: запускаем приложение в Kubernetes. Самый простой способ попробовать Kubernetes — установить и настроить на своем локальном окружении <a href="https://github.com/kubernetes/minikube">minikube</a>.</p>
<p>Kubernetes скачивает образы из реестра (Docker registry). В нашем случае достаточно публичного реестра — <a href="https://hub.docker.com/">Docker Hub</a>. Нам понадобится еще одна переменная и еще одна команда в Makefile:</p>
<pre><div class="codehilite"><pre><span></span>CONTAINER_IMAGE?=docker.io/webdeva/${APP}
...
container: build
docker build -t $(CONTAINER_IMAGE):$(RELEASE) .
...
push: container
docker push $(CONTAINER_IMAGE):$(RELEASE)
</pre></div>
</pre>
<p>Здесь переменная CONTAINER_IMAGE задаёт репозиторий реестра, куда мы будем отправлять и откуда мы будем скачивать образы контейнеров. Как можно заметить, в данном примере в пути к реестру используется имя пользователя (webdeva). Если у вас нет аккаунта на hub.docker.com, самое время его завести и затем залогиниться с помощью команды docker login. После этого вы сможете отправлять образы в реестр.</p>
<p>Давайте попробуем make push:</p>
<pre><div class="codehilite"><pre><span></span>$ make push
...
docker build -t docker.io/webdeva/advent:0.0.1 .
Sending build context to Docker daemon 5.25MB
...
Successfully built d3cc8f4121fe
Successfully tagged webdeva/advent:0.0.1
docker push docker.io/webdeva/advent:0.0.1
The push refers to a repository [docker.io/webdeva/advent]
ee1f0f98199f: Pushed
0.0.1: digest: sha256:fb3a25b19946787e291f32f45931ffd95a933100c7e55ab975e523a02810b04c size: 528
</pre></div>
</pre>
<p>Работает! Теперь созданный образ можно <a href="https://hub.docker.com/r/webdeva/advent/tags/">найти в реестре</a>.</p>
<p>Определим необходимые конфигурации (манифесты) для Kubernetes. Они представляют собой статические файлы в формате JSON или YAML, так что для подстановки "переменных" нам придется воспользоваться помощью утилиты sed. В этом примере мы рассмотрим три типа ресурсов: <a href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/">deployment</a>, <a href="https://kubernetes.io/docs/concepts/services-networking/service/">service</a> и <a href="https://kubernetes.io/docs/concepts/services-networking/ingress/">ingress</a>.</p>
<p><em>Примечание</em>. Проект <a href="https://github.com/kubernetes/helm">helm</a> решает задачу управления релизами конфигураций в Kubernetes в целом и рассматривает вопросы создания гибких конфигураций в частности. Так что, если простого sed недостаточно, есть смысл познакомиться с Helm.</p>
<p>Рассмотрим конфигурацию для deployment:</p>
<pre><div class="codehilite"><pre><span></span>apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: {{ .ServiceName }}
labels:
app: {{ .ServiceName }}
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 50%
maxSurge: 1
template:
metadata:
labels:
app: {{ .ServiceName }}
spec:
containers:
<span class="k">-</span> name: {{ .ServiceName }}
image: docker.io/webdeva/{{ .ServiceName }}:{{ .Release }}
imagePullPolicy: Always
ports:
<span class="k">-</span> containerPort: 8000
livenessProbe:
httpGet:
path: /healthz
port: 8000
readinessProbe:
httpGet:
path: /readyz
port: 8000
resources:
limits:
cpu: 10m
memory: 30Mi
requests:
cpu: 10m
memory: 30Mi
terminationGracePeriodSeconds: 30
</pre></div>
</pre>
<p>Вопросы конфигурирования Kubernetes лучше рассмотреть в рамках отдельной статьи, но, как можно заметить, кроме всего прочего здесь определяются реестр и образ контейнера, а также правила для liveness- и readiness-проб.</p>
<p>Типичная конфигурация для service выглядит проще:</p>
<pre><div class="codehilite"><pre><span></span>apiVersion: v1
kind: Service
metadata:
name: {{ .ServiceName }}
labels:
app: {{ .ServiceName }}
spec:
ports:
<span class="k">-</span> port: 80
targetPort: 8000
protocol: TCP
name: http
selector:
app: {{ .ServiceName }}
</pre></div>
</pre>
<p>И, наконец, ingress. Здесь мы определяем конфигурацию ingress-контроллера, который поможет, например, получить доступ к сервису извне Kubernetes. Предположим, что мы хотим направлять запросы в сервис при обращению к домену advent.test (который в реальности, конечно, не существует):</p>
<pre><div class="codehilite"><pre><span></span>apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
ingress.kubernetes.io/rewrite-target: /
labels:
app: {{ .ServiceName }}
name: {{ .ServiceName }}
spec:
backend:
serviceName: {{ .ServiceName }}
servicePort: 80
rules:
<span class="k">-</span> host: advent.test
http:
paths:
<span class="k">-</span> path: /
backend:
serviceName: {{ .ServiceName }}
servicePort: 80
</pre></div>
</pre>
<p>Для того чтобы проверить, как работает конфигурация, установим minikube, используя его <a href="https://github.com/kubernetes/minikube#installation">официальную документацию</a>. Кроме того, нам понадобится утилита <a href="https://kubernetes.io/docs/tasks/tools/install-kubectl/">kubectl</a> для применения конфигураций и проверки сервиса.</p>
<p>Для запуска minikube, включения ingress и подготовки kubectl понадобятся следующие команды:</p>
<pre><div class="codehilite"><pre><span></span>minikube start
minikube addons enable ingress
kubectl config use-context minikube
</pre></div>
</pre>
<p>Теперь добавим в Makefile отдельную цель для установки сервиса в minikube:</p>
<pre><div class="codehilite"><pre><span></span>minikube: push
for t in $(shell find ./kubernetes/advent -type f -name "*.yaml"); do \
cat $$t | \
gsed -E "s/\{\{(\s*)\.Release(\s*)\}\}/$(RELEASE)/g" | \
gsed -E "s/\{\{(\s*)\.ServiceName(\s*)\}\}/$(APP)/g"; \
echo ---; \
done > tmp.yaml
kubectl apply -f tmp.yaml
</pre></div>
</pre>
<p>Эти команды "компилируют" все *.yaml-конфигурации в один файл, заменяют "переменные" Release и ServiceName реальными значениями (я использую gsed вместо обычного sed) и запускают kubectl apply для установки приложения в Kubernetes.</p>
<p>Проверим, как применились конфигурации:</p>
<pre><div class="codehilite"><pre><span></span>$ kubectl get deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
advent 3 3 3 3 1d
$ kubectl get service
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
advent 10.109.133.147 <none> 80/TCP 1d
$ kubectl get ingress
NAME HOSTS ADDRESS PORTS AGE
advent advent.test 192.168.64.2 80 1d
</pre></div>
</pre>
<p>Теперь попробуем отправить запрос к сервису через заданный домен. Прежде всего, нам нужно добавить домен advent.test в локальный файл /etc/hosts (для Windows --%SystemRoot%\System32\drivers\etc\hosts):</p>
<pre><div class="codehilite"><pre><span></span>echo "$(minikube ip) advent.test" | sudo tee -a /etc/hosts
</pre></div>
</pre>
<p>И теперь можно проверять работу сервиса:</p>
<pre><div class="codehilite"><pre><span></span>curl -i http://advent.test/home
HTTP/1.1 200 OK
Server: nginx/1.13.6
Date: Sun, 10 Dec 2017 20:40:37 GMT
Content-Type: application/json
Content-Length: 72
Connection: keep-alive
Vary: Accept-Encoding
{"buildTime":"2017-12-10_11:29:59","commit":"020a181","release":"0.0.5"}%
</pre></div>
</pre>
<p>Ура, работает!</p>
</div>
</article>
</div>
<div class="blog__tile blog__tile_slim">
<div class="blog-post__footer">
<div class="blog-post__footer-item blog-post__footer-item_right">
<div class="inline-block">
<div class="blog-post__footer-text blog-post__footer-text_share">Поделиться</div>
<div class="blog-post__footer-icons">
<div class="blog-post__footer-icon-box hover-ic js-share" data-href="https://otus.ru/nest/post/1389/" data-type="tg">
<div class="blog-post__footer-icon ic ic-tg-square ic-tg-square-hover"></div>
</div>
<div class="blog-post__footer-icon-box hover-ic js-share" data-href="https://otus.ru/nest/post/1389/" data-type="tw">
<div class="blog-post__footer-icon ic ic-twitter-square ic-twitter-square-hover"></div>
</div>
<div class="blog-post__footer-icon-box hover-ic js-share" data-href="https://otus.ru/nest/post/1389/" data-type="vk">
<div class="blog-post__footer-icon ic ic-vk-square ic-vk-square-hover"></div>
</div>
</div>
</div>
<div class="inline-block float-right_ssm">
<div class="blog__counters-item blog__counters-item_bookmark">
<a href="#"
class="js-blog-post-mark blog-post__footer-icon blog-post__footer-icon_star"
post_id=1389></a>
</div>
</div>
</div>
<div class="blog-post__footer-item">
<div class="blog-vote">
<div class="blog-vote__item blog-vote__item_border blog-vote__item_left js-blog-post-dislike"
data-url="/nest/vote/post/" data-id=1389></div>
<div class="blog-vote__item blog-vote__item_border blog-vote__item_center blog-vote__item_pos js-post-votes"
data-url="/nest/vote/post/" data-id=1389>
5
</div>
<div class="blog-vote__item blog-vote__item_border blog-vote__item_right js-blog-post-like"
data-url="/nest/vote/post/" data-id=1389></div>
</div>
</div>
<div class="inline-block float-right_ssm">
<a class="blog-post__footer-item" href="/nest/post/1389/#comments">
<div class="blog-post__footer-icon blog-post__footer-icon_comments"></div>
<div class="blog-post__footer-text js-blog-post-comments-counter">1</div>
</a>
<div class="blog-post__footer-item">
<div class="blog-post__footer-icon blog-post__footer-icon_views"></div>
<div class="blog-post__footer-text">189</div>
</div>
</div>
</div>
</div>
</div>
<div
id="formSubscribe"
class="blog-subscribe__container js-subscribe-container"
>
<form
method="post"
novalidate
action="/nest/blog/subscribe/"
class="js-ajax-form js-new-validation blog-subscribe blog__external"
data-before-send='[
{"action": "addClass", "el": "#formSubscribe .js-content", "class": "hidden"},
{"action": "show", "el": "#formSubscribe .js-loader"}
]'
data-after-complete='[
{"action": "hide", "el": "#formSubscribe .js-loader"}
]'
data-after-error='[{"action": "removeClass", "el": "#formSubscribe .js-content", "class": "hidden"}]'
data-after-success='[
{"action": "addClass", "el": "#formSubscribe .js-block-common", "class": "hidden"},
{"action": "show", "el": "#formSubscribe .js-block-success"},
{"action": "addClass", "el": "#formSubscribe.js-subscribe-container", "class": "blog-subscribe__container_finish"}
]'
data-success-msg="false"
>
<div class="js-block-common">
<p class="blog-subscribe__title">Не пропустите новые полезные статьи!</p>
<div class="blog-subscribe__fields">
<input type="hidden" name="csrfmiddlewaretoken" value="ZIfZ8joK9HE52VNXgIHlgScQsoeumcxOIPvRlRpT4Ovcd2wQ9nDHrj5NelH97Lt9">
<input type="hidden" name="object_id" value="115"/>
<div class="js-content">
<div class="new-input-line blog-subscribe__input-line">
<div class="new-input-group new-input-group_right blog-subscribe__group">
<div class="new-input new-input_fake new-input_full">
<input
type="email"
class="new-input new-input_full js-placeholder new-input_border-no blog-subscribe__input"
data-title="email"
autocomplete="email"
name="email"
required
placeholder="Введите ваш email"
/>
<div class="new-input__error-sign new-ic new-ic-warning js-new-input-error">
<div class="new-input__error-text-container">
<p class="new-input__error-text js-new-input-error-text"></p>
</div>
</div>
</div>
<button
type="submit"
class="new-input-group__addon new-input-group__addon_button new-button new-button_blue blog-subscribe__button"
>
Подписаться
</button>
</div>
</div>
<div class="new-input-line new-input-line_last">
<label class="checkbox checkbox_new">
<input required type="checkbox" checked name="subscription_agree" value="true">
<div class="checkbox__label blog-subscribe__checkbox-text">
Соглашаюсь получать полезные новости, статьи,
приглашения на мастер-классы и специальные предложения OTUS
</div>
</label>
<div class="new-input__error-sign new-ic new-ic-warning js-new-input-error">
<div class="new-input__error-text-container">
<p class="new-input__error-text js-new-input-error-text"></p>
</div>
</div>
</div>
</div>
<div class="hide js-loader">
<i class="ic loader loader_md loader_absolute-center ic-loader"></i>
</div>
</div>
</div>
<div class="js-block-success blog-subscribe__success hide">
<p class="blog-subscribe__title">Спасибо за подписку!</p>
<p class="blog-subscribe__text text-center">
Мы отправили вам письмо для подтверждения вашего email.
<br/>
С уважением, OTUS!
</p>
</div>
</form>
</div>
<div class="blog__tile" id="author_block">
<div class="blog__h2">Автор</div>
<div class="post-info">
<a href="/profile/67150/">
<div class="post-info__avatar post-info__avatar_big ic ic-blog-default-avatar" style="background-image: url(https://cdn.otus.ru/media/public/a5/6c/avatar-67150-a56c90.png);"></div>
<div class="post-info__author">Елена Граховац</div>
</a>
<div class="post-info__text">
Рейтинг:
<div class="post-info__text-ratingprofile__rating_pos">
+18
</div>
</div>
<div class="post-info__text">
2367 дней
</div>
<div class="post-info__button">
</div>
</div>
</div>
<div class="blog__comments blog__comments-blog-default">
<div data-comments>
<div class="blog__h2">
<div class="text text_inline text_default js-blog-comments-counter">
1 комментарий
</div>
</div>
<div class="js-comments">
<div id="comment813"
class="blog-comment blog-comment__level_0 js-comment"
data-comment-id="813"
data-parent-comment-id=""
>
<div class="blog-comment__avatar">
<a href="/profile/3945/">
<div class="post-info__avatar ic ic-blog-default-avatar" style="background-image: url(/static/img/default-avatars/11.svg);"></div>
</a>
</div>
<div class="blog-comment__content">
<a class="post-info__author" href="/profile/3945/" title="reddaemon">reddaemon</a>
<div class="post-info__time" comment_id="813">02.08.20 в 14:21</div>
<div class="blog-comment__votes">
<div class="js-vote blog-vote">
<div class="js-vote-like js-blog-comment-like blog-vote__item blog-vote__item_left blog-vote__item_border blog-vote__item_comment"
data-url="/nest/vote/comment/"
data-id="813"
data-value="-1">
</div>
<div class="js-votes blog-vote__item blog-vote__item_border blog-vote__item_center blog-vote__item_comment blog-vote__item_pos">
1
</div>
<div class="js-vote-like blog-vote__item blog-vote__item_border blog-vote__item_right blog-vote__item_comment"
data-url="/nest/vote/comment/"
data-id="813"
data-value="1">
</div>
</div>
</div>
<div class="markdown">
<div class="blog-comment__text js-blog-comment-text" data-comment-id="813"><p>Елена, спасибо за статью! Единственное, на OS X не получилось запустить ingress: "Due to docker networking limitations on darwin, ingress addon is not supported for this driver.
Alternatively to use this addon you can use a vm-based driver:</p>
<pre><code> 'minikube start --vm=true'
</code></pre>
<p>To track the update on this work in progress feature please check:
https://github.com/kubernetes/minikube/issues/7332
"</p></div>
</div>
</div>
</div>
</div>
<div class="blog-comment-deny">
Для комментирования необходимо <a href="/login/?next=https%3A%2F%2Fotus.ru%2Fnest%2Fpost%2F1389%2F">авторизоваться</a>
</div>
</div>
</div>
</div>
<div class="container__col container__col_4 container__col_md-0">
<div class="blog-tile-wrapper">
<div class="blog-tile">
<div class="blog-tile__title">Популярное</div>
<div class="blog-tile__item blog-tile__item_last">Сегодня тут пусто</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="blog-footer">
<div class="container cookies__container">
<div class="cookies__margin-block cookies_hide js-cookie">
<div class="cookies">
<div class="cookies__title">
Посещая наш сайт, вы принимаете <a class="cookies__link" href="/legal/cookie/" target="_blank">политику использования cookie-файлов</a>
</div>
<button class="js-cookie-accept cookies__button">ОК</button>
</div>
</div>
</div>
<footer class="footer2 footer2_header3 footer2_desktop footer2_not-subscribed no-print ">
<div class="footer2__container container">
<div class="footer2__container-box">
<div class="footer2__content">
<div class="container__row">
<div class="container__col container__col_4">
<div class="container__row">
<div class="container__col container__col_6 container__col_md-5">
<div class="footer2__links">
<div class="footer2__links-row">
<a href="/about" class="footer2__link" title="О нас">О нас</a>
</div>
<div class="footer2__links-row">
<a href="/smi/" class="footer2__link" title="СМИ о нас">СМИ о нас</a>
</div>
<div class="footer2__links-row">
<a href="/reviews" class="footer2__link" title="Отзывы">Отзывы</a>
</div>
<div class="footer2__links-row">
<a href="/contacts/" class="footer2__link" title="Контакты">Контакты</a>
</div>
<div class="footer2__links-row">
<a href="/journal/" class="footer2__link" title="Блог">Блог</a>
</div>
<div class="footer2__links-row">
<a href="/faq/" class="footer2__link" title="FAQ">FAQ</a>
</div>
</div>
</div>
<div class="container__col container__col_6 container__col_md-7">
<div class="footer2__icons">
<div class="footer2__social">
<a href="https://vk.com/club145052891" target="_blank" rel="noreferrer nofollow" class="footer2__icon ic ic-vk-footer2 ic-vk-footer2-hover"></a>
<a href="https://zen.yandex.ru/id/5bbcbc1ba5bd5400a990e7d9" target="_blank" rel="noreferrer nofollow" class="footer2__icon ic ic-zen ic-zen-hover"></a>
<a href="https://www.youtube.com/channel/UCetgtvy93o3i3CvyGXKFU3g" target="_blank" rel="noreferrer nofollow" class="footer2__icon ic ic-yt-footer2 ic-yt-footer2-hover"></a>
</div>
<a href="https://ttttt.me/Otusjava" target="_blank" rel="noreferrer nofollow" class="footer2__link-extended hover-ic">
<div class="footer2__icon ic ic-inline ic-tlgrm-footer2 ic-tlgrm-footer2-hover"></div>
<p class="footer2__link-extended-text">Канал в Telegram</p>
</a>
<a href="https://ttttt.me/joinchat/JMakp0NXc-L8nNneHCtx7A" target="_blank" rel="noreferrer nofollow" class="footer2__link-extended hover-ic" >
<div class="footer2__icon ic ic-inline ic-tlgrm-footer2 ic-tlgrm-footer2-hover"></div>
<p class="footer2__link-extended-text">Группа в Telegram</p>
</a>
</div>
</div>
</div>
</div>
<div class="container__col container__col_4">
<div class="footer2__links footer2__links_center">
<div class="footer2__links-row">
<a href="/b2b" class="footer2__link" rel="nofollow" title="Корпоративное обучение">
Корпоративное обучение
</a>
</div>
<div class="footer2__links-row">
<a href="/lessons/" class="footer2__link" title="Каталог курсов">
Каталог курсов
</a>
</div>
<div class="footer2__links-row">
<a href="/about/loyalty/" class="footer2__link" title="Программы лояльности">Программы лояльности</a>
</div>
<div class="footer2__links-row">
<a href="/professions/" class="footer2__link" title="Каталог профессий">Каталог профессий</a>
</div>
<div class="footer2__links-row">
<a href="/employers/all/" class="footer2__link" title="Наши партнеры">Наши партнеры</a>
</div>
<div class="footer2__links-row">
<a href="/teach/" class="footer2__link" title="Стать преподавателем">
Стать преподавателем
</a>
</div>
</div>
</div>
<div class="container__col container__col_4">
<p class="footer2__text footer2__text_margin-bot">Подписка на новости IT, анонсы открытых уроков, спец. предложения</p>
<form method="post" class="footer2__subscribe js-subscribe" action="/lessons/subscribe/">
<input type="hidden" name="csrfmiddlewaretoken" value="ZIfZ8joK9HE52VNXgIHlgScQsoeumcxOIPvRlRpT4Ovcd2wQ9nDHrj5NelH97Lt9">
<input
required
type="email"
name="email"
class="input footer2__subscribe-input"
placeholder="Электронная почта"
value=""
/>
<button
class="footer2__subscribe-button button button_blue button_as-input"
type="submit"
disabled
>
Подписаться
</button>
<div class="new-input-line new-input-line_relative new-input-line_triple footer2__subscribe-policy">
<label class="new-checkbox new-checkbox_vertical-center new-log-reg__checkbox">
<input type="checkbox" checked name="terms_agree" value="true"
class="js-remove-field-error">
<div class="new-checkbox__label">
Я принимаю условия
<a
class="new-link-dotted-blue"
target="_blank"
href="/legal/privacy/"
>
Политики обработки персональных данных
</a>
и
<a
class="new-link-dotted-blue"
target="_blank"
href="/legal/terms/"
>
Пользовательского соглашения
</a>
и даю
<a target="_blank" class="new-link-dotted-blue" href="
/legal/lead_privacy_agree/"
">
свое согласие на обработку персональных данных
</a>
</div>
</label>
</div>
</form>
<p class="footer2__text footer2__text_margin-bot">
По всем вопросам пишите на
<a class="footer2__link" href="mailto:help@otus.ru" target="_blank" rel="nofollow noreferer" title="help@otus.ru">help@otus.ru</a>
</p>
<p class="footer2__text footer2__text_margin-bot">
<a
class="footer2__link"
href="/legal/common/"
target="_blank"
rel="nofollow noreferer"
title="Сведения об образовательной организации"
>
Сведения об образовательной организации
</a>
</p>
<p class="footer2__text footer2__text_margin-bot">
<a
class="footer2__link"
href="/legal/it_company_accreditation/"
target="_blank"
rel="nofollow noreferer"
title="OTUS является аккредитованной IT-компанией"
>
OTUS является аккредитованной IT-компанией
</a>
</p>
<p class="footer2__text footer2__text_margin-bot">
<a
class="footer2__link"
href="/legal/recommendations/"
target="_blank"
rel="nofollow noreferer"
title="Сведения о рекомендательных технологиях"
>
Сведения о рекомендательных технологиях
</a>
</p>
<p class="footer2__text footer2__text_margin-bot">
<a
class="footer2__link"
href="https://reestr.digital.gov.ru/reestr/2704482/"
target="_blank"
rel="nofollow noreferer"
title="В реестре отечественного ПО №24216"
>
В реестре отечественного ПО №24216
</a>
</p>
</div>
</div>
</div>
<div class="footer2__info">
<div class="container__row">
<div class="container__col container__col_bottom container__col_8">
<div class="container__row">
<div class="container__col container__col_3 container__col_md-7">
<p
class="footer2__text footer2__text_nowrap footer2__text_margin-right "
>
© 2015-2026 OTUS
</p>
</div>
<div class="container__col container__col_3 container__col_md-5">
<a
class="footer2__link footer2__link-white-space-normal"
href="/legal/terms/"
title="Условия использования сервиса"
>
Условия использования сервиса
</a>
</div>
</div>
</div>
<div class="container__col container__col_middle container__col_4">
<div class="footer2__info-logos footer2__info-logos_desktop">
<div class="footer2__info-logos-row">
<div class="footer2__info-logo-box">
<div class="runet__wrapper">
<div class="runet">
<div class="runet__text">Премия Рунета <br>2018</div>
</div>
</div>
</div>
<div class="footer2__info-logo-box">
<a class="footer2__info-logo footer2__info-logo_skolkovo" href="http://sk.ru/?utm_source=otus" target="_blank" rel="noreferrer nofollow"></a>
</div>
</div>
<div class="footer2__info-logos-row">
<div class="footer2__info-logo-box footer2__info-logo-box_not-first footer2__info-logo-box_kts">
<a class="footer2__info-logo footer2__info-logo_kts" href="https://ktsstudio.com/?utm_source=otus" target="_blank" rel="noreferrer nofollow"></a>
</div>
<div class="footer2__info-logo-box footer2__info-logo-box_not-first">
<a class="footer2__info-logo footer2__info-logo_uno" href="http://goodlookin.ru/?utm_source=otus" target="_blank" rel="noreferrer nofollow"></a>
</div>
</div>
<div class="footer2__info-logos-row">
<div class="footer2__info-logo-box"></div>
<div class="footer2__info-logo-box">
<div class="runet-mobile">
<div class="runet-mobile__text">Премия Рунета <br>2018</div>
</div>
</div>
<div class="footer2__info-logo-box"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</footer>
<div class="footer2 footer2_mobile no-print ">
<div class="container footer2-mobile__container">
<div class="footer2-mobile__wrapper">
<div class="footer2-mobile__row">
<div class="container__row">
<div class="container__col container__col_12">
<p class="footer2__text footer2__text_margin-bot">Подписка на новости IT, анонсы открытых уроков, спец. предложения</p>
<form method="post" class="footer2__subscribe js-subscribe" action="/lessons/subscribe/">
<input type="hidden" name="csrfmiddlewaretoken" value="ZIfZ8joK9HE52VNXgIHlgScQsoeumcxOIPvRlRpT4Ovcd2wQ9nDHrj5NelH97Lt9">
<input
required
type="email"
name="email"
class="input footer2__subscribe-input"
placeholder="Электронная почта"
value=""
/>
<button
class="footer2__subscribe-button button button_blue button_as-input"
type="submit"
disabled
>
Подписаться
</button>
<div class="new-input-line new-input-line_relative new-input-line_triple footer2__subscribe-policy">
<label class="new-checkbox new-checkbox_vertical-center new-log-reg__checkbox">
<input type="checkbox" checked name="terms_agree" value="true"
class="js-remove-field-error">
<div class="new-checkbox__label">
Я принимаю условия
<a
class="new-link-dotted-blue"
target="_blank"
href="/legal/privacy/"
>
Политики обработки персональных данных
</a>
и
<a
class="new-link-dotted-blue"
target="_blank"
href="/legal/terms/"
>
Пользовательского соглашения
</a>
и даю
<a target="_blank" class="new-link-dotted-blue" href="
/legal/lead_privacy_agree/"
">
свое согласие на обработку персональных данных
</a>
</div>
</label>
</div>
</form>
<p class="footer2__text footer2__text_margin-bot">
По всем вопросам пишите на
<a class="footer2__link"
href="mailto:help@otus.ru"
target="_blank" rel="nofollow noreferer"
title="help@otus.ru">help@otus.ru</a>
</p>
<p class="footer2__text footer2__text_margin-bot">
<a class="footer2__link"
href="/legal/common/"
target="_blank" rel="nofollow noreferer"
title="Сведения об образовательной организации"
>
Сведения об образовательной организации
</a>
</p>
<p class="footer2__text footer2__text_margin-bot">
<a
class="footer2__link"
href="/legal/it_company_accreditation/"
target="_blank"
rel="nofollow noreferer"
title="OTUS является аккредитованной IT-компанией"
>
OTUS является аккредитованной IT-компанией
</a>
</p>
<p class="footer2__text footer2__text_margin-bot">
<a
class="footer2__link"
href="/legal/recommendations/"
target="_blank"
rel="nofollow noreferer"
title="Сведения о рекомендательных технологиях"
>
Сведения о рекомендательных технологиях
</a>
</p>
<p class="footer2__text footer2__text_margin-bot">
<a
class="footer2__link"
href="https://reestr.digital.gov.ru/reestr/2704482/"
target="_blank"
rel="nofollow noreferer"
title="В реестре отечественного ПО №24216"
>
В реестре отечественного ПО №24216
</a>
</p>
</div>
</div>
</div>
<div class="footer2-mobile__row footer2-mobile__row_social">
<div class="container__row">
<div class="container__col container__col_7 footer2-mobile__col_tg">
<a href="https://ttttt.me/Otusjava" target="_blank" rel="noreferrer nofollow" class="footer2__link-extended hover-ic">
<div class="footer2__icon ic ic-inline ic-tlgrm-footer2 ic-tlgrm-footer2-hover"></div>
<p class="footer2__link-extended-text">Канал в Telegram</p>
</a>
<a href="https://ttttt.me/joinchat/JMakp0NXc-L8nNneHCtx7A" target="_blank" rel="noreferrer nofollow" class="footer2__link-extended hover-ic" >
<div class="footer2__icon ic ic-inline ic-tlgrm-footer2 ic-tlgrm-footer2-hover"></div>
<p class="footer2__link-extended-text">Группа в Telegram</p>
</a>
</div>
<div class="container__col container__col_5 footer2-mobile__col_social">
<div class="footer2__social footer2__social_mobile">
<a href="https://vk.com/club145052891" target="_blank" rel="noreferrer nofollow" class="footer2__icon ic ic-vk-footer2 ic-vk-footer2-hover"></a>
<a href="https://zen.yandex.ru/id/5bbcbc1ba5bd5400a990e7d9" target="_blank" rel="noreferrer nofollow" class="footer2__icon ic ic-zen ic-zen-hover"></a>
<a href="https://www.youtube.com/channel/UCetgtvy93o3i3CvyGXKFU3g" target="_blank" rel="noreferrer nofollow" class="footer2__icon ic ic-yt-footer2 ic-yt-footer2-hover"></a>
</div>
</div>
</div>
</div>
<div class="footer2-mobile__row">
<div class="container__row">
<div class="container__col container__col_6 container__col_xs375-8">
<div class="footer2__links ">
<div class="footer2__links-row">
<a href="/b2b" class="footer2__link" rel="nofollow" title="Корпоративное обучение">
Корпоративное обучение
</a>
</div>
<div class="footer2__links-row">
<a href="/lessons/" class="footer2__link" rel=nofollow title="Каталог курсов">
Каталог курсов
</a>
</div>
<div class="footer2__links-row">
<a href="/about/loyalty/" class="footer2__link" rel=nofollow title="Программы лояльности">Программы лояльности</a>
</div>
<div class="footer2__links-row">
<a href="/professions/" class="footer2__link" rel=nofollow title="Каталог профессий">Каталог профессий</a>
</div>
<div class="footer2__links-row">
<a href="/employers/all/" class="footer2__link" rel=nofollow title="Наши партнеры">Наши партнеры</a>
</div>
<div class="footer2__links-row">
<a href="/teach/" class="footer2__link" rel=nofollow title="Стать преподавателем">
Стать преподавателем
</a>
</div>
</div>
</div>
<div class="container__col container__col_6 container__col_xs375-4">
<div class="footer2__links">
<div class="footer2__links-row">
<a href="/about" class="footer2__link" rel=nofollow title="О нас">О нас</a>
</div>
<div class="footer2__links-row">
<a href="/smi/" class="footer2__link" rel=nofollow title="СМИ о нас">СМИ о нас</a>
</div>
<div class="footer2__links-row">
<a href="/reviews" class="footer2__link" rel=nofollow title="Отзывы">Отзывы</a>
</div>
<div class="footer2__links-row">
<a href="/contacts/" class="footer2__link" rel=nofollow title="Контакты">Контакты</a>
</div>
<div class="footer2__links-row">
<a href="/journal/" class="footer2__link" rel=nofollow title="Блог">Блог</a>
</div>
<div class="footer2__links-row">
<a href="/faq/" class="footer2__link" rel=nofollow title="FAQ">FAQ</a>
</div>
</div>
</div>
</div>
</div>
<div class="footer2-mobile__row footer2-mobile__row_mark">
<div class="footer2-mobile__mark">
<p
class="footer2__text footer2__text_nowrap footer2__text_margin-right footer2__text_margin-right"
>
© 2015-2026 OTUS
</p>
<a
class="footer2__link"
href="/legal/terms/"
title="Пользовательское соглашение"
>
Пользовательское соглашение
</a>
</div>
<div class="footer2-mobile__logos">
<div class="footer2__info-logos footer2__info-logos_tablet">
<div class="footer2__info-logos-row_mobile">
<div class="footer2__info-logo-box">
<a class="footer2__info-logo footer2__info-logo_skolkovo" href="http://sk.ru/?utm_source=otus" target="_blank" rel="noreferrer nofollow"></a>
</div>
<div class="footer2__info-logo-box">
<div class="runet-mobile">
<div class="runet-mobile__text">Премия Рунета <br>2018</div>
</div>
</div>
<div class="footer2__info-logo-box footer2__info-logo-box_not-first footer2__info-logo-box_kts">
<a class="footer2__info-logo footer2__info-logo_kts" href="https://ktsstudio.com/?utm_source=otus" target="_blank" rel="noreferrer nofollow"></a>
</div>
<div class="footer2__info-logo-box footer2__info-logo-box_not-first">
<a class="footer2__info-logo footer2__info-logo_uno" href="http://goodlookin.ru/?utm_source=otus" target="_blank" rel="noreferrer nofollow"></a>
</div>
</div>
</div>
<div class="footer2__info-logos footer2__info-logos_mobile">
<div class="footer2__info-logos-row">
<div class="footer2__info-logo-box">
<div class="runet-mobile">
<div class="runet-mobile__text">Премия Рунета <br>2018</div>
</div>
</div>
<div class="footer2__info-logo-box">
<a class="footer2__info-logo footer2__info-logo_skolkovo" href="http://sk.ru/?utm_source=otus" target="_blank" rel="noreferrer nofollow"></a>
</div>
</div>
<div class="footer2__info-logos-row">
<div class="footer2__info-logo-box footer2__info-logo-box_not-first footer2__info-logo-box_kts">
<a class="footer2__info-logo footer2__info-logo_kts" href="https://ktsstudio.com/?utm_source=otus" target="_blank" rel="noreferrer nofollow"></a>
</div>
<div class="footer2__info-logo-box footer2__info-logo-box_not-first">
<a class="footer2__info-logo footer2__info-logo_uno" href="http://goodlookin.ru/?utm_source=otus" target="_blank" rel="noreferrer nofollow"></a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal-container hide-top hide-transparent new-log-reg-container"
data-query='{"next": "/nest/post/1389/"}'
data-modal-ajax="/login-registration/"
data-modal-ajax-once="true"
data-modal-id="new-log-reg"
data-modal-hide-remove-class="hide-top,hide-transparent"
data-modal-hide-add-class="hide-transparent"
data-modal-loading="true"
data-modal-hide-add-delay-class="hide-top">
<div class="new-log-reg-loader">
<div class="new-log-reg__login">
<div class="loader loader_md loader_absolute-center ic-loader ic"></div>
</div>
</div>
<div class="new-log-reg-wrapper js-modal-content">
<div class="new-log-reg__login"></div>
</div>
</div>
<div class="modal-container hide-top hide-transparent new-log-reg-container"
data-query='{"next": "/nest/post/1389/"}'
data-modal-ajax="/login-registration/"
data-modal-id="new-log-reg-event"
data-modal-hide-remove-class="hide-top,hide-transparent"
data-modal-hide-add-class="hide-transparent"
data-modal-loading="true"
data-modal-hide-add-delay-class="hide-top">
<div class="new-log-reg-loader">
<div class="new-log-reg__login">
<div class="loader loader_md loader_absolute-center ic-loader ic"></div>
</div>
</div>
<div class="new-log-reg-wrapper js-modal-content">
<div class="new-log-reg__login"></div>
</div>
</div>
<div class="modal-container hide" data-modal-id="restore-password">
<div class="modal-wrapper modal-wrapper_dark js-modal-wrapper">
<div class="modal new-log-reg__popup">
<div class="new-log-reg__popup-body">
<div class="modal__close new-ic new-ic-close-inverse new-log-reg__popup-close js-close-modal"></div>
<p class="new-log-reg__popup-title">Восстановление пароля</p>
<form method="post" class="js-restore-password" action="/api/restore_password.send_email">
<input type="hidden" name="csrfmiddlewaretoken" value="ZIfZ8joK9HE52VNXgIHlgScQsoeumcxOIPvRlRpT4Ovcd2wQ9nDHrj5NelH97Lt9">
<div class="new-log-reg__popup-text new-log-reg__popup-text_slim">
Введите электронную почту для восстановления пароля
</div>
<div class="new-input-line new-input-line_slim new-input-line_relative">
<input type="email"
class="new-input new-input_full js-placeholder js-input
js-required
"
maxlength=""
name="email"
autocomplete="off"
required
placeholder="Электронная почта"
/>
<div class="new-input-error new-input-error_bottom js-validation-error hide "></div>
<div class="new-input-error new-input-error_info new-input-error_bottom hide"></div>
</div>
<div class="new-input-line js-error hide">
<span class="new-input-line__error new-log-reg__popup-error">
Пользователь с таким email не найден
</span>
</div>
<div class="new-input-line">
<button class="new-button new-button_md new-button_full new-button_blue"
type="submit">Восстановить
</button>
</div>
</form>
</div>
</div>
</div>
</div>
<div class="modal-container hide" data-modal-id="phone_duplicate">
<div class="modal-wrapper modal-wrapper_dark js-modal-wrapper" data-no-wrapper-close="true">
<div class="modal new-log-reg__popup new-log-reg__popup-body">
<button class="new-log-reg__popup-close new-ic-close-inverse js-close-modal js-stats"
data-event="Register;double_tel_bad"
style=""></button>
<form>
<p class="new-log-reg__popup-title">
Ваш телефон уже привязан к<br/>другой учетной записи
</p>
<p class="new-log-reg__popup-text">
Ваш телефон <b><nobr class="js-phone-duplicate-phone"></nobr></b> уже
привязан к учетной записи <b><nobr class="js-phone-duplicate-acc"></nobr></b>.
Выберите учетную запись, с которой желаете продолжить работу.
Мы привяжем к ней телефон.
</p>
<input class="js-dod-phone-dup-modal-phone" type="hidden" value="" name="phone">
<div class="dod-phone-dup-modal__loader-container">
<div class="js-loader-content">
<div class="new-input-line">
<button
class="new-button new-button_md new-button_full new-button_one-line
new-button_blue-inverse js-stats js-dod-phone-dup-modal-submit"
type="submit"
data-value="1"
data-event="Register;double_tel_ok"
>
Текущий аккаунт <nobr class="js-phone-duplicate-self-acc"></nobr>
</button>
</div>
<div class="new-input-line">
<button
class="new-button new-button_md new-button_full new-button_one-line
new-button_blue js-stats js-dod-phone-dup-modal-submit"
type="submit"
data-value="0"
data-event="Register;double_tel_ok"
>
Войти в аккаунт <nobr class="js-phone-duplicate-acc"></nobr>
</button>
</div>
<div class="new-input-line js-error hide">
<span class="new-input-line__error new-log-reg__popup-error js-error-text"></span>
</div>
</div>
<div
class="js-loader loader loader_absolute-center loader_md ic ic-loader"
style="display: none;"
></div>
</div>
</form>
</div>
</div>
</div>
<div class="modal-container hide" data-modal-id="teacher-enrollment">
<div class="modal-wrapper modal-wrapper_dark js-modal-wrapper" data-no-wrapper-close="true">
<div class="modal new-log-reg__popup">
<form class="new-log-reg__popup-body js-email-terms-update js-form-in-modal"
action="/teacher/request/"
data-modal="teacher-enrollment">
<div class="modal__close new-ic new-ic-close-inverse new-log-reg__popup-close js-close-modal"></div>
<div class="new-log-reg__popup-title">
Заполните номер телефона
</div>
<div class="new-log-reg__popup-text new-log-reg__popup-text_slim">
Для отправки заявки в преподаватели заполните номер телефона
</div>
<div class="new-input-line new-input-line_slim new-input-line_relative">
<input type="text"
class="new-input new-input_full js-placeholder js-input
js-required
"
maxlength="255"
name="phone"
autocomplete="off"
data-js-mask="phone"
required
placeholder="Телефон"
/>
<div class="new-input-error new-input-error_bottom js-validation-error hide "></div>
<div class="new-input-error new-input-error_info new-input-error_bottom hide"></div>
</div>
<div class="new-input-line js-error hide">
<span class="new-input-line__error new-log-reg__popup-error js-text"></span>
</div>
<div class="new-input-line">
<button class="new-button new-button_md new-button_full new-button_blue"
type="submit">Отправить
</button>
</div>
</form>
</div>
</div>
</div>
<script src="https://otus.ru/static/js/common.792bd.js" ></script>
<script src="https://otus.ru/static/js/vendor.common.2ae83.js" ></script>
<script src="https://otus.ru/static/js/vendor.otus.90c85.js" ></script>
<script src="https://otus.ru/static/js/otus.714df.js" ></script>
<script src="https://otus.ru/static/js/vendor.react.3b8bf.js" ></script>
<script src="https://otus.ru/static/js/vendor.common.2ae83.js" ></script>
<script src="https://otus.ru/static/js/vendor.otus-react:header-search.706a9.js" ></script>
<script src="https://otus.ru/static/js/otus-react:header-search.34d9b.js" ></script>
<script type="text/javascript">(window.Image ? (new Image()) : document.createElement('img')).src = 'https://vk.com/rtrg?r=w1EsimsoVZRm*rb04TRjaay1IST5bHFNpthXLyHrq1GCPGzgOmMRcY3mDDdxA17TQOlx6ykxwlrtBtW7sMri/2f364oz1QGDuVvxHFqMqER5NT9mlhp1lYbEMKPIB7NgDRQQp5s2IxBuu*caPsHzTtfILgZJsV5bbkH0m8*GleA-&pixel_id=1000094479';</script>
<script type="text/javascript">(window.Image ? (new Image()) : document.createElement('img')).src = 'https://vk.com/rtrg?p=VK-RTRG-182645-Hs1B';</script>
<script type="text/javascript">(window.Image ? (new Image()) : document.createElement('img')).src = 'https://vk.com/rtrg?p=VK-RTRG-110005-dVnpE';</script>
<script type="text/javascript">(window.Image ? (new Image()) : document.createElement('img')).src = 'https://vk.com/rtrg?p=VK-RTRG-226047-a8wzo';</script>
<noscript>
<div>
<img src="https://mc.yandex.ru/watch/34531570" style="position:absolute; left:-9999px; top: 0;" alt=""/>
<img src="https://mc.yandex.ru/watch/82755226" style="position:absolute; left:-9999px; top: 0;" alt=""/>
<img src="https://mc.yandex.ru/watch/93715742" style="position:absolute; left:-9999px; top: 0;" alt=""/>
</div>
</noscript>
<img height="1" width="1" src="https://happy.otus.ru/pixel/otus.gif?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyZWZlcmVyIjoiaHR0cHM6Ly9vdHVzLnJ1L25lc3QvcG9zdC8xMzg5Lz91dG1fc291cmNlPXR5cGVpbiZ1dG1fbWVkaXVtPWRpcmVjdCZ1dG1fY2FtcGFpZ249Tm9uZSJ9.Bq70u8Kd1U0eaCa6FqJJ8-iI-uzWkdiDxJCWq761e5c" style="position:absolute; left:-9999px; top: 0;" alt="" />
</body>
</html>