Compare commits

...

11 Commits

Author SHA1 Message Date
183407fed0
Deploy PRs to a test server 2025-04-08 23:21:08 +02:00
f06a7381e7
useFetch hook (with optional view transition)
Had to use a .d.ts and .js file to get all the types to align and make all the tools happy, IDE/eslint/TypeScript.
2025-04-06 17:38:51 +02:00
6542cee415
Fix for browsers that do not support view transitions 2025-04-04 13:05:38 +02:00
2258f67b54
Add basic routing
Everything sould be set up to start adding features
2025-04-04 13:05:38 +02:00
a53ec6a3fe
Basic splash screen while loading initial data 2025-04-04 13:05:38 +02:00
a8889a231a
Connect frontend and backend 2025-04-03 09:55:52 +02:00
525e76cd5b
Generate OpenAPI specification 2025-04-03 09:55:52 +02:00
33988953d5
Add prettier 2025-04-03 09:55:52 +02:00
843ac8f76d
npm audit fix 2025-04-03 09:55:52 +02:00
cd9660c0b1
Protected backend with OAuth 2 login
On unauthorized HTTP response navigate to the URL indicated by the X-Authorization-Url header to begin the process of logging in.
2025-04-03 09:55:51 +02:00
f60f9f5ac5
npm create vite@latest 2025-04-03 09:55:51 +02:00
53 changed files with 5117 additions and 0 deletions

@ -0,0 +1,14 @@
name: Remove branch deployment from branch.dsv.su.se
on:
pull_request:
types:
- closed
jobs:
cleanup:
runs-on: ubuntu-latest
steps:
- uses: https://gitea.dsv.su.se/ansv7779/action-branch-deploy@v2
with:
cleanup-ssh-key: ${{ secrets.BRANCH_CLEANUP_KEY }}
compose-file: branch-compose.yaml
mode: 'cleanup'

@ -0,0 +1,27 @@
name: Deploy to branch.dsv.su.se
on:
- pull_request
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- id: deploy
uses: https://gitea.dsv.su.se/ansv7779/action-branch-deploy@v2
with:
ssh-key: ${{ secrets.BRANCH_DEPLOY_KEY }}
compose-file: branch-compose.yaml
mode: 'deploy'
- name: Post URL to deployment as comment
uses: actions/github-script@v7
if: github.event.action == 'opened'
env:
BRANCH_URL: ${{ steps.deploy.outputs.url }}
with:
script: |
const url = process.env.BRANCH_URL;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `Deployed to ${url}`
})

@ -17,3 +17,13 @@ services:
MOCK_FILE_PATH: /mocks
volumes:
- ./src/mock-api:/mocks
oauth2:
build: https://gitea.dsv.su.se/DMC/oauth2-authorization-server.git
restart: unless-stopped
ports:
- '63164:8080'
environment:
CLIENT_ID: studentportalen
CLIENT_SECRET: p4ssw0rd
CLIENT_REDIRECT_URI: http://localhost:8080/login/oauth2/code/studentportalen
CLIENT_SCOPES: openid profile email offline_access

@ -14,10 +14,12 @@
<groupId>se.su.dsv.studentportalen</groupId>
<artifactId>bff</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>24</java.version>
<springdoc.version>2.8.6</springdoc.version>
</properties>
<dependencies>
@ -25,6 +27,17 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<!-- OpenAPI specification -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>${springdoc.version}</version>
</dependency>
</dependencies>
<build>

@ -0,0 +1,12 @@
package se.su.dsv.studentportalen.bff;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("se.su.dsv.frontend")
public record FrontendConfiguration(String url) {
public FrontendConfiguration {
if (url == null || url.isBlank()) {
throw new IllegalArgumentException("se.su.dsv.frontend.url must not be null or blank");
}
}
}

@ -5,12 +5,64 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatchers;
import org.springframework.web.cors.CorsConfiguration;
import se.su.dsv.studentportalen.bff.login.BFFAuthenticationEntryPoint;
import java.util.List;
import static org.springframework.security.web.util.matcher.AntPathRequestMatcher.antMatcher;
@SpringBootApplication
@EnableConfigurationProperties
@ConfigurationPropertiesScan
public class Studentportalen extends SpringBootServletInitializer {
private static final RequestMatcher DOCUMENTATION_MATCHER = RequestMatchers.anyOf(
antMatcher("/swagger"),
antMatcher("/swagger-ui/**"),
antMatcher("/v3/api-docs/**"));
public static void main(String[] args) {
SpringApplication.run(Studentportalen.class, args);
}
@Bean
public SecurityFilterChain securityFilterChain(
HttpSecurity http,
FrontendConfiguration frontendConfiguration)
throws Exception
{
http.exceptionHandling(exception -> exception
.authenticationEntryPoint(new BFFAuthenticationEntryPoint()));
http.oauth2Login(login -> login
.defaultSuccessUrl(frontendConfiguration.url(), true));
http.authorizeHttpRequests(authorize -> authorize
.requestMatchers(DOCUMENTATION_MATCHER).permitAll()
.anyRequest().authenticated());
http.cors(cors -> cors
.configurationSource(_ -> frontendOnlyCors(frontendConfiguration)));
return http.build();
}
private static CorsConfiguration frontendOnlyCors(FrontendConfiguration frontendConfiguration) {
var corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowedOrigins(List.of(frontendConfiguration.url()));
corsConfiguration.setAllowedMethods(List.of("GET", "POST"));
// Allow the frontend to see the X-Authorization-Url header
corsConfiguration.setExposedHeaders(List.of("X-Authorization-Url"));
// To allow the session cookie to be included
corsConfiguration.setAllowCredentials(true);
// Content-Type is allowed by default but with a restriction on the value
// The restriction does not allow "application/json" so we add it as an allowed header
corsConfiguration.setAllowedHeaders(List.of("Content-Type"));
return corsConfiguration;
}
}

@ -0,0 +1,7 @@
/// Everything related to the API used by the frontend
@NonNullApi
@NonNullFields
package se.su.dsv.studentportalen.bff.frontend;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

@ -0,0 +1,20 @@
package se.su.dsv.studentportalen.bff.frontend.profile;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Objects;
public record Profile(
@JsonProperty(value = "name", required = true) String name,
@JsonProperty(value = "language", required = true) Language language)
{
public enum Language {
@JsonProperty("sv") SWEDISH,
@JsonProperty("en") ENGLISH
}
public Profile {
Objects.requireNonNull(name, "name must be specified");
Objects.requireNonNull(language, "language must be specified");
}
}

@ -0,0 +1,19 @@
package se.su.dsv.studentportalen.bff.frontend.profile;
import org.springframework.http.MediaType;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public class ProfileController {
@GetMapping("/profile")
public Profile getProfile(
@AuthenticationPrincipal(errorOnInvalidType = true) OAuth2User currentUser)
{
return new Profile(currentUser.getAttribute("name"), Profile.Language.ENGLISH);
}
}

@ -0,0 +1,19 @@
package se.su.dsv.studentportalen.bff.login;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
public class BFFAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) {
String loginUri = ServletUriComponentsBuilder.fromRequest(request)
.replacePath("/oauth2/authorization/studentportalen")
.build()
.toUriString();
response.addHeader("X-Authorization-Url", loginUri);
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
}
}

@ -0,0 +1,17 @@
/// This package contains the classes and logic for handling the login process
/// described in section 6.1 of [OAuth 2.0 for Browser-Based Applications](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-browser-based-apps#name-backend-for-frontend-bff).
///
/// The frontend running in the browser will attempt to make a request to the
/// backend-for-frontend (BFF). If the client is not already authenticated (by
/// checking the session cookie), the [se.su.dsv.studentportalen.bff.login.BFFAuthenticationEntryPoint]
/// will respond sending a `401 Unauthorized` response with the header
/// `X-Authorization-Url` set to where the frontend can begin the authentication
/// flow. This initial request corresponds to the request labelled (B) in
/// [figure 1](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-browser-based-apps#figure-1).
/// The frontend will then do a full browser navigation to the provided URL (C)
/// which triggers the OAuth 2.0 authorization code flow.
///
/// The entire flow is then performed by Spring Security (D, E, F, and G).
/// Once complete, the user is sent back to the frontend (H) with a valid
/// session.
package se.su.dsv.studentportalen.bff.login;

@ -0,0 +1,7 @@
spring.security.oauth2.client.provider.dsv.issuer-uri: ${OAUTH2_ISSUER_URI}
spring.security.oauth2.client.registration.studentportalen.client-id: ${OAUTH2_CLIENT_ID}
spring.security.oauth2.client.registration.studentportalen.client-secret: ${OAUTH2_CLIENT_SECRET}
se.su.dsv.backend-api.daisy-url: ${BACKEND_API_DAISY}
se.su.dsv.frontend.url: ${FRONTEND_URL}
server.forward-headers-strategy: framework

@ -3,3 +3,18 @@ se:
dsv:
backend-api:
daisy-url: http://localhost:63163/daisy
frontend:
url: http://localhost:5173
spring.security.oauth2.client:
provider:
dsv:
issuer-uri: http://localhost:63164
registration:
studentportalen:
client-id: studentportalen
client-secret: p4ssw0rd
# Lift the restrictions imposed by __Host- prefix during development
# Ideally we keep it on, but it breaks in Chromium on Linux
server.servlet.session.cookie.name: studentportalen-bff-session

@ -1,3 +1,33 @@
# The following properties need to be set in each specific environment
spring.security.oauth2.client.provider.dsv.issuer-uri: ...
spring.security.oauth2.client.registration.studentportalen.client-id: ...
spring.security.oauth2.client.registration.studentportalen.client-secret: ...
se.su.dsv.backend-api.daisy-url: ...
se.su.dsv.frontend.url: ...
# Common properties for all environments
spring:
application:
name: studentportalen-bff
security.oauth2.client:
registration:
studentportalen:
provider: dsv
scope:
- openid
- profile
- email
- offline_access
server.servlet.session:
cookie:
# See https://datatracker.ietf.org/doc/html/draft-ietf-oauth-browser-based-apps#section-6.1.3.2
secure: true
http-only: true
same-site: strict
path: /
name: __Host-JSESSIONID
springdoc:
swagger-ui:
path: /swagger

30
branch-bff.Dockerfile Normal file

@ -0,0 +1,30 @@
FROM eclipse-temurin:24 AS build
WORKDIR /build
COPY mvnw mvnw
COPY .mvn/ .mvn/
COPY pom.xml pom.xml
RUN ./mvnw dependency:go-offline \
--batch-mode \
--fail-fast
COPY src/ src/
RUN ./mvnw package \
--batch-mode \
--fail-fast \
-DskipTests
FROM eclipse-temurin:24 AS runtime
WORKDIR /bff
COPY --from=build /build/target/*.war ./bff.war
ENV SPRING_PROFILES_ACTIVE=branch
EXPOSE 8080
ENTRYPOINT ["java", "--enable-preview", "-jar", "bff.war"]

68
branch-compose.yaml Normal file

@ -0,0 +1,68 @@
services:
frontend:
build:
context: ./frontend
dockerfile: ../branch-frontend.Dockerfile
args:
BACKEND_URL: https://bff-${VHOST}
restart: unless-stopped
networks:
- traefik
environment:
VITE_BACKEND_URL: https://bff-${VHOST}
labels:
- "traefik.enable=true"
- "traefik.http.routers.frontend-${COMPOSE_PROJECT_NAME}.rule=Host(`${VHOST}`)"
- "traefik.http.routers.frontend-${COMPOSE_PROJECT_NAME}.tls.certresolver=letsencrypt"
bff:
build:
context: ./bff
dockerfile: ../branch-bff.Dockerfile
restart: unless-stopped
networks:
- internal
- traefik
environment:
OAUTH2_ISSUER_URI: https://oauth2-${VHOST}
OAUTH2_CLIENT_ID: studentportalen
OAUTH2_CLIENT_SECRET: p4ssw0rd
FRONTEND_URL: https://${VHOST}
BACKEND_API_DAISY: http://mock-apis:8080/daisy
labels:
- "traefik.enable=true"
- "traefik.http.routers.bff-${COMPOSE_PROJECT_NAME}.rule=Host(`bff-${VHOST}`)"
- "traefik.http.routers.bff-${COMPOSE_PROJECT_NAME}.tls.certresolver=letsencrypt"
oauth2:
build: https://gitea.dsv.su.se/DMC/oauth2-authorization-server.git#main #branch=main, it defaults to master
restart: unless-stopped
networks:
- traefik
environment:
CLIENT_ID: studentportalen
CLIENT_SECRET: p4ssw0rd
CLIENT_SCOPES: openid profile email offline_access
CLIENT_REDIRECT_URI: https://bff-${VHOST}/login/oauth2/code/studentportalen
labels:
- "traefik.enable=true"
- "traefik.http.routers.oauth2-${COMPOSE_PROJECT_NAME}.rule=Host(`oauth2-${VHOST}`)"
- "traefik.http.routers.oauth2-${COMPOSE_PROJECT_NAME}.tls.certresolver=letsencrypt"
mock-apis:
build: https://gitea.dsv.su.se/DMC/apimposter.git#main #branch=main, it defaults to master
restart: unless-stopped
networks:
- internal
environment:
MOCK_BASE_PATH: / # HTTP base path for the mock server
MOCK_FILE_PATH: /mocks
volumes:
- ./bff/src/mock-api:/mocks
networks:
internal:
name: ${COMPOSE_PROJECT_NAME}_internal
traefik:
name: traefik
external: true

@ -0,0 +1,25 @@
FROM node:20 AS build
WORKDIR /build
COPY package.json .
COPY package-lock.json .
RUN npm install
COPY public/ public/
COPY src/ src/
COPY index.html .
COPY tsconfig.json .
COPY tsconfig.app.json .
COPY tsconfig.node.json .
COPY vite.config.ts .
ARG BACKEND_URL
ENV VITE_BACKEND_URL=${BACKEND_URL}
RUN npm run build
FROM httpd:2.4 AS runtime
COPY --from=build /build/dist/ /usr/local/apache2/htdocs/

1
frontend/.env Normal file

@ -0,0 +1 @@
VITE_BACKEND_URL=http://localhost:8080/

24
frontend/.gitignore vendored Normal file

@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

1
frontend/.prettierignore Normal file

@ -0,0 +1 @@
src/lib/api.d.ts

1
frontend/.prettierrc Normal file

@ -0,0 +1 @@
{}

14
frontend/README.md Normal file

@ -0,0 +1,14 @@
# Studentportalen frontend
## Developing
### Prerequisites
- Node v20
- npm
Run `npm install` to install all dependencies then run `npm run dev` to start the development server.
Run `npm run format` and `npm run lint` to format and lint the code.
Run `npm run update-api` after having started the BFF to update the typed API client.

33
frontend/eslint.config.js Normal file

@ -0,0 +1,33 @@
import js from "@eslint/js";
import globals from "globals";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import tseslint from "typescript-eslint";
import eslintConfigPrettier from "eslint-config-prettier/flat";
export default tseslint.config(
{ ignores: ["dist"] },
{
extends: [
js.configs.recommended,
...tseslint.configs.recommended,
eslintConfigPrettier,
],
files: ["**/*.{ts,tsx}"],
languageOptions: {
ecmaVersion: 2023,
globals: globals.browser,
},
plugins: {
"react-hooks": reactHooks,
"react-refresh": reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
"react-refresh/only-export-components": [
"warn",
{ allowConstantExport: true },
],
},
},
);

14
frontend/index.html Normal file

@ -0,0 +1,14 @@
<!doctype html>
<html lang="en">
<head>
<link rel="preload" href="/src/assets/SU_logo_optimized.svg" as="image" />
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

3248
frontend/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

36
frontend/package.json Normal file

@ -0,0 +1,36 @@
{
"name": "frontend",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint .",
"format": "prettier . --write",
"update-api": "openapi-typescript http://localhost:8080/v3/api-docs --output src/lib/api.d.ts",
"preview": "vite preview"
},
"dependencies": {
"openapi-fetch": "^0.13.5",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-router": "^7.4.1"
},
"devDependencies": {
"@eslint/js": "^9.21.0",
"@types/react": "^19.0.10",
"@types/react-dom": "^19.0.4",
"@vitejs/plugin-react-swc": "^3.8.0",
"eslint": "^9.21.0",
"eslint-config-prettier": "^10.1.1",
"eslint-plugin-react-hooks": "^5.1.0",
"eslint-plugin-react-refresh": "^0.4.19",
"globals": "^15.15.0",
"openapi-typescript": "^7.6.1",
"prettier": "3.5.3",
"typescript": "~5.7.2",
"typescript-eslint": "^8.24.1",
"vite": "^6.2.0"
}
}

1
frontend/public/vite.svg Normal file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

(image error) Size: 1.5 KiB

14
frontend/src/App.css Normal file

@ -0,0 +1,14 @@
#app {
height: 100vh;
background-color: var(--color-su-primary);
display: flex;
justify-content: center;
flex-direction: column;
text-align: center;
color: white;
padding: 1em;
align-items: center;
}
#app > img {
max-width: 30em;
}

37
frontend/src/App.tsx Normal file

@ -0,0 +1,37 @@
import "./App.css";
import suLogoLandscape from "./assets/SU_logo_optimized.svg";
import { ProfileContext } from "./hooks/profile.ts";
import Studentportalen from "./Studentportalen.tsx";
import { useViewTransitioningFetch } from "./hooks/fetch";
function App() {
const { data: profile, error } = useViewTransitioningFetch("/profile");
if (!profile) {
return splashScreen("Loading...");
}
if (error) {
return splashScreen("Application failed to start");
}
return (
<ProfileContext value={profile}>
<Studentportalen />
</ProfileContext>
);
}
function splashScreen(extraContent: string) {
return (
<div id={"app"}>
<img src={suLogoLandscape} alt={"Stockholm University"} />
<div>
<h1>Student portal</h1>
<h2>Department of Computer and Systems Sciences</h2>
{extraContent}
</div>
</div>
);
}
export default App;

@ -0,0 +1,17 @@
import { BrowserRouter, Route, Routes } from "react-router";
import Home from "./studentportalen/Home.tsx";
import Layout from "./studentportalen/Layout.tsx";
export default function Studentportalen() {
return (
<>
<BrowserRouter>
<Routes>
<Route element={<Layout />}>
<Route index element={<Home />} />
</Route>
</Routes>
</BrowserRouter>
</>
);
}

File diff suppressed because one or more lines are too long

After

(image error) Size: 31 KiB

@ -0,0 +1,379 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Logotyper" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 671.54 283.1" style="enable-background:new 0 0 671.54 283.1;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
</style>
<g>
<g id="Group_33" transform="translate(-337.004 -221)">
<g id="Group_27" transform="translate(143.967)">
<path id="Path_1187" class="st0" d="M388.85,289.02c0.14,0.16,0.07,0.27-0.08,0.4c-0.27,0.22-1.77,2.43-1.95,2.7
c-0.11,0.18-0.13-0.14-0.07-0.32c0.51-1.48,0.08-3.13-1.08-4.18c-1.21-0.92-2.93-0.68-3.84,0.53c-0.01,0.02-0.03,0.04-0.04,0.06
c-0.94,1.4-0.97,2.67,0,6.33c1.01,3.81,0.59,5.21-0.8,6.83c-1.87,1.85-4.82,2.05-6.92,0.47c-2.71-1.89-2.82-2.32-3.24-2.49
c-0.33-0.14-0.32-0.4,0-0.8c0.48-0.57,2.09-2.75,2.36-3.16c0.18-0.28,0.22,0.04,0.03,0.45c-0.84,1.64-0.4,3.64,1.05,4.77
c1.18,1.1,3.03,1.03,4.13-0.15c0.06-0.07,0.12-0.14,0.18-0.21c0.8-0.96,1.27-1.89,0.14-6.26c-1.2-4.61-0.37-6.12,1.37-7.48
c1.79-1.46,4.37-1.44,6.14,0.04c0.7,0.55,1.35,1.14,1.97,1.78c0.22,0.22,0.34,0.46,0.46,0.57S388.78,288.93,388.85,289.02z"/>
<path id="Path_1188" class="st0" d="M244.24,341.13c0.06-0.16,0.24-0.08,0.47,0c0.95,0.26,1.92,0.43,2.9,0.51
c0.49,0-0.34,0.37-0.59,0.4c-0.69,0.09-2.05,0.49-2.67,2.77c-0.42,1.3,0.29,2.69,1.59,3.11c0.07,0.02,0.13,0.04,0.2,0.06
c2,0.4,3.06-0.36,5.99-2.72c1.78-1.92,4.44-2.75,6.99-2.19c2.41,0.86,3.79,3.4,3.2,5.89c-0.27,1.31-0.79,2.56-1.54,3.68
c-0.12,0.34-0.28,0.46-0.78,0.32c-0.64-0.18-3.05-0.53-3.48-0.58c-0.78-0.09-0.45-0.4,0-0.44c1.24-0.16,3.94-0.5,4.48-3.15
c0.36-1.38-0.47-2.78-1.84-3.14c-0.08-0.02-0.17-0.04-0.25-0.05c-1.23-0.3-2.57-0.26-6.03,2.61c-3.73,3.09-5.32,3.08-7.33,2.17
c-2.1-0.92-3.19-3.26-2.55-5.47c0.21-1.14,0.59-2.24,1.13-3.26C244.24,341.52,244.2,341.24,244.24,341.13z"/>
<path id="Path_1189" class="st0" d="M358.57,449.92c-0.26,0-0.21-0.22-0.25-0.4c0,0-0.66-2.19-0.72-2.37
c-0.06-0.17,0.13-0.24,0.26-0.08c0.95,1.05,2.39,1.51,3.77,1.2c1.48-0.35,2.41-1.82,2.09-3.31c-0.52-1.6-2.09-2.35-5.53-3.93
c-3.1-1.43-4.1-2.86-4.4-4.64c-0.26-2.68,1.41-5.17,4-5.95c2.59-0.8,3.2-0.72,3.72-0.98c0.4-0.21,0.45,0.61,0.5,0.76
c0.25,0.69,0.92,2.84,1.08,3.24c0.16,0.4-0.14,0.51-0.33,0.1c-0.89-1.57-2.69-2.38-4.45-2c-2.31,0.75-2.65,2.4-2.33,3.49
c0.36,1.2,0.57,2.17,4.92,4c4.23,1.78,5.06,3.6,5.08,5.65c-0.14,2.34-1.88,4.28-4.2,4.66c-0.68,0.18-1.38,0.28-2.09,0.31
c-0.31,0.05-0.55,0.07-0.71,0.09C358.82,449.78,358.78,449.92,358.57,449.92z"/>
<path id="Path_1190" class="st0" d="M390.91,293.8c0.62-0.27,1.21-0.61,1.74-1.03c0.22-0.18,0.64,0,0.9,0.26
c0.17,0.17,3.95,3.91,4.69,4.71c1.01,1.07,4.36,4.15,4.79,4.57c0.43,0.42,0.84,0.64,0.4,0.93c-0.44,0.28-1.36,0.8-1.64,0.95
c-0.28,0.15-0.19,0.03-0.19-0.28c0-0.32-0.22-0.8-1.16-1.77c-0.94-0.97-2.02-2.1-2.22-2.26c-0.2-0.16-0.27-0.19-0.44-0.04
c-0.27,0.24-3.97,4-4.79,4.86c-2.07,1.94-3.99,4.04-5.74,6.27c-0.15,0.77,0.1,0.93,0.2,1.07c0.1,0.14,0.22,0.77-0.02,0.53
c-0.24-0.24-1.79-1.93-2.15-2.27c-0.36-0.34-1.87-1.6-2.09-1.81s-0.06-0.32,0.31-0.17c0.51,0.29,1.13,0.3,1.65,0.03
c2.07-1.66,4.02-3.48,5.83-5.42c0.59-0.59,4.6-4.77,4.71-4.89c0.18-0.2,0.25-0.3,0-0.62c-1.02-1.07-2.11-2.08-3.25-3.02
c-0.32-0.26-0.72-0.41-1.13-0.43C390.98,293.97,390.56,293.96,390.91,293.8z"/>
<path id="Path_1191" class="st0" d="M253.1,323.87c-0.35-0.4-1.2-1.11-1.67-1.51c-0.22-0.18-0.1-0.42,0.1-0.74
c0.12-0.2,2.77-5.07,3.38-5.99c0.8-1.24,3.2-5.23,3.49-5.75c0.3-0.52,0.52-0.91,0.77-0.68c0.43,0.43,0.83,0.9,1.2,1.39
c0.21,0.3,0.09,0.15-0.22,0.15s-0.72,0.63-1.45,1.77c-0.52,0.83-0.99,1.68-1.41,2.56c-0.15,0.32,0.06,0.4,0.24,0.54
c0.31,0.2,4.69,2.91,5.73,3.52c2.4,1.48,4.93,2.75,7.54,3.8c0.8-0.04,0.78-0.17,0.92-0.27c0.22-0.16,0.67-0.23,0.45,0
c-0.58,0.75-1.1,1.53-1.57,2.35c-0.37,0.66-1.22,2.24-1.33,2.49s-0.12-0.16-0.1-0.5c0.02-0.4,0.27-0.77-0.33-1.26
c-1.06-0.87-6.1-3.82-6.79-4.25c-0.69-0.43-5.63-3.22-5.99-3.34c-0.26-0.09-0.47-0.4-0.67-0.03c-0.88,1.36-1.63,2.8-2.23,4.31
c-0.09,0.33-0.09,0.69-0.02,1.02C253.25,323.89,253.27,324.05,253.1,323.87z"/>
<path id="Path_1192" class="st0" d="M275.67,294.27c-0.24-0.67-0.56-1.31-0.94-1.91c-0.16-0.32-0.17-0.31,0.26-0.66
c0.19-0.15,4.6-3.41,5.47-4.08c1.2-0.92,5.25-3.65,5.73-4c0.48-0.35,1.02-0.56,1.2-0.12c0.18,0.44,0.66,1.63,0.75,1.93
c0.12,0.44-0.06,0.11-0.38-0.16c-0.24-0.22-0.68-0.18-1.81,0.58c-1.13,0.76-2.71,1.8-2.92,2s-0.18,0.2-0.08,0.4
c0.25,0.5,3.16,4.77,3.98,5.85c1.65,2.43,3.48,4.74,5.46,6.91c0.3,0.15,0.65,0.16,0.96,0.04c0.24-0.05,0.53,0.03,0.13,0.26
c-0.4,0.23-1.6,1.04-2.04,1.33c-0.44,0.29-1.57,1.16-1.96,1.51c-0.47,0.4-0.34-0.03-0.13-0.31c0.21-0.28,0.36-0.46,0.06-1.16
c-1.28-2.28-2.7-4.49-4.25-6.6c-0.48-0.68-4.31-5.8-4.56-6.13c-0.14-0.18-0.18-0.24-0.52,0s-3.32,2.51-3.76,2.92
c-0.34,0.33-0.52,0.4-0.56,0.84C275.74,293.96,275.75,294.6,275.67,294.27z"/>
<path id="Path_1193" class="st0" d="M410.65,311.56c3.75,3.82,3.69,9.95-0.13,13.7c-0.18,0.18-0.38,0.36-0.58,0.52
c-3.91,3.33-9.72,3.13-13.38-0.47c-3.67-3.9-3.49-10.03,0.4-13.7c3.66-3.79,9.7-3.9,13.5-0.24
C410.52,311.44,410.59,311.5,410.65,311.56z M399.28,313.9c-3.31,2.4-4.04,7.03-1.63,10.34c0.05,0.07,0.1,0.13,0.15,0.2
c3.26,2.47,7.91,1.89,10.46-1.32c3.34-2.57,3.97-7.35,1.4-10.69c-0.1-0.13-0.2-0.26-0.31-0.38
C407.5,310.43,403.39,309.9,399.28,313.9L399.28,313.9z"/>
<path id="Path_1194" class="st0" d="M416.12,403.32c-1.72,4.99-7.17,7.65-12.16,5.92c-0.34-0.12-0.67-0.25-0.99-0.41
c-4.51-2.07-6.79-7.17-5.31-11.91c1.8-4.95,7.26-7.52,12.23-5.75C414.94,392.85,417.72,398.25,416.12,403.32z M408.98,394.02
c-3.48-1.91-7.85-0.64-9.77,2.84c-0.08,0.14-0.15,0.29-0.22,0.44c-0.86,2.53,0.14,6.33,5.74,8.43c5.43,2.03,9.51,0,10.44-3.64
C415.52,400.73,415.6,396.39,408.98,394.02z"/>
<path id="Path_1195" class="st0" d="M409.07,347.58c-0.82-0.03-1.64-0.12-2.45-0.26c-0.56-0.12-0.64-0.13-0.8-0.36
c-1.62-2.1-2.51-4.68-2.51-7.34c-0.37-4.49,2.45-8.63,6.76-9.95c3.84-1.05,7.94,0.33,10.36,3.5c1.34,1.9,2.1,4.15,2.17,6.47
c0.09,1.37,0.21,2.19,0.27,2.63c0.12,0.74,0.11,0.94,0.27,1.14c0.16,0.2-0.07,0.4-0.35,0.4s-1.36,0.18-1.91,0.31
c-0.4,0.1-1.25,0.33-1.36,0.36c-0.59,0.14-0.57,0-0.11-0.36c1-0.52,1.69-1.48,1.88-2.59c0.49-2.57-0.22-5.22-1.94-7.19
c-2.32-2.4-5.94-3-8.92-1.49c-3.3,1.24-5.52,4.36-5.59,7.89c-0.18,2.79,1.47,5.38,4.08,6.39
C409.54,347.37,409.9,347.56,409.07,347.58z"/>
<path id="Path_1196" class="st0" d="M424.46,349.87c0,0.72,0.33,3.97,0.46,4.6c0.16,0.76-0.18,0.4-0.22,0.14
c-0.12-0.42-0.48-0.72-0.91-0.76c-2.65,0.03-5.3,0.23-7.92,0.59c2.18,1.95,4.47,3.76,6.88,5.43c0.54,0.45,1.15,0.8,1.8,1.04
c0.17,0,0.08,0.13,0.16-0.09c0.1-0.3,0.4-1.27,0.36,0.2c0,0.35-0.03,1.41,0,1.68c0.03,0.27,0.13,1.01,0.15,1.17
c0.11,0.8-0.02,0.63-0.61-0.09c-1.04-1.08-2.18-2.04-3.42-2.88c-0.65-0.47-4.77-3.6-4.77-3.6s-5.92,5.62-7.04,6.85
c-0.88,0.88-1.65,1.86-2.31,2.92c-0.19,0.43-0.35,0.64-0.28,0.23c0.05-0.26,0.23-1.88,0.27-2.59c0.04-0.62,0.1-2.54,0.11-2.73
c0.02-0.4,0.18-0.1,0.4-0.04c1.42-0.9,2.7-2.01,3.81-3.28c1.39-1.37,3.7-3.88,3.88-4.12c-1.93,0.13-3.85,0.36-5.75,0.68
c-0.73,0.09-1.43,0.34-2.05,0.74c-0.22,0.2-0.36,0.46-0.4,0.76c-0.03,0.24-0.26,0.35-0.3,0.04c-0.04-0.32-0.11-2-0.15-2.6
c-0.04-0.6-0.24-2-0.28-2.2c-0.04-0.2,0.16-0.36,0.28-0.08c0.08,0.27,0.29,0.47,0.55,0.55c0.66,0.26,1.55,0.27,8.08-0.5
c2.59-0.18,5.17-0.55,7.7-1.11c0.69-0.18,1.12-0.44,1.2-1.02C424.18,349.47,424.48,348.81,424.46,349.87z"/>
<path id="Path_1197" class="st0" d="M424.58,372.31c-0.13,0.59-0.66,3.81-0.66,4.46c0,0.65-0.3,0.66-0.38,0.22
c-0.02-0.38-0.26-0.72-0.61-0.87c-1.04-0.43-2.13-0.7-3.25-0.8c-2.26-0.36-3.74-0.62-3.74-0.62s-0.7,2.98-1.09,4.79
c-0.49,2.27-1.03,5.27-1.03,5.27l4.36,1.23c1.17,0.32,2.96,1.06,3.53,0.1c0.4-0.68,0.65-0.53,0.27,0.2
c-0.13,0.26-0.93,3.35-1.05,3.97c-0.24,1.15-0.4,0.42-0.34,0.15c0.06-0.27,0.27-0.74-0.74-1.14c-1.01-0.4-4.42-1.55-7.43-2.4
c-2.52-0.9-5.14-1.51-7.8-1.84c-0.68,0.06-0.86,0.21-1.02,0.44c-0.23,0.32-0.63,0.42-0.31-0.11c0.53-1.34,0.93-2.72,1.2-4.13
c0.2-1.34,0.4-0.4,0.38-0.15c-0.04,0.44,0.21,0.86,0.62,1.03c2.25,0.91,4.56,1.66,6.91,2.25c0,0,0.7-2.75,1.16-4.87
c0.55-2.5,0.92-4.97,0.92-4.97s-1.38-0.22-2.36-0.4c-1.68-0.31-3.38-0.5-5.09-0.55c-0.35,0.1-0.64,0.35-0.78,0.69
c-0.07,0.23-0.52,0.66-0.27-0.16c0.3-1.35,0.5-2.71,0.59-4.09c0.06-1.15,0.36-0.65,0.37-0.32c0.05,0.33,0.24,0.62,0.52,0.8
c2.54,0.75,5.14,1.25,7.78,1.49c2.75,0.55,5.54,0.85,8.33,0.9c0.64-0.22,0.6-0.46,0.72-0.73
C424.41,371.88,424.76,371.47,424.58,372.31z"/>
<path id="Path_1198" class="st0" d="M406.64,417.68c-1.1,1.09-2.11,2.27-3.02,3.51c-0.47,0.64-0.4,0.13-0.28-0.12
c0.23-0.46,0.09-0.61-0.09-1.01c-1.66-1.83-3.5-3.48-5.48-4.95c-1.87-1.83-3.98-3.4-6.28-4.67c-0.4,0-0.73-0.05-1.54,0.69
c-1.12,1.04-2.12,2.21-2.98,3.47c-0.3,0.57-0.43,1.22-0.37,1.87c0,0.44-0.13,0.4-0.28,0c-0.26-0.8-0.46-1.62-0.61-2.45
c-0.03-0.25,0.07-0.49,0.26-0.65c0.45-0.49,4.28-4.83,4.84-5.45c0.64-0.69,1.23-1.42,1.78-2.19c0.36-0.62,0.48-0.18,0.37,0.14
c-0.23,0.38-0.29,0.84-0.18,1.27c1.76,2.1,3.81,3.94,6.08,5.48c2.02,1.96,4.29,3.65,6.74,5.02c0.33,0.05,0.66-0.06,0.9-0.28
C406.68,417.2,407.16,417.32,406.64,417.68z"/>
<path id="Path_1199" class="st0" d="M383.18,417.49c0.2,0.5,2.15,3.85,4.18,7.26c2.11,3.52,4.4,7.19,4.7,7.75
c0.62,1.08,0.64,1.34-0.43,0.8c-1.55-0.77-7.76-3.9-8.79-4.4c-1.03-0.5-6.11-3.08-6.11-3.08s1.1,8.29,1.2,8.75
c0.1,0.47,0.98,7.37,1.03,7.72c0.05,0.35,0.05,0.9-0.58,0.31c-0.62-0.59-10.43-13.1-10.92-13.67c-0.35-0.45-0.87-0.75-1.43-0.84
c-0.26-0.05-0.52-0.04-0.77,0.04c-0.25,0.09-0.44-0.14-0.08-0.28c0.44-0.17,3.94-1.97,4.28-2.19c0.22-0.13,0.52,0.04,0.18,0.25
c-0.44,0.27-0.5,0.46-0.4,0.86c0.22,0.95,7.32,9.77,7.32,9.77s-1.2-7.92-1.41-8.93c-0.21-1.01-0.9-5.68-0.9-5.68s0-0.3,0.3-0.14
c0.3,0.16,7.24,3.7,7.99,4.06s5.19,2.56,5.19,2.56s-3.9-6.33-5.51-8.85c-0.23-0.44-0.6-0.78-1.05-0.97
c-0.55-0.11-0.72,0.12-1.04,0.26c-0.16,0.07-0.4-0.13,0.07-0.4c0.57-0.35,1.11-0.74,1.62-1.17c0.4-0.31,1.4-1.27,1.56-1.43
c0.16-0.16,0.4,0.04,0.23,0.21C383.12,416.36,382.93,416.98,383.18,417.49z"/>
<path id="Path_1200" class="st0" d="M340.34,441.57c-0.04,0.33,0.06,4.16,0.1,4.64c0,0.22-0.18,0.16-0.31-0.33
c-0.12-0.38-0.42-0.67-0.8-0.78c-1.42-0.18-2.86-0.21-4.3-0.08c-0.09,1.66,0.04,3.32,0.38,4.95c0.44,0.48,0.51,0.43,0.7,0.47
c0.2,0.04,0.67,0.29,0.36,0.26c-0.6-0.06-3.94-0.06-4.69,0.02c-0.55,0.06-0.27-0.2,0.19-0.3c0.46-0.1,0.7-0.36,0.87-0.94
c0.13-1.49,0.16-2.99,0.09-4.49c-1.53-0.05-3.07,0.03-4.59,0.24c-0.33,0.19-0.54,0.54-0.55,0.92c-0.04,0.32-0.38,0.6-0.33,0.17
c0.1-1.38,0.11-2.76,0.04-4.14c-0.08-0.55,0.05-0.47,0.23-0.14c0.22,0.4,0.15,0.63,0.62,0.82c1.52,0.15,3.05,0.21,4.58,0.16
c0,0,0.03-3.77-0.08-4.35c-0.07-0.5-0.46-0.89-0.97-0.96c-0.27-0.02-0.52-0.27-0.16-0.23c1.49,0.11,2.99,0.11,4.48,0
c0.48-0.05,0.2,0.21-0.16,0.3c-0.47,0.09-0.85,0.45-0.95,0.92c-0.15,0.58-0.13,4.29-0.13,4.29s3.51,0.04,4.15-0.09
c0.48-0.08,0.86-0.46,0.94-0.94C340.13,441.64,340.38,441.25,340.34,441.57z"/>
<path id="Path_1201" class="st0" d="M308.51,450.59c-1.62-0.79-3.33-1.4-5.09-1.82c-0.56-0.09-0.04-0.24,0.31-0.21
c0.46,0.04,0.85,0.1,1.2-0.25c1.96-3.73,3.55-7.63,4.77-11.66c0.91-2.44-0.32-5.15-2.76-6.06c-0.18-0.07-0.36-0.12-0.55-0.17
c-4-1.43-5.59,0.75-7.77,4.84c-1.58,2.86-2.95,5.84-4.11,8.89c-0.03,0.33,0.12,0.65,0.4,0.83c0.36,0.29,0.56,0.76,0.22,0.49
c-1.39-0.86-2.86-1.58-4.4-2.13c-0.34-0.11-0.07-0.3,0.36-0.21c0.36,0.08,0.52,0,0.87-0.25c2.12-3.33,4.05-6.76,5.81-10.3
c1.05-1.94,2.89-3.34,5.04-3.82c3.29-0.33,6.5,1.08,8.5,3.71c1.19,1.86,1.49,4.16,0.8,6.27c-0.4,1.65-4,9.69-4,10.79
c-0.02,0.31,0.13,0.6,0.4,0.76C308.73,450.45,308.86,450.8,308.51,450.59z"/>
<path id="Path_1202" class="st0" d="M283.31,439.86c0,0-0.75-8.14-0.98-10.95c-0.26-3.27-1.08-9.59-1.08-9.59
s-6.39,6.92-7.22,7.76c-0.83,0.84-1.6,1.67-1.6,2.24c0,0.33,0.13,0.65,0.36,0.9c0.08,0.16,0.22,0.72,0.06,0.52
c-0.55-0.63-1.14-1.22-1.75-1.78c-0.54-0.49-1.1-0.95-1.69-1.37c-0.44-0.29,0.1-0.24,0.34-0.09c0.25,0.19,0.57,0.26,0.88,0.19
c2.46-2.14,4.77-4.45,6.91-6.91c1.71-1.78,5.54-5.99,5.94-6.54c0.28-0.4,0.28-0.22,0.31,0.2c0.04,0.52,0.71,8.89,0.85,9.86
c0.13,0.9,0.56,6.59,0.62,7.23s0.25,2.77,0.25,2.77s2.94-4.22,3.92-5.75c1.19-1.53,2.2-3.2,3.02-4.96
c0.01-0.5-0.24-0.96-0.66-1.23c-0.13-0.14-0.24-0.48,0.06-0.22c1.25,1.05,2.61,1.95,4.05,2.71c0.62,0.29-0.31,0.11-0.47,0.04
c-0.39-0.12-0.81-0.12-1.2,0c-1.87,2.19-3.57,4.52-5.08,6.97c-0.76,1.11-2.98,4.22-3.5,5.07c-0.52,0.84-1.71,2.59-1.95,3.03
C283.47,440.36,283.37,440.33,283.31,439.86z"/>
<path id="Path_1203" class="st0" d="M275.07,405.78c0.44,0.76,0.94,1.48,1.49,2.17c0.57,0.71,1.18,1.37,1.84,2
c0.35,0.33-0.14,0.21-0.46-0.03c-0.32-0.24-0.69-0.35-1.71,0.2c-1.2,0.64-11.68,9.47-12.08,9.99c-0.49,0.6-0.45,0.9-0.24,1.36
c0.16,0.36,0.05,0.67-0.09,0.44c-0.91-1.41-1.95-2.73-3.11-3.94c-0.46-0.34,0.02-0.26,0.32-0.08c0.3,0.17,0.4,0.17,0.76,0
c4.64-3.28,9.06-6.87,13.22-10.75c0.12-0.34,0.08-0.72-0.1-1.03C274.9,405.84,274.84,405.38,275.07,405.78z"/>
<path id="Path_1204" class="st0" d="M265.98,334.45c-0.83,1.65-1.51,3.36-2.03,5.13c-0.1,0.46-0.33-0.02-0.26-0.36
c0.12-0.58,0.2-0.88-0.76-1.52c-4.82-2.22-9.79-4.07-14.88-5.56c-0.42-0.04-0.82,0.18-1.01,0.55c-0.2,0.26-0.62,0.37-0.36,0
c0.79-1.65,1.47-3.35,2.03-5.09c0.09-0.56,0.31,0,0.25,0.32c-0.14,0.37-0.05,0.78,0.23,1.05c5,2.47,10.22,4.48,15.58,5.99
c0.68-0.11,0.61-0.34,0.84-0.55C265.83,334.2,266.3,333.97,265.98,334.45z"/>
<path id="Path_1205" class="st0" d="M261.32,402.92l3.97-5.3c0,0-6.96,0.38-8.45,0.5c-1.49,0.12-5.82,0.31-6.31,1.01
c-0.32,0.47,0,0.99,0,1.15c0.06,0.32,0,0.82-0.16,0.44c-0.08-0.24-0.62-1.65-1.05-2.63c-0.4-0.88-0.9-1.95-1.03-2.15
c-0.22-0.32,0.15-0.24,0.36,0c0.23,0.29,0.57,0.49,0.94,0.56c2.9,0.11,5.81,0.07,8.7-0.12c1.25-0.05,10.45-0.65,11.22-0.58
c0.4,0.04,0.78-0.16,0.28,0.6c-0.28,0.43-5.77,7.62-6.19,8.2c-2.04,2.56-3.92,5.24-5.63,8.02c-0.06,0.36-0.04,0.72,0.06,1.07
c0.06,0.28,0.02,1.05-0.08,0.8c-0.9-1.74-1.93-3.4-3.09-4.99c-0.4-0.51,0.13-0.16,0.44-0.05c0.31,0.12,0.5,0.04,0.85-0.2
C258.04,407.27,259.76,405.15,261.32,402.92z"/>
<path id="Path_1206" class="st0" d="M261.9,376.76c0.26,0.75,1.07,4.05,1.48,5.49c0.14,0.51,1.05,3.87,1.33,4.43
c0.13,0.27-0.47-0.16-0.59-0.44c-0.04-0.22-0.16-0.41-0.35-0.54c-0.19-0.11-0.4-0.17-0.62-0.18c-2.73,0.54-5.42,1.29-8.04,2.22
c-2.63,0.67-5.2,1.59-7.66,2.75c-0.32,0.28-0.43,0.73-0.29,1.13c0.04,0.26-0.16,1.2-0.26,0.61c-0.15-1.04-0.37-2.07-0.64-3.08
c-0.4-1.38-2-7.08-2.07-7.32c-0.13-0.32-0.15-0.44,0.09-0.53c0.72-0.24,1.43-0.52,2.13-0.84c0.5-0.3,0.31,0.13,0.03,0.42
c-0.28,0.29-0.4,0.43-0.36,1.32c0.34,1.68,0.78,3.34,1.33,4.96c0,0,2.35-0.62,3.12-0.9s3.32-1.03,3.32-1.03
c-0.4-1.61-0.9-3.19-1.51-4.74c-0.37-0.49-0.62-0.4-1-0.36c-0.28,0.02-0.76-0.18-0.4-0.26c1.38-0.3,2.72-0.72,4.02-1.25
c0.45-0.22,0,0.34-0.21,0.46c-0.38,0.2-0.6,0.61-0.56,1.04c0.08,0.86,0.28,1.71,0.58,2.53c0.17,0.48,0.65,2.12,0.65,2.12
s4.25-1.23,4.96-1.56c0.71-0.34,1.26-0.34,1.11-1.75c-0.24-1.68-0.75-3.31-1.51-4.83c-0.26-0.41-0.6-0.77-0.99-1.05
c-0.16-0.13-0.72-0.6-0.4-0.49c0.98,0.31,1.94,0.68,2.88,1.1C261.66,376.3,261.82,376.51,261.9,376.76z"/>
<path id="Path_1207" class="st0" d="M282.78,309.83c-0.51,0.54-4.24,4.58-5.29,5.76c-0.35,0.4-1.2,1.35-1.43,1.64
c-0.19,0.22-0.28-0.22-0.12-0.49c0.25-0.29,0.29-0.7,0.12-1.04c-1.98-2.22-4.16-4.24-6.51-6.06c-1.86-1.81-3.89-3.44-6.07-4.86
c-0.4-0.09-0.81-0.03-1.16,0.19c-0.24,0.12-0.8,0.36-0.4-0.03c0.4-0.39,1.02-1.07,1.91-2.04c0.97-1.05,4.96-5.19,5.12-5.41
s0.32-0.28,0.49-0.1c0.5,0.53,1.03,1.03,1.6,1.49c0.6,0.36,0.06,0.32-0.25,0.25c-0.32-0.07-0.43-0.17-1.08,0.21
c-1.27,1.06-2.43,2.24-3.47,3.52l4.77,4.4c0,0,3.32-3.09,3.38-3.72c0.05-0.27,0.03-0.54-0.07-0.8c-0.08-0.25-0.05-0.69,0.16-0.4
c0.77,0.95,1.65,1.82,2.61,2.57c0.4,0.3-0.07,0.3-0.3,0.2c-0.35-0.15-0.48-0.4-1.13-0.08c-1.19,1.06-2.29,2.21-3.31,3.44
c0,0,3.4,2.92,4.04,3.38c0.83,0.61,1.43,0.76,2.26,0c1.23-1.06,2.3-2.28,3.2-3.64c0.2-0.46,0.28-0.97,0.23-1.47
c0.02-0.3,0.2-0.66,0.25-0.42c0.05,0.24,0.75,2.4,0.8,2.75C283.17,309.42,283.09,309.5,282.78,309.83z"/>
<path id="Path_1208" class="st0" d="M260.58,367.65c0.03,0.4,0.13,2.31,0.26,3.16c0.07,0.48-0.22-0.12-0.29-0.36
c-0.04-0.3-0.23-0.56-0.5-0.69c-2.67-0.18-5.35-0.07-7.99,0.34c-2.98,0.1-5.94,0.5-8.84,1.2c-0.31,0.32-0.46,0.76-0.4,1.2
c0,0.26-0.46,1.11-0.45,0.47c0-0.4,0-2.1-0.1-2.7c-0.29-2.05-0.39-4.12-0.3-6.18c0.46-2.23,2.37-3.88,4.65-4
c1.97-0.01,3.76,1.12,4.61,2.89c0.33-0.44,0.74-0.82,1.2-1.12c2.7-1.58,5.24-3.4,7.59-5.46c0.19-0.38,0.24-0.81,0.15-1.23
c-0.06-0.72,0.1-1.23,0.45,0c0.34,1.36,0.15,2.8-0.53,4.03c-1.57,1.59-3.34,2.96-5.27,4.08c-0.8,0.55-2.67,1.6-2.67,2.7
c-0.01,0.54,0.04,1.07,0.15,1.6c0,0,2.74-0.28,3.48-0.36c1.37-0.03,2.73-0.26,4.03-0.7c0.22-0.2,0.35-0.5,0.34-0.8
c0.03-0.21,0.47-1.13,0.44,0.06C260.52,366.18,260.54,367.25,260.58,367.65z M249.41,363.17c-1.94-1.24-4.51-0.73-5.83,1.16
c-0.48,1.23-0.61,2.56-0.37,3.86l3.94-0.26c0.62-0.04,4.06-0.28,4.06-0.28s0.35-3.2-1.8-4.49V363.17z"/>
<path id="Path_1209" class="st0" d="M328.95,307.11c-2.39-2.85-3.7-6.45-3.71-10.16c0.09-2.34,0.98-4.59,2.52-6.36l0.92-1.13
c2.28-2.26,3.59-5.33,3.63-8.55c0.12-2.01-0.11-4.03-0.67-5.96c-0.82,6.44-4.1,12.31-9.16,16.38c-2.28,1.98-6.09,5.28-6.09,9.41
c0.26,4.61,2.07,8.99,5.12,12.45c-0.91-2.36-1.38-4.86-1.38-7.39c-0.02-1.72,0.19-3.43,0.62-5.09l0.07-0.23l0.12,0.21
C322.71,303.76,325.57,306.05,328.95,307.11z"/>
<path id="Path_1210" class="st0" d="M330.13,289.41c2-0.77,9.17-3.91,9.17-8.94c-0.28-3.2-1.64-6.22-3.87-8.54
C337.54,278.29,335.42,285.29,330.13,289.41z"/>
<path id="Path_1211" class="st0" d="M357.06,279.77c-2.69,2.53-5.86,4.47-9.33,5.72l-0.12-0.17c2.95-3.43,4.81-7.66,5.35-12.15
c-5.67,8.93-9.13,10.47-13.13,12.23l-1.75,0.8c-4.79,2.27-10.29,5.51-10.29,10.6c-0.38,3.7,0.72,7.4,3.06,10.29
c-0.43-1.47-0.65-2.98-0.67-4.51c-0.03-1.03,0.1-2.07,0.4-3.06l0.15-0.4l0.06,0.4c1.05,3.22,3.15,6,5.97,7.89
c-0.08-0.8-0.13-1.61-0.12-2.42c0-3.75,0.87-10.39,6.69-12.88C353.83,287.62,356.45,281.82,357.06,279.77z"/>
<path id="Path_1212" class="st0" d="M348.36,300.57c-0.41-3.63,0.3-7.3,2.03-10.52c-7.5,2.91-12.46,10.11-12.51,18.15
c0,0.45,0,0.8,0.04,1.05c1.28-3.54,3.47-6.69,6.35-9.12l0.07-0.06l0.07,0.04c0,0,0.04,0.03,0.04,0.13
c-0.44,2.78-1.02,5.54-1.75,8.26C343.72,307.86,348.36,304.64,348.36,300.57z"/>
<path id="Path_1213" class="st0" d="M358.27,299.89c0-1.47-0.27-2.94-0.8-4.32c-0.48,1.66-1.42,3.15-2.71,4.3l0,0l-0.15-0.15
c0.92-1.44,1.34-3.15,1.17-4.86c-0.01-1.21-0.12-2.41-0.34-3.6c-0.09-0.51-0.14-1.03-0.14-1.55c0.06-2.13,0.69-4.2,1.83-5.99
c-2.9,2.21-4.97,5.33-5.88,8.86c-0.62,2.18-1.11,4.39-1.48,6.62c-0.11,0.79-0.28,1.58-0.51,2.35c-0.8,2.81-1.89,5.54-3.25,8.13
c2.09-1.32,3.75-3.21,4.79-5.45l0.15-0.3l0.06,0.33c0.09,0.68,0.13,1.36,0.12,2.05c0.02,1.94-0.36,3.87-1.11,5.66
C351.51,310.78,358.27,305.09,358.27,299.89z"/>
<path id="Path_1214" class="st0" d="M370.27,288.65c-2.3-1.69-5.24-2.24-7.99-1.49l-0.34,0.11l0.22-0.28
c1.45-1.76,3.21-3.24,5.19-4.36c-3.06-0.62-6.22,0.44-8.29,2.76c-1.27,2.26-1.88,4.83-1.77,7.42c0,0.54,0,0.95,0.04,1.23
c2.32-4.03,2.59-4.02,2.67-4l0.1,0.04v0.08c0.09,0.51,0.13,1.03,0.12,1.55c-0.05,1.76-0.22,3.51-0.52,5.24
C363.83,289.06,368.9,288.61,370.27,288.65z"/>
<path id="Path_1215" class="st0" d="M336.4,428.59l0.43-19c0.29,0.41,0.56,0.84,0.8,1.29c0.33,0.72,0.6,1.48,0.8,2.25
c0.41,0.44,0.69,0.98,0.8,1.57c0.14,0.93,0.58,4.06,0.74,4.79c0.15,0.74,0.14,1.32,0.58,1.32c2.54,0,3.96-4.2,3.42-5.53
c-0.52-1.06-1.18-2.05-1.96-2.93c0,0-1.37-4.35-1.6-4.89c-0.23-0.54-1.22-1.03-1.51-1.22c-0.15-0.1-1.04-0.98-1.9-1.84l0.12-5.33
c-0.28,0.02-0.56,0.02-0.84,0c-2.28,0.03-4.48-0.87-6.09-2.49l0.93,31.99L336.4,428.59z M342.8,418.2
c-1.12,1.56-1.27,1.6-1.66,1.6s-0.4-1.71-0.14-2.59c0.26-0.88,0.88-1.81,1.71-1.76C343.39,415.51,343.93,416.64,342.8,418.2
L342.8,418.2z"/>
<path id="Path_1216" class="st0" d="M378.59,356.33c2.06,0.65,4.2,1.04,6.35,1.17c3.63-0.51,6.98-2.21,9.53-4.84
c1.31-0.91,2.68-1.72,4.1-2.44c0,0-2.64-0.05-5.96-0.34c-3.09-0.25-6.2,0.11-9.14,1.07c-1.67,0.61-3.19,1.58-4.45,2.83
c-0.5,0.57-1.14,0.99-1.86,1.22c-0.98,0.24-1.81,0.44-1.81,0.44c0.23-0.86,0.69-1.63,1.32-2.25c1.72-1.18,3.31-2.54,4.74-4.06
c2.29-2.74,4.23-5.76,5.77-8.98c0.24-0.93,2.25-5.43,2.25-5.43c-1.64,1.17-3.36,2.24-5.13,3.2c-2.82,1.49-5.22,3.65-6.99,6.31
c-1.2,2.26-1.84,4.78-1.86,7.34c-0.14,2.42-1.15,4.71-2.83,6.45c-1.57,1.7-3.27,3.29-5.08,4.74c-0.89,0.68-1.9,1.19-2.98,1.51
c-0.67,0.14-1.37,0.18-2.05,0.1c0,0,1.03-1.32,1.66-1.51c1.74-0.59,3.31-1.58,4.59-2.88c2.04-2.53,3.45-5.51,4.1-8.7
c0.2-0.93,1.07-3.76,1.07-3.76c-1.28,1.22-2.67,2.31-4.16,3.28c-2.62,1.74-4.84,4.02-6.5,6.7c-0.96,1.56-1.26,3.45-0.83,5.23
c0,0.4-0.14,0.64-0.8,1.27c-0.62,0.49-1.36,0.82-2.15,0.93c-1.63,0.6-3.35,0.94-5.09,1.03c-2.03-0.2-4.03-0.57-5.99-1.12
c-0.68-0.05-1.76,0.59-2.2,0.64c-0.41-0.02-0.82-0.07-1.22-0.14c-0.44,0-1.81,0.05-1.81,0.05c0.26-0.72,0.4-1.48,0.44-2.25
c0.05-0.34,0.15-0.83,0.64-0.93c0.83-0.37,1.63-0.79,2.4-1.27c0.44-0.22,0.93-0.32,1.42-0.29c1.89-0.04,3.73-0.55,5.38-1.47
c2.79-1.83,5.13-4.27,6.84-7.14c1.17-1.2,2.45-2.3,3.81-3.28c0,0-2.49,0.68-5.33,1.51c-3.03,0.89-5.88,2.28-8.45,4.11
c-1.11,1.01-2.05,2.18-2.8,3.47c-0.4,0.86-0.9,1.68-1.47,2.44c-0.44,0.34-1.86,1.07-1.86,0.88c0.23-0.63,0.52-1.24,0.88-1.81
c0.34-0.59,1.42-2.3,2.1-3.32c0.53-0.83,0.96-1.71,1.27-2.64c0.29-0.91,0.72-1.76,1.27-2.54c1.08-1.59,2.87-2.56,4.79-2.59
c2.02,0.02,4.05-0.08,6.06-0.3c2.63-0.42,5.13-1.43,7.33-2.93c0.8-0.44,4.25-2.98,4.25-2.98s-3.37,0.59-4.45,0.73
c-2.56,0.11-5.1,0.38-7.63,0.8c-2.34,0.75-4.54,1.89-6.5,3.37c-1.44,0.99-2.83,2.06-4.15,3.2c0-0.62,0.05-1.24,0.15-1.86
c0.11-0.82,0.6-1.55,1.32-1.96c2.01-1.1,3.88-2.44,5.57-4c1.77-1.95,3.25-4.13,4.4-6.5c0.3-0.88,2.05-4.4,2.05-4.4
c-1.18,1-2.49,1.82-3.91,2.45c-2.89,1.41-5.46,3.4-7.53,5.87c-1.14,1.39-1.82,3.1-1.95,4.89c-0.03,0.8-0.16,1.58-0.4,2.35
c-0.39,0.77-0.59,1.63-0.59,2.49c-0.05,0.96-0.26,1.91-0.64,2.8c-0.15,0.61-0.36,1.2-0.64,1.76c-0.26,0.34-0.48,0.72-0.64,1.12
c-0.68,1.15-1.45,2.24-2.3,3.28c0,0-0.64-0.8,0.34-2.88c1.12-2.23,1.8-4.65,2-7.14c-0.1-2.03-0.48-4.04-1.13-5.96
c-0.44-1.17-1.91-5.33-1.91-5.33c-0.13,1.32-0.41,2.61-0.83,3.86c-1.16,2.76-1.92,5.67-2.25,8.65c0.1,2.41,0.82,4.75,2.11,6.79
c0.62,0.75,0.89,1.73,0.73,2.69c-0.11,0.86-0.47,1.68-1.03,2.35c-0.36,0.72-0.6,1.5-0.68,2.3c-0.43,2.01-1.67,3.76-3.42,4.84
c-0.15,0.12-0.34,0.26-0.55,0.4l0.69-26.82c-0.01-6.13,1.5-12.17,4.4-17.58c0.47-0.68,0.72-1.01,0.72-1.01
c2.17-2.98,5.52-4.9,9.19-5.27v-2.19c0,0-16.85-0.03-20.13-0.03h-0.06c-3.26,0-18.44,0.03-18.44,0.03v2.19
c3.67,0.37,7.02,2.29,9.19,5.27c2.88,4,4.66,6.37,5.17,19.07l0.93,30.65c-1.35,0.86-2.27,2.26-2.53,3.85
c-0.4-0.59-0.49-1.33-0.24-2c0.84-1.83,1.13-3.87,0.83-5.87c-0.94-2.95-2.41-5.7-4.35-8.12c-0.93-1.07-2.64-3.71-2.64-3.71
s0.05,2.45-0.1,4.4c-0.53,2.69-0.41,5.47,0.34,8.11c0.77,2.19,2.21,4.09,4.1,5.43c0.61,0.49,1.01,1.19,1.12,1.96
c0.15,0.66,0.11,1.35-0.1,2c-0.02,0.72-0.11,1.44-0.24,2.15c-0.2,0.72-0.8,1.12-0.88,1.76c-0.17,1.01-0.41,2.01-0.73,2.98
c-0.15,0.54-0.49,0.64-0.93,1.37c-0.25,0.36-0.37,0.79-0.34,1.22c-0.94-0.76-1.8-1.63-2.54-2.59c-1.08-2.96-3.64-5.14-6.74-5.72
c-2.1-0.34-4.24-0.38-6.35-0.14c-1.78-0.04-3.56-0.25-5.31-0.63c1.53,0.49,2.89,1.43,3.89,2.69c1.89,2.1,4.2,3.77,6.79,4.89
c1.68,0.5,3.47,0.48,5.13-0.05c0.73-0.19,1.27-0.49,1.91-0.24c0.54,0.31,1,0.72,1.37,1.22c0,0-1.13,0.64-1.96,1.03
c-2.86,1-5.32,2.9-6.99,5.43c-0.88,2.14-1.52,4.37-1.91,6.65c-0.28,1.27-0.62,2.53-1.03,3.76c0,0,1.66-1.42,3.03-2.35
c2.13-1.27,4.02-2.9,5.57-4.84c1.55-2.38,2.44-5.13,2.59-7.97c0-0.57,0.42-1.05,0.98-1.13c0.58,0.18,0.99,0.71,1.03,1.32
c0.01,0.7,0.23,1.39,0.64,1.96c0.29,0.44,0.98,1.03,1.57,1.86c0.55,1.13,1.02,2.29,1.42,3.47c0.4,0.8,0.59,0.68,1.17,1.76
c0.59,1.07,0.49,1.66,0.98,2.49c0.49,0.83,0.73,0.74,0.73,0.74l-0.29-5.19c-0.15-0.09-0.29-0.2-0.4-0.34
c-0.19-0.28-0.35-0.57-0.49-0.88c0,0,0.88-0.59,1.47-0.88c0.42-0.25,0.94-0.21,1.32,0.1c1.78,1.42,3.94,2.28,6.21,2.49
c3.65-0.72,7.15-2.04,10.36-3.91c1.32-0.56,2.68-1.04,4.06-1.42c0,0-2.93-0.29-4.5-0.64c-2.37-0.53-4.77-0.94-7.19-1.22
c-0.67,0.01-1.34,0.09-2,0.24l0.13-1.57c0,0-1.29,1.09-1.73,1.43c-1.01,0.66-2.09,1.2-3.23,1.6c-0.76,0.29-1.55,0.52-2.35,0.68
c0,0-0.2-0.2-0.34,0.54s-0.24,0.64-1.07,0.83c-0.54,0.13-1.06,0.31-1.56,0.54c0,0,0.68-1.76,0.8-2.05
c0.12-0.29,0.24-0.58,1.27-0.8c2.61-0.53,5.03-1.76,6.99-3.57c2.16-2.06,3.87-4.54,5.03-7.28c0.93-1.6,2.1-3.05,3.47-4.3
c0,0-2.25,0.88-6.5,2.35c-0.2,0.07-0.4,0.14-0.59,0.22l0.15-5.61l0,0v-0.4l-0.29,0.14c-0.64,0.29-2.49,0.83-3.22,1.17
c-0.73,0.34-1.32,1.12-1.91,1.42c-1.03,0.38-1.97,0.96-2.76,1.71l0.05,0.92l0,0l0.19,5.99c-1.1,1.43-1.77,3.15-1.92,4.94
c-0.2,1.12-0.34,1.66-0.49,2.25c-0.21,0.66-0.45,1.32-0.73,1.96c-0.46-0.89-1.02-1.73-1.66-2.49c-0.57-0.62-0.74-1.51-0.44-2.3
c0.23-0.87,0.54-1.73,0.93-2.54c0.44-1.12,1.03-3.28,1.37-3.96c0.34-0.68,0.2,0.64,0.93-3.37c0.43-2.45,2.18-4.46,4.55-5.23
c0.59-0.3,1.17-1.07,1.91-1.42c0.73-0.34,2.59-0.88,3.22-1.17c1.39-0.53,2.64-1.37,3.67-2.45c0.54-0.84,1.28-1.52,2.15-2
c1.05-0.36,2.16-0.53,3.27-0.49c1.6-0.1,1.95,1.17,2.3,1.6c0.29,0.43,0.43,0.95,0.4,1.47c-0.15,2.49,0.93,4.9,2.88,6.45
c2.56,1.91,5.58,3.11,8.75,3.47c1.47,0.4,5.13,1.91,5.13,1.91s-0.64-0.24-3.13-4.11c-1.61-2.77-3.79-5.17-6.39-7.03
c-1.56-0.74-3.21-1.29-4.9-1.63c-0.58-0.1-1.13-0.33-1.6-0.68c-0.45-0.49-0.85-1.01-1.22-1.57c0.21-0.03,0.42-0.03,0.64,0
c1.54,0.67,3.21,0.99,4.89,0.93c1.97,0.01,3.92-0.46,5.67-1.37c0.63-0.25,1.34-0.18,1.91,0.2c0.64,0.4,1.42,0.93,2.98,1.91
c2.16,1.46,4.68,2.32,7.28,2.49c3.15-0.19,6.25-0.86,9.19-2c1.23-0.5,2.51-0.9,3.81-1.17c0,0-2.44-0.44-3.81-0.74
c-2.9-0.98-5.9-1.63-8.95-1.95c-2.01,0.01-3.97,0.59-5.67,1.66c-0.52,0.54-1.31,0.7-2,0.4c-0.71-0.14-1.28-0.64-1.51-1.32
c2.01-0.09,3.94-0.81,5.52-2.05c1.32-1.06,2.54-2.26,3.62-3.57c0.63-0.6,1.14-1.35,2.49-2.59
C375.76,356.13,377.27,355.8,378.59,356.33z M385.7,351.25c3.16-0.63,6.39-0.75,9.59-0.36c-0.8,0.2-5.67,2.3-9.09,3.2
c-2.43,0.6-4.9,0.99-7.4,1.17l-0.05-0.1C380.74,353.36,383.12,352.02,385.7,351.25z M378.35,344.26c2.09-2.87,4.93-5.1,8.22-6.43
c0,0-4.19,5.57-5.51,7.35c-1.33,1.79-4.75,6.84-4.75,6.84c-0.11-2.73,0.61-5.44,2.06-7.76H378.35z M364.66,356.77
c1.82-2.64,4.26-4.79,7.1-6.28c0,0-2.91,4.9-4.54,7.15c-1.63,2.25-4,5-4,5s-0.94-1.94,1.46-5.87H364.66z M351.85,354.32
c2.79-1.51,5.69-2.81,8.68-3.88c0,0-5,4.44-7.5,6.23c-1.75,1.21-3.6,2.29-5.51,3.22c0.82-2.27,2.35-4.22,4.36-5.57L351.85,354.32
z M359.97,344.36c2.9-0.57,5.84-0.89,8.79-0.97c0,0-5.77,2.04-8.12,2.8c-2.13,0.6-4.3,1.06-6.48,1.38
c1.76-1.37,3.73-2.46,5.83-3.21L359.97,344.36z M352.25,340.08c2.44-2.6,5.33-4.74,8.53-6.33c0,0-3.73,3.72-6.33,6.79
c-2.6,3.07-4.34,5.16-4.34,5.16l-0.05,0.1c0.34-2.04,1.09-3.99,2.21-5.73L352.25,340.08z M343.37,355.8
c-1.25-1.97-1.91-4.25-1.89-6.58c0.16-2.96,0.96-5.85,2.35-8.47c0,0-0.1,4.79,0.05,7.5c0.01,2.52-0.15,5.05-0.5,7.55
L343.37,355.8z M311.81,384.09c-2.02-0.85-3.95-1.89-5.77-3.12c2.84-0.4,5.73-0.26,8.53,0.4c2.17,0.87,3.84,2.67,4.54,4.9
c0,0-4.93-1.36-7.27-2.19L311.81,384.09z M310.8,402.47c0.31-2.93,1.17-5.78,2.54-8.39c1.3-1.77,3.15-3.06,5.27-3.65
L310.8,402.47z M338.47,391.52c2.83,0.11,5.64,0.5,8.39,1.15c-3.22,0.78-6.48,1.37-9.77,1.77c-2.06,0.14-4.13,0.11-6.19-0.08
c0,0,1.56-2.26,7.6-2.86L338.47,391.52z M332.12,383.39c2.86-1.96,6.01-3.46,9.34-4.44c0,0-5.61,4.79-7.86,6.79
c-1.81,1.7-3.51,3.51-5.1,5.41c-0.01-3.01,1.33-5.86,3.66-7.78L332.12,383.39z M325.9,374.99c-1.1-1.94-1.97-3.99-2.6-6.13
c-0.68-2.48-1.69-8.47-1.69-8.47c1.72,2.42,3.27,4.96,4.65,7.59c0.65,2.31,0.53,4.77-0.33,7L325.9,374.99z M350.15,368.87
c2.12,0.47,4.16,1.23,6.07,2.25c2.74,2.11,4.96,4.81,6.48,7.91c-2.44-1.33-4.8-2.81-7.04-4.44c-2.04-1.64-3.89-3.51-5.51-5.57
V368.87z M371.89,365.45c3.08,0.22,6.12,0.84,9.03,1.84c0,0-6.84,0.87-9.03,0.87c-1.97-0.07-3.93-0.26-5.87-0.56
c1.74-1.22,3.78-1.96,5.9-2.15L371.89,365.45z"/>
<path id="Path_1217" class="st0" d="M361.37,338.3c-0.91,0.5-1.44,1.51-1.33,2.55c-0.12,0.71,0.36,1.39,1.08,1.51
c0.23,0.04,0.48,0.01,0.7-0.07c1.01-0.3,1.66-1.27,1.55-2.32c0.04-0.89-0.65-1.66-1.54-1.7
C361.67,338.25,361.52,338.27,361.37,338.3z"/>
<path id="Path_1218" class="st0" d="M385.58,345.63c-0.91,0.5-1.44,1.5-1.33,2.54c-0.12,0.71,0.35,1.39,1.06,1.51
c0.24,0.04,0.48,0.02,0.71-0.07c1.01-0.3,1.67-1.28,1.55-2.33c0.04-0.9-0.65-1.65-1.55-1.7
C385.88,345.58,385.73,345.6,385.58,345.63z"/>
<path id="Path_1219" class="st0" d="M344.59,368.63c-0.91,0.51-1.43,1.51-1.33,2.55c-0.12,0.71,0.35,1.38,1.06,1.51
c0.24,0.04,0.48,0.02,0.71-0.08c1.01-0.3,1.66-1.27,1.55-2.32c0.04-0.9-0.65-1.66-1.55-1.71
C344.89,368.58,344.74,368.6,344.59,368.63z"/>
<path id="Path_1220" class="st0" d="M373.24,360.94c-0.33,0.64-0.08,1.43,0.56,1.77c0.21,0.11,0.45,0.16,0.68,0.14
c1.05,0.02,1.97-0.71,2.18-1.74c0.32-0.84-0.1-1.77-0.94-2.09c-0.15-0.06-0.3-0.09-0.45-0.1
C374.26,359.12,373.45,359.92,373.24,360.94z"/>
<path id="Path_1221" class="st0" d="M360.92,368.61c-0.91,0.51-1.43,1.51-1.33,2.55c-0.12,0.71,0.36,1.39,1.07,1.51
c0.24,0.04,0.48,0.02,0.7-0.07c1.01-0.3,1.66-1.28,1.55-2.33c0.04-0.9-0.65-1.66-1.55-1.7
C361.22,368.57,361.07,368.58,360.92,368.61z"/>
<path id="Path_1222" class="st0" d="M341.44,385.33c-0.91,0.5-1.44,1.5-1.33,2.54c-0.13,0.71,0.35,1.39,1.06,1.52
c0.24,0.04,0.48,0.02,0.71-0.07c1.01-0.3,1.66-1.28,1.55-2.33c0.04-0.9-0.65-1.65-1.55-1.7
C341.73,385.28,341.58,385.3,341.44,385.33z"/>
<path id="Path_1223" class="st0" d="M311.04,392.41c1.01-0.3,1.66-1.28,1.55-2.33c0.04-0.9-0.65-1.66-1.55-1.7
c-0.15-0.01-0.3,0.01-0.45,0.04c-0.91,0.51-1.44,1.51-1.33,2.55c-0.12,0.71,0.36,1.39,1.07,1.51
C310.57,392.52,310.82,392.5,311.04,392.41z"/>
<path id="Path_1224" class="st0" d="M320.23,271.21c1.67,2.3,2.61,5.05,2.72,7.89c0,1.07-0.12,2.8-0.12,2.8
c-0.17,1.67-0.48,3.32-0.93,4.93c1.49-2.11,2.64-4.43,3.43-6.89l0.06-0.27l0.13,0.24c0.54,1.04,0.89,2.17,1.02,3.34
c0.63-1.45,0.98-3,1.02-4.58C327.24,274.74,324.16,271.6,320.23,271.21z"/>
<path id="Path_1225" class="st0" d="M321.12,283.36L321.12,283.36c-0.07-1.23-0.21-2.46-0.43-3.68c-1.7,3.43-4.15,6.43-7.16,8.79
c-2.79,1.95-4.55,5.06-4.79,8.45c0.56,5.03,3.14,9.61,7.15,12.69c-1.24-3.34-1.89-6.88-1.93-10.44c0.12-1.87,1.04-3.59,2.53-4.73
l0.3-0.3c1.12-1.06,2.14-2.21,3.05-3.46l0,0c0.48-0.72,0.84-1.51,1.06-2.34c0.09-0.39,0.15-0.8,0.19-1.2l0,0
C321.18,285.88,321.2,284.62,321.12,283.36z"/>
<path id="Path_1226" class="st0" d="M290.99,341.24c-0.91,0-1.65,0.74-1.65,1.65c0,0.01,0,0.01,0,0.02
c0.01,0.41,0.18,0.79,0.47,1.08c-0.19-0.06-0.39-0.1-0.59-0.1c-1.15,0-2.07,0.94-2.07,2.08c0,1.14,0.93,2.06,2.07,2.07
c0.18-0.01,0.37-0.03,0.55-0.08c-0.46,1.51-1.87,2.53-3.44,2.51c-3.05,0-4.27-3.29-4.4-4.07c0.32,1.08,1.45,1.71,2.54,1.39
c1.08-0.32,1.71-1.45,1.39-2.54c-0.26-0.87-1.06-1.47-1.97-1.47c-0.21,0.01-0.41,0.05-0.61,0.12c0.84-0.75,0.92-2.04,0.17-2.89
c-0.75-0.84-2.04-0.92-2.89-0.17c-0.43,0.38-0.68,0.93-0.69,1.51c0.01,0.6,0.27,1.17,0.72,1.57c-0.21-0.08-0.44-0.13-0.67-0.14
c-1.13-0.01-2.06,0.9-2.07,2.04c-0.01,1.13,0.9,2.06,2.04,2.07c0.92,0.01,1.74-0.6,1.99-1.49c-0.12,0.94-1.84,4.07-4.4,4.07
c-1.59,0.06-3.02-0.97-3.46-2.51c0.18,0.05,0.36,0.07,0.55,0.08c1.15,0,2.07-0.94,2.07-2.08c0-1.14-0.93-2.06-2.07-2.07
c-0.2,0-0.4,0.03-0.59,0.1c0.29-0.28,0.46-0.67,0.47-1.08c0.01-0.91-0.73-1.66-1.64-1.66c-0.01,0-0.02,0-0.02,0
c-0.36-0.04-0.72,0.03-1.04,0.2c0.43,1.7,0.94,5.11,1.02,5.59l1.43,9.31h15.38c0,0,0-0.16,0.04-0.28l1.39-9.04
c0.31-2.11,0.68-4.34,1-5.59C291.7,341.27,291.34,341.2,290.99,341.24z"/>
<path id="Path_1227" class="st0" d="M320.05,341.24c-0.91,0-1.64,0.74-1.64,1.65c0,0,0,0.01,0,0.01
c0.01,0.41,0.18,0.79,0.47,1.08c-0.19-0.06-0.39-0.1-0.59-0.1c-1.15,0-2.07,0.94-2.07,2.08c0,1.14,0.93,2.06,2.07,2.07
c0.18-0.01,0.37-0.03,0.55-0.08c-0.46,1.51-1.87,2.53-3.44,2.51c-3.05,0-4.27-3.29-4.4-4.07c0.32,1.08,1.45,1.71,2.54,1.39
c1.08-0.32,1.71-1.45,1.39-2.54c-0.26-0.87-1.06-1.47-1.97-1.47c-0.21,0.01-0.41,0.05-0.61,0.12c0.84-0.75,0.92-2.04,0.17-2.89
c-0.75-0.84-2.04-0.92-2.89-0.17c-0.43,0.38-0.68,0.93-0.69,1.51c0.01,0.6,0.27,1.17,0.72,1.57c-0.21-0.08-0.44-0.13-0.67-0.14
c-1.13-0.01-2.06,0.9-2.07,2.04c-0.01,1.13,0.9,2.06,2.04,2.07c0.92,0.01,1.74-0.6,1.99-1.49c-0.12,0.94-1.84,4.07-4.4,4.07
c-1.59,0.06-3.02-0.97-3.46-2.51c0.18,0.05,0.36,0.07,0.55,0.08c1.15,0,2.07-0.94,2.07-2.08c0-1.14-0.93-2.06-2.07-2.07
c-0.2,0-0.4,0.03-0.59,0.1c0.29-0.28,0.46-0.67,0.47-1.08c0.01-0.91-0.73-1.66-1.64-1.66c-0.01,0-0.02,0-0.03,0
c-0.36-0.04-0.72,0.03-1.04,0.2c0.43,1.7,0.94,5.11,1.02,5.59l1.43,9.31h15.38c0,0,0-0.16,0.04-0.28l1.39-9.04
c0.31-2.11,0.72-4.47,1-5.59C320.77,341.27,320.41,341.2,320.05,341.24z"/>
<path id="Path_1228" class="st0" d="M306.66,359.85c-1,0-1.81,0.81-1.81,1.81c0,0.01,0,0.01,0,0.02c0.01,0.45,0.19,0.88,0.52,1.2
c-1.21-0.36-2.48,0.32-2.84,1.53c-0.36,1.21,0.32,2.48,1.53,2.84c0.21,0.06,0.44,0.1,0.66,0.1c0.2-0.01,0.41-0.04,0.6-0.09
c-0.51,1.66-2.06,2.79-3.8,2.76c-3.37,0-4.71-3.63-4.83-4.49c0.35,1.2,1.61,1.88,2.8,1.53c1.2-0.35,1.88-1.61,1.53-2.8
c-0.28-0.96-1.17-1.63-2.17-1.62c-0.23,0.01-0.45,0.05-0.67,0.13c0.93-0.83,1.02-2.25,0.19-3.19c-0.83-0.93-2.25-1.02-3.19-0.19
c-0.48,0.42-0.75,1.03-0.76,1.67c0.01,0.66,0.3,1.29,0.8,1.73c-0.23-0.09-0.48-0.14-0.73-0.15c-1.25-0.01-2.27,0.99-2.28,2.25
c-0.01,1.25,0.99,2.27,2.25,2.28c1.02,0.01,1.91-0.66,2.2-1.64c-0.13,1.03-2.03,4.49-4.85,4.49c-1.76,0.06-3.33-1.07-3.82-2.76
c0.2,0.05,0.4,0.08,0.6,0.09c1.26,0.05,2.33-0.93,2.38-2.19c0.05-1.26-0.93-2.33-2.19-2.38c-0.06,0-0.13,0-0.19,0
c-0.22,0-0.44,0.04-0.65,0.11c0.33-0.31,0.51-0.75,0.52-1.2c0.01-1-0.8-1.83-1.8-1.83c-0.01,0-0.02,0-0.03,0
c-0.39-0.05-0.79,0.03-1.14,0.22c0.48,1.88,1.03,5.63,1.12,6.15l1.57,10.27h16.96c0,0,0.02-0.17,0.04-0.3l1.53-9.99
c0.34-2.33,0.8-4.94,1.1-6.15C307.45,359.86,307.05,359.79,306.66,359.85z"/>
</g>
</g>
<g>
<path class="st0" d="M292.05,156.13h-5.16c-0.07,6.74-0.14,13.42-0.14,24.7c0,5.99,0.41,9.36,2.41,11.83
c1.93,2.41,5.43,3.44,10.39,3.44c4.82,0,8.53-1.17,10.73-4.06c2-2.62,2.06-6.74,2.13-13.28l0.14-22.63h-5.99v-4.34h16.65v4.34
h-5.3l-0.14,26.08c0,5.5-0.62,9.49-3.78,13.35c-2.75,3.37-7.84,5.23-14.65,5.23c-8.39,0-13-2.13-15.82-5.99
c-2.27-3.1-2.68-6.47-2.68-14.52c0-7.84,0.07-16.79,0.14-24.15h-5.57v-4.34h16.65V156.13z"/>
<path class="st0" d="M350.99,195.62h4.54c0-5.5,0.28-11.28,0.28-16.99c0-3.44-0.14-10.32-8.05-10.32
c-5.02,0-10.53,3.03-10.53,12.66l-0.14,14.65h5.16v4.33h-15.41v-4.33h4.54l0.28-26.83h-5.71v-4.33h11.35
c0,1.38-0.07,3.3-0.21,4.27l-0.55,3.58h0.14c1.51-5.37,7.22-8.67,12.59-8.67c9.77,0,12.18,6.6,12.18,13.35
c0,6.05-0.27,13.14-0.27,18.65h5.23v4.33h-15.41V195.62z"/>
<path class="st0" d="M376.65,168.79h-6.47v-4.33h12.11l-0.28,31.17h5.64v4.33h-16.92v-4.33h5.64L376.65,168.79z M378.79,146.5
c2.34,0,4.27,1.93,4.27,4.27c0,2.34-1.93,4.27-4.27,4.27c-2.34,0-4.27-1.93-4.27-4.27C374.52,148.42,376.45,146.5,378.79,146.5z"
/>
<path class="st0" d="M387.85,164.45h14.59v4.33h-4.27l8.19,22.77c0.34,0.96,0.55,2,0.76,3.03h0.14c0.21-1.03,0.41-2.06,0.76-3.03
l8.39-22.77h-4.61v-4.33h14.17v4.33h-3.92l-12.25,31.17h-5.64l-12.32-31.17h-3.99V164.45z"/>
<path class="st0" d="M433.97,182.68c0.21,7.29,3.37,13.42,13.48,13.42c3.85,0,7.7-1.17,10.66-2.68l-0.21,4.88
c-2.61,1.31-8.12,2.48-11.7,2.48c-11.21,0-18.16-6.12-18.16-18.51c0-10.46,5.64-18.64,16.44-18.64
c14.04,0,15.34,12.73,15.34,19.06H433.97z M453.92,178.35c0-5.57-3.51-10.39-9.43-10.39c-6.05,0-10.18,4.54-10.52,10.39H453.92z"
/>
<path class="st0" d="M470.71,168.79h-6.05v-4.33h11.7v1.93c0,2.06-0.41,6.26-0.76,9.15h0.07h0.14c1.38-5.23,3.23-11.7,12.04-11.7
c0.48,0,3.3,0.28,3.58,0.55l-0.55,5.09c-0.96-0.34-2.48-0.55-3.85-0.55c-7.29,0-10.53,7.16-10.66,13.42l-0.28,13.28h5.99v4.33
h-16.65v-4.33h5.02L470.71,168.79z"/>
<path class="st0" d="M519.81,174.29h-5.09l-0.28-5.02c-1.31-1.1-4.61-1.31-6.26-1.31c-3.58,0-8.19,1.17-8.19,5.44
c0,3.85,3.44,5.02,8.67,5.92c9.01,1.51,12.8,4.27,12.8,10.11c0,6.33-4.27,11.35-14.52,11.35c-3.85,0-9.97-0.96-12.18-2.13
l-0.27-9.08h5.09l0.27,5.3c2.13,1.03,5.71,1.58,8.05,1.58c3.72,0,8.19-1.58,8.19-5.92c0-3.51-3.65-4.75-7.5-5.57
c-9.49-2.06-14.24-3.72-14.24-10.66c0-5.71,3.79-10.66,13.97-10.66c2.96,0,8.46,0.96,11.21,2.13L519.81,174.29z"/>
<path class="st0" d="M532.86,168.79h-6.47v-4.33h12.11l-0.28,31.17h5.64v4.33h-16.92v-4.33h5.64L532.86,168.79z M534.99,146.5
c2.34,0,4.27,1.93,4.27,4.27c0,2.34-1.93,4.27-4.27,4.27c-2.34,0-4.27-1.93-4.27-4.27C530.72,148.42,532.65,146.5,534.99,146.5z"
/>
<path class="st0" d="M546.4,164.45h5.71l0.27-8.67l5.64-0.34l-0.27,9.01h11.15v4.33h-11.22c-0.14,5.92-0.27,11.9-0.27,17.82
c0,5.09,0,9.5,5.44,9.5c2.89,0,5.5-0.83,7.02-1.44l-0.21,4.47c-1.79,0.89-5.09,1.65-7.98,1.65c-9.91,0-9.91-7.09-9.91-11.63
c0-4.34,0.21-15.21,0.28-20.37h-5.64V164.45z"/>
<path class="st0" d="M571.76,164.45h15v4.33h-4.47l8.46,22.08c0.41,1.24,0.83,2.89,0.96,3.72h0.14c0.14-0.83,0.55-2.48,0.96-3.72
l7.91-22.08h-5.02v-4.33h14.17v4.33h-3.92l-10.87,29.93c-5.02,13.97-9.08,19.33-18.03,19.33c-1.72,0-3.16-0.27-4.2-0.62v-4.68
c0.83,0.28,2.61,0.62,3.99,0.62c4.06,0,8.26-2.48,10.94-8.94l1.17-2.89l-13-32.75h-4.2V164.45z"/>
<path class="st0" d="M276.94,127.75h5.66v6.56c2.21,1.31,6.42,1.79,9.46,1.79c6.9,0,11.46-3.18,11.46-8.98
c0-12.91-26.52-5.25-26.52-22.58c0-5.87,3.45-13.74,17.88-13.74c3.52,0,9.94,0.9,12.98,2.28v9.74h-5.38v-6.01
c-1.8-0.76-5.8-1.31-8.08-1.31c-5.18,0-11.05,2-11.05,8.36c0,12.29,26.52,4.63,26.52,22.44c0,10.63-9.12,14.5-18.44,14.5
c-7.94,0-11.81-1.86-14.5-2.42V127.75z"/>
<path class="st0" d="M314.23,104.34h5.73l0.28-8.7l5.66-0.34l-0.28,9.04h11.19v4.35h-11.25c-0.14,5.94-0.28,11.95-0.28,17.88
c0,5.11,0,9.53,5.46,9.53c2.9,0,5.52-0.83,7.04-1.45l-0.21,4.49c-1.79,0.9-5.11,1.66-8.01,1.66c-9.94,0-9.94-7.11-9.94-11.67
c0-4.35,0.21-15.26,0.28-20.44h-5.66V104.34z"/>
<path class="st0" d="M358.07,103.51c10.84,0,17.26,7.46,17.26,17.68c0,11.33-6.42,19.61-17.26,19.61
c-10.84,0-17.26-7.46-17.26-17.67C340.8,111.79,347.23,103.51,358.07,103.51z M358.07,136.1c7.6,0,11.33-6.21,11.33-13.95
c0-7.73-3.73-13.95-11.33-13.95c-7.59,0-11.32,6.21-11.32,13.95C346.74,129.89,350.47,136.1,358.07,136.1z"/>
<path class="st0" d="M409.78,139.07c-2.76,0.83-6.35,1.73-10.29,1.73c-14.09,0-18.58-9.32-18.58-18.64
c0-13.6,9.87-18.64,17.82-18.64c3.94,0,7.87,0.48,11.53,1.79v9.32h-5.11v-5.59c-1.52-0.55-4.35-0.83-5.94-0.83
c-10.29,0-12.36,8.15-12.36,13.95c0,1.93,0.28,13.95,13.53,13.95c3.52,0,6.35-0.97,9.67-2L409.78,139.07z"/>
<path class="st0" d="M420.15,91.22h-6.91v-4.35h12.57l-0.14,33.14l13.6-11.19v-0.14h-4.97v-4.35h15.47v4.35h-3.66l-14.78,12.02
l16.09,14.92h3.87v4.35h-15.47v-4.35h4.28v-0.14l-14.43-13.74l-0.14,13.88h4.7v4.35h-15.47v-4.35h5.11L420.15,91.22z"/>
<path class="st0" d="M460.4,91.22h-6.91v-4.35h12.57L466,105.58c0,1.59-0.41,5.11-0.69,6.63h0.14c1.52-5.39,7.25-8.7,12.64-8.7
c9.81,0,12.22,6.63,12.22,13.39c0,6.08-0.28,13.19-0.28,18.71h5.25v4.35h-15.47v-4.35h4.56c0-5.53,0.27-11.33,0.27-17.06
c0-3.45-0.14-10.36-8.08-10.36c-5.04,0-10.57,3.04-10.57,12.71l-0.21,14.71h5.25v4.35h-16.02v-4.35h5.11L460.4,91.22z"/>
<path class="st0" d="M516.3,103.51c10.84,0,17.26,7.46,17.26,17.68c0,11.33-6.42,19.61-17.26,19.61
c-10.84,0-17.26-7.46-17.26-17.67C499.04,111.79,505.46,103.51,516.3,103.51z M516.3,136.1c7.6,0,11.32-6.21,11.32-13.95
c0-7.73-3.73-13.95-11.32-13.95c-7.6,0-11.32,6.21-11.32,13.95C504.98,129.89,508.7,136.1,516.3,136.1z"/>
<path class="st0" d="M542.77,91.22h-6.91v-4.35h12.57l-0.28,48.75h5.66v4.35h-16.43v-4.35h5.11L542.77,91.22z"/>
<path class="st0" d="M558.84,135.62h4.56l0.27-26.93h-5.73v-4.35h11.39c0,1.38-0.07,3.32-0.21,4.28l-0.55,3.59h0.14
c1.52-5.39,7.25-8.7,12.64-8.7c6.49,0,9.87,3.73,10.77,8.35h0.14c0.69-1.52,2.9-8.35,12.08-8.35c9.8,0,12.22,6.63,12.22,13.39
c0,6.08-0.28,13.19-0.28,18.71h5.25v4.35h-15.47v-4.35h4.56c0.07-5.8,0.27-11.53,0.27-17.26c0-5.18-1.11-10.15-7.73-10.15
c-4.63,0-10.15,3.04-10.22,12.71l-0.14,14.71h5.11v4.35h-15.54v-4.35h4.55c0.07-5.8,0.28-11.53,0.28-17.26
c0-5.18-1.1-10.15-7.73-10.15c-4.63,0-10.15,3.04-10.22,12.71l-0.14,14.71h5.18v4.35h-15.47V135.62z"/>
</g>
</g>
</svg>

After

(image error) Size: 40 KiB

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>

After

(image error) Size: 4.0 KiB

@ -0,0 +1,33 @@
import createClient, { Middleware } from "openapi-fetch";
import type { paths } from "../lib/api";
const client = createClient<paths>({
baseUrl: import.meta.env.VITE_BACKEND_URL,
});
const includeCredentials: Middleware = {
onRequest({ request, options }) {
return new Request(request, { ...options, credentials: "include" });
},
};
const initiateAuthorizationOnUnauthorized: Middleware = {
onResponse({ response }) {
if (response.status === 401) {
const authorizationUrl = response.headers.get("X-Authorization-Url");
if (authorizationUrl) {
window.location.href = authorizationUrl;
}
}
return response;
},
};
client.use(includeCredentials);
client.use(initiateAuthorizationOnUnauthorized);
export function useBackend() {
return {
client,
};
}

39
frontend/src/hooks/fetch.d.ts vendored Normal file

@ -0,0 +1,39 @@
// Using a .js & .d.ts file to make the types work well at use sites
// and make TypeScript, IDE, and eslint happy.
//
// Important to use `useMemo` on any options object passed in
// since it is used as a dependency to re-fetch
import {
PathsWithMethod,
type RequiredKeysOf,
} from "openapi-typescript-helpers";
import { paths } from "../lib/api";
import { FetchResponse, MaybeOptionalInit } from "openapi-fetch";
type InitParam<Init> =
RequiredKeysOf<Init> extends never
? [(Init & { [key: string]: unknown })?]
: [Init & { [key: string]: unknown }];
export function useViewTransitioningFetch<
Path extends PathsWithMethod<paths, "get">,
Init extends MaybeOptionalInit<paths[Path], "get">,
>(
path: Path,
...init: InitParam<Init>
): Omit<
FetchResponse<paths[Path]["get"], Init, "application/json">,
"response"
>;
export function useFetch<
Path extends PathsWithMethod<paths, "get">,
Init extends MaybeOptionalInit<paths[Path], "get">,
>(
path: Path,
...init: InitParam<Init>
): Omit<
FetchResponse<paths[Path]["get"], Init, "application/json">,
"response"
>;

@ -0,0 +1,65 @@
// Using a .js & .d.ts file to make the types work well at use sites
// and make TypeScript, IDE, and eslint happy.
//
// Important to use `useMemo` on any options object passed in
// since it is used as a dependency to re-fetch
import { useBackend } from "./backend.ts";
import { useEffect, useState } from "react";
export function useFetch(path, options) {
const { client } = useBackend();
const [response, setResponse] = useState({});
useEffect(() => {
const abortController = new AbortController();
void doFetch(client, path, options, abortController, setResponse);
return () => {
abortController.abort();
};
}, [client, path, options]);
return { data: response.data, error: response.error };
}
export function useViewTransitioningFetch(path, options) {
const { client } = useBackend();
const [response, setResponse] = useState({});
useEffect(() => {
const abortController = new AbortController();
withViewTransition(function () {
return doFetch(client, path, options, abortController, setResponse);
});
return () => {
abortController.abort();
};
}, [client, path, options]);
return { data: response.data, error: response.error };
}
async function doFetch(client, path, options, abortController, setResponse) {
try {
const response = await client.GET(path, {
...options,
signal: abortController.signal,
});
setResponse(response);
} catch (error) {
if (abortController.signal.aborted) {
return;
}
setResponse({ error });
}
}
function withViewTransition(f) {
if (document.startViewTransition) void document.startViewTransition(f);
else void f();
}

@ -0,0 +1,15 @@
import { createContext, useContext } from "react";
export type Profile = {
name: string;
language: "en" | "sv";
};
export const ProfileContext = createContext<Profile>({
name: "Unknown",
language: "en",
});
export function useProfile() {
return useContext(ProfileContext);
}

11
frontend/src/index.css Normal file

@ -0,0 +1,11 @@
:root {
--color-su-primary: #002f5f;
--color-su-primary-80: #33587f;
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
}

529
frontend/src/lib/api.d.ts vendored Normal file

@ -0,0 +1,529 @@
/**
* This file was auto-generated by openapi-typescript.
* Do not make direct changes to the file.
*/
export interface paths {
"/profile": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get: operations["getProfile"];
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/test": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get: operations["helloWorld"];
put: operations["helloWorld_2"];
post: operations["helloWorld_1"];
delete: operations["helloWorld_3"];
options: operations["helloWorld_6"];
head: operations["helloWorld_5"];
patch: operations["helloWorld_4"];
trace?: never;
};
"/test/name": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get: operations["name"];
put: operations["name_2"];
post: operations["name_1"];
delete: operations["name_3"];
options: operations["name_6"];
head: operations["name_5"];
patch: operations["name_4"];
trace?: never;
};
"/test/email": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get: operations["email"];
put: operations["email_2"];
post: operations["email_1"];
delete: operations["email_3"];
options: operations["email_6"];
head: operations["email_5"];
patch: operations["email_4"];
trace?: never;
};
}
export type webhooks = Record<string, never>;
export interface components {
schemas: {
Profile: {
name: string;
/** @enum {string} */
language: "sv" | "en";
};
};
responses: never;
parameters: never;
requestBodies: never;
headers: never;
pathItems: never;
}
export type $defs = Record<string, never>;
export interface operations {
getProfile: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["Profile"];
};
};
};
};
helloWorld: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": string;
};
};
};
};
helloWorld_2: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": string;
};
};
};
};
helloWorld_1: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": string;
};
};
};
};
helloWorld_3: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": string;
};
};
};
};
helloWorld_6: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": string;
};
};
};
};
helloWorld_5: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": string;
};
};
};
};
helloWorld_4: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": string;
};
};
};
};
name: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": string;
};
};
};
};
name_2: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": string;
};
};
};
};
name_1: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": string;
};
};
};
};
name_3: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": string;
};
};
};
};
name_6: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": string;
};
};
};
};
name_5: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": string;
};
};
};
};
name_4: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": string;
};
};
};
};
email: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": string;
};
};
};
};
email_2: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": string;
};
};
};
};
email_1: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": string;
};
};
};
};
email_3: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": string;
};
};
};
};
email_6: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": string;
};
};
};
};
email_5: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": string;
};
};
};
};
email_4: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": string;
};
};
};
};
}

10
frontend/src/main.tsx Normal file

@ -0,0 +1,10 @@
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import "./index.css";
import App from "./App.tsx";
createRoot(document.getElementById("root")!).render(
<StrictMode>
<App />
</StrictMode>,
);

@ -0,0 +1,3 @@
export default function Footer() {
return <footer></footer>;
}

@ -0,0 +1,14 @@
import "./header.css";
import suLogo from "../assets/SU_logo_optimized.svg";
import { useProfile } from "../hooks/profile.ts";
export default function Header() {
const profile = useProfile();
return (
<header>
<img src={suLogo} alt="Stockholm University" />
<span>{profile.name}</span>
</header>
);
}

@ -0,0 +1,8 @@
export default function Home() {
return (
<>
<h1>Home screen</h1>
<p>Here you can see the latest and greatest</p>
</>
);
}

@ -0,0 +1,20 @@
import Header from "./Header.tsx";
import Menu from "./Menu.tsx";
import { Outlet } from "react-router";
import Footer from "./Footer.tsx";
import "./layout.css";
export default function Layout() {
return (
<>
<div id={"layout"}>
<Header />
<Menu />
<main>
<Outlet />
</main>
<Footer />
</div>
</>
);
}

@ -0,0 +1,23 @@
import { NavLink } from "react-router";
import "./menu.css";
import { useState } from "react";
export default function Menu() {
const [subMenuVisible, setSubMenuVisible] = useState(false);
return (
<menu className={"main"}>
<li>
<NavLink to={"/"}>Home</NavLink>
</li>
<li>
<button onClick={() => setSubMenuVisible((current) => !current)}>
<span>| | |</span>
</button>
<menu className={"sub " + (subMenuVisible ? "visible" : "")}>
<li>Profile</li>
<li>Log out</li>
</menu>
</li>
</menu>
);
}

@ -0,0 +1,12 @@
header {
height: 4em;
background-color: var(--color-su-primary);
display: flex;
justify-content: space-between;
align-items: center;
padding-right: 1em;
color: white;
img {
max-height: 100%;
}
}

@ -0,0 +1,6 @@
#layout {
min-height: 100vh;
}
main {
padding: 0 1em;
}

@ -0,0 +1,57 @@
menu.main {
position: fixed;
bottom: 0;
background-color: var(--color-su-primary);
margin: 0;
padding: 0;
left: 0;
right: 0;
display: flex;
li {
list-style: none;
margin: 0;
flex-basis: 1px;
&:last-child {
margin-left: auto;
}
}
a,
button {
color: white;
padding: 1.3em;
display: block;
margin: 0;
height: 100%;
width: 100%;
min-width: 5em;
}
button {
background: none;
border: none;
span {
transform: rotate(90deg);
display: block;
}
}
menu.sub.visible {
display: flex;
}
menu.sub {
flex-direction: column-reverse;
display: none;
position: absolute;
bottom: 100%;
right: 0;
padding: 0;
margin: 0;
color: white;
background-color: var(--color-su-primary-80);
li {
min-width: 10em;
padding: 1em;
border: 1px solid black;
border-bottom: none;
}
}
}

1
frontend/src/vite-env.d.ts vendored Normal file

@ -0,0 +1 @@
/// <reference types="vite/client" />

@ -0,0 +1,26 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "ES2023",
"useDefineForClassFields": true,
"lib": ["ES2023", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["src"]
}

7
frontend/tsconfig.json Normal file

@ -0,0 +1,7 @@
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
}

@ -0,0 +1,24 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"target": "ES2022",
"lib": ["ES2023"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["vite.config.ts"]
}

7
frontend/vite.config.ts Normal file

@ -0,0 +1,7 @@
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react-swc";
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
});