1
0
mirror of synced 2024-11-21 20:16:02 +03:00

remove mapping, correct template

This commit is contained in:
DmitryZagorulko 2018-05-22 10:34:39 +03:00 committed by Alex Lushpai
parent 33d046f3b3
commit 34b447e4e6
13 changed files with 350 additions and 364 deletions

View File

@ -27,12 +27,5 @@ type Bot struct {
Active bool `json:"active,omitempty"`
}
// Mapping model
type Mapping struct {
ID int `gorm:"primary_key"`
SiteCode string `gorm:"site_code" json:"site_code,omitempty"`
BotID string `gorm:"bot_id" json:"bot_id,omitempty"`
}
//Bots list
type Bots []Bot

View File

@ -1,28 +1,5 @@
package main
func createMapping(s []Mapping) error {
tx := orm.DB.Begin()
if tx.Error != nil {
return tx.Error
}
defer func() {
if r := recover(); r != nil {
logger.Warning(r)
tx.Rollback()
}
}()
for _, val := range s {
if err := tx.Create(&val).Error; err != nil {
tx.Rollback()
return err
}
}
return tx.Commit().Error
}
func getConnection(uid string) (*Connection, error) {
var connection Connection
orm.DB.First(&connection, "client_id = ?", uid)

View File

@ -18,7 +18,7 @@ import (
)
var (
templates = template.Must(template.ParseFiles("templates/header.html", "templates/form.html", "templates/home.html"))
templates = template.Must(template.ParseFiles("templates/layout.html", "templates/form.html", "templates/home.html"))
validPath = regexp.MustCompile("^/(save|settings)/([a-zA-Z0-9]+)$")
localizer *i18n.Localizer
bundle = &i18n.Bundle{DefaultLanguage: language.English}
@ -91,6 +91,7 @@ func connectHandler(w http.ResponseWriter, r *http.Request) {
&p,
map[string]interface{}{
"ButConnect": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "but_connect"}),
"ApiKey": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "api_key"}),
},
}
renderTemplate(w, "home", &res)
@ -125,7 +126,7 @@ func addBotHandler(w http.ResponseWriter, r *http.Request) {
bot, err := GetBotInfo(b.Token)
if err != nil {
logger.Error(b.Token, err.Error())
http.Error(w, "set correct bot token", http.StatusInternalServerError)
http.Error(w, localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "incorrect_token"}), http.StatusInternalServerError)
return
}
@ -244,30 +245,6 @@ func activityBotHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}
func mappingHandler(w http.ResponseWriter, r *http.Request) {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
raven.CaptureErrorAndWait(err, nil)
return
}
var rec []Mapping
err = json.Unmarshal(body, &rec)
if err != nil {
raven.CaptureErrorAndWait(err, nil)
return
}
err = createMapping(rec)
if err != nil {
raven.CaptureErrorAndWait(err, nil)
return
}
w.WriteHeader(http.StatusOK)
}
func settingsHandler(w http.ResponseWriter, r *http.Request, uid string) {
setLocale(r.Header.Get("Accept-Language"))
@ -299,14 +276,12 @@ func settingsHandler(w http.ResponseWriter, r *http.Request, uid string) {
sites.Sites,
map[string]interface{}{
"ButConnect": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "but_connect"}),
"ApiKey": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "api_key"}),
"TabSettings": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "tab_settings"}),
"TabBots": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "tab_bots"}),
"TabMapping": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "tab_mapping"}),
"TableName": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "table_name"}),
"TableToken": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "table_token"}),
"TableActivity": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "table_activity"}),
"MapSites": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "map_sites"}),
"MapOption": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "map_option"}),
},
}
@ -348,13 +323,24 @@ func saveHandler(w http.ResponseWriter, r *http.Request) {
func createHandler(w http.ResponseWriter, r *http.Request) {
setLocale(r.Header.Get("Accept-Language"))
c := Connection{
ClientID: GenerateToken(),
APIURL: string([]byte(r.FormValue("api_url"))),
APIKEY: string([]byte(r.FormValue("api_key"))),
body, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
err := validate(c)
var c Connection
err = json.Unmarshal(body, &c)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
c.ClientID = GenerateToken()
err = validate(c)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
logger.Error(c.APIURL, err.Error())
@ -388,9 +374,12 @@ func createHandler(w http.ResponseWriter, r *http.Request) {
Active: true,
Name: "MG Telegram",
ClientID: c.ClientID,
BaseURL: config.HTTPServer.Host,
BaseURL: fmt.Sprintf(
"https://%s",
config.HTTPServer.Host,
),
AccountURL: fmt.Sprintf(
"%s/settings/%s",
"https://%s/settings/%s",
config.HTTPServer.Host,
c.ClientID,
),
@ -398,7 +387,7 @@ func createHandler(w http.ResponseWriter, r *http.Request) {
Integrations: &v5.Integrations{
MgTransport: &v5.MgTransport{
WebhookUrl: fmt.Sprintf(
"%s/webhook",
"https://%s/webhook",
config.HTTPServer.Host,
),
},

View File

@ -9,7 +9,6 @@ import (
func setTransportRoutes() {
http.HandleFunc("/add-bot/", addBotHandler)
http.HandleFunc("/activity-bot/", activityBotHandler)
http.HandleFunc("/map-bot/", mappingHandler)
}
// GetBotInfo function

View File

@ -1,219 +1,78 @@
{{template "header"}}
<div class="container">
<div class="row" style="margin-top: 5%">
<div class="col s8 offset-s3">
<ul class="tabs" id="tab">
<li class="tab col s3"><a class="active" href="#tab1">{{.Locale.TabSettings}}</a></li>
<li class="tab col s3"><a href="#tab2">{{.Locale.TabBots}}</a></li>
<li class="tab col s3"><a href="#tab3">{{.Locale.TabMapping}}</a></li>
</ul>
</div>
<div class="col s8 offset-s3">
<p id="msg"></p>
</div>
<div id="tab1" class="col s12">
<div class="row" style="margin-top: 5%">
<form id="save" class="col s8 offset-s2" action="/save/" method="POST">
<input name="clientId" type="hidden" value="{{.Conn.ClientID}}">
<div class="row">
<div class="input-field col s12">
<input placeholder="API Url" id="api_url" name="api_url" type="text" class="validate" value="{{.Conn.APIURL}}">
</div>
</div>
<div class="row">
<div class="input-field col s12">
<input placeholder="API Key" id="api_key" name="api_key" type="text" class="validate" value="{{.Conn.APIKEY}}">
</div>
</div>
<div class="row">
<div class="input-field col s6 offset-s5">
<button class="btn waves-effect waves-light red lighten-1" type="submit" name="action">
{{.Locale.ButConnect}}
<i class="material-icons right">sync</i>
</button>
</div>
</div>
</form>
</div>
</div>
<div id="tab2" class="col s12">
<div class="row" style="margin-top: 5%">
<form id="add-bot" class="col s8 offset-s2" action="/add-bot/" method="POST">
<input name="clientId" type="hidden" value="{{.Conn.ClientID}}">
<div class="row">
<div class="input-field col s11">
<input placeholder="{{.Locale.TableToken}}" id="token" name="token" type="text" class="validate">
</div>
<div class="input-field col s1">
<button class="btn btn-meddium waves-effect waves-light red" type="submit" name="action">
<i class="material-icons">add</i>
</button>
</div>
</div>
</form>
{{if .Bots}}
<table class="col s8 offset-s2">
<thead>
<tr>
<th>{{.Locale.TableName}}</th>
<th>{{.Locale.TableToken}}</th>
<th style="text-align: right">{{.Locale.TableActivity}}</th>
</tr>
</thead>
<tbody>
{{range .Bots}}
<tr>
<td>{{.Name}}</td>
<td>{{.Token}}</td>
<td>
<button class="activity-bot btn btn-meddium waves-effect waves-light red" type="submit" name="action" style="float: right"
data-activity="{{.Active}}" data-id="{{.Token}}">
<i class="material-icons">{{if .Active}}stop{{else}}play_arrow{{end}}</i>
</button>
</td>
</tr>
{{end}}
</tbody>
</table>
{{end}}
</div>
</div>
<div id="tab3" class="col s12">
<div class="row" style="margin-top: 5%">
{{ $sites := .Sites }}
{{ $bots := .Bots }}
{{ $locale := .Locale }}
{{if and $sites $bots}}
<table class="col s8 offset-s2">
<thead>
<tr>
<th>{{.Locale.MapSites}}</th>
<th>{{.Locale.TabBots}}</th>
</tr>
</thead>
<tbody>
{{range $site := $sites}}
<tr>
<td>{{$site.Name}}</td>
<td>
<select class="browser-default">
<option value="" disabled selected>{{$locale.MapOption}}</option>
{{range $bot := $bots}}
<option data-code="{{$site.Code}}" data-bot="{{$bot.ID}}">{{$bot.Name}}</option>
{{end}}
</select>
</td>
</tr>
{{end}}
</tbody>
</table>
</div>
<div class="row">
<div class="input-field col s6 offset-s5">
<button class="btn btn-meddium waves-effect waves-light red" type="submit" id="map-bot">
{{.Locale.ButConnect}}
<i class="material-icons">save</i>
</button>
</div>
</div>
{{end}}
</div>
</div>
</div>
<script>
$("#save").on("submit", function(e) {
e.preventDefault();
send(
$(this).attr('action'),
formDataToObj($(this).serializeArray()),
function (data) {
return 0;
}
)
});
$("#add-bot").on("submit", function(e) {
e.preventDefault();
send(
$(this).attr('action'),
formDataToObj($(this).serializeArray()),
function (data) {
location.reload();
}
)
});
$('.activity-bot').on("click", function(e) {
let but = $(this);
send("/activity-bot/",
{
token: but.attr("data-id"),
active: (but.attr("data-activity") == 'true'),
clientId: $('input[name=clientId]').val(),
},
function (data) {
if (but.attr("data-activity") == 'true') {
but.find('i').replaceWith('<i class="material-icons">play_arrow</i>');
but.attr("data-activity", "false")
} else {
but.find('i').replaceWith('<i class="material-icons">stop</i>');
but.attr("data-activity", "true")
}
}
)
});
$('#map-bot').on("click", function(e) {
let mapping = [];
$('select option:selected').each(function() {
let site_code = $(this).attr("data-code");
let bot_id = $(this).attr("data-bot");
if (site_code && bot_id) {
mapping.push({site_code: site_code, bot_id: bot_id});
}
});
if (!$.isEmptyObject(mapping)) {
send("/map-bot/", mapping);
}
});
function send(url, data, callback) {
$('#msg').empty();
$.ajax({
url: url,
data: JSON.stringify(data),
type: "POST",
success: callback,
error: function (res){
if (res.status < 400) {
if (res.responseText) {
document.location.replace(
location.protocol.concat("//").concat(window.location.host) + res.responseText
);
}
} else {
$('#msg').text(res.responseText);
}
}
});
}
function formDataToObj(formArray) {
let obj = {};
for (let i = 0; i < formArray.length; i++){
obj[formArray[i]['name']] = formArray[i]['value'];
}
return obj;
}
document.addEventListener('DOMContentLoaded', function() {
M.Tabs.init(document.getElementById("tab"));
});
</script>
<div class="row indent-top">
<div class="col s6 offset-s3">
<ul class="tabs" id="tab">
<li class="tab col s6"><a class="active" href="#tab1">{{.Locale.TabSettings}}</a></li>
<li class="tab col s6"><a href="#tab2">{{.Locale.TabBots}}</a></li>
</ul>
</div>
</body>
</html>
<div class="col s6 offset-s3">
<div id="msg" class="indent-top"></div>
</div>
<div id="tab1" class="col s12">
<div class="row indent-top">
<form id="save" class="col s8 offset-s2" action="/save/" method="POST">
<input name="clientId" type="hidden" value="{{.Conn.ClientID}}">
<div class="row">
<div class="input-field col s12">
<input placeholder="API Url" id="api_url" name="api_url" type="text" class="validate" value="{{.Conn.APIURL}}">
</div>
</div>
<div class="row">
<div class="input-field col s12">
<input placeholder="{{.Locale.ApiKey}}" id="api_key" name="api_key" type="text" class="validate" value="{{.Conn.APIKEY}}">
</div>
</div>
<div class="row">
<div class="input-field col s6 offset-s5">
<button class="btn waves-effect waves-light red lighten-1" type="submit" name="action">
{{.Locale.ButConnect}}
<i class="material-icons right">sync</i>
</button>
</div>
</div>
</form>
</div>
</div>
<div id="tab2" class="col s12">
<div class="row indent-top">
<form id="add-bot" class="col s8 offset-s2" action="/add-bot/" method="POST">
<input name="clientId" type="hidden" value="{{.Conn.ClientID}}">
<div class="row">
<div class="input-field col s11">
<input placeholder="{{.Locale.TableToken}}" id="token" name="token" type="text" class="validate">
</div>
<div class="input-field col s1">
<button class="btn btn-meddium waves-effect waves-light red" type="submit" name="action">
<i class="material-icons">add</i>
</button>
</div>
</div>
</form>
<table id="bots" class="col s8 offset-s2">
<thead>
<tr>
<th>{{.Locale.TableName}}</th>
<th>{{.Locale.TableToken}}</th>
<th class="text-left">{{.Locale.TableActivity}}</th>
</tr>
</thead>
<tbody>
{{range .Bots}}
<tr>
<td>{{.Name}}</td>
<td>{{.Token}}</td>
<td>
<button class="activity-bot btn btn-meddium waves-effect waves-light red" type="submit" name="action"
data-activity="{{.Active}}" data-token="{{.Token}}">
<i class="material-icons">{{if .Active}}stop{{else}}play_arrow{{end}}</i>
</button>
</td>
</tr>
{{end}}
</tbody>
</table>
</div>
</div>
</div>
{{template "footer"}}

View File

@ -1,13 +0,0 @@
{{ define "header" }}
<html>
<head>
<meta title="Telegram transport">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link rel="stylesheet" href="../web/materialize.min.css">
<link rel="stylesheet" href="../web/font.css" >
<script src="../web/materialize.min.js"></script>
<script src="../web/jquery-3.3.1.min.js"></script>
</head>
<body>
{{ end }}

View File

@ -1,57 +1,28 @@
{{template "header"}}
<div class="container">
<div class="row" style="margin-top: 5%">
<form class="col s8 offset-s2" method="POST" id="save-crm" action="/create/">
<p id="msg"></p>
<div class="row">
<div class="input-field col s12">
<input placeholder="API Url" id="api_url" name="api_url" type="text" class="validate">
</div>
</div>
<div class="row">
<div class="input-field col s12">
<input placeholder="API Key" id="api_key" name="api_key" type="text" class="validate">
</div>
</div>
<div class="row">
<div class="input-field col s6 offset-s5">
<button class="btn waves-effect waves-light red lighten-1" type="submit" name="action">
{{.Locale.ButConnect}}
<i class="material-icons right">sync</i>
</button>
</div>
</div>
</form>
</div>
<div class="row indent-top">
<div class="col s6 offset-s3">
<div id="msg" class="indent-top"></div>
</div>
</body>
<script>
$('#save-crm').on("submit", function(e) {
e.preventDefault();
send($(this).attr('action'), $(this).serialize())
});
function send(url, data) {
$.ajax({
url: url,
data: data,
success: function(res){
console.log(res);
},
error: function (res){
if (res.status < 400) {
if (res.responseText) {
document.location.replace(
location.protocol.concat("//").concat(window.location.host) + res.responseText
);
}
} else {
$('#msg').text(res.responseText);
}
}
});
}
</script>
</html>
<form class="col s8 offset-s2" method="POST" id="save-crm" action="/create/">
<div id="msg"></div>
<div class="row">
<div class="input-field col s12">
<input placeholder="API Url" id="api_url" name="api_url" type="text" class="validate">
</div>
</div>
<div class="row">
<div class="input-field col s12">
<input placeholder="{{.Locale.ApiKey}}" id="api_key" name="api_key" type="text" class="validate">
</div>
</div>
<div class="row">
<div class="input-field col s6 offset-s5">
<button class="btn waves-effect waves-light red lighten-1" type="submit" name="action">
{{.Locale.ButConnect}}
<i class="material-icons right">sync</i>
</button>
</div>
</div>
</form>
</div>
{{template "footer"}}

25
templates/layout.html Normal file
View File

@ -0,0 +1,25 @@
{{ define "header" }}
<html>
<head>
<meta title="Telegram transport">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link rel="stylesheet" href="../web/materialize.min.css">
<link rel="stylesheet" href="../web/font.css" >
<link rel="stylesheet" href="../web/style.css" >
</head>
<body>
<div class="container">
<div class="indent-top center-align">
<img id="logo" src="../web/telegram_logo.svg" alt="telegram" >
</div>
{{ end }}
{{ define "footer" }}
</div>
<script src="../web/materialize.min.js"></script>
<script src="../web/jquery-3.3.1.min.js"></script>
<script src="../web/script.js"></script>
</body>
</html>
{{ end }}

View File

@ -1,12 +1,10 @@
but_connect: Save
tab_settings: Connection settings
tab_bots: Bots
tab_mapping: Mapping
table_name: Bot name
table_token: Bot token
table_activity: Activity
map_sites: Sites
map_option: Choose your option
api_key: API Key
no_bot_token: Enter the bot token
incorrect_data: Incorrect data
@ -21,3 +19,4 @@ error_creating_connection: Error while creating connection
connection_already_created: Connection already created
missing_url_key: Missing crm url or apiKey
incorrect_url: Enter the correct CRM url
incorrect_token: Set correct bot token

View File

@ -1,12 +1,11 @@
but_connect: Сохранить
tab_settings: Настройки CRM
tab_bots: Боты
tab_mapping: Cоответствие
table_name: Имя
table_token: Токен
table_activity: Активность
map_sites: Сайты
map_option: Выберите бота
api_key: API Ключ
no_bot_token: Введите токен
wrong_data: Неверные данные
@ -15,12 +14,10 @@ bot_already_created: Бот уже создан
not_find_account: Не удалось найти учетную запись, обратитесь в службу технической поддержки
error_activating_channel: Ошибка при активации канала
error_deactivating_channel: Ошибка при отключении канала
correct_url_key: Введите правильный URL или apiKey
correct_url_key: Введите корректный URL или apiKey
error_creating_integration: Ошибка при создании интеграции
error_creating_connection: Ошибка при создании соединения
connection_already_created: Соединение уже создано
missing_url_key: Отсутствует URL или apiKey
incorrect_url: Введите правильный URL CRM
incorrect_url: Введите корректный URL CRM
incorrect_token: Установите корректный токен

108
web/script.js Normal file
View File

@ -0,0 +1,108 @@
$('#save-crm').on("submit", function(e) {
e.preventDefault();
send(
$(this).attr('action'),
formDataToObj($(this).serializeArray()),
function () {
return 0;
}
)
});
$("#save").on("submit", function(e) {
e.preventDefault();
send(
$(this).attr('action'),
formDataToObj($(this).serializeArray()),
function () {
return 0;
}
)
});
$("#add-bot").on("submit", function(e) {
e.preventDefault();
send(
$(this).attr('action'),
formDataToObj($(this).serializeArray()),
function (data) {
let bots = $("#bots");
if (bots.hasClass("hide")) {
bots.removeClass("hide")
}
$("#bots tbody").append(getBotTemplate(data));
}
)
});
$(document).on("click", ".activity-bot", function(e) {
let but = $(this);
send("/activity-bot/",
{
token: but.attr("data-token"),
active: (but.attr("data-activity") === 'true'),
clientId: $('input[name=clientId]').val(),
},
function () {
if (but.attr("data-activity") === 'true') {
but.find('i').replaceWith('<i class="material-icons">play_arrow</i>');
but.attr("data-activity", "false")
} else {
but.find('i').replaceWith('<i class="material-icons">stop</i>');
but.attr("data-activity", "true")
}
}
)
});
function send(url, data, callback) {
$('#msg').empty();
$.ajax({
url: url,
data: JSON.stringify(data),
type: "POST",
success: callback,
error: function (res){
if (res.status < 400) {
if (res.responseText) {
document.location.replace(
location.protocol.concat("//").concat(window.location.host) + res.responseText
);
}
} else {
$('#msg').html(`<p class="err-msg truncate">${res.responseText}</p>`);
}
}
});
}
function getBotTemplate(data) {
let bot = JSON.parse(data);
tmpl =
`<tr>
<td>${bot.name}</td>
<td>${bot.token}</td>
<td>
<button class="activity-bot btn btn-meddium waves-effect waves-light red" type="submit" name="action"
data-activity="true" data-token="${bot.token}">
<i class="material-icons">stop</i>
</button>
</td>
</tr>`;
return tmpl;
}
function formDataToObj(formArray) {
let obj = {};
for (let i = 0; i < formArray.length; i++){
obj[formArray[i]['name']] = formArray[i]['value'];
}
return obj;
}
$( document ).ready(function() {
M.Tabs.init(document.getElementById("tab"));
if ($("table tbody").children().length === 0) {
$("#bots").addClass("hide");
}
});

24
web/style.css Normal file
View File

@ -0,0 +1,24 @@
.indent-top {
margin-top: 2%;
}
.text-left{
text-align: right;
}
#bots .activity-bot{
float: right;
}
#msg{
height: 23px;
}
.err-msg{
color: red;
margin: 0;
}
#logo{
height: 80px;
border-bottom: 1px solid red;
}

58
web/telegram_logo.svg Normal file
View File

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="170"
height="50"
version="1.1"
sodipodi:docname="Telegram text logo2.svg"
inkscape:version="0.48.5 r10040"
id="svg3007">
<defs
id="defs3009" />
<sodipodi:namedview
id="base"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.9899495"
inkscape:cx="-115.33299"
inkscape:cy="-29.10437"
inkscape:document-units="px"
showgrid="false"
showborder="true"
inkscape:window-width="1280"
inkscape:window-height="962"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg3007" />
<metadata
id="metadata3012">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
transform="translate(2.0203051,-1001.8571)">
<path
id="path3037"
style="fill:#000000"
d="m 83.155472,1043.9958 c -1.00897,-0.1855 -1.96835,-0.4668 -2.94737,-0.7588 -0.007,-1.0285 0.0834,-2.0972 0.27945,-3.0729 8.79587,2.5387 10.8337,0.8765 10.98371,-4.7483 l 0,-1.3514 -1.13569,1.038 c -1.47774,1.3505 -2.92429,1.8332 -5.07994,1.6948 -4.28229,-0.2748 -6.6539,-3.406 -6.66094,-8.7945 -0.004,-3.2222 0.70796,-5.2692 2.49964,-7.1847 2.39005,-2.5551 6.48012,-3.0465 9.33991,-1.122 l 1.03702,0.6979 0,-0.7308 0,-0.7308 1.8421,0.061 1.84211,0.061 0.0609,7.2632 c 0.0949,11.324 -0.23645,13.5351 -2.35141,15.6902 -2.83552,2.3932 -5.73302,2.3852 -9.70947,1.9885 z m 5.57301,-11.1493 c 0.48945,-0.2497 1.3068,-0.8382 1.81634,-1.3079 l 0.92644,-0.854 0,-3.5335 0,-3.5334 -0.65969,-0.5551 c -2.25725,-1.8994 -4.68386,-2.0438 -6.51672,-0.3879 -1.18858,1.0738 -1.71225,2.624 -1.7282,5.1161 -0.0193,3.0101 0.62904,4.5345 2.2522,5.2962 1.07547,0.5046 2.63749,0.4085 3.90963,-0.2405 z m -53.27448,2.3845 c -2.15175,-2.0525 -3.16459,-5.2677 -2.73366,-8.6781 0.35004,-2.7703 1.19489,-4.5767 2.85696,-6.1088 1.3186,-1.2154 2.55729,-1.7263 4.51029,-1.8602 4.75649,-0.326 7.57662,2.9187 7.59054,8.7332 l 0.004,1.5263 c -3.63093,0.097 -7.78258,-0.2289 -11.15789,0.2776 0.49364,3.1269 2.75376,5.4645 5.89474,5.5108 1.88735,0 3.24506,-0.4788 5.05953,-0.8366 l 0.0552,2.8796 c 0,0 -4.2377,1.0063 -5.85157,0.9942 -2.47688,0.01 -4.82827,-1.1145 -6.22787,-2.438 z m 8.43714,-9.9139 c -0.004,-1.7928 -1.16986,-3.4767 -2.59275,-3.7437 -2.24609,-0.4213 -3.96719,0.8806 -4.53152,3.4279 l -0.19822,0.8947 3.66183,0 3.66183,0 -10e-4,-0.5789 z m 19.14181,9.9139 c -2.15175,-2.0525 -3.16459,-5.2677 -2.73366,-8.6781 0.35004,-2.7703 1.19489,-4.5767 2.85696,-6.1088 1.3186,-1.2154 2.55729,-1.7263 4.51028,-1.8602 4.7565,-0.326 7.57662,2.9187 7.59055,8.7332 l 0.004,1.5263 c -3.87507,-0.05 -7.58727,-0.034 -11.25555,-0.064 0.21864,3.6924 2.60437,6.0438 5.99239,5.8526 1.90496,0.037 3.57714,-0.4819 5.05954,-0.8366 0.32954,0.2036 0.24922,2.5379 -0.0972,2.8254 -0.47841,0.397 -4.08529,1.0605 -5.69917,1.0484 -2.47682,0.01 -4.82834,-1.1148 -6.22783,-2.4382 z m 8.43714,-9.9139 c -0.004,-1.7928 -1.16986,-3.4767 -2.59275,-3.7437 -2.24609,-0.4213 -3.96719,0.8806 -4.53152,3.4279 l -0.19822,0.8947 3.66183,0 3.66183,0 -10e-4,-0.5789 z m 44.158598,12.0809 c -2.6345,-0.9828 -3.9318,-3.8164 -3.0677,-6.7004 0.3454,-1.1529 1.6649,-2.571 3.0003,-3.2244 1.263,-0.6179 3.8179,-1.1377 5.6468,-1.1488 l 1.2105,-0.01 0,-1.4841 c -0.071,-4.0094 -3.2394,-3.7486 -6.3658,-2.6135 -0.8409,0.3026 -1.9388,0.5527 -2.1415,0.6154 -0.026,-0.9406 -0.1242,-1.5866 -0.1242,-3.0258 l 1.7368,-0.5495 c 1.1575,-0.3662 2.4406,-0.5896 3.8464,-0.6697 3.3764,-0.1924 5.2014,0.5481 6.2677,2.5432 0.4384,0.8201 0.4699,1.1968 0.5697,6.799 0.1055,5.9206 0.1066,5.9319 0.6161,6.4738 0.3057,0.3252 1.4234,0.6406 1.7663,0.6406 -0.01,1.2358 0.1332,1.1853 -0.016,2.3446 -0.4912,0.1323 -2.1243,0.2968 -2.734,0.2463 -1.193,-0.099 -1.9325,-0.5993 -2.5012,-1.6926 l -0.3032,-0.5828 -0.7821,0.6259 c -1.8048,1.4445 -4.8149,2.0852 -6.6245,1.4101 z m 4.4232,-3.1681 c 0.4643,-0.1638 1.1856,-0.5191 1.6028,-0.7895 l 0.7587,-0.4916 0,-2.1579 0,-2.158 -0.9031,0 c -2.1237,0 -4.6531,1.0898 -5.1718,2.2281 -0.5714,1.2542 -0.093,2.7443 1.064,3.3146 0.8612,0.4244 1.5549,0.4386 2.6442,0.054 z m -101.212208,-7.9128 0,-10.9474 -4.31579,0 -4.31579,0 0,-1.4737 0,-1.4736 10.63158,0 10.63158,0 0,1.4736 0,1.4737 -4.31579,0 -4.31579,0 0,10.9474 0,10.9475 -2,0 -2,0 z m 33.47369,-2.2105 0,-13.1579 1.89473,0 1.89474,0 0,13.1579 0,13.158 -1.89474,0 -1.89473,0 z m 48.210518,4 0,-9.1743 c 1.2281,0.041 2.505,-0.016 3.733,0.024 -0.012,0.7575 0.033,1.5121 0.077,2.2676 1.7272,-1.8978 3.5592,-2.3862 5.0931,-2.5497 l 1.4127,-0.1465 0,1.8046 0,1.8047 c -2.3688,-0.6955 -4.8378,0.8702 -5.9666,2.3907 -0.4335,0.6025 -0.4593,0.9081 -0.5598,6.6317 l -0.1052,6 c -1.2281,0.041 -2.4562,0.081 -3.68423,0.122 l 0,-9.1744 z m 31.3684,0 0,-9.1579 c 1.2632,0 2.5263,0 3.7895,0 0,0.8384 0,2.3018 0,3.1402 1.5981,-1.7967 3.5324,-3.4881 5.6842,-3.456 2.6311,-0.1033 3.7089,1.5973 4.883,3.4845 3.2896,-3.7043 9.29,-4.769 11.1442,-0.363 0.1785,6.0172 0.075,8.25 -0.02,15.5029 -1.2211,0.041 -2.3445,-0.016 -3.5657,0.024 0.056,-4.6806 -0.012,-9.972 -0.1262,-14.3671 -0.4683,-0.9211 -1.3374,-1.6449 -2.8359,-1.2488 -1.4986,0.3962 -2.8543,1.5623 -4.2655,3.209 0,4.0814 0.049,8.3094 0.049,12.3908 l -1.8868,0 -1.8868,0 c -0.04,-4.7836 -0.081,-9.5673 -0.1212,-14.3509 -0.7567,-0.8753 -1.3605,-1.3878 -2.7897,-1.0472 -1.4291,0.3405 -3.3278,1.4703 -4.2629,3.2632 0,4.0449 -0.049,8.09 -0.049,12.1349 -1.2631,0 -2.4775,0 -3.7406,0 0,-3.0529 -2e-4,-6.1059 0,-9.1589 z"
inkscape:connector-curvature="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.0 KiB