portosaurus 2.1.10 → 2.1.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +1 -1
- package/src/cli/init.mjs +20 -12
- package/src/core/buildDocuConfig.mjs +1 -1
- package/src/plugins/favicon.mjs +29 -3
- package/src/template/gitignore +9 -0
- package/src/template/notes/index.mdx +9 -0
- package/src/theme/config/metaTags.js +0 -218
- package/src/template/static/img/svg/icon-blog.svg +0 -2
- package/src/template/static/img/svg/icon-note.svg +0 -2
package/README.md
CHANGED
|
@@ -137,7 +137,7 @@ module.exports = {
|
|
|
137
137
|
- [Docusaurus](https://docusaurus.io/) - The static site builder framework this is built upon.
|
|
138
138
|
- [React](https://react.dev) - UI library for building the interactive components.
|
|
139
139
|
- [React Icons](https://react-icons.github.io/) - Icon library used throughout the site.
|
|
140
|
-
- Libraries listed in [package.json](
|
|
140
|
+
- Libraries listed in [package.json](./package.json) - Essential dependencies.
|
|
141
141
|
- [Hugo Profile](https://hugo-profile.netlify.app/) - Design inspiration.
|
|
142
142
|
- [Catppuccin](https://github.com/catppuccin/catppuccin) - Color scheme that inspired the site's palette.
|
|
143
143
|
- [Deepseek R1](https://www.deepseek.com/) hosted using [Ollama](https://ollama.com/library/deepseek-r1) - prism.js theme & project card component.
|
package/package.json
CHANGED
package/src/cli/init.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { getPackageManager } from "../utils/packageManager.mjs";
|
|
|
5
5
|
import { PortoRoot, mirrorSync } from "../utils/cliHelpers.mjs";
|
|
6
6
|
|
|
7
7
|
export async function initCommand(projectName, options) {
|
|
8
|
-
const
|
|
8
|
+
const UsrProjDir = path.resolve(process.cwd(), projectName);
|
|
9
9
|
const templateDir = path.resolve(PortoRoot, "src/template");
|
|
10
10
|
const packageJson = JSON.parse(
|
|
11
11
|
fs.readFileSync(path.resolve(PortoRoot, "package.json"), "utf8"),
|
|
@@ -29,7 +29,10 @@ export async function initCommand(projectName, options) {
|
|
|
29
29
|
|
|
30
30
|
const contentDirs = ["blog", "notes", "static"];
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
const dotGitIgnore = path.join(UsrProjDir, ".gitignore");
|
|
33
|
+
const plainGitIgnore = path.join(UsrProjDir, "gitignore");
|
|
34
|
+
|
|
35
|
+
if (fs.existsSync(UsrProjDir)) {
|
|
33
36
|
logger.error(`Target Directory "${projectName}" already exists.`);
|
|
34
37
|
process.exit(1);
|
|
35
38
|
}
|
|
@@ -45,11 +48,11 @@ export async function initCommand(projectName, options) {
|
|
|
45
48
|
const { execSync } = await import("child_process");
|
|
46
49
|
|
|
47
50
|
// Create user project directory
|
|
48
|
-
fs.mkdirSync(
|
|
51
|
+
fs.mkdirSync(UsrProjDir, { recursive: true });
|
|
49
52
|
|
|
50
53
|
// Git Init
|
|
51
54
|
try {
|
|
52
|
-
execSync("git init", { cwd:
|
|
55
|
+
execSync("git init", { cwd: UsrProjDir, stdio: "ignore" });
|
|
53
56
|
} catch {
|
|
54
57
|
logger.warn("Failed to initialize git repository.");
|
|
55
58
|
process.exit(1);
|
|
@@ -57,12 +60,17 @@ export async function initCommand(projectName, options) {
|
|
|
57
60
|
|
|
58
61
|
// Make Content directories
|
|
59
62
|
for (const dir of contentDirs) {
|
|
60
|
-
fs.mkdirSync(path.join(
|
|
63
|
+
fs.mkdirSync(path.join(UsrProjDir, dir), { recursive: true });
|
|
61
64
|
}
|
|
62
65
|
|
|
63
66
|
// Copy template files, dirs
|
|
64
67
|
if (fs.existsSync(templateDir)) {
|
|
65
|
-
mirrorSync(templateDir,
|
|
68
|
+
mirrorSync(templateDir, UsrProjDir, TemplateVars, ignoreList);
|
|
69
|
+
|
|
70
|
+
// Rename gitignore to .gitignore (to bypass npm publish exclusions)
|
|
71
|
+
if (fs.existsSync(plainGitIgnore) && !fs.existsSync(dotGitIgnore)) {
|
|
72
|
+
fs.renameSync(plainGitIgnore, dotGitIgnore);
|
|
73
|
+
}
|
|
66
74
|
} else {
|
|
67
75
|
logger.error(`Portosaurus template directory not found: ${templateDir}`);
|
|
68
76
|
process.exit(1);
|
|
@@ -72,13 +80,13 @@ export async function initCommand(projectName, options) {
|
|
|
72
80
|
try {
|
|
73
81
|
// Add all files to git
|
|
74
82
|
execSync("git add .", {
|
|
75
|
-
cwd:
|
|
83
|
+
cwd: UsrProjDir,
|
|
76
84
|
stdio: "ignore",
|
|
77
85
|
});
|
|
78
86
|
|
|
79
87
|
// Initial Commit
|
|
80
88
|
execSync('git commit -m "Initialize Portosaurus project"', {
|
|
81
|
-
cwd:
|
|
89
|
+
cwd: UsrProjDir,
|
|
82
90
|
stdio: "ignore",
|
|
83
91
|
});
|
|
84
92
|
} catch {
|
|
@@ -89,7 +97,7 @@ export async function initCommand(projectName, options) {
|
|
|
89
97
|
|
|
90
98
|
// GitHub Pages setup
|
|
91
99
|
if (options.githubPages === false) {
|
|
92
|
-
const ghDir = path.join(
|
|
100
|
+
const ghDir = path.join(UsrProjDir, ".github");
|
|
93
101
|
|
|
94
102
|
// Delete copied .github directory
|
|
95
103
|
if (fs.existsSync(ghDir)) {
|
|
@@ -103,10 +111,10 @@ export async function initCommand(projectName, options) {
|
|
|
103
111
|
);
|
|
104
112
|
}
|
|
105
113
|
|
|
106
|
-
logger.success(`Created ${projectName} at ${
|
|
114
|
+
logger.success(`Created ${projectName} at ${UsrProjDir}`);
|
|
107
115
|
|
|
108
116
|
// Install dependencies
|
|
109
|
-
const pm = getPackageManager(
|
|
117
|
+
const pm = getPackageManager(UsrProjDir);
|
|
110
118
|
|
|
111
119
|
logger.info(`Installing dependencies with ${pm.name}...`);
|
|
112
120
|
|
|
@@ -114,7 +122,7 @@ export async function initCommand(projectName, options) {
|
|
|
114
122
|
logger.info(`Running ${pm.install}...`);
|
|
115
123
|
try {
|
|
116
124
|
const { execSync } = await import("child_process");
|
|
117
|
-
execSync(pm.install, { cwd:
|
|
125
|
+
execSync(pm.install, { cwd: UsrProjDir, stdio: "inherit" });
|
|
118
126
|
logger.success("Dependencies installed!");
|
|
119
127
|
} catch {
|
|
120
128
|
logger.error(
|
|
@@ -120,7 +120,7 @@ export function buildDocuConfig(rawUserConfig, UserRoot) {
|
|
|
120
120
|
tagline: UserConfig.hero_section.description,
|
|
121
121
|
favicon: resolveStaticAsset(
|
|
122
122
|
UserConfig.favicon,
|
|
123
|
-
resolveStaticAsset(
|
|
123
|
+
resolveStaticAsset("favicon/favicon.ico", "img/icon.png"),
|
|
124
124
|
),
|
|
125
125
|
url: siteUrl,
|
|
126
126
|
baseUrl: basePath,
|
package/src/plugins/favicon.mjs
CHANGED
|
@@ -233,12 +233,18 @@ export async function generateFavicons(context, options = {}) {
|
|
|
233
233
|
|
|
234
234
|
// Cleanup temporary files
|
|
235
235
|
tempFiles.forEach(cleanupFile);
|
|
236
|
-
return
|
|
236
|
+
return {
|
|
237
|
+
success: true,
|
|
238
|
+
html: response.html || [],
|
|
239
|
+
};
|
|
237
240
|
} catch (error) {
|
|
238
241
|
logger.warn(`Favicon generation skipped: ${error.message}`);
|
|
239
242
|
tempFiles.forEach(cleanupFile);
|
|
240
243
|
// Don't throw - allow the build to continue
|
|
241
|
-
return
|
|
244
|
+
return {
|
|
245
|
+
success: false,
|
|
246
|
+
html: [],
|
|
247
|
+
};
|
|
242
248
|
}
|
|
243
249
|
}
|
|
244
250
|
|
|
@@ -251,6 +257,8 @@ export default function (context, options = {}) {
|
|
|
251
257
|
generateOnDev = true,
|
|
252
258
|
} = options;
|
|
253
259
|
|
|
260
|
+
let generatedTags = [];
|
|
261
|
+
|
|
254
262
|
return {
|
|
255
263
|
name: "favicon-generator",
|
|
256
264
|
|
|
@@ -262,13 +270,31 @@ export default function (context, options = {}) {
|
|
|
262
270
|
|
|
263
271
|
if (shouldGenerate) {
|
|
264
272
|
// Non-fatal execution
|
|
265
|
-
await generateFavicons(context, {
|
|
273
|
+
const result = await generateFavicons(context, {
|
|
266
274
|
imagePath,
|
|
267
275
|
outputPath,
|
|
268
276
|
circular,
|
|
269
277
|
shape,
|
|
270
278
|
});
|
|
279
|
+
if (result.success) {
|
|
280
|
+
generatedTags = result.html;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
|
|
285
|
+
injectHtmlTags() {
|
|
286
|
+
if (generatedTags.length > 0) {
|
|
287
|
+
return {
|
|
288
|
+
headTags: generatedTags.map((tag) => {
|
|
289
|
+
// Convert string tags to Docusaurus headTags objects if needed
|
|
290
|
+
// Actually Docusaurus supports returning a string or objects
|
|
291
|
+
// The simplest is to return the strings as raw HTML if possible
|
|
292
|
+
// But injectHtmlTags expects objects or strings
|
|
293
|
+
return tag;
|
|
294
|
+
}),
|
|
295
|
+
};
|
|
271
296
|
}
|
|
297
|
+
return {};
|
|
272
298
|
},
|
|
273
299
|
};
|
|
274
300
|
}
|
|
@@ -18,222 +18,4 @@ export const metaTags = [
|
|
|
18
18
|
content: backgroundColor,
|
|
19
19
|
},
|
|
20
20
|
},
|
|
21
|
-
|
|
22
|
-
// Android Chrome icons
|
|
23
|
-
{
|
|
24
|
-
tagName: "link",
|
|
25
|
-
attributes: {
|
|
26
|
-
rel: "icon",
|
|
27
|
-
type: "image/png",
|
|
28
|
-
sizes: "36x36",
|
|
29
|
-
href: "/favicon/android-chrome-36x36.png",
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
tagName: "link",
|
|
34
|
-
attributes: {
|
|
35
|
-
rel: "icon",
|
|
36
|
-
type: "image/png",
|
|
37
|
-
sizes: "48x48",
|
|
38
|
-
href: "/favicon/android-chrome-48x48.png",
|
|
39
|
-
},
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
tagName: "link",
|
|
43
|
-
attributes: {
|
|
44
|
-
rel: "icon",
|
|
45
|
-
type: "image/png",
|
|
46
|
-
sizes: "72x72",
|
|
47
|
-
href: "/favicon/android-chrome-72x72.png",
|
|
48
|
-
},
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
tagName: "link",
|
|
52
|
-
attributes: {
|
|
53
|
-
rel: "icon",
|
|
54
|
-
type: "image/png",
|
|
55
|
-
sizes: "96x96",
|
|
56
|
-
href: "/favicon/android-chrome-96x96.png",
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
tagName: "link",
|
|
61
|
-
attributes: {
|
|
62
|
-
rel: "icon",
|
|
63
|
-
type: "image/png",
|
|
64
|
-
sizes: "144x144",
|
|
65
|
-
href: "/favicon/android-chrome-144x144.png",
|
|
66
|
-
},
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
tagName: "link",
|
|
70
|
-
attributes: {
|
|
71
|
-
rel: "icon",
|
|
72
|
-
type: "image/png",
|
|
73
|
-
sizes: "192x192",
|
|
74
|
-
href: "/favicon/android-chrome-192x192.png",
|
|
75
|
-
},
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
tagName: "link",
|
|
79
|
-
attributes: {
|
|
80
|
-
rel: "icon",
|
|
81
|
-
type: "image/png",
|
|
82
|
-
sizes: "256x256",
|
|
83
|
-
href: "/favicon/android-chrome-256x256.png",
|
|
84
|
-
},
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
tagName: "link",
|
|
88
|
-
attributes: {
|
|
89
|
-
rel: "icon",
|
|
90
|
-
type: "image/png",
|
|
91
|
-
sizes: "384x384",
|
|
92
|
-
href: "/favicon/android-chrome-384x384.png",
|
|
93
|
-
},
|
|
94
|
-
},
|
|
95
|
-
{
|
|
96
|
-
tagName: "link",
|
|
97
|
-
attributes: {
|
|
98
|
-
rel: "icon",
|
|
99
|
-
type: "image/png",
|
|
100
|
-
sizes: "512x512",
|
|
101
|
-
href: "/favicon/android-chrome-512x512.png",
|
|
102
|
-
},
|
|
103
|
-
},
|
|
104
|
-
|
|
105
|
-
// Apple touch icons
|
|
106
|
-
{
|
|
107
|
-
tagName: "link",
|
|
108
|
-
attributes: {
|
|
109
|
-
rel: "apple-touch-icon",
|
|
110
|
-
sizes: "57x57",
|
|
111
|
-
href: "/favicon/apple-touch-icon-57x57.png",
|
|
112
|
-
},
|
|
113
|
-
},
|
|
114
|
-
{
|
|
115
|
-
tagName: "link",
|
|
116
|
-
attributes: {
|
|
117
|
-
rel: "apple-touch-icon",
|
|
118
|
-
sizes: "60x60",
|
|
119
|
-
href: "/favicon/apple-touch-icon-60x60.png",
|
|
120
|
-
},
|
|
121
|
-
},
|
|
122
|
-
{
|
|
123
|
-
tagName: "link",
|
|
124
|
-
attributes: {
|
|
125
|
-
rel: "apple-touch-icon",
|
|
126
|
-
sizes: "72x72",
|
|
127
|
-
href: "/favicon/apple-touch-icon-72x72.png",
|
|
128
|
-
},
|
|
129
|
-
},
|
|
130
|
-
{
|
|
131
|
-
tagName: "link",
|
|
132
|
-
attributes: {
|
|
133
|
-
rel: "apple-touch-icon",
|
|
134
|
-
sizes: "76x76",
|
|
135
|
-
href: "/favicon/apple-touch-icon-76x76.png",
|
|
136
|
-
},
|
|
137
|
-
},
|
|
138
|
-
{
|
|
139
|
-
tagName: "link",
|
|
140
|
-
attributes: {
|
|
141
|
-
rel: "apple-touch-icon",
|
|
142
|
-
sizes: "114x114",
|
|
143
|
-
href: "/favicon/apple-touch-icon-114x114.png",
|
|
144
|
-
},
|
|
145
|
-
},
|
|
146
|
-
{
|
|
147
|
-
tagName: "link",
|
|
148
|
-
attributes: {
|
|
149
|
-
rel: "apple-touch-icon",
|
|
150
|
-
sizes: "120x120",
|
|
151
|
-
href: "/favicon/apple-touch-icon-120x120.png",
|
|
152
|
-
},
|
|
153
|
-
},
|
|
154
|
-
{
|
|
155
|
-
tagName: "link",
|
|
156
|
-
attributes: {
|
|
157
|
-
rel: "apple-touch-icon",
|
|
158
|
-
sizes: "144x144",
|
|
159
|
-
href: "/favicon/apple-touch-icon-144x144.png",
|
|
160
|
-
},
|
|
161
|
-
},
|
|
162
|
-
{
|
|
163
|
-
tagName: "link",
|
|
164
|
-
attributes: {
|
|
165
|
-
rel: "apple-touch-icon",
|
|
166
|
-
sizes: "152x152",
|
|
167
|
-
href: "/favicon/apple-touch-icon-152x152.png",
|
|
168
|
-
},
|
|
169
|
-
},
|
|
170
|
-
{
|
|
171
|
-
tagName: "link",
|
|
172
|
-
attributes: {
|
|
173
|
-
rel: "apple-touch-icon",
|
|
174
|
-
sizes: "167x167",
|
|
175
|
-
href: "/favicon/apple-touch-icon-167x167.png",
|
|
176
|
-
},
|
|
177
|
-
},
|
|
178
|
-
{
|
|
179
|
-
tagName: "link",
|
|
180
|
-
attributes: {
|
|
181
|
-
rel: "apple-touch-icon",
|
|
182
|
-
sizes: "180x180",
|
|
183
|
-
href: "/favicon/apple-touch-icon-180x180.png",
|
|
184
|
-
},
|
|
185
|
-
},
|
|
186
|
-
{
|
|
187
|
-
tagName: "link",
|
|
188
|
-
attributes: {
|
|
189
|
-
rel: "apple-touch-icon",
|
|
190
|
-
sizes: "1024x1024",
|
|
191
|
-
href: "/favicon/apple-touch-icon-1024x1024.png",
|
|
192
|
-
},
|
|
193
|
-
},
|
|
194
|
-
{
|
|
195
|
-
tagName: "link",
|
|
196
|
-
attributes: {
|
|
197
|
-
rel: "apple-touch-icon-precomposed",
|
|
198
|
-
href: "/favicon/apple-touch-icon-precomposed.png",
|
|
199
|
-
},
|
|
200
|
-
},
|
|
201
|
-
|
|
202
|
-
// Standard favicons
|
|
203
|
-
{
|
|
204
|
-
tagName: "link",
|
|
205
|
-
attributes: {
|
|
206
|
-
rel: "icon",
|
|
207
|
-
type: "image/png",
|
|
208
|
-
sizes: "16x16",
|
|
209
|
-
href: "/favicon/favicon-16x16.png",
|
|
210
|
-
},
|
|
211
|
-
},
|
|
212
|
-
{
|
|
213
|
-
tagName: "link",
|
|
214
|
-
attributes: {
|
|
215
|
-
rel: "icon",
|
|
216
|
-
type: "image/png",
|
|
217
|
-
sizes: "32x32",
|
|
218
|
-
href: "/favicon/favicon-32x32.png",
|
|
219
|
-
},
|
|
220
|
-
},
|
|
221
|
-
{
|
|
222
|
-
tagName: "link",
|
|
223
|
-
attributes: {
|
|
224
|
-
rel: "icon",
|
|
225
|
-
type: "image/png",
|
|
226
|
-
sizes: "48x48",
|
|
227
|
-
href: "/favicon/favicon-48x48.png",
|
|
228
|
-
},
|
|
229
|
-
},
|
|
230
|
-
|
|
231
|
-
// Web manifest
|
|
232
|
-
{
|
|
233
|
-
tagName: "link",
|
|
234
|
-
attributes: {
|
|
235
|
-
rel: "manifest",
|
|
236
|
-
href: "/favicon/manifest.webmanifest",
|
|
237
|
-
},
|
|
238
|
-
},
|
|
239
21
|
];
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
2
|
-
<svg stroke="#fab387" fill="#2e8555" stroke-width="0" viewBox="0 0 448 512" color="#fab387" style="color:#fab387" height="24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M162.4 196c4.8-4.9 6.2-5.1 36.4-5.1 27.2 0 28.1.1 32.1 2.1 5.8 2.9 8.3 7 8.3 13.6 0 5.9-2.4 10-7.6 13.4-2.8 1.8-4.5 1.9-31.1 2.1-16.4.1-29.5-.2-31.5-.8-10.3-2.9-14.1-17.7-6.6-25.3zm61.4 94.5c-53.9 0-55.8.2-60.2 4.1-3.5 3.1-5.7 9.4-5.1 13.9.7 4.7 4.8 10.1 9.2 12 2.2 1 14.1 1.7 56.3 1.2l47.9-.6 9.2-1.5c9-5.1 10.5-17.4 3.1-24.4-5.3-4.7-5-4.7-60.4-4.7zm223.4 130.1c-3.5 28.4-23 50.4-51.1 57.5-7.2 1.8-9.7 1.9-172.9 1.8-157.8 0-165.9-.1-172-1.8-8.4-2.2-15.6-5.5-22.3-10-5.6-3.8-13.9-11.8-17-16.4-3.8-5.6-8.2-15.3-10-22C.1 423 0 420.3 0 256.3 0 93.2 0 89.7 1.8 82.6 8.1 57.9 27.7 39 53 33.4c7.3-1.6 332.1-1.9 340-.3 21.2 4.3 37.9 17.1 47.6 36.4 7.7 15.3 7-1.5 7.3 180.6.2 115.8 0 164.5-.7 170.5zm-85.4-185.2c-1.1-5-4.2-9.6-7.7-11.5-1.1-.6-8-1.3-15.5-1.7-12.4-.6-13.8-.8-17.8-3.1-6.2-3.6-7.9-7.6-8-18.3 0-20.4-8.5-39.4-25.3-56.5-12-12.2-25.3-20.5-40.6-25.1-3.6-1.1-11.8-1.5-39.2-1.8-42.9-.5-52.5.4-67.1 6.2-27 10.7-46.3 33.4-53.4 62.4-1.3 5.4-1.6 14.2-1.9 64.3-.4 62.8 0 72.1 4 84.5 9.7 30.7 37.1 53.4 64.6 58.4 9.2 1.7 122.2 2.1 133.7.5 20.1-2.7 35.9-10.8 50.7-25.9 10.7-10.9 17.4-22.8 21.8-38.5 3.2-10.9 2.9-88.4 1.7-93.9z"></path></svg>
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
2
|
-
<svg stroke="#fab387" fill="#2e8555" stroke-width="0" viewBox="0 0 448 512" color="#fab387" style="color:#fab387" height="24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M162.4 196c4.8-4.9 6.2-5.1 36.4-5.1 27.2 0 28.1.1 32.1 2.1 5.8 2.9 8.3 7 8.3 13.6 0 5.9-2.4 10-7.6 13.4-2.8 1.8-4.5 1.9-31.1 2.1-16.4.1-29.5-.2-31.5-.8-10.3-2.9-14.1-17.7-6.6-25.3zm61.4 94.5c-53.9 0-55.8.2-60.2 4.1-3.5 3.1-5.7 9.4-5.1 13.9.7 4.7 4.8 10.1 9.2 12 2.2 1 14.1 1.7 56.3 1.2l47.9-.6 9.2-1.5c9-5.1 10.5-17.4 3.1-24.4-5.3-4.7-5-4.7-60.4-4.7zm223.4 130.1c-3.5 28.4-23 50.4-51.1 57.5-7.2 1.8-9.7 1.9-172.9 1.8-157.8 0-165.9-.1-172-1.8-8.4-2.2-15.6-5.5-22.3-10-5.6-3.8-13.9-11.8-17-16.4-3.8-5.6-8.2-15.3-10-22C.1 423 0 420.3 0 256.3 0 93.2 0 89.7 1.8 82.6 8.1 57.9 27.7 39 53 33.4c7.3-1.6 332.1-1.9 340-.3 21.2 4.3 37.9 17.1 47.6 36.4 7.7 15.3 7-1.5 7.3 180.6.2 115.8 0 164.5-.7 170.5zm-85.4-185.2c-1.1-5-4.2-9.6-7.7-11.5-1.1-.6-8-1.3-15.5-1.7-12.4-.6-13.8-.8-17.8-3.1-6.2-3.6-7.9-7.6-8-18.3 0-20.4-8.5-39.4-25.3-56.5-12-12.2-25.3-20.5-40.6-25.1-3.6-1.1-11.8-1.5-39.2-1.8-42.9-.5-52.5.4-67.1 6.2-27 10.7-46.3 33.4-53.4 62.4-1.3 5.4-1.6 14.2-1.9 64.3-.4 62.8 0 72.1 4 84.5 9.7 30.7 37.1 53.4 64.6 58.4 9.2 1.7 122.2 2.1 133.7.5 20.1-2.7 35.9-10.8 50.7-25.9 10.7-10.9 17.4-22.8 21.8-38.5 3.2-10.9 2.9-88.4 1.7-93.9z"></path></svg>
|