Unverified Commit 3a57145e authored by NGPixel's avatar NGPixel

refactor: initial import from v3 prototype

parent b5b4b088
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# Wiki.js - CONFIGURATION # # Wiki.js - CONFIGURATION #
####################################################################### #######################################################################
# Full documentation + examples: # Full documentation + examples:
# https://docs.requarks.io/install # https://docs.js.wiki/install
# --------------------------------------------------------------------- # ---------------------------------------------------------------------
# Port the server should listen to # Port the server should listen to
...@@ -13,25 +13,20 @@ port: 3000 ...@@ -13,25 +13,20 @@ port: 3000
# --------------------------------------------------------------------- # ---------------------------------------------------------------------
# Database # Database
# --------------------------------------------------------------------- # ---------------------------------------------------------------------
# Supported Database Engines: # PostgreSQL 9.6 or later required
# - postgres = PostgreSQL 9.5 or later
# - mysql = MySQL 8.0 or later (5.7.8 partially supported, refer to docs)
# - mariadb = MariaDB 10.2.7 or later
# - mssql = MS SQL Server 2012 or later
# - sqlite = SQLite 3.9 or later
db: db:
type: postgres
# PostgreSQL / MySQL / MariaDB / MS SQL Server only:
host: localhost host: localhost
port: 5432 port: 5432
user: wikijs user: wikijs
pass: wikijsrocks pass: wikijsrocks
db: wiki db: wiki
schemas:
wiki: wiki
scheduler: scheduler
ssl: false ssl: false
# Optional - PostgreSQL / MySQL / MariaDB only: # Optional
# -> Uncomment lines you need below and set `auto` to false # -> Uncomment lines you need below and set `auto` to false
# -> Full list of accepted options: https://nodejs.org/api/tls.html#tls_tls_createsecurecontext_options # -> Full list of accepted options: https://nodejs.org/api/tls.html#tls_tls_createsecurecontext_options
sslOptions: sslOptions:
...@@ -43,12 +38,6 @@ db: ...@@ -43,12 +38,6 @@ db:
# pfx: path/to/cert.pfx # pfx: path/to/cert.pfx
# passphrase: xyz123 # passphrase: xyz123
# Optional - PostgreSQL only:
schema: public
# SQLite only:
storage: path/to/database.sqlite
####################################################################### #######################################################################
# ADVANCED OPTIONS # # ADVANCED OPTIONS #
####################################################################### #######################################################################
...@@ -102,15 +91,12 @@ pool: ...@@ -102,15 +91,12 @@ pool:
bindIP: 0.0.0.0 bindIP: 0.0.0.0
# --------------------------------------------------------------------- # ---------------------------------------------------------------------
# Log Level # Logging
# --------------------------------------------------------------------- # ---------------------------------------------------------------------
# Possible values: error, warn, info (default), verbose, debug, silly # Possible values: error, warn, info (default), verbose, debug, silly
logLevel: info logLevel: info
# ---------------------------------------------------------------------
# Log Format
# ---------------------------------------------------------------------
# Output format for logging, possible values: default, json # Output format for logging, possible values: default, json
logFormat: default logFormat: default
...@@ -124,15 +110,6 @@ logFormat: default ...@@ -124,15 +110,6 @@ logFormat: default
offline: false offline: false
# --------------------------------------------------------------------- # ---------------------------------------------------------------------
# High-Availability
# ---------------------------------------------------------------------
# Set to true if you have multiple concurrent instances running off the
# same DB (e.g. Kubernetes pods / load balanced instances). Leave false
# otherwise. You MUST be using PostgreSQL to use this feature.
ha: false
# ---------------------------------------------------------------------
# Data Path # Data Path
# --------------------------------------------------------------------- # ---------------------------------------------------------------------
# Writeable data path used for cache and temporary user uploads. # Writeable data path used for cache and temporary user uploads.
......
{ {
"name": "wiki", "name": "wiki",
"version": "2.0.0", "version": "3.0.0",
"releaseDate": "2019-01-01T01:01:01.000Z", "releaseDate": "2022-01-01T01:01:01.000Z",
"description": "A modern, lightweight and powerful wiki app built on NodeJS, Git and Markdown", "description": "The most powerful and extensible open source Wiki software",
"main": "wiki.js", "main": "wiki.js",
"dev": true, "dev": true,
"scripts": { "scripts": {
"start": "node server", "start": "node server",
"dev": "node dev", "dev": "node dev",
"build": "webpack --profile --config dev/webpack/webpack.prod.js",
"watch": "webpack --config dev/webpack/webpack.dev.js",
"test": "eslint --format codeframe --ext .js,.vue . && pug-lint server/views && jest", "test": "eslint --format codeframe --ext .js,.vue . && pug-lint server/views && jest",
"cypress:open": "cypress open" "cypress:open": "cypress open"
}, },
...@@ -33,7 +31,7 @@ ...@@ -33,7 +31,7 @@
}, },
"homepage": "https://github.com/Requarks/wiki#readme", "homepage": "https://github.com/Requarks/wiki#readme",
"engines": { "engines": {
"node": ">=10.12" "node": ">=16.0"
}, },
"dependencies": { "dependencies": {
"@azure/storage-blob": "12.2.1", "@azure/storage-blob": "12.2.1",
......
...@@ -8,16 +8,17 @@ defaults: ...@@ -8,16 +8,17 @@ defaults:
# File defaults # File defaults
port: 80 port: 80
db: db:
type: postgres
host: localhost host: localhost
port: 5432 port: 5432
user: wikijs user: wikijs
pass: wikijsrocks pass: wikijsrocks
db: wiki db: wiki
ssl: false ssl: false
storage: ./db.sqlite
sslOptions: sslOptions:
auto: true auto: true
schemas:
wiki: wiki
scheduler: scheduler
ssl: ssl:
enabled: false enabled: false
pool: pool:
...@@ -26,7 +27,6 @@ defaults: ...@@ -26,7 +27,6 @@ defaults:
logLevel: info logLevel: info
logFormat: default logFormat: default
offline: false offline: false
ha: false
bodyParserLimit: 5mb bodyParserLimit: 5mb
# DB defaults # DB defaults
api: api:
...@@ -88,7 +88,7 @@ defaults: ...@@ -88,7 +88,7 @@ defaults:
ldapdebug: false ldapdebug: false
sqllog: false sqllog: false
# System defaults # System defaults
channel: STABLE channel: NEXT
setup: false setup: false
dataPath: ./data dataPath: ./data
cors: cors:
......
...@@ -7,7 +7,7 @@ const fs = require('fs') ...@@ -7,7 +7,7 @@ const fs = require('fs')
const Objection = require('objection') const Objection = require('objection')
const migrationSource = require('../db/migrator-source') const migrationSource = require('../db/migrator-source')
const migrateFromBeta = require('../db/beta') const migrateFromLegacy = require('../db/legacy')
/* global WIKI */ /* global WIKI */
...@@ -20,15 +20,12 @@ module.exports = { ...@@ -20,15 +20,12 @@ module.exports = {
listener: null, listener: null,
/** /**
* Initialize DB * Initialize DB
*
* @return {Object} DB instance
*/ */
init() { init() {
let self = this let self = this
// Fetch DB Config // Fetch DB Config
let dbClient = null
let dbConfig = (!_.isEmpty(process.env.DATABASE_URL)) ? process.env.DATABASE_URL : { let dbConfig = (!_.isEmpty(process.env.DATABASE_URL)) ? process.env.DATABASE_URL : {
host: WIKI.config.db.host.toString(), host: WIKI.config.db.host.toString(),
user: WIKI.config.db.user.toString(), user: WIKI.config.db.user.toString(),
...@@ -74,84 +71,22 @@ module.exports = { ...@@ -74,84 +71,22 @@ module.exports = {
} }
} }
// Engine-specific config if (dbUseSSL && _.isPlainObject(dbConfig)) {
switch (WIKI.config.db.type) { dbConfig.ssl = (sslOptions === true) ? { rejectUnauthorized: true } : sslOptions
case 'postgres':
dbClient = 'pg'
if (dbUseSSL && _.isPlainObject(dbConfig)) {
dbConfig.ssl = (sslOptions === true) ? { rejectUnauthorized: true } : sslOptions
}
break
case 'mariadb':
case 'mysql':
dbClient = 'mysql2'
if (dbUseSSL && _.isPlainObject(dbConfig)) {
dbConfig.ssl = sslOptions
}
// Fix mysql boolean handling...
dbConfig.typeCast = (field, next) => {
if (field.type === 'TINY' && field.length === 1) {
let value = field.string()
return value ? (value === '1') : null
}
return next()
}
break
case 'mssql':
dbClient = 'mssql'
if (_.isPlainObject(dbConfig)) {
dbConfig.appName = 'Wiki.js'
_.set(dbConfig, 'options.appName', 'Wiki.js')
dbConfig.enableArithAbort = true
_.set(dbConfig, 'options.enableArithAbort', true)
if (dbUseSSL) {
dbConfig.encrypt = true
_.set(dbConfig, 'options.encrypt', true)
}
}
break
case 'sqlite':
dbClient = 'sqlite3'
dbConfig = { filename: WIKI.config.db.storage }
break
default:
WIKI.logger.error('Invalid DB Type')
process.exit(1)
} }
// Initialize Knex // Initialize Knex
this.knex = Knex({ this.knex = Knex({
client: dbClient, client: 'pg',
useNullAsDefault: true, useNullAsDefault: true,
asyncStackTraces: WIKI.IS_DEBUG, asyncStackTraces: WIKI.IS_DEBUG,
connection: dbConfig, connection: dbConfig,
searchPath: [WIKI.config.db.schemas.wiki],
pool: { pool: {
...WIKI.config.pool, ...WIKI.config.pool,
async afterCreate(conn, done) { async afterCreate(conn, done) {
// -> Set Connection App Name // -> Set Connection App Name
switch (WIKI.config.db.type) { await conn.query(`set application_name = 'Wiki.js'`)
case 'postgres':
await conn.query(`set application_name = 'Wiki.js'`)
// -> Set schema if it's not public
if (WIKI.config.db.schema && WIKI.config.db.schema !== 'public') {
await conn.query(`set search_path TO ${WIKI.config.db.schema}, public;`)
}
done()
break
case 'mysql':
await conn.promise().query(`set autocommit = 1`)
done()
break
default:
done()
break
}
} }
}, },
debug: WIKI.IS_DEBUG debug: WIKI.IS_DEBUG
...@@ -191,18 +126,19 @@ module.exports = { ...@@ -191,18 +126,19 @@ module.exports = {
async syncSchemas () { async syncSchemas () {
return self.knex.migrate.latest({ return self.knex.migrate.latest({
tableName: 'migrations', tableName: 'migrations',
migrationSource migrationSource,
schemaName: WIKI.config.db.schemas.wiki
}) })
}, },
// -> Migrate DB Schemas from beta // -> Migrate DB Schemas from 2.x
async migrateFromBeta () { async migrateFromLegacy () {
return migrateFromBeta.migrate(self.knex) return migrateFromLegacy.migrate(self.knex)
} }
} }
let initTasksQueue = (WIKI.IS_MASTER) ? [ let initTasksQueue = (WIKI.IS_MASTER) ? [
initTasks.connect, initTasks.connect,
initTasks.migrateFromBeta, initTasks.migrateFromLegacy,
initTasks.syncSchemas initTasks.syncSchemas
] : [ ] : [
() => { return Promise.resolve() } () => { return Promise.resolve() }
...@@ -210,7 +146,6 @@ module.exports = { ...@@ -210,7 +146,6 @@ module.exports = {
// Perform init tasks // Perform init tasks
WIKI.logger.info(`Using database driver ${dbClient} for ${WIKI.config.db.type} [ OK ]`)
this.onReady = Promise.each(initTasksQueue, t => t()).return(true) this.onReady = Promise.each(initTasksQueue, t => t()).return(true)
return { return {
...@@ -222,14 +157,6 @@ module.exports = { ...@@ -222,14 +157,6 @@ module.exports = {
* Subscribe to database LISTEN / NOTIFY for multi-instances events * Subscribe to database LISTEN / NOTIFY for multi-instances events
*/ */
async subscribeToNotifications () { async subscribeToNotifications () {
const useHA = (WIKI.config.ha === true || WIKI.config.ha === 'true' || WIKI.config.ha === 1 || WIKI.config.ha === '1')
if (!useHA) {
return
} else if (WIKI.config.db.type !== 'postgres') {
WIKI.logger.warn(`Database engine doesn't support pub/sub. Will not handle concurrent instances: [ DISABLED ]`)
return
}
const PGPubSub = require('pg-pubsub') const PGPubSub = require('pg-pubsub')
this.listener = new PGPubSub(this.knex.client.connectionSettings, { this.listener = new PGPubSub(this.knex.client.connectionSettings, {
...@@ -254,7 +181,7 @@ module.exports = { ...@@ -254,7 +181,7 @@ module.exports = {
WIKI.configSvc.subscribeToEvents() WIKI.configSvc.subscribeToEvents()
WIKI.models.pages.subscribeToEvents() WIKI.models.pages.subscribeToEvents()
WIKI.logger.info(`High-Availability Listener initialized successfully: [ OK ]`) WIKI.logger.info(`PG PubSub Listener initialized successfully: [ OK ]`)
}, },
/** /**
* Unsubscribe from database LISTEN / NOTIFY * Unsubscribe from database LISTEN / NOTIFY
......
const _ = require('lodash')
const path = require('path')
const fs = require('fs-extra')
const semver = require('semver')
/* global WIKI */
module.exports = {
async migrate (knex) {
const migrationsTableExists = await knex.schema.hasTable('migrations')
if (!migrationsTableExists) {
return
}
const dbCompat = {
charset: (WIKI.config.db.type === `mysql` || WIKI.config.db.type === `mariadb`)
}
const migrations = await knex('migrations')
if (_.some(migrations, m => m.name.indexOf('2.0.0-beta') >= 0)) {
// -> Pre-beta.241 locale field length fix
const localeColnInfo = await knex('pages').columnInfo('localeCode')
if (WIKI.config.db.type !== 'sqlite' && localeColnInfo.maxLength === 2) {
// -> Load locales
const locales = await knex('locales')
await knex.schema
// -> Remove constraints
.table('users', table => {
table.dropForeign('localeCode')
})
.table('pages', table => {
table.dropForeign('localeCode')
})
.table('pageHistory', table => {
table.dropForeign('localeCode')
})
.table('pageTree', table => {
table.dropForeign('localeCode')
})
// -> Recreate locales table
.dropTable('locales')
.createTable('locales', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.string('code', 5).notNullable().primary()
table.json('strings')
table.boolean('isRTL').notNullable().defaultTo(false)
table.string('name').notNullable()
table.string('nativeName').notNullable()
table.integer('availability').notNullable().defaultTo(0)
table.string('createdAt').notNullable()
table.string('updatedAt').notNullable()
})
await knex('locales').insert(locales)
// -> Alter columns length
await knex.schema
.table('users', table => {
table.string('localeCode', 5).notNullable().defaultTo('en').alter()
})
.table('pages', table => {
table.string('localeCode', 5).alter()
})
.table('pageHistory', table => {
table.string('localeCode', 5).alter()
})
.table('pageTree', table => {
table.string('localeCode', 5).alter()
})
// -> Restore restraints
.table('users', table => {
table.foreign('localeCode').references('code').inTable('locales')
})
.table('pages', table => {
table.foreign('localeCode').references('code').inTable('locales')
})
.table('pageHistory', table => {
table.foreign('localeCode').references('code').inTable('locales')
})
.table('pageTree', table => {
table.foreign('localeCode').references('code').inTable('locales')
})
}
// -> Advance to latest beta/rc migration state
const baseMigrationPath = path.join(WIKI.SERVERPATH, (WIKI.config.db.type !== 'sqlite') ? 'db/beta/migrations' : 'db/beta/migrations-sqlite')
await knex.migrate.latest({
tableName: 'migrations',
migrationSource: {
async getMigrations() {
const migrationFiles = await fs.readdir(baseMigrationPath)
return migrationFiles.sort(semver.compare).map(m => ({
file: m,
directory: baseMigrationPath
}))
},
getMigrationName(migration) {
return migration.file
},
getMigration(migration) {
return require(path.join(baseMigrationPath, migration.file))
}
}
})
// -> Cleanup migration table
await knex('migrations').truncate()
// -> Advance to stable 2.0 migration state
await knex('migrations').insert({
name: '2.0.0.js',
batch: 1,
migration_time: knex.fn.now()
})
}
}
}
exports.up = knex => {
return knex.schema
// =====================================
// MODEL TABLES
// =====================================
// ASSETS ------------------------------
.createTable('assets', table => {
table.increments('id').primary()
table.string('filename').notNullable()
table.string('basename').notNullable()
table.string('ext').notNullable()
table.enum('kind', ['binary', 'image']).notNullable().defaultTo('binary')
table.string('mime').notNullable().defaultTo('application/octet-stream')
table.integer('fileSize').unsigned().comment('In kilobytes')
table.json('metadata')
table.string('createdAt').notNullable()
table.string('updatedAt').notNullable()
table.integer('folderId').unsigned().references('id').inTable('assetFolders')
table.integer('authorId').unsigned().references('id').inTable('users')
})
// ASSET FOLDERS -----------------------
.createTable('assetFolders', table => {
table.increments('id').primary()
table.string('name').notNullable()
table.string('slug').notNullable()
table.integer('parentId').unsigned().references('id').inTable('assetFolders')
})
// AUTHENTICATION ----------------------
.createTable('authentication', table => {
table.string('key').notNullable().primary()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.json('config').notNullable()
table.boolean('selfRegistration').notNullable().defaultTo(false)
table.json('domainWhitelist').notNullable()
table.json('autoEnrollGroups').notNullable()
})
// COMMENTS ----------------------------
.createTable('comments', table => {
table.increments('id').primary()
table.text('content').notNullable()
table.string('createdAt').notNullable()
table.string('updatedAt').notNullable()
table.integer('pageId').unsigned().references('id').inTable('pages')
table.integer('authorId').unsigned().references('id').inTable('users')
})
// EDITORS -----------------------------
.createTable('editors', table => {
table.string('key').notNullable().primary()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.json('config').notNullable()
})
// GROUPS ------------------------------
.createTable('groups', table => {
table.increments('id').primary()
table.string('name').notNullable()
table.json('permissions').notNullable()
table.json('pageRules').notNullable()
table.boolean('isSystem').notNullable().defaultTo(false)
table.string('createdAt').notNullable()
table.string('updatedAt').notNullable()
})
// LOCALES -----------------------------
.createTable('locales', table => {
table.string('code', 5).notNullable().primary()
table.json('strings')
table.boolean('isRTL').notNullable().defaultTo(false)
table.string('name').notNullable()
table.string('nativeName').notNullable()
table.string('createdAt').notNullable()
table.string('updatedAt').notNullable()
})
// LOGGING ----------------------------
.createTable('loggers', table => {
table.string('key').notNullable().primary()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.string('level').notNullable().defaultTo('warn')
table.json('config')
})
// NAVIGATION ----------------------------
.createTable('navigation', table => {
table.string('key').notNullable().primary()
table.json('config')
})
// PAGE HISTORY ------------------------
.createTable('pageHistory', table => {
table.increments('id').primary()
table.string('path').notNullable()
table.string('hash').notNullable()
table.string('title').notNullable()
table.string('description')
table.boolean('isPrivate').notNullable().defaultTo(false)
table.boolean('isPublished').notNullable().defaultTo(false)
table.string('publishStartDate')
table.string('publishEndDate')
table.text('content')
table.string('contentType').notNullable()
table.string('createdAt').notNullable()
table.integer('pageId').unsigned().references('id').inTable('pages')
table.string('editorKey').references('key').inTable('editors')
table.string('localeCode', 5).references('code').inTable('locales')
table.integer('authorId').unsigned().references('id').inTable('users')
})
// PAGES -------------------------------
.createTable('pages', table => {
table.increments('id').primary()
table.string('path').notNullable()
table.string('hash').notNullable()
table.string('title').notNullable()
table.string('description')
table.boolean('isPrivate').notNullable().defaultTo(false)
table.boolean('isPublished').notNullable().defaultTo(false)
table.string('privateNS')
table.string('publishStartDate')
table.string('publishEndDate')
table.text('content')
table.text('render')
table.json('toc')
table.string('contentType').notNullable()
table.string('createdAt').notNullable()
table.string('updatedAt').notNullable()
table.string('editorKey').references('key').inTable('editors')
table.string('localeCode', 5).references('code').inTable('locales')
table.integer('authorId').unsigned().references('id').inTable('users')
table.integer('creatorId').unsigned().references('id').inTable('users')
})
// PAGE TREE ---------------------------
.createTable('pageTree', table => {
table.increments('id').primary()
table.string('path').notNullable()
table.integer('depth').unsigned().notNullable()
table.string('title').notNullable()
table.boolean('isPrivate').notNullable().defaultTo(false)
table.boolean('isFolder').notNullable().defaultTo(false)
table.string('privateNS')
table.integer('parent').unsigned().references('id').inTable('pageTree')
table.integer('pageId').unsigned().references('id').inTable('pages')
table.string('localeCode', 5).references('code').inTable('locales')
})
// RENDERERS ---------------------------
.createTable('renderers', table => {
table.string('key').notNullable().primary()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.json('config')
})
// SEARCH ------------------------------
.createTable('searchEngines', table => {
table.string('key').notNullable().primary()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.json('config')
})
// SETTINGS ----------------------------
.createTable('settings', table => {
table.string('key').notNullable().primary()
table.json('value')
table.string('updatedAt').notNullable()
})
// STORAGE -----------------------------
.createTable('storage', table => {
table.string('key').notNullable().primary()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.string('mode', ['sync', 'push', 'pull']).notNullable().defaultTo('push')
table.json('config')
})
// TAGS --------------------------------
.createTable('tags', table => {
table.increments('id').primary()
table.string('tag').notNullable().unique()
table.string('title')
table.string('createdAt').notNullable()
table.string('updatedAt').notNullable()
})
// USER KEYS ---------------------------
.createTable('userKeys', table => {
table.increments('id').primary()
table.string('kind').notNullable()
table.string('token').notNullable()
table.string('createdAt').notNullable()
table.string('validUntil').notNullable()
table.integer('userId').unsigned().references('id').inTable('users')
})
// USERS -------------------------------
.createTable('users', table => {
table.increments('id').primary()
table.string('email').notNullable()
table.string('name').notNullable()
table.string('providerId')
table.string('password')
table.boolean('tfaIsActive').notNullable().defaultTo(false)
table.string('tfaSecret')
table.string('jobTitle').defaultTo('')
table.string('location').defaultTo('')
table.string('pictureUrl')
table.string('timezone').notNullable().defaultTo('America/New_York')
table.boolean('isSystem').notNullable().defaultTo(false)
table.boolean('isActive').notNullable().defaultTo(false)
table.boolean('isVerified').notNullable().defaultTo(false)
table.string('createdAt').notNullable()
table.string('updatedAt').notNullable()
table.string('providerKey').references('key').inTable('authentication').notNullable().defaultTo('local')
table.string('localeCode', 5).references('code').inTable('locales').notNullable().defaultTo('en')
table.string('defaultEditor').references('key').inTable('editors').notNullable().defaultTo('markdown')
})
// =====================================
// RELATION TABLES
// =====================================
// PAGE HISTORY TAGS ---------------------------
.createTable('pageHistoryTags', table => {
table.increments('id').primary()
table.integer('pageId').unsigned().references('id').inTable('pageHistory').onDelete('CASCADE')
table.integer('tagId').unsigned().references('id').inTable('tags').onDelete('CASCADE')
})
// PAGE TAGS ---------------------------
.createTable('pageTags', table => {
table.increments('id').primary()
table.integer('pageId').unsigned().references('id').inTable('pages').onDelete('CASCADE')
table.integer('tagId').unsigned().references('id').inTable('tags').onDelete('CASCADE')
})
// USER GROUPS -------------------------
.createTable('userGroups', table => {
table.increments('id').primary()
table.integer('userId').unsigned().references('id').inTable('users').onDelete('CASCADE')
table.integer('groupId').unsigned().references('id').inTable('groups').onDelete('CASCADE')
})
// =====================================
// REFERENCES
// =====================================
.table('users', table => {
table.unique(['providerKey', 'email'])
})
}
exports.down = knex => {
return knex.schema
.dropTableIfExists('userGroups')
.dropTableIfExists('pageHistoryTags')
.dropTableIfExists('pageHistory')
.dropTableIfExists('pageTags')
.dropTableIfExists('assets')
.dropTableIfExists('assetFolders')
.dropTableIfExists('comments')
.dropTableIfExists('editors')
.dropTableIfExists('groups')
.dropTableIfExists('locales')
.dropTableIfExists('navigation')
.dropTableIfExists('pages')
.dropTableIfExists('renderers')
.dropTableIfExists('settings')
.dropTableIfExists('storage')
.dropTableIfExists('tags')
.dropTableIfExists('userKeys')
.dropTableIfExists('users')
}
exports.up = knex => {
return knex.schema
.renameTable('pageHistory', 'pageHistory_old')
.createTable('pageHistory', table => {
table.increments('id').primary()
table.string('path').notNullable()
table.string('hash').notNullable()
table.string('title').notNullable()
table.string('description')
table.boolean('isPrivate').notNullable().defaultTo(false)
table.boolean('isPublished').notNullable().defaultTo(false)
table.string('publishStartDate')
table.string('publishEndDate')
table.text('content')
table.string('contentType').notNullable()
table.string('createdAt').notNullable()
table.string('action').defaultTo('updated')
table.integer('pageId').unsigned()
table.string('editorKey').references('key').inTable('editors')
table.string('localeCode', 5).references('code').inTable('locales')
table.integer('authorId').unsigned().references('id').inTable('users')
})
.raw(`INSERT INTO pageHistory SELECT id,path,hash,title,description,isPrivate,isPublished,publishStartDate,publishEndDate,content,contentType,createdAt,'updated' AS action,pageId,editorKey,localeCode,authorId FROM pageHistory_old;`)
.dropTable('pageHistory_old')
}
exports.down = knex => {
return knex.schema
.renameTable('pageHistory', 'pageHistory_old')
.createTable('pageHistory', table => {
table.increments('id').primary()
table.string('path').notNullable()
table.string('hash').notNullable()
table.string('title').notNullable()
table.string('description')
table.boolean('isPrivate').notNullable().defaultTo(false)
table.boolean('isPublished').notNullable().defaultTo(false)
table.string('publishStartDate')
table.string('publishEndDate')
table.text('content')
table.string('contentType').notNullable()
table.string('createdAt').notNullable()
table.integer('pageId').unsigned().references('id').inTable('pages')
table.string('editorKey').references('key').inTable('editors')
table.string('localeCode', 5).references('code').inTable('locales')
table.integer('authorId').unsigned().references('id').inTable('users')
})
.raw('INSERT INTO pageHistory SELECT id,path,hash,title,description,isPrivate,isPublished,publishStartDate,publishEndDate,content,contentType,createdAt,NULL as pageId,editorKey,localeCode,authorId FROM pageHistory_old;')
.dropTable('pageHistory_old')
}
exports.up = knex => {
return knex.schema
.table('assets', table => {
table.dropColumn('basename')
table.string('hash').notNullable().defaultTo('')
})
}
exports.down = knex => {
return knex.schema
.table('assets', table => {
table.dropColumn('hash')
table.string('basename').notNullable().defaultTo('')
})
}
exports.up = knex => {
return knex.schema
.createTable('analytics', table => {
table.string('key').notNullable().primary()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.json('config').notNullable()
})
}
exports.down = knex => {
return knex.schema
.dropTableIfExists('analytics')
}
exports.up = knex => {
return knex.schema
.table('locales', table => {
table.integer('availability').notNullable().defaultTo(0)
})
}
exports.down = knex => {
return knex.schema
.table('locales', table => {
table.dropColumn('availability')
})
}
exports.up = knex => {
return knex.schema
.table('users', table => {
table.boolean('mustChangePwd').notNullable().defaultTo(false)
})
}
exports.down = knex => {
return knex.schema
.table('users', table => {
table.dropColumn('mustChangePwd')
})
}
exports.up = knex => {
return knex.schema
.createTable('pageLinks', table => {
table.increments('id').primary()
table.integer('pageId').unsigned().references('id').inTable('pages').onDelete('CASCADE')
table.string('path').notNullable()
table.string('localeCode', 5).notNullable()
})
.table('pageLinks', table => {
table.index(['path', 'localeCode'])
})
}
exports.down = knex => {
return knex.schema
.dropTableIfExists('pageLinks')
}
exports.up = knex => {
return knex.schema
.table('storage', table => {
table.string('syncInterval')
table.json('state')
})
}
exports.down = knex => {
return knex.schema
.table('storage', table => {
table.dropColumn('syncInterval')
table.dropColumn('state')
})
}
exports.up = knex => {
return knex.schema
.createTable('assetData', table => {
table.integer('id').primary()
table.binary('data').notNullable()
})
}
exports.down = knex => {
return knex.schema
.dropTableIfExists('assetData')
}
exports.up = knex => {
return knex.schema
.dropTable('pageTree')
.createTable('pageTree', table => {
table.integer('id').primary()
table.string('path').notNullable()
table.integer('depth').unsigned().notNullable()
table.string('title').notNullable()
table.boolean('isPrivate').notNullable().defaultTo(false)
table.boolean('isFolder').notNullable().defaultTo(false)
table.string('privateNS')
table.integer('parent').unsigned().references('id').inTable('pageTree').onDelete('CASCADE')
table.integer('pageId').unsigned().references('id').inTable('pages').onDelete('CASCADE')
table.string('localeCode', 5).references('code').inTable('locales')
})
}
exports.down = knex => {
return knex.schema
.dropTable('pageTree')
.createTable('pageTree', table => {
table.integer('id').primary()
table.string('path').notNullable()
table.integer('depth').unsigned().notNullable()
table.string('title').notNullable()
table.boolean('isPrivate').notNullable().defaultTo(false)
table.boolean('isFolder').notNullable().defaultTo(false)
table.string('privateNS')
table.integer('parent').unsigned().references('id').inTable('pageTree')
table.integer('pageId').unsigned().references('id').inTable('pages')
table.string('localeCode', 5).references('code').inTable('locales')
})
}
/* global WIKI */
exports.up = knex => {
const dbCompat = {
charset: (WIKI.config.db.type === `mysql` || WIKI.config.db.type === `mariadb`)
}
return knex.schema
// =====================================
// MODEL TABLES
// =====================================
// ASSETS ------------------------------
.createTable('assets', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.increments('id').primary()
table.string('filename').notNullable()
table.string('basename').notNullable()
table.string('ext').notNullable()
table.enum('kind', ['binary', 'image']).notNullable().defaultTo('binary')
table.string('mime').notNullable().defaultTo('application/octet-stream')
table.integer('fileSize').unsigned().comment('In kilobytes')
table.json('metadata')
table.string('createdAt').notNullable()
table.string('updatedAt').notNullable()
})
// ASSET FOLDERS -----------------------
.createTable('assetFolders', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.increments('id').primary()
table.string('name').notNullable()
table.string('slug').notNullable()
table.integer('parentId').unsigned().references('id').inTable('assetFolders')
})
// AUTHENTICATION ----------------------
.createTable('authentication', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.string('key').notNullable().primary()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.json('config').notNullable()
table.boolean('selfRegistration').notNullable().defaultTo(false)
table.json('domainWhitelist').notNullable()
table.json('autoEnrollGroups').notNullable()
})
// COMMENTS ----------------------------
.createTable('comments', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.increments('id').primary()
table.text('content').notNullable()
table.string('createdAt').notNullable()
table.string('updatedAt').notNullable()
})
// EDITORS -----------------------------
.createTable('editors', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.string('key').notNullable().primary()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.json('config').notNullable()
})
// GROUPS ------------------------------
.createTable('groups', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.increments('id').primary()
table.string('name').notNullable()
table.json('permissions').notNullable()
table.json('pageRules').notNullable()
table.boolean('isSystem').notNullable().defaultTo(false)
table.string('createdAt').notNullable()
table.string('updatedAt').notNullable()
})
// LOCALES -----------------------------
.createTable('locales', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.string('code', 2).notNullable().primary()
table.json('strings')
table.boolean('isRTL').notNullable().defaultTo(false)
table.string('name').notNullable()
table.string('nativeName').notNullable()
table.string('createdAt').notNullable()
table.string('updatedAt').notNullable()
})
// LOGGING ----------------------------
.createTable('loggers', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.string('key').notNullable().primary()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.string('level').notNullable().defaultTo('warn')
table.json('config')
})
// NAVIGATION ----------------------------
.createTable('navigation', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.string('key').notNullable().primary()
table.json('config')
})
// PAGE HISTORY ------------------------
.createTable('pageHistory', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.increments('id').primary()
table.string('path').notNullable()
table.string('hash').notNullable()
table.string('title').notNullable()
table.string('description')
table.boolean('isPrivate').notNullable().defaultTo(false)
table.boolean('isPublished').notNullable().defaultTo(false)
table.string('publishStartDate')
table.string('publishEndDate')
table.text('content')
table.string('contentType').notNullable()
table.string('createdAt').notNullable()
})
// PAGES -------------------------------
.createTable('pages', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.increments('id').primary()
table.string('path').notNullable()
table.string('hash').notNullable()
table.string('title').notNullable()
table.string('description')
table.boolean('isPrivate').notNullable().defaultTo(false)
table.boolean('isPublished').notNullable().defaultTo(false)
table.string('privateNS')
table.string('publishStartDate')
table.string('publishEndDate')
table.text('content')
table.text('render')
table.json('toc')
table.string('contentType').notNullable()
table.string('createdAt').notNullable()
table.string('updatedAt').notNullable()
})
// PAGE TREE ---------------------------
.createTable('pageTree', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.increments('id').primary()
table.string('path').notNullable()
table.integer('depth').unsigned().notNullable()
table.string('title').notNullable()
table.boolean('isPrivate').notNullable().defaultTo(false)
table.boolean('isFolder').notNullable().defaultTo(false)
table.string('privateNS')
})
// RENDERERS ---------------------------
.createTable('renderers', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.string('key').notNullable().primary()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.json('config')
})
// SEARCH ------------------------------
.createTable('searchEngines', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.string('key').notNullable().primary()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.json('config')
})
// SETTINGS ----------------------------
.createTable('settings', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.string('key').notNullable().primary()
table.json('value')
table.string('updatedAt').notNullable()
})
// STORAGE -----------------------------
.createTable('storage', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.string('key').notNullable().primary()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.string('mode', ['sync', 'push', 'pull']).notNullable().defaultTo('push')
table.json('config')
})
// TAGS --------------------------------
.createTable('tags', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.increments('id').primary()
table.string('tag').notNullable().unique()
table.string('title')
table.string('createdAt').notNullable()
table.string('updatedAt').notNullable()
})
// USER KEYS ---------------------------
.createTable('userKeys', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.increments('id').primary()
table.string('kind').notNullable()
table.string('token').notNullable()
table.string('createdAt').notNullable()
table.string('validUntil').notNullable()
})
// USERS -------------------------------
.createTable('users', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.increments('id').primary()
table.string('email').notNullable()
table.string('name').notNullable()
table.string('providerId')
table.string('password')
table.boolean('tfaIsActive').notNullable().defaultTo(false)
table.string('tfaSecret')
table.string('jobTitle').defaultTo('')
table.string('location').defaultTo('')
table.string('pictureUrl')
table.string('timezone').notNullable().defaultTo('America/New_York')
table.boolean('isSystem').notNullable().defaultTo(false)
table.boolean('isActive').notNullable().defaultTo(false)
table.boolean('isVerified').notNullable().defaultTo(false)
table.string('createdAt').notNullable()
table.string('updatedAt').notNullable()
})
// =====================================
// RELATION TABLES
// =====================================
// PAGE HISTORY TAGS ---------------------------
.createTable('pageHistoryTags', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.increments('id').primary()
table.integer('pageId').unsigned().references('id').inTable('pageHistory').onDelete('CASCADE')
table.integer('tagId').unsigned().references('id').inTable('tags').onDelete('CASCADE')
})
// PAGE TAGS ---------------------------
.createTable('pageTags', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.increments('id').primary()
table.integer('pageId').unsigned().references('id').inTable('pages').onDelete('CASCADE')
table.integer('tagId').unsigned().references('id').inTable('tags').onDelete('CASCADE')
})
// USER GROUPS -------------------------
.createTable('userGroups', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.increments('id').primary()
table.integer('userId').unsigned().references('id').inTable('users').onDelete('CASCADE')
table.integer('groupId').unsigned().references('id').inTable('groups').onDelete('CASCADE')
})
// =====================================
// REFERENCES
// =====================================
.table('assets', table => {
table.integer('folderId').unsigned().references('id').inTable('assetFolders')
table.integer('authorId').unsigned().references('id').inTable('users')
})
.table('comments', table => {
table.integer('pageId').unsigned().references('id').inTable('pages')
table.integer('authorId').unsigned().references('id').inTable('users')
})
.table('pageHistory', table => {
table.integer('pageId').unsigned().references('id').inTable('pages')
table.string('editorKey').references('key').inTable('editors')
table.string('localeCode', 2).references('code').inTable('locales')
table.integer('authorId').unsigned().references('id').inTable('users')
})
.table('pages', table => {
table.string('editorKey').references('key').inTable('editors')
table.string('localeCode', 2).references('code').inTable('locales')
table.integer('authorId').unsigned().references('id').inTable('users')
table.integer('creatorId').unsigned().references('id').inTable('users')
})
.table('pageTree', table => {
table.integer('parent').unsigned().references('id').inTable('pageTree')
table.integer('pageId').unsigned().references('id').inTable('pages')
table.string('localeCode', 2).references('code').inTable('locales')
})
.table('userKeys', table => {
table.integer('userId').unsigned().references('id').inTable('users')
})
.table('users', table => {
table.string('providerKey').references('key').inTable('authentication').notNullable().defaultTo('local')
table.string('localeCode', 2).references('code').inTable('locales').notNullable().defaultTo('en')
table.string('defaultEditor').references('key').inTable('editors').notNullable().defaultTo('markdown')
table.unique(['providerKey', 'email'])
})
}
exports.down = knex => {
return knex.schema
.dropTableIfExists('userGroups')
.dropTableIfExists('pageHistoryTags')
.dropTableIfExists('pageHistory')
.dropTableIfExists('pageTags')
.dropTableIfExists('assets')
.dropTableIfExists('assetFolders')
.dropTableIfExists('comments')
.dropTableIfExists('editors')
.dropTableIfExists('groups')
.dropTableIfExists('locales')
.dropTableIfExists('navigation')
.dropTableIfExists('pages')
.dropTableIfExists('renderers')
.dropTableIfExists('settings')
.dropTableIfExists('storage')
.dropTableIfExists('tags')
.dropTableIfExists('userKeys')
.dropTableIfExists('users')
}
exports.up = knex => {
return knex.schema
.table('pageHistory', table => {
table.string('action').defaultTo('updated')
table.dropForeign('pageId')
})
}
exports.down = knex => {
return knex.schema
.table('pageHistory', table => {
table.dropColumn('action')
table.integer('pageId').unsigned().references('id').inTable('pages')
})
}
exports.up = knex => {
return knex.schema
.table('assets', table => {
table.dropColumn('basename')
table.string('hash').notNullable()
})
}
exports.down = knex => {
return knex.schema
.table('assets', table => {
table.dropColumn('hash')
table.string('basename').notNullable()
})
}
/* global WIKI */
exports.up = knex => {
const dbCompat = {
blobLength: (WIKI.config.db.type === `mysql` || WIKI.config.db.type === `mariadb`)
}
return knex.schema
.table('assetData', table => {
if (dbCompat.blobLength) {
table.dropColumn('data')
}
})
.table('assetData', table => {
if (dbCompat.blobLength) {
table.specificType('data', 'LONGBLOB').notNullable()
}
})
}
exports.down = knex => {
return knex.schema
.table('assetData', table => {})
}
/* global WIKI */
exports.up = knex => {
const dbCompat = {
charset: (WIKI.config.db.type === `mysql` || WIKI.config.db.type === `mariadb`)
}
return knex.schema
.createTable('analytics', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.string('key').notNullable().primary()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.json('config').notNullable()
})
}
exports.down = knex => {
return knex.schema
.dropTableIfExists('analytics')
}
exports.up = knex => {
return knex.schema
.table('locales', table => {
table.integer('availability').notNullable().defaultTo(0)
})
}
exports.down = knex => {
return knex.schema
.table('locales', table => {
table.dropColumn('availability')
})
}
exports.up = knex => {
return knex.schema
.table('users', table => {
table.boolean('mustChangePwd').notNullable().defaultTo(false)
})
}
exports.down = knex => {
return knex.schema
.table('users', table => {
table.dropColumn('mustChangePwd')
})
}
/* global WIKI */
exports.up = knex => {
const dbCompat = {
charset: (WIKI.config.db.type === `mysql` || WIKI.config.db.type === `mariadb`)
}
return knex.schema
.createTable('pageLinks', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.increments('id').primary()
table.integer('pageId').unsigned().references('id').inTable('pages').onDelete('CASCADE')
table.string('path').notNullable()
table.string('localeCode', 5).notNullable()
})
.table('pageLinks', table => {
table.index(['path', 'localeCode'])
})
}
exports.down = knex => {
return knex.schema
.dropTableIfExists('pageLinks')
}
exports.up = knex => {
return knex.schema
.table('storage', table => {
table.string('syncInterval')
table.json('state')
})
}
exports.down = knex => {
return knex.schema
.table('storage', table => {
table.dropColumn('syncInterval')
table.dropColumn('state')
})
}
/* global WIKI */
exports.up = knex => {
const dbCompat = {
charset: (WIKI.config.db.type === `mysql` || WIKI.config.db.type === `mariadb`)
}
return knex.schema
.createTable('assetData', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.integer('id').primary()
table.binary('data').notNullable()
})
}
exports.down = knex => {
return knex.schema
.dropTableIfExists('assetData')
}
/* global WIKI */
exports.up = async knex => {
const dbCompat = {
charset: (WIKI.config.db.type === `mysql` || WIKI.config.db.type === `mariadb`),
selfCascadeDelete: WIKI.config.db.type !== 'mssql'
}
return knex.schema
.dropTable('pageTree')
.createTable('pageTree', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.integer('id').unsigned().primary()
table.string('path').notNullable()
table.integer('depth').unsigned().notNullable()
table.string('title').notNullable()
table.boolean('isPrivate').notNullable().defaultTo(false)
table.boolean('isFolder').notNullable().defaultTo(false)
table.string('privateNS')
})
.table('pageTree', table => {
if (dbCompat.selfCascadeDelete) {
table.integer('parent').unsigned().references('id').inTable('pageTree').onDelete('CASCADE')
} else {
table.integer('parent').unsigned()
}
table.integer('pageId').unsigned().references('id').inTable('pages').onDelete('CASCADE')
table.string('localeCode', 5).references('code').inTable('locales')
})
}
exports.down = knex => {
const dbCompat = {
charset: (WIKI.config.db.type === `mysql` || WIKI.config.db.type === `mariadb`),
selfCascadeDelete: WIKI.config.db.type !== 'mssql'
}
return knex.schema
.dropTable('pageTree')
.createTable('pageTree', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.integer('id').primary()
table.string('path').notNullable()
table.integer('depth').unsigned().notNullable()
table.string('title').notNullable()
table.boolean('isPrivate').notNullable().defaultTo(false)
table.boolean('isFolder').notNullable().defaultTo(false)
table.string('privateNS')
})
.table('pageTree', table => {
table.integer('parent').unsigned().references('id').inTable('pageTree')
table.integer('pageId').unsigned().references('id').inTable('pages')
table.string('localeCode', 5).references('code').inTable('locales')
})
}
/* global WIKI */
exports.up = knex => {
return knex.schema
.table('pages', table => {
switch (WIKI.config.db.type) {
case 'mariadb':
case 'mysql':
table.specificType('content', 'LONGTEXT').alter()
table.specificType('render', 'LONGTEXT').alter()
break
case 'mssql':
table.specificType('content', 'VARCHAR(max)').alter()
table.specificType('render', 'VARCHAR(max)').alter()
break
}
})
}
exports.down = knex => { }
const _ = require('lodash')
/* global WIKI */
module.exports = {
async migrate (knex) {
const migrationsTableExists = await knex.schema.hasTable('migrations')
if (!migrationsTableExists) {
return
}
const migrations = await knex('migrations')
if (_.some(migrations, m => m.name.indexOf('2.5.128') >= 0)) {
// TODO: 2.x MIGRATIONS for 3.0
WIKI.logger.error('Upgrading from 2.x is not yet supported. A future release will allow for upgrade from 2.x. Exiting...')
process.exit(1)
// -> Cleanup migration table
await knex('migrations').truncate()
// -> Advance to stable 3.0 migration state
await knex('migrations').insert({
name: '3.0.0.js',
batch: 1,
migration_time: knex.fn.now()
})
} else {
console.error('CANNOT UPGRADE FROM OLDER UNSUPPORTED VERSION. UPGRADE TO THE LATEST 2.X VERSION FIRST! Exiting...')
process.exit(1)
}
}
}
exports.up = knex => {
return knex.schema
// =====================================
// MODEL TABLES
// =====================================
// ANALYTICS ---------------------------
.createTable('analytics', table => {
table.string('key').notNullable().primary()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.json('config').notNullable()
})
// ASSETS ------------------------------
.createTable('assets', table => {
table.increments('id').primary()
table.string('filename').notNullable()
table.string('hash').notNullable().defaultTo('')
table.string('ext').notNullable()
table.enum('kind', ['binary', 'image']).notNullable().defaultTo('binary')
table.string('mime').notNullable().defaultTo('application/octet-stream')
table.integer('fileSize').unsigned().comment('In kilobytes')
table.json('metadata')
table.string('createdAt').notNullable()
table.string('updatedAt').notNullable()
table.integer('folderId').unsigned().references('id').inTable('assetFolders')
table.integer('authorId').unsigned().references('id').inTable('users')
})
// ASSET DATA --------------------------
.createTable('assetData', table => {
table.integer('id').primary()
table.binary('data').notNullable()
})
// ASSET FOLDERS -----------------------
.createTable('assetFolders', table => {
table.increments('id').primary()
table.string('name').notNullable()
table.string('slug').notNullable()
table.integer('parentId').unsigned().references('id').inTable('assetFolders')
})
// AUTHENTICATION ----------------------
.createTable('authentication', table => {
table.string('key').notNullable().primary()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.json('config').notNullable()
table.boolean('selfRegistration').notNullable().defaultTo(false)
table.json('domainWhitelist').notNullable()
table.json('autoEnrollGroups').notNullable()
})
// COMMENTS ----------------------------
.createTable('comments', table => {
table.increments('id').primary()
table.text('content').notNullable()
table.string('createdAt').notNullable()
table.string('updatedAt').notNullable()
table.integer('pageId').unsigned().references('id').inTable('pages')
table.integer('authorId').unsigned().references('id').inTable('users')
})
// EDITORS -----------------------------
.createTable('editors', table => {
table.string('key').notNullable().primary()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.json('config').notNullable()
})
// GROUPS ------------------------------
.createTable('groups', table => {
table.increments('id').primary()
table.string('name').notNullable()
table.json('permissions').notNullable()
table.json('pageRules').notNullable()
table.boolean('isSystem').notNullable().defaultTo(false)
table.string('createdAt').notNullable()
table.string('updatedAt').notNullable()
})
// LOCALES -----------------------------
.createTable('locales', table => {
table.string('code', 5).notNullable().primary()
table.json('strings')
table.boolean('isRTL').notNullable().defaultTo(false)
table.string('name').notNullable()
table.string('nativeName').notNullable()
table.integer('availability').notNullable().defaultTo(0)
table.string('createdAt').notNullable()
table.string('updatedAt').notNullable()
})
// LOGGING ----------------------------
.createTable('loggers', table => {
table.string('key').notNullable().primary()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.string('level').notNullable().defaultTo('warn')
table.json('config')
})
// NAVIGATION ----------------------------
.createTable('navigation', table => {
table.string('key').notNullable().primary()
table.json('config')
})
// PAGE HISTORY ------------------------
.createTable('pageHistory', table => {
table.increments('id').primary()
table.string('path').notNullable()
table.string('hash').notNullable()
table.string('title').notNullable()
table.string('description')
table.boolean('isPrivate').notNullable().defaultTo(false)
table.boolean('isPublished').notNullable().defaultTo(false)
table.string('publishStartDate')
table.string('publishEndDate')
table.text('content')
table.string('contentType').notNullable()
table.string('createdAt').notNullable()
table.string('action').defaultTo('updated')
table.integer('pageId').unsigned()
table.string('editorKey').references('key').inTable('editors')
table.string('localeCode', 5).references('code').inTable('locales')
table.integer('authorId').unsigned().references('id').inTable('users')
})
// PAGE LINKS --------------------------
.createTable('pageLinks', table => {
table.increments('id').primary()
table.integer('pageId').unsigned().references('id').inTable('pages').onDelete('CASCADE')
table.string('path').notNullable()
table.string('localeCode', 5).notNullable()
})
// PAGES -------------------------------
.createTable('pages', table => {
table.increments('id').primary()
table.string('path').notNullable()
table.string('hash').notNullable()
table.string('title').notNullable()
table.string('description')
table.boolean('isPrivate').notNullable().defaultTo(false)
table.boolean('isPublished').notNullable().defaultTo(false)
table.string('privateNS')
table.string('publishStartDate')
table.string('publishEndDate')
table.text('content')
table.text('render')
table.json('toc')
table.string('contentType').notNullable()
table.string('createdAt').notNullable()
table.string('updatedAt').notNullable()
table.string('editorKey').references('key').inTable('editors')
table.string('localeCode', 5).references('code').inTable('locales')
table.integer('authorId').unsigned().references('id').inTable('users')
table.integer('creatorId').unsigned().references('id').inTable('users')
})
// PAGE TREE ---------------------------
.createTable('pageTree', table => {
table.integer('id').primary()
table.string('path').notNullable()
table.integer('depth').unsigned().notNullable()
table.string('title').notNullable()
table.boolean('isPrivate').notNullable().defaultTo(false)
table.boolean('isFolder').notNullable().defaultTo(false)
table.string('privateNS')
table.integer('parent').unsigned().references('id').inTable('pageTree').onDelete('CASCADE')
table.integer('pageId').unsigned().references('id').inTable('pages').onDelete('CASCADE')
table.string('localeCode', 5).references('code').inTable('locales')
})
// RENDERERS ---------------------------
.createTable('renderers', table => {
table.string('key').notNullable().primary()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.json('config')
})
// SEARCH ------------------------------
.createTable('searchEngines', table => {
table.string('key').notNullable().primary()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.json('config')
})
// SETTINGS ----------------------------
.createTable('settings', table => {
table.string('key').notNullable().primary()
table.json('value')
table.string('updatedAt').notNullable()
})
// STORAGE -----------------------------
.createTable('storage', table => {
table.string('key').notNullable().primary()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.string('mode', ['sync', 'push', 'pull']).notNullable().defaultTo('push')
table.json('config')
table.string('syncInterval')
table.json('state')
})
// TAGS --------------------------------
.createTable('tags', table => {
table.increments('id').primary()
table.string('tag').notNullable().unique()
table.string('title')
table.string('createdAt').notNullable()
table.string('updatedAt').notNullable()
})
// USER KEYS ---------------------------
.createTable('userKeys', table => {
table.increments('id').primary()
table.string('kind').notNullable()
table.string('token').notNullable()
table.string('createdAt').notNullable()
table.string('validUntil').notNullable()
table.integer('userId').unsigned().references('id').inTable('users')
})
// USERS -------------------------------
.createTable('users', table => {
table.increments('id').primary()
table.string('email').notNullable()
table.string('name').notNullable()
table.string('providerId')
table.string('password')
table.boolean('tfaIsActive').notNullable().defaultTo(false)
table.string('tfaSecret')
table.string('jobTitle').defaultTo('')
table.string('location').defaultTo('')
table.string('pictureUrl')
table.string('timezone').notNullable().defaultTo('America/New_York')
table.boolean('isSystem').notNullable().defaultTo(false)
table.boolean('isActive').notNullable().defaultTo(false)
table.boolean('isVerified').notNullable().defaultTo(false)
table.boolean('mustChangePwd').notNullable().defaultTo(false)
table.string('createdAt').notNullable()
table.string('updatedAt').notNullable()
table.string('providerKey').references('key').inTable('authentication').notNullable().defaultTo('local')
table.string('localeCode', 5).references('code').inTable('locales').notNullable().defaultTo('en')
table.string('defaultEditor').references('key').inTable('editors').notNullable().defaultTo('markdown')
})
// =====================================
// RELATION TABLES
// =====================================
// PAGE HISTORY TAGS ---------------------------
.createTable('pageHistoryTags', table => {
table.increments('id').primary()
table.integer('pageId').unsigned().references('id').inTable('pageHistory').onDelete('CASCADE')
table.integer('tagId').unsigned().references('id').inTable('tags').onDelete('CASCADE')
})
// PAGE TAGS ---------------------------
.createTable('pageTags', table => {
table.increments('id').primary()
table.integer('pageId').unsigned().references('id').inTable('pages').onDelete('CASCADE')
table.integer('tagId').unsigned().references('id').inTable('tags').onDelete('CASCADE')
})
// USER GROUPS -------------------------
.createTable('userGroups', table => {
table.increments('id').primary()
table.integer('userId').unsigned().references('id').inTable('users').onDelete('CASCADE')
table.integer('groupId').unsigned().references('id').inTable('groups').onDelete('CASCADE')
})
// =====================================
// REFERENCES
// =====================================
.table('users', table => {
table.unique(['providerKey', 'email'])
})
// =====================================
// INDEXES
// =====================================
.table('pageLinks', table => {
table.index(['path', 'localeCode'])
})
}
exports.down = knex => { }
exports.up = knex => {
return knex.schema
.alterTable('pageHistory', table => {
table.string('versionDate').notNullable().defaultTo('')
})
.raw(`UPDATE pageHistory AS h1 SET versionDate = COALESCE((SELECT createdAt FROM pageHistory AS h2 WHERE h2.pageId = h1.pageId AND h2.id < h1.id ORDER BY h2.id DESC LIMIT 1), h1.createdAt, '')`)
}
exports.down = knex => { }
exports.up = knex => {
return knex.schema
.createTable('apiKeys', table => {
table.increments('id').primary()
table.string('name').notNullable()
table.text('key').notNullable()
table.string('expiration').notNullable()
table.boolean('isRevoked').notNullable().defaultTo(false)
table.string('createdAt').notNullable()
table.string('updatedAt').notNullable()
})
}
exports.down = knex => { }
exports.up = knex => {
return knex.schema
.alterTable('users', table => {
table.string('lastLoginAt')
})
}
exports.down = knex => { }
exports.up = knex => {
return knex.schema
.createTable('commentProviders', table => {
table.string('key').notNullable().primary()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.json('config').notNullable()
})
}
exports.down = knex => { }
exports.up = knex => {
return knex.schema
.alterTable('pageTree', table => {
table.json('ancestors')
})
}
exports.down = knex => { }
exports.up = knex => {
return knex.schema
.alterTable('pages', table => {
table.json('extra').notNullable().defaultTo('{}')
})
.alterTable('pageHistory', table => {
table.json('extra').notNullable().defaultTo('{}')
})
.alterTable('users', table => {
table.string('dateFormat').notNullable().defaultTo('')
table.string('appearance').notNullable().defaultTo('')
})
}
exports.down = knex => { }
exports.up = knex => {
return knex.schema
.alterTable('comments', table => {
table.text('render').notNullable().defaultTo('')
table.string('name').notNullable().defaultTo('')
table.string('email').notNullable().defaultTo('')
table.string('ip').notNullable().defaultTo('')
})
}
exports.down = knex => { }
exports.up = knex => {
return knex.schema
.alterTable('comments', table => {
table.integer('replyTo').unsigned().notNullable().defaultTo(0)
})
}
exports.down = knex => { }
exports.up = async knex => {
// Check for users using disabled strategies
let protectedStrategies = []
const disabledStrategies = await knex('authentication').where('isEnabled', false)
if (disabledStrategies) {
const incompatibleUsers = await knex('users').distinct('providerKey').whereIn('providerKey', disabledStrategies.map(s => s.key))
if (incompatibleUsers && incompatibleUsers.length > 0) {
protectedStrategies = incompatibleUsers.map(u => u.providerKey)
}
}
// Delete disabled strategies
await knex('authentication').whereNotIn('key', protectedStrategies).andWhere('isEnabled', false).del()
// Update table schema
await knex.schema
.alterTable('authentication', table => {
table.integer('order').unsigned().notNullable().defaultTo(0)
table.string('strategyKey').notNullable().defaultTo('')
table.string('displayName').notNullable().defaultTo('')
})
// Fix pre-2.5 strategies
const strategies = await knex('authentication')
let idx = 1
for (const strategy of strategies) {
await knex('authentication').where('key', strategy.key).update({
strategyKey: strategy.key,
order: (strategy.key === 'local') ? 0 : idx++
})
}
}
exports.down = knex => { }
const has = require('lodash/has')
exports.up = async knex => {
// -> Fix 2.5.1 added isEnabled columns for beta users
const localStrategy = await knex('authentication').where('key', 'local').first()
if (localStrategy && !has(localStrategy, 'isEnabled')) {
await knex.schema
.alterTable('authentication', table => {
table.boolean('isEnabled').notNullable().defaultTo(true)
})
}
}
exports.down = knex => { }
exports.up = async knex => {
// -> Fix 2.5.117 new installations without isEnabled on local auth (#2382)
await knex('authentication').where('key', 'local').update({ isEnabled: true })
}
exports.down = knex => { }
exports.up = async knex => {
await knex.schema
.alterTable('groups', table => {
table.string('redirectOnLogin').notNullable().defaultTo('/')
})
}
exports.down = knex => { }
exports.up = knex => {
return knex.schema
.createTable('userAvatars', table => {
table.integer('id').primary()
table.binary('data').notNullable()
})
}
exports.down = knex => { }
exports.up = async knex => {
await knex('users').update({
email: knex.raw('LOWER(email)')
})
}
exports.down = knex => { }
/* global WIKI */
exports.up = knex => {
const dbCompat = {
blobLength: (WIKI.config.db.type === `mysql` || WIKI.config.db.type === `mariadb`),
charset: (WIKI.config.db.type === `mysql` || WIKI.config.db.type === `mariadb`),
selfCascadeDelete: WIKI.config.db.type !== 'mssql'
}
return knex.schema
// =====================================
// MODEL TABLES
// =====================================
// ANALYTICS ---------------------------
.createTable('analytics', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.string('key').notNullable().primary()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.json('config').notNullable()
})
// ASSETS ------------------------------
.createTable('assets', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.increments('id').primary()
table.string('filename').notNullable()
table.string('hash').notNullable()
table.string('ext').notNullable()
table.enum('kind', ['binary', 'image']).notNullable().defaultTo('binary')
table.string('mime').notNullable().defaultTo('application/octet-stream')
table.integer('fileSize').unsigned().comment('In kilobytes')
table.json('metadata')
table.string('createdAt').notNullable()
table.string('updatedAt').notNullable()
})
// ASSET DATA --------------------------
.createTable('assetData', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.integer('id').primary()
if (dbCompat.blobLength) {
table.specificType('data', 'LONGBLOB').notNullable()
} else {
table.binary('data').notNullable()
}
})
// ASSET FOLDERS -----------------------
.createTable('assetFolders', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.increments('id').primary()
table.string('name').notNullable()
table.string('slug').notNullable()
table.integer('parentId').unsigned().references('id').inTable('assetFolders')
})
// AUTHENTICATION ----------------------
.createTable('authentication', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.string('key').notNullable().primary()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.json('config').notNullable()
table.boolean('selfRegistration').notNullable().defaultTo(false)
table.json('domainWhitelist').notNullable()
table.json('autoEnrollGroups').notNullable()
})
// COMMENTS ----------------------------
.createTable('comments', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.increments('id').primary()
table.text('content').notNullable()
table.string('createdAt').notNullable()
table.string('updatedAt').notNullable()
})
// EDITORS -----------------------------
.createTable('editors', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.string('key').notNullable().primary()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.json('config').notNullable()
})
// GROUPS ------------------------------
.createTable('groups', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.increments('id').primary()
table.string('name').notNullable()
table.json('permissions').notNullable()
table.json('pageRules').notNullable()
table.boolean('isSystem').notNullable().defaultTo(false)
table.string('createdAt').notNullable()
table.string('updatedAt').notNullable()
})
// LOCALES -----------------------------
.createTable('locales', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.string('code', 5).notNullable().primary()
table.json('strings')
table.boolean('isRTL').notNullable().defaultTo(false)
table.string('name').notNullable()
table.string('nativeName').notNullable()
table.integer('availability').notNullable().defaultTo(0)
table.string('createdAt').notNullable()
table.string('updatedAt').notNullable()
})
// LOGGING ----------------------------
.createTable('loggers', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.string('key').notNullable().primary()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.string('level').notNullable().defaultTo('warn')
table.json('config')
})
// NAVIGATION ----------------------------
.createTable('navigation', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.string('key').notNullable().primary()
table.json('config')
})
// PAGE HISTORY ------------------------
.createTable('pageHistory', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.increments('id').primary()
table.string('path').notNullable()
table.string('hash').notNullable()
table.string('title').notNullable()
table.string('description')
table.boolean('isPrivate').notNullable().defaultTo(false)
table.boolean('isPublished').notNullable().defaultTo(false)
table.string('publishStartDate')
table.string('publishEndDate')
table.string('action').defaultTo('updated')
table.integer('pageId').unsigned()
table.text('content')
table.string('contentType').notNullable()
table.string('createdAt').notNullable()
})
// PAGE LINKS --------------------------
.createTable('pageLinks', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.increments('id').primary()
table.string('path').notNullable()
table.string('localeCode', 5).notNullable()
})
// PAGES -------------------------------
.createTable('pages', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.increments('id').primary()
table.string('path').notNullable()
table.string('hash').notNullable()
table.string('title').notNullable()
table.string('description')
table.boolean('isPrivate').notNullable().defaultTo(false)
table.boolean('isPublished').notNullable().defaultTo(false)
table.string('privateNS')
table.string('publishStartDate')
table.string('publishEndDate')
switch (WIKI.config.db.type) {
case 'postgres':
case 'sqlite':
table.text('content')
table.text('render')
break
case 'mariadb':
case 'mysql':
table.specificType('content', 'LONGTEXT')
table.specificType('render', 'LONGTEXT')
break
case 'mssql':
table.specificType('content', 'VARCHAR(max)')
table.specificType('render', 'VARCHAR(max)')
break
}
table.json('toc')
table.string('contentType').notNullable()
table.string('createdAt').notNullable()
table.string('updatedAt').notNullable()
})
// PAGE TREE ---------------------------
.createTable('pageTree', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.integer('id').unsigned().primary()
table.string('path').notNullable()
table.integer('depth').unsigned().notNullable()
table.string('title').notNullable()
table.boolean('isPrivate').notNullable().defaultTo(false)
table.boolean('isFolder').notNullable().defaultTo(false)
table.string('privateNS')
})
// RENDERERS ---------------------------
.createTable('renderers', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.string('key').notNullable().primary()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.json('config')
})
// SEARCH ------------------------------
.createTable('searchEngines', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.string('key').notNullable().primary()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.json('config')
})
// SETTINGS ----------------------------
.createTable('settings', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.string('key').notNullable().primary()
table.json('value')
table.string('updatedAt').notNullable()
})
// STORAGE -----------------------------
.createTable('storage', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.string('key').notNullable().primary()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.string('mode', ['sync', 'push', 'pull']).notNullable().defaultTo('push')
table.json('config')
table.string('syncInterval')
table.json('state')
})
// TAGS --------------------------------
.createTable('tags', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.increments('id').primary()
table.string('tag').notNullable().unique()
table.string('title')
table.string('createdAt').notNullable()
table.string('updatedAt').notNullable()
})
// USER KEYS ---------------------------
.createTable('userKeys', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.increments('id').primary()
table.string('kind').notNullable()
table.string('token').notNullable()
table.string('createdAt').notNullable()
table.string('validUntil').notNullable()
})
// USERS -------------------------------
.createTable('users', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.increments('id').primary()
table.string('email').notNullable()
table.string('name').notNullable()
table.string('providerId')
table.string('password')
table.boolean('tfaIsActive').notNullable().defaultTo(false)
table.string('tfaSecret')
table.string('jobTitle').defaultTo('')
table.string('location').defaultTo('')
table.string('pictureUrl')
table.string('timezone').notNullable().defaultTo('America/New_York')
table.boolean('isSystem').notNullable().defaultTo(false)
table.boolean('isActive').notNullable().defaultTo(false)
table.boolean('isVerified').notNullable().defaultTo(false)
table.boolean('mustChangePwd').notNullable().defaultTo(false)
table.string('createdAt').notNullable()
table.string('updatedAt').notNullable()
})
// =====================================
// RELATION TABLES
// =====================================
// PAGE HISTORY TAGS ---------------------------
.createTable('pageHistoryTags', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.increments('id').primary()
table.integer('pageId').unsigned().references('id').inTable('pageHistory').onDelete('CASCADE')
table.integer('tagId').unsigned().references('id').inTable('tags').onDelete('CASCADE')
})
// PAGE TAGS ---------------------------
.createTable('pageTags', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.increments('id').primary()
table.integer('pageId').unsigned().references('id').inTable('pages').onDelete('CASCADE')
table.integer('tagId').unsigned().references('id').inTable('tags').onDelete('CASCADE')
})
// USER GROUPS -------------------------
.createTable('userGroups', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.increments('id').primary()
table.integer('userId').unsigned().references('id').inTable('users').onDelete('CASCADE')
table.integer('groupId').unsigned().references('id').inTable('groups').onDelete('CASCADE')
})
// =====================================
// REFERENCES
// =====================================
.table('assets', table => {
table.integer('folderId').unsigned().references('id').inTable('assetFolders')
table.integer('authorId').unsigned().references('id').inTable('users')
})
.table('comments', table => {
table.integer('pageId').unsigned().references('id').inTable('pages')
table.integer('authorId').unsigned().references('id').inTable('users')
})
.table('pageHistory', table => {
table.string('editorKey').references('key').inTable('editors')
table.string('localeCode', 5).references('code').inTable('locales')
table.integer('authorId').unsigned().references('id').inTable('users')
})
.table('pageLinks', table => {
table.integer('pageId').unsigned().references('id').inTable('pages').onDelete('CASCADE')
table.index(['path', 'localeCode'])
})
.table('pages', table => {
table.string('editorKey').references('key').inTable('editors')
table.string('localeCode', 5).references('code').inTable('locales')
table.integer('authorId').unsigned().references('id').inTable('users')
table.integer('creatorId').unsigned().references('id').inTable('users')
})
.table('pageTree', table => {
if (dbCompat.selfCascadeDelete) {
table.integer('parent').unsigned().references('id').inTable('pageTree').onDelete('CASCADE')
} else {
table.integer('parent').unsigned()
}
table.integer('pageId').unsigned().references('id').inTable('pages').onDelete('CASCADE')
table.string('localeCode', 5).references('code').inTable('locales')
})
.table('userKeys', table => {
table.integer('userId').unsigned().references('id').inTable('users')
})
.table('users', table => {
table.string('providerKey').references('key').inTable('authentication').notNullable().defaultTo('local')
table.string('localeCode', 5).references('code').inTable('locales').notNullable().defaultTo('en')
table.string('defaultEditor').references('key').inTable('editors').notNullable().defaultTo('markdown')
table.unique(['providerKey', 'email'])
})
}
exports.down = knex => { }
/* global WIKI */
exports.up = knex => {
return knex.schema
.alterTable('pageHistory', table => {
switch (WIKI.config.db.type) {
// No change needed for PostgreSQL and SQLite
case 'mariadb':
case 'mysql':
table.specificType('content', 'LONGTEXT').alter()
break
case 'mssql':
table.specificType('content', 'VARCHAR(max)').alter()
break
}
})
}
exports.down = knex => { }
const _ = require('lodash')
/* global WIKI */
exports.up = async knex => {
let sqlVersionDate = ''
switch (WIKI.config.db.type) {
case 'postgres':
sqlVersionDate = 'UPDATE "pageHistory" h1 SET "versionDate" = COALESCE((SELECT prev."createdAt" FROM "pageHistory" prev WHERE prev."pageId" = h1."pageId" AND prev.id < h1.id ORDER BY prev.id DESC LIMIT 1), h1."createdAt")'
break
case 'mssql':
sqlVersionDate = 'UPDATE h1 SET "versionDate" = COALESCE((SELECT TOP 1 prev."createdAt" FROM "pageHistory" prev WHERE prev."pageId" = h1."pageId" AND prev.id < h1.id ORDER BY prev.id DESC), h1."createdAt") FROM "pageHistory" h1'
break
case 'mysql':
case 'mariadb':
// -> Fix for 2.2.50 failed migration
const pageHistoryColumns = await knex.schema.raw('SHOW COLUMNS FROM pageHistory')
if (_.some(pageHistoryColumns[0], ['Field', 'versionDate'])) {
console.info('MySQL 2.2.50 Migration Fix - Dropping failed versionDate column...')
await knex.schema.raw('ALTER TABLE pageHistory DROP COLUMN versionDate')
console.info('versionDate column dropped successfully.')
}
sqlVersionDate = `UPDATE pageHistory AS h1 INNER JOIN pageHistory AS h2 ON h2.id = (SELECT prev.id FROM (SELECT * FROM pageHistory) AS prev WHERE prev.pageId = h1.pageId AND prev.id < h1.id ORDER BY prev.id DESC LIMIT 1) SET h1.versionDate = h2.createdAt`
break
// case 'mariadb':
// sqlVersionDate = `UPDATE pageHistory AS h1 INNER JOIN pageHistory AS h2 ON h2.id = (SELECT prev.id FROM pageHistory AS prev WHERE prev.pageId = h1.pageId AND prev.id < h1.id ORDER BY prev.id DESC LIMIT 1) SET h1.versionDate = h2.createdAt`
// break
}
await knex.schema
.alterTable('pageHistory', table => {
table.string('versionDate').notNullable().defaultTo('')
})
.raw(sqlVersionDate)
}
exports.down = knex => { }
/* global WIKI */
exports.up = knex => {
const dbCompat = {
charset: (WIKI.config.db.type === `mysql` || WIKI.config.db.type === `mariadb`)
}
return knex.schema
.createTable('apiKeys', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.increments('id').primary()
table.string('name').notNullable()
table.text('key').notNullable()
table.string('expiration').notNullable()
table.boolean('isRevoked').notNullable().defaultTo(false)
table.string('createdAt').notNullable()
table.string('updatedAt').notNullable()
})
}
exports.down = knex => { }
exports.up = knex => {
return knex.schema
.alterTable('users', table => {
table.string('lastLoginAt')
})
}
exports.down = knex => { }
exports.up = knex => {
return knex.schema
.alterTable('pageTree', table => {
table.json('ancestors')
})
}
exports.down = knex => { }
/* global WIKI */
exports.up = knex => {
return knex.schema
.alterTable('pages', table => {
if (WIKI.config.db.type === 'mysql') {
table.json('extra')
} else {
table.json('extra').notNullable().defaultTo('{}')
}
})
.alterTable('pageHistory', table => {
if (WIKI.config.db.type === 'mysql') {
table.json('extra')
} else {
table.json('extra').notNullable().defaultTo('{}')
}
})
.alterTable('users', table => {
table.string('dateFormat').notNullable().defaultTo('')
table.string('appearance').notNullable().defaultTo('')
})
}
exports.down = knex => { }
/* global WIKI */
exports.up = knex => {
const dbCompat = {
charset: (WIKI.config.db.type === `mysql` || WIKI.config.db.type === `mariadb`)
}
return knex.schema
.createTable('commentProviders', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.string('key').notNullable().primary()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.json('config').notNullable()
})
}
exports.down = knex => { }
exports.up = knex => {
return knex.schema
.alterTable('comments', table => {
table.text('render').notNullable().defaultTo('')
table.string('name').notNullable().defaultTo('')
table.string('email').notNullable().defaultTo('')
table.string('ip').notNullable().defaultTo('')
})
}
exports.down = knex => { }
exports.up = knex => {
return knex.schema
.alterTable('comments', table => {
table.integer('replyTo').unsigned().notNullable().defaultTo(0)
})
}
exports.down = knex => { }
exports.up = async knex => {
// Check for users using disabled strategies
let protectedStrategies = []
const disabledStrategies = await knex('authentication').where('isEnabled', false)
if (disabledStrategies) {
const incompatibleUsers = await knex('users').distinct('providerKey').whereIn('providerKey', disabledStrategies.map(s => s.key))
if (incompatibleUsers && incompatibleUsers.length > 0) {
protectedStrategies = incompatibleUsers.map(u => u.providerKey)
}
}
// Delete disabled strategies
await knex('authentication').whereNotIn('key', protectedStrategies).andWhere('isEnabled', false).del()
// Update table schema
await knex.schema
.alterTable('authentication', table => {
table.integer('order').unsigned().notNullable().defaultTo(0)
table.string('strategyKey').notNullable().defaultTo('')
table.string('displayName').notNullable().defaultTo('')
})
// Fix pre-2.5 strategies
const strategies = await knex('authentication')
let idx = 1
for (const strategy of strategies) {
await knex('authentication').where('key', strategy.key).update({
strategyKey: strategy.key,
order: (strategy.key === 'local') ? 0 : idx++
})
}
}
exports.down = knex => { }
const has = require('lodash/has')
exports.up = async knex => {
// -> Fix 2.5.1 added isEnabled columns for beta users
const localStrategy = await knex('authentication').where('key', 'local').first()
if (localStrategy && !has(localStrategy, 'isEnabled')) {
await knex.schema
.alterTable('authentication', table => {
table.boolean('isEnabled').notNullable().defaultTo(true)
})
}
}
exports.down = knex => { }
exports.up = async knex => {
// -> Fix 2.5.117 new installations without isEnabled on local auth (#2382)
await knex('authentication').where('key', 'local').update({ isEnabled: true })
}
exports.down = knex => { }
exports.up = async knex => {
await knex.schema
.alterTable('groups', table => {
table.string('redirectOnLogin').notNullable().defaultTo('/')
})
}
exports.down = knex => { }
/* global WIKI */
exports.up = knex => {
const dbCompat = {
blobLength: (WIKI.config.db.type === `mysql` || WIKI.config.db.type === `mariadb`),
charset: (WIKI.config.db.type === `mysql` || WIKI.config.db.type === `mariadb`)
}
return knex.schema
.createTable('userAvatars', table => {
if (dbCompat.charset) { table.charset('utf8mb4') }
table.integer('id').primary()
if (dbCompat.blobLength) {
table.specificType('data', 'LONGBLOB').notNullable()
} else {
table.binary('data').notNullable()
}
})
}
exports.down = knex => { }
exports.up = async knex => {
await knex('users').update({
email: knex.raw('LOWER(??)', ['email'])
})
}
exports.down = knex => { }
const { v4: uuid } = require('uuid')
const bcrypt = require('bcryptjs-then')
const crypto = require('crypto')
const pem2jwk = require('pem-jwk').pem2jwk
/* global WIKI */
exports.up = async knex => {
WIKI.logger.info('Running 3.0.0 database migration...')
// =====================================
// PG EXTENSIONS
// =====================================
await knex.raw('CREATE EXTENSION IF NOT EXISTS pgcrypto;')
await knex.schema
// =====================================
// MODEL TABLES
// =====================================
// ANALYTICS ---------------------------
.createTable('analytics', table => {
table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
table.string('module').notNullable()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.jsonb('config').notNullable()
})
// API KEYS ----------------------------
.createTable('apiKeys', table => {
table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
table.string('name').notNullable()
table.text('key').notNullable()
table.string('expiration').notNullable()
table.boolean('isRevoked').notNullable().defaultTo(false)
table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
})
// ASSETS ------------------------------
.createTable('assets', table => {
table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
table.string('filename').notNullable()
table.string('hash').notNullable().index()
table.string('ext').notNullable()
table.enum('kind', ['binary', 'image']).notNullable().defaultTo('binary')
table.string('mime').notNullable().defaultTo('application/octet-stream')
table.integer('fileSize').unsigned().comment('In kilobytes')
table.jsonb('metadata')
table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
})
// ASSET DATA --------------------------
.createTable('assetData', table => {
table.uuid('id').notNullable().index()
table.binary('data').notNullable()
})
// ASSET FOLDERS -----------------------
.createTable('assetFolders', table => {
table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
table.string('name').notNullable()
table.string('slug').notNullable()
})
// AUTHENTICATION ----------------------
.createTable('authentication', table => {
table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
table.string('module').notNullable()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.integer('order').unsigned().notNullable().defaultTo(0)
table.string('displayName').notNullable().defaultTo('')
table.jsonb('config').notNullable().defaultTo('{}')
table.boolean('selfRegistration').notNullable().defaultTo(false)
table.jsonb('domainWhitelist').notNullable().defaultTo('[]')
table.jsonb('autoEnrollGroups').notNullable().defaultTo('[]')
table.jsonb('hideOnSites').notNullable().defaultTo('[]')
})
// COMMENTS ----------------------------
.createTable('comments', table => {
table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
table.uuid('replyTo')
table.text('content').notNullable()
table.text('render').notNullable().defaultTo('')
table.string('name').notNullable().defaultTo('')
table.string('email').notNullable().defaultTo('')
table.string('ip').notNullable().defaultTo('')
table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
})
// GROUPS ------------------------------
.createTable('groups', table => {
table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
table.string('name').notNullable()
table.jsonb('permissions').notNullable()
table.jsonb('rules').notNullable()
table.string('redirectOnLogin').notNullable().defaultTo('')
table.string('redirectOnFirstLogin').notNullable().defaultTo('')
table.string('redirectOnLogout').notNullable().defaultTo('')
table.boolean('isSystem').notNullable().defaultTo(false)
table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
})
// HOOKS -------------------------------
.createTable('hooks', table => {
table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
table.string('name').notNullable()
table.jsonb('events').notNullable().defaultTo('[]')
table.string('url').notNullable()
table.boolean('includeMetadata').notNullable().defaultTo(false)
table.boolean('includeContent').notNullable().defaultTo(false)
table.boolean('acceptUntrusted').notNullable().defaultTo(false)
table.string('authHeader')
table.enum('state', ['pending', 'error', 'success']).notNullable().defaultTo('pending')
table.string('lastErrorMessage')
table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
})
// LOCALES -----------------------------
.createTable('locales', table => {
table.string('code', 5).notNullable().primary()
table.jsonb('strings')
table.boolean('isRTL').notNullable().defaultTo(false)
table.string('name').notNullable()
table.string('nativeName').notNullable()
table.integer('availability').notNullable().defaultTo(0)
table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
})
// NAVIGATION ----------------------------
.createTable('navigation', table => {
table.string('key').notNullable().primary()
table.jsonb('config')
})
// PAGE HISTORY ------------------------
.createTable('pageHistory', table => {
table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
table.uuid('pageId').notNullable().index()
table.string('path').notNullable()
table.string('hash').notNullable()
table.string('title').notNullable()
table.string('description')
table.enu('publishState', ['draft', 'published', 'scheduled']).notNullable().defaultTo('draft')
table.timestamp('publishStartDate')
table.timestamp('publishEndDate')
table.string('action').defaultTo('updated')
table.text('content')
table.string('contentType').notNullable()
table.jsonb('extra').notNullable().defaultTo('{}')
table.jsonb('tags').defaultTo('[]')
table.timestamp('versionDate').notNullable().defaultTo(knex.fn.now())
table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
})
// PAGE LINKS --------------------------
.createTable('pageLinks', table => {
table.increments('id').primary()
table.string('path').notNullable()
table.string('localeCode', 5).notNullable()
})
// PAGES -------------------------------
.createTable('pages', table => {
table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
table.string('slug')
table.string('path').notNullable()
table.string('hash').notNullable()
table.string('title').notNullable()
table.string('description')
table.enu('publishState', ['draft', 'published', 'scheduled']).notNullable().defaultTo('draft')
table.timestamp('publishStartDate')
table.timestamp('publishEndDate')
table.text('content')
table.text('render')
table.jsonb('toc')
table.string('contentType').notNullable()
table.jsonb('extra').notNullable().defaultTo('{}')
table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
})
// PAGE TREE ---------------------------
.createTable('pageTree', table => {
table.integer('id').unsigned().primary()
table.string('path').notNullable()
table.integer('depth').unsigned().notNullable()
table.string('title').notNullable()
table.boolean('isFolder').notNullable().defaultTo(false)
table.jsonb('ancestors')
})
// RENDERERS ---------------------------
.createTable('renderers', table => {
table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
table.string('module').notNullable()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.jsonb('config')
})
// SETTINGS ----------------------------
.createTable('settings', table => {
table.string('key').notNullable().primary()
table.jsonb('value')
})
// SITES -------------------------------
.createTable('sites', table => {
table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
table.string('hostname').notNullable()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.jsonb('config').notNullable()
table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
})
// STORAGE -----------------------------
.createTable('storage', table => {
table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
table.string('module').notNullable()
table.boolean('isEnabled').notNullable().defaultTo(false)
table.jsonb('contentTypes')
table.jsonb('assetDelivery')
table.jsonb('versioning')
table.jsonb('schedule')
table.jsonb('config')
table.jsonb('state')
})
// TAGS --------------------------------
.createTable('tags', table => {
table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
table.string('tag').notNullable()
table.jsonb('display').notNullable().defaultTo('{}')
table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
})
// USER AVATARS ------------------------
.createTable('userAvatars', table => {
table.uuid('id').notNullable().primary()
table.binary('data').notNullable()
})
// USER KEYS ---------------------------
.createTable('userKeys', table => {
table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
table.string('kind').notNullable()
table.string('token').notNullable()
table.timestamp('validUntil').notNullable()
table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
})
// USERS -------------------------------
.createTable('users', table => {
table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
table.string('email').notNullable()
table.string('name').notNullable()
table.jsonb('auth')
table.jsonb('tfa')
table.jsonb('meta')
table.jsonb('prefs')
table.string('pictureUrl')
table.boolean('isSystem').notNullable().defaultTo(false)
table.boolean('isActive').notNullable().defaultTo(false)
table.boolean('isVerified').notNullable().defaultTo(false)
table.timestamp('lastLoginAt').index()
table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now())
})
// =====================================
// RELATION TABLES
// =====================================
// PAGE TAGS ---------------------------
.createTable('pageTags', table => {
table.increments('id').primary()
table.uuid('pageId').references('id').inTable('pages').onDelete('CASCADE')
table.uuid('tagId').references('id').inTable('tags').onDelete('CASCADE')
})
// USER GROUPS -------------------------
.createTable('userGroups', table => {
table.increments('id').primary()
table.uuid('userId').references('id').inTable('users').onDelete('CASCADE')
table.uuid('groupId').references('id').inTable('groups').onDelete('CASCADE')
})
// =====================================
// REFERENCES
// =====================================
.table('analytics', table => {
table.uuid('siteId').notNullable().references('id').inTable('sites')
})
.table('assets', table => {
table.uuid('folderId').notNullable().references('id').inTable('assetFolders').index()
table.uuid('authorId').notNullable().references('id').inTable('users')
table.uuid('siteId').notNullable().references('id').inTable('sites').index()
})
.table('assetFolders', table => {
table.uuid('parentId').references('id').inTable('assetFolders').index()
})
.table('comments', table => {
table.uuid('pageId').notNullable().references('id').inTable('pages').index()
table.uuid('authorId').notNullable().references('id').inTable('users').index()
})
.table('navigation', table => {
table.uuid('siteId').notNullable().references('id').inTable('sites').index()
})
.table('pageHistory', table => {
table.string('localeCode', 5).references('code').inTable('locales')
table.uuid('authorId').notNullable().references('id').inTable('users')
table.uuid('siteId').notNullable().references('id').inTable('sites').index()
})
.table('pageLinks', table => {
table.uuid('pageId').notNullable().references('id').inTable('pages').onDelete('CASCADE')
table.index(['path', 'localeCode'])
})
.table('pages', table => {
table.string('localeCode', 5).references('code').inTable('locales').index()
table.uuid('authorId').notNullable().references('id').inTable('users').index()
table.uuid('creatorId').notNullable().references('id').inTable('users').index()
table.uuid('siteId').notNullable().references('id').inTable('sites').index()
})
.table('pageTree', table => {
table.integer('parent').unsigned().references('id').inTable('pageTree').onDelete('CASCADE')
table.uuid('pageId').notNullable().references('id').inTable('pages').onDelete('CASCADE')
table.string('localeCode', 5).references('code').inTable('locales')
})
.table('storage', table => {
table.uuid('siteId').notNullable().references('id').inTable('sites')
})
.table('tags', table => {
table.uuid('siteId').notNullable().references('id').inTable('sites')
table.unique(['siteId', 'tag'])
})
.table('userKeys', table => {
table.uuid('userId').notNullable().references('id').inTable('users')
})
.table('users', table => {
table.string('localeCode', 5).references('code').inTable('locales').notNullable().defaultTo('en')
})
// =====================================
// DEFAULT DATA
// =====================================
// -> SYSTEM CONFIG
await knex('settings').insert([
{
key: 'update',
value: {
locales: true
}
},
{
key: 'mail',
value: {
senderName: '',
senderEmail: '',
host: '',
port: 465,
secure: true,
verifySSL: true,
user: '',
pass: '',
useDKIM: false,
dkimDomainName: '',
dkimKeySelector: '',
dkimPrivateKey: ''
}
},
{
key: 'security',
value: {
corsConfig: '',
corsMode: 'OFF',
cspDirectives: '',
disallowFloc: true,
disallowIframe: true,
disallowOpenRedirect: true,
enforceCsp: false,
enforceHsts: false,
enforceSameOriginReferrerPolicy: true,
forceAssetDownload: true,
hstsDuration: 0,
trustProxy: false,
authJwtAudience: 'urn:wiki.js',
authJwtExpiration: '30m',
authJwtRenewablePeriod: '14d',
uploadMaxFileSize: 10485760,
uploadMaxFiles: 20,
uploadScanSVG: true
}
}
])
// -> DEFAULT LOCALE
await knex('locales').insert({
code: 'en',
strings: {},
isRTL: false,
name: 'English',
nativeName: 'English'
})
// -> DEFAULT SITE
WIKI.logger.info('Generating certificates...')
const secret = crypto.randomBytes(32).toString('hex')
const certs = crypto.generateKeyPairSync('rsa', {
modulusLength: 2048,
publicKeyEncoding: {
type: 'pkcs1',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs1',
format: 'pem',
cipher: 'aes-256-cbc',
passphrase: secret
}
})
const siteId = uuid()
await knex('sites').insert({
id: siteId,
hostname: '*',
isEnabled: true,
config: {
auth: {
audience: 'urn:wiki.js',
tokenExpiration: '30m',
tokenRenewal: '14d',
certs: {
jwk: pem2jwk(certs.publicKey),
public: certs.publicKey,
private: certs.privateKey
},
secret
},
title: 'My Wiki Site',
description: '',
company: '',
contentLicense: '',
defaults: {
timezone: 'America/New_York',
dateFormat: 'YYYY-MM-DD',
timeFormat: '12h'
},
features: {
ratings: false,
ratingsMode: 'off',
comments: false,
contributions: false,
profile: true,
search: true
},
logoText: true,
robots: {
index: true,
follow: true
},
locale: 'en',
localeNamespacing: false,
localeNamespaces: [],
theme: {
dark: false,
colorPrimary: '#1976d2',
colorSecondary: '#02c39a',
colorAccent: '#f03a47',
colorHeader: '#000000',
colorSidebar: '#1976d2',
injectCSS: '',
injectHead: '',
injectBody: '',
sidebarPosition: 'left',
tocPosition: 'right',
showSharingMenu: true,
showPrintBtn: true
}
}
})
// -> DEFAULT GROUPS
const groupAdminId = uuid()
const groupGuestId = '10000000-0000-4000-0000-000000000001'
await knex('groups').insert([
{
id: groupAdminId,
name: 'Administrators',
permissions: JSON.stringify(['manage:system']),
rules: JSON.stringify([]),
isSystem: true
},
{
id: groupGuestId,
name: 'Guests',
permissions: JSON.stringify(['read:pages', 'read:assets', 'read:comments']),
rules: JSON.stringify([
{
id: uuid(),
name: 'Default Rule',
roles: ['read:pages', 'read:assets', 'read:comments'],
match: 'START',
mode: 'DENY',
path: '',
locales: [],
sites: []
}
]),
isSystem: true
}
])
// -> AUTHENTICATION MODULE
const authModuleId = uuid()
await knex('authentication').insert({
id: authModuleId,
module: 'local',
isEnabled: true,
displayName: 'Local Authentication'
})
// -> USERS
const userAdminId = uuid()
const userGuestId = uuid()
await knex('users').insert([
{
id: userAdminId,
email: process.env.ADMIN_EMAIL ?? 'admin@example.com',
auth: {
[authModuleId]: {
password: await bcrypt.hash(process.env.ADMIN_PASS || '12345678', 12),
mustChangePwd: !process.env.ADMIN_PASS,
restrictLogin: false,
tfaRequired: false,
tfaSecret: ''
}
},
name: 'Administrator',
isSystem: false,
isActive: true,
isVerified: true,
meta: {
location: '',
jobTitle: '',
pronouns: ''
},
prefs: {
timezone: 'America/New_York',
dateFormat: 'YYYY-MM-DD',
timeFormat: '12h',
darkMode: false
},
localeCode: 'en'
},
{
id: userGuestId,
email: 'guest@example.com',
name: 'Guest',
isSystem: true,
isActive: true,
isVerified: true,
localeCode: 'en'
}
])
await knex('userGroups').insert([
{
userId: userAdminId,
groupId: groupAdminId
},
{
userId: userGuestId,
groupId: groupGuestId
}
])
// -> STORAGE MODULE
await knex('storage').insert({
module: 'db',
siteId,
isEnabled: true,
contentTypes: {
activeTypes: ['pages', 'images', 'documents', 'others', 'large'],
largeThreshold: '5MB'
},
assetDelivery: {
streaming: true,
directAccess: false
},
versioning: {
enabled: false
},
state: {
current: 'ok'
}
})
WIKI.logger.info('Completed 3.0.0 database migration.')
}
exports.down = knex => { }
...@@ -2,7 +2,7 @@ const path = require('path') ...@@ -2,7 +2,7 @@ const path = require('path')
const fs = require('fs-extra') const fs = require('fs-extra')
const semver = require('semver') const semver = require('semver')
const baseMigrationPath = path.join(WIKI.SERVERPATH, (WIKI.config.db.type !== 'sqlite') ? 'db/migrations' : 'db/migrations-sqlite') const baseMigrationPath = path.join(WIKI.SERVERPATH, 'db/migrations')
/* global WIKI */ /* global WIKI */
......
const graphHelper = require('../../helpers/graph') const graphHelper = require('../../helpers/graph')
const _ = require('lodash') const _ = require('lodash')
const CleanCSS = require('clean-css')
const path = require('path')
/* global WIKI */ /* global WIKI */
module.exports = { module.exports = {
Query: { Query: {
async sites () {
const sites = await WIKI.models.sites.query()
return sites.map(s => ({
...s.config,
id: s.id,
hostname: s.hostname,
isEnabled: s.isEnabled
}))
},
async siteById (obj, args) {
const site = await WIKI.models.sites.query().findById(args.id)
return site ? {
...site.config,
id: site.id,
hostname: site.hostname,
isEnabled: site.isEnabled
} : null
},
async siteByHostname (obj, args) {
let site = await WIKI.models.sites.query().where({
hostname: args.hostname
}).first()
if (!site && !args.exact) {
site = await WIKI.models.sites.query().where({
hostname: '*'
}).first()
}
return site ? {
...site.config,
id: site.id,
hostname: site.hostname,
isEnabled: site.isEnabled
} : null
},
// LEGACY
async site() { return {} } async site() { return {} }
}, },
Mutation: { Mutation: {
/**
* CREATE SITE
*/
async createSite (obj, args) {
try {
// -> Validate inputs
if (!args.hostname || args.hostname.length < 1 || !/^(\\*)|([a-z0-9\-.:]+)$/.test(args.hostname)) {
throw WIKI.ERROR(new Error('Invalid Site Hostname'), 'SiteCreateInvalidHostname')
}
if (!args.title || args.title.length < 1 || !/^[^<>"]+$/.test(args.title)) {
throw WIKI.ERROR(new Error('Invalid Site Title'), 'SiteCreateInvalidTitle')
}
// -> Check for duplicate catch-all
if (args.hostname === '*') {
const site = await WIKI.models.sites.query().where({
hostname: args.hostname
}).first()
if (site) {
throw WIKI.ERROR(new Error('A site with a catch-all hostname already exists! Cannot have 2 catch-all hostnames.'), 'SiteCreateDuplicateCatchAll')
}
}
// -> Create site
const newSite = await WIKI.models.sites.createSite(args.hostname, {
title: args.title
})
return {
status: graphHelper.generateSuccess('Site created successfully'),
site: newSite
}
} catch (err) {
return graphHelper.generateError(err)
}
},
/**
* UPDATE SITE
*/
async updateSite (obj, args) {
try {
// -> Load site
const site = await WIKI.models.sites.query().findById(args.id)
if (!site) {
throw WIKI.ERROR(new Error('Invalid Site ID'), 'SiteInvalidId')
}
// -> Check for bad input
if (_.has(args.patch, 'hostname') && _.trim(args.patch.hostname).length < 1) {
throw WIKI.ERROR(new Error('Hostname is invalid.'), 'SiteInvalidHostname')
}
// -> Check for duplicate catch-all
if (args.patch.hostname === '*' && site.hostname !== '*') {
const dupSite = await WIKI.models.sites.query().where({ hostname: '*' }).first()
if (dupSite) {
throw WIKI.ERROR(new Error(`Site ${dupSite.config.title} with a catch-all hostname already exists! Cannot have 2 catch-all hostnames.`), 'SiteUpdateDuplicateCatchAll')
}
}
// -> Format Code
if (args.patch?.theme?.injectCSS) {
args.patch.theme.injectCSS = new CleanCSS({ inline: false }).minify(args.patch.theme.injectCSS).styles
}
// -> Update site
await WIKI.models.sites.updateSite(args.id, {
hostname: args.patch.hostname ?? site.hostname,
isEnabled: args.patch.isEnabled ?? site.isEnabled,
config: _.defaultsDeep(_.omit(args.patch, ['hostname', 'isEnabled']), site.config)
})
return {
status: graphHelper.generateSuccess('Site updated successfully')
}
} catch (err) {
WIKI.logger.warn(err)
return graphHelper.generateError(err)
}
},
/**
* DELETE SITE
*/
async deleteSite (obj, args) {
try {
// -> Ensure site isn't last one
const sitesCount = await WIKI.models.sites.query().count('id').first()
if (sitesCount?.count && _.toNumber(sitesCount?.count) <= 1) {
throw WIKI.ERROR(new Error('Cannot delete the last site. At least 1 site must exists at all times.'), 'SiteDeleteLastSite')
}
// -> Delete site
await WIKI.models.sites.deleteSite(args.id)
return {
status: graphHelper.generateSuccess('Site deleted successfully')
}
} catch (err) {
WIKI.logger.warn(err)
return graphHelper.generateError(err)
}
},
/**
* UPLOAD LOGO
*/
async uploadSiteLogo (obj, args) {
try {
const { filename, mimetype, createReadStream } = await args.image
WIKI.logger.info(`Processing site logo ${filename} of type ${mimetype}...`)
if (!WIKI.extensions.ext.sharp.isInstalled) {
throw new Error('This feature requires the Sharp extension but it is not installed.')
}
console.info(mimetype)
const destFormat = mimetype.startsWith('image/svg') ? 'svg' : 'png'
const destPath = path.resolve(
process.cwd(),
WIKI.config.dataPath,
`assets/logo.${destFormat}`
)
await WIKI.extensions.ext.sharp.resize({
format: destFormat,
inputStream: createReadStream(),
outputPath: destPath,
width: 100
})
WIKI.logger.info('New site logo processed successfully.')
return {
status: graphHelper.generateSuccess('Site logo uploaded successfully')
}
} catch (err) {
return graphHelper.generateError(err)
}
},
/**
* UPLOAD FAVICON
*/
async uploadSiteFavicon (obj, args) {
const { filename, mimetype, createReadStream } = await args.image
console.info(filename, mimetype)
return {
status: graphHelper.generateSuccess('Site favicon uploaded successfully')
}
},
// LEGACY
async site() { return {} } async site() { return {} }
}, },
SiteQuery: { SiteQuery: {
......
const { Kind, GraphQLScalarType } = require('graphql')
function ensureObject (value) {
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
throw new TypeError(`JSONObject cannot represent non-object value: ${value}`)
}
return value
}
function parseLiteral (typeName, ast, variables) {
switch (ast.kind) {
case Kind.STRING:
case Kind.BOOLEAN:
return ast.value
case Kind.INT:
case Kind.FLOAT:
return parseFloat(ast.value)
case Kind.OBJECT:
return parseObject(typeName, ast, variables)
case Kind.LIST:
return ast.values.map((n) => parseLiteral(typeName, n, variables))
case Kind.NULL:
return null
case Kind.VARIABLE:
return variables ? variables[ast.name.value] : undefined
default:
throw new TypeError(`${typeName} cannot represent value: ${ast}`)
}
}
function parseObject (typeName, ast, variables) {
const value = Object.create(null)
ast.fields.forEach((field) => {
// eslint-disable-next-line no-use-before-define
value[field.name.value] = parseLiteral(typeName, field.value, variables)
})
return value
}
module.exports = {
JSON: new GraphQLScalarType({
name: 'JSON',
description:
'The `JSON` scalar type represents JSON objects as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf).',
specifiedByUrl:
'http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf',
serialize: ensureObject,
parseValue: ensureObject,
parseLiteral: (ast, variables) => {
if (ast.kind !== Kind.OBJECT) {
throw new TypeError(`JSONObject cannot represent non-object value: ${ast}`)
}
return parseObject('JSONObject', ast, variables)
}
})
}
const { Kind, GraphQLScalarType } = require('graphql')
// const { Kind } = require('graphql/language')
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
const nilUUID = '00000000-0000-0000-0000-000000000000'
function isUUID (value) {
return uuidRegex.test(value) || nilUUID === value
}
module.exports = {
UUID: new GraphQLScalarType({
name: 'UUID',
description: 'The `UUID` scalar type represents UUID values as specified by [RFC 4122](https://tools.ietf.org/html/rfc4122).',
serialize: (value) => {
if (!isUUID(value)) {
throw new TypeError(`UUID cannot represent non-UUID value: ${value}`)
}
return value.toLowerCase()
},
parseValue: (value) => {
if (!isUUID(value)) {
throw new TypeError(`UUID cannot represent non-UUID value: ${value}`)
}
return value.toLowerCase()
},
parseLiteral: (ast) => {
if (ast.kind === Kind.STRING) {
if (isUUID(ast.value)) {
return ast.value
}
}
return undefined
}
})
}
...@@ -34,6 +34,11 @@ type ResponseStatus { ...@@ -34,6 +34,11 @@ type ResponseStatus {
message: String message: String
} }
enum OrderByDirection {
asc
desc
}
# ROOT # ROOT
# ---- # ----
......
# SCALARS # SCALARS
scalar Date scalar Date
scalar JSON
# scalar Upload
scalar UUID
# =============================================== # ===============================================
# SITE # SITES
# =============================================== # ===============================================
extend type Query { extend type Query {
sites: [Site] @auth(requires: ["manage:system"])
siteById (
id: UUID!
): Site @auth(requires: ["manage:system"])
siteByHostname (
hostname: String!
exact: Boolean!
): Site @auth(requires: ["manage:system"])
# Legacy
site: SiteQuery site: SiteQuery
} }
extend type Mutation { extend type Mutation {
createSite (
hostname: String!
title: String!
): SiteCreateResponse @auth(requires: ["manage:system"])
updateSite (
id: UUID!
patch: SiteUpdateInput!
): DefaultResponse @auth(requires: ["manage:system"])
uploadSiteLogo (
id: UUID!
image: Upload!
): DefaultResponse @auth(requires: ["manage:system"])
uploadSiteFavicon (
id: UUID!
image: Upload!
): DefaultResponse @auth(requires: ["manage:system"])
deleteSite (
id: UUID!
): DefaultResponse @auth(requires: ["manage:system"])
# Legacy
site: SiteMutation site: SiteMutation
} }
...@@ -64,6 +101,135 @@ type SiteMutation { ...@@ -64,6 +101,135 @@ type SiteMutation {
# TYPES # TYPES
# ----------------------------------------------- # -----------------------------------------------
type Site {
id: UUID
hostname: String
isEnabled: Boolean
title: String
description: String
company: String
contentLicense: String
logoText: Boolean
robots: SiteRobots
features: SiteFeatures
defaults: SiteDefaults
locale: String
localeNamespaces: [String]
localeNamespacing: Boolean
theme: SiteTheme
}
type SiteRobots {
index: Boolean
follow: Boolean
}
type SiteFeatures {
ratings: Boolean
ratingsMode: SitePageRatingModes
comments: Boolean
contributions: Boolean
profile: Boolean
search: Boolean
}
type SiteDefaults {
timezone: String
dateFormat: String
timeFormat: String
}
type SiteLocale {
locale: String
autoUpdate: Boolean
namespacing: Boolean
namespaces: [String]
}
type SiteTheme {
dark: Boolean
colorPrimary: String
colorSecondary: String
colorAccent: String
colorHeader: String
colorSidebar: String
injectCSS: String
injectHead: String
injectBody: String
sidebarPosition: SiteThemePosition
tocPosition: SiteThemePosition
showSharingMenu: Boolean
showPrintBtn: Boolean
}
enum SiteThemePosition {
left
right
}
enum SitePageRatingModes {
off
thumbs
stars
}
type SiteCreateResponse {
status: ResponseStatus
site: Site
}
input SiteUpdateInput {
hostname: String
isEnabled: Boolean
title: String
description: String
company: String
contentLicense: String
logoText: Boolean
robots: SiteRobotsInput
features: SiteFeaturesInput
defaults: SiteDefaultsInput
theme: SiteThemeInput
}
input SiteRobotsInput {
index: Boolean
follow: Boolean
}
input SiteFeaturesInput {
ratings: Boolean
ratingsMode: SitePageRatingModes
comments: Boolean
contributions: Boolean
profile: Boolean
search: Boolean
}
input SiteDefaultsInput {
timezone: String
dateFormat: String
timeFormat: String
}
input SiteThemeInput {
dark: Boolean
colorPrimary: String
colorSecondary: String
colorAccent: String
colorHeader: String
colorSidebar: String
injectCSS: String
injectHead: String
injectBody: String
sidebarPosition: SiteThemePosition
tocPosition: SiteThemePosition
showSharingMenu: Boolean
showPrintBtn: Boolean
}
# LEGACY
type SiteConfig { type SiteConfig {
host: String host: String
title: String title: String
......
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
/dist
/src-capacitor
/src-cordova
/.quasar
/node_modules
.eslintrc.js
module.exports = {
// https://eslint.org/docs/user-guide/configuring#configuration-cascading-and-hierarchy
// This option interrupts the configuration hierarchy at this file
// Remove this if you have an higher level ESLint config file (it usually happens into a monorepos)
root: true,
parserOptions: {
ecmaVersion: '2021' // Allows for the parsing of modern ECMAScript features
},
env: {
node: true,
browser: true,
'vue/setup-compiler-macros': true
},
// Rules order is important, please avoid shuffling them
extends: [
// Base ESLint recommended rules
// 'eslint:recommended',
// Uncomment any of the lines below to choose desired strictness,
// but leave only one uncommented!
// See https://eslint.vuejs.org/rules/#available-rules
'plugin:vue/vue3-essential', // Priority A: Essential (Error Prevention)
'plugin:vue/vue3-strongly-recommended', // Priority B: Strongly Recommended (Improving Readability)
// 'plugin:vue/vue3-recommended', // Priority C: Recommended (Minimizing Arbitrary Choices and Cognitive Overhead)
'standard'
],
plugins: [
// https://eslint.vuejs.org/user-guide/#why-doesn-t-it-work-on-vue-files
// required to lint *.vue files
'vue'
],
globals: {
ga: 'readonly', // Google Analytics
__statics: 'readonly',
__QUASAR_SSR__: 'readonly',
__QUASAR_SSR_SERVER__: 'readonly',
__QUASAR_SSR_CLIENT__: 'readonly',
__QUASAR_SSR_PWA__: 'readonly',
process: 'readonly',
APOLLO_CLIENT: 'readonly'
},
// add your custom rules here
rules: {
// allow async-await
'generator-star-spacing': 'off',
// allow paren-less arrow functions
'arrow-parens': 'off',
'one-var': 'off',
'no-void': 'off',
'multiline-ternary': 'off',
'import/first': 'off',
'import/named': 'error',
'import/namespace': 'error',
'import/default': 'error',
'import/export': 'error',
'import/extensions': 'off',
'import/no-unresolved': 'off',
'import/no-extraneous-dependencies': 'off',
'prefer-promise-reject-errors': 'off',
'no-unused-vars': 'off',
// allow debugger during development only
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
}
}
.DS_Store
.thumbs.db
node_modules
# Quasar core related directories
.quasar
/dist
# Cordova related directories and files
/src-cordova/node_modules
/src-cordova/platforms
/src-cordova/plugins
/src-cordova/www
# Capacitor related directories and files
/src-capacitor/www
/src-capacitor/node_modules
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
{
"recommendations": [
"dbaeumer.vscode-eslint",
"editorconfig.editorconfig",
"johnsoncodehk.volar",
"wayou.vscode-todo-highlight"
],
"unwantedRecommendations": [
"octref.vetur",
"hookyqr.beautify",
"dbaeumer.jshint",
"ms-vscode.vscode-typescript-tslint-plugin"
]
}
\ No newline at end of file
{
"editor.bracketPairColorization.enabled": true,
"editor.guides.bracketPairs": true,
"editor.formatOnSave": true,
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
"editor.codeActionsOnSave": [
"source.fixAll.eslint"
],
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"vue"
],
"i18n-ally.localesPaths": "src/i18n/locales"
}
# Wiki.js (ux)
The most powerful and extensible open source Wiki software
## Install the dependencies
```bash
yarn
# or
npm install
```
### Start the app in development mode (hot-code reloading, error reporting, etc.)
```bash
quasar dev
```
### Lint the files
```bash
yarn lint
# or
npm run lint
```
### Build the app for production
```bash
quasar build
```
### Customize the configuration
See [Configuring quasar.config.js](https://v2.quasar.dev/quasar-cli-vite/quasar-config-js).
module.exports = {
client: {
service: {
name: 'wiki-core',
// URL to the GraphQL API
url: 'http://localhost:11511'
},
// Files processed by the extension
includes: [
'src/**/*.vue',
'src/**/*.js'
]
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="format-detection" content="telephone=no">
<meta name="msapplication-tap-highlight" content="no">
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
<title>Wiki.js</title>
<!--preload-links-->
<style type="text/css">
@keyframes initspinner {
to { transform: rotate(360deg); }
}
.init-loading {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(255,255,255,.75);
z-index: 2000000000;
backdrop-filter: blur(10px);
}
.body--dark .init-loading {
background-color: rgba(0,0,0,.75);
}
.init-loading:before {
content: '';
box-sizing: border-box;
position: absolute;
top: 50%;
left: 50%;
width: 50px;
height: 50px;
margin-top: -25px;
margin-left: -25px;
border-radius: 50%;
border-top: 2px solid #1976D2;
border-right: 2px solid transparent;
animation: initspinner .6s linear infinite;
z-index: 2000000000;
}
</style>
<noscript>
<style type="text/css">
.init-loading {
display: none !important;
}
.q-drawer-container {
display: none !important;
}
.scroll.relative-position {
position: static !important;
}
.scroll.relative-position > .absolute {
position: relative !important;
}
</style>
</noscript>
</head>
<body>
<div class="init-loading"></div>
<div id="app"><!-- quasar:entry-point --></div>
<script type="module" src="/entry-client.js"></script>
</body>
</html>
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"src/*": [
"src/*"
],
"app/*": [
"*"
],
"components/*": [
"src/components/*"
],
"layouts/*": [
"src/layouts/*"
],
"pages/*": [
"src/pages/*"
],
"assets/*": [
"src/assets/*"
],
"boot/*": [
"src/boot/*"
],
"stores/*": [
"src/stores/*"
],
"vue$": [
"node_modules/vue/dist/vue.runtime.esm-bundler.js"
]
}
},
"exclude": [
"dist",
".quasar",
"node_modules"
]
}
\ No newline at end of file
{
"name": "ux",
"version": "0.0.1",
"description": "The most powerful and extensible open source Wiki software",
"productName": "Wiki.js",
"author": "Nicolas Giard <nick@requarks.io>",
"private": true,
"scripts": {
"dev": "quasar dev",
"build": "quasar build",
"lint": "eslint --ext .js,.vue ./"
},
"dependencies": {
"@apollo/client": "3.5.10",
"@codemirror/autocomplete": "0.19.15",
"@codemirror/basic-setup": "0.19.1",
"@codemirror/closebrackets": "0.19.1",
"@codemirror/commands": "0.19.8",
"@codemirror/comment": "0.19.1",
"@codemirror/fold": "0.19.3",
"@codemirror/gutter": "0.19.9",
"@codemirror/highlight": "0.19.8",
"@codemirror/history": "0.19.2",
"@codemirror/lang-css": "0.19.3",
"@codemirror/lang-html": "0.19.4",
"@codemirror/lang-javascript": "0.19.7",
"@codemirror/lang-json": "0.19.2",
"@codemirror/lang-markdown": "0.19.6",
"@codemirror/matchbrackets": "0.19.4",
"@codemirror/search": "0.19.9",
"@codemirror/state": "0.19.9",
"@codemirror/tooltip": "0.19.16",
"@codemirror/view": "0.19.47",
"@lezer/common": "0.15.12",
"@quasar/extras": "1.13.5",
"@tiptap/core": "2.0.0-beta.174",
"@tiptap/extension-code-block": "2.0.0-beta.37",
"@tiptap/extension-code-block-lowlight": "2.0.0-beta.68",
"@tiptap/extension-color": "2.0.0-beta.9",
"@tiptap/extension-dropcursor": "2.0.0-beta.25",
"@tiptap/extension-font-family": "2.0.0-beta.21",
"@tiptap/extension-gapcursor": "2.0.0-beta.34",
"@tiptap/extension-hard-break": "2.0.0-beta.30",
"@tiptap/extension-highlight": "2.0.0-beta.33",
"@tiptap/extension-history": "2.0.0-beta.21",
"@tiptap/extension-image": "2.0.0-beta.27",
"@tiptap/extension-mention": "2.0.0-beta.95",
"@tiptap/extension-placeholder": "2.0.0-beta.48",
"@tiptap/extension-table": "2.0.0-beta.48",
"@tiptap/extension-table-cell": "2.0.0-beta.20",
"@tiptap/extension-table-header": "2.0.0-beta.22",
"@tiptap/extension-table-row": "2.0.0-beta.19",
"@tiptap/extension-task-item": "2.0.0-beta.31",
"@tiptap/extension-task-list": "2.0.0-beta.26",
"@tiptap/extension-text-align": "2.0.0-beta.29",
"@tiptap/extension-text-style": "2.0.0-beta.23",
"@tiptap/extension-typography": "2.0.0-beta.20",
"@tiptap/starter-kit": "2.0.0-beta.183",
"@tiptap/vue-3": "2.0.0-beta.90",
"@vue/apollo-option": "4.0.0-alpha.16",
"apollo-upload-client": "17.0.0",
"browser-fs-access": "0.26.1",
"clipboard": "2.0.10",
"filesize": "8.0.7",
"filesize-parser": "1.5.0",
"graphql": "16.3.0",
"graphql-tag": "2.12.6",
"js-cookie": "3.0.1",
"jwt-decode": "3.1.2",
"lodash": "4.17.21",
"luxon": "2.3.1",
"pinia": "2.0.13",
"pug": "3.0.2",
"quasar": "2.6.5",
"tippy.js": "6.3.7",
"uuid": "8.3.2",
"v-network-graph": "0.5.9",
"vue": "3.2.31",
"vue-i18n": "9.1.9",
"vue-router": "4.0.14",
"vuedraggable": "4.1.0",
"zxcvbn": "4.4.2"
},
"devDependencies": {
"@intlify/vite-plugin-vue-i18n": "3.4.0",
"@quasar/app-vite": "1.0.0-beta.13",
"@types/lodash": "4.14.181",
"autoprefixer": "10.4.4",
"eslint": "8.12.0",
"eslint-config-standard": "17.0.0-1",
"eslint-plugin-import": "2.26.0",
"eslint-plugin-n": "15.1.0",
"eslint-plugin-promise": "6.0.0",
"eslint-plugin-vue": "8.6.0"
},
"engines": {
"node": "^18 || ^16",
"npm": ">= 6.13.4",
"yarn": ">= 1.21.1"
},
"eslint.packageManager": "yarn"
}
/* eslint-disable */
// https://github.com/michael-ciniawsky/postcss-load-config
module.exports = {
plugins: [
// https://github.com/postcss/autoprefixer
require('autoprefixer')({
overrideBrowserslist: [
'last 4 Chrome versions',
'last 4 Firefox versions',
'last 4 Edge versions',
'last 4 Safari versions',
'last 4 Android versions',
'last 4 ChromeAndroid versions',
'last 4 FirefoxAndroid versions',
'last 4 iOS versions'
]
})
// https://github.com/elchininet/postcss-rtlcss
// If you want to support RTL css, then
// 1. yarn/npm install postcss-rtlcss
// 2. optionally set quasar.config.js > framework > lang to an RTL language
// 3. uncomment the following line:
// require('postcss-rtlcss')
]
}
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><path fill="#546E7A" d="M5 22H7V26H5zM41 22H43V26H41z"/><path fill="#FFC107" d="M40,19H8v20c0,2.209,1.791,4,4,4h24c2.209,0,4-1.791,4-4V19z"/><path fill="#FFECB3" d="M36,31H12v-2c0,0,0-1,1-1s21,0,22,0s1,1,1,1V31z"/><path fill="#37474F" d="M10,19v1c0,1.104,0.896,2,2,2h24c1.104,0,2-0.896,2-2v-1H10z"/><path fill="#37474F" d="M28.619 19h-9.238C17.924 19.733 17 20.804 17 22c0 2.209 3.134 4 7 4s7-1.791 7-4C31 20.804 30.076 19.733 28.619 19zM36 38c0 1.104-.896 2-2 2H14c-1.104 0-2-.896-2-2v-7h24V38zM7 23H8V25H7zM40 23H41V25H40z"/><g><path fill="#90CAF9" d="M12 5H36V20H12z"/><path fill="#90CAF9" d="M24 18.57A3 1.715 0 1 0 24 22A3 1.715 0 1 0 24 18.57Z"/></g><g><path fill="#1976D2" d="M16 9H32V11H16zM16 13H28V15H16z"/></g><g><path fill="#B0BEC5" d="M15 33A1 1 0 1 0 15 35 1 1 0 1 0 15 33zM15 36A1 1 0 1 0 15 38 1 1 0 1 0 15 36zM33 33A1 1 0 1 0 33 35 1 1 0 1 0 33 33zM33 36A1 1 0 1 0 33 38 1 1 0 1 0 33 36zM18 33A1 1 0 1 0 18 35 1 1 0 1 0 18 33zM21 33A1 1 0 1 0 21 35 1 1 0 1 0 21 33zM24 33A1 1 0 1 0 24 35 1 1 0 1 0 24 33zM27 33A1 1 0 1 0 27 35 1 1 0 1 0 27 33zM30 33A1 1 0 1 0 30 35 1 1 0 1 0 30 33zM31 37c0 .553-.447 1-1 1H18c-.552 0-1-.447-1-1l0 0c0-.553.448-1 1-1h12C30.553 36 31 36.447 31 37L31 37z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><path fill="#388e3c" d="M17.204 19.122l-4.907 2.715C12.113 21.938 12 22.126 12 22.329v5.433c0 .203.113.39.297.492l4.908 2.717c.183.101.41.101.593 0l4.907-2.717C22.887 28.152 23 27.965 23 27.762v-5.433c0-.203-.113-.39-.297-.492l-4.906-2.715c-.092-.051-.195-.076-.297-.076-.103 0-.205.025-.297.076M42.451 24.013l-.818.452c-.031.017-.049.048-.049.082v.906c0 .034.019.065.049.082l.818.453c.031.017.068.017.099 0l.818-.453c.03-.017.049-.048.049-.082v-.906c0-.034-.019-.065-.05-.082l-.818-.452C42.534 24.004 42.517 24 42.5 24S42.466 24.004 42.451 24.013"/><path fill="#37474f" d="M35.751,13.364l-2.389-1.333c-0.075-0.042-0.167-0.041-0.241,0.003 c-0.074,0.044-0.12,0.123-0.12,0.209L33,20.295l-2.203-1.219C30.705,19.025,30.602,19,30.5,19c-0.102,0-0.205,0.025-0.297,0.076 h0.001l-4.907,2.715C25.113,21.892,25,22.08,25,22.282v5.433c0,0.203,0.113,0.39,0.297,0.492l4.908,2.717 c0.183,0.101,0.41,0.101,0.593,0l4.907-2.717C35.887,28.106,36,27.918,36,27.715V13.788C36,13.612,35.904,13.45,35.751,13.364z M32.866,26.458l-2.23,1.235c-0.083,0.046-0.186,0.046-0.269,0l-2.231-1.235C28.051,26.412,28,26.326,28,26.234v-2.47 c0-0.092,0.051-0.177,0.135-0.224l2.231-1.234h-0.001c0.042-0.023,0.088-0.034,0.135-0.034c0.047,0,0.093,0.012,0.135,0.034 l2.23,1.234C32.949,23.587,33,23.673,33,23.765v2.47C33,26.326,32.949,26.412,32.866,26.458z"/><path fill="#2e7d32" d="M17.204,19.122L12,27.762c0,0.203,0.113,0.39,0.297,0.492l4.908,2.717 c0.183,0.101,0.41,0.101,0.593,0L23,22.329c0-0.203-0.113-0.39-0.297-0.492l-4.906-2.715c-0.092-0.051-0.195-0.076-0.297-0.076 c-0.103,0-0.205,0.025-0.297,0.076"/><path fill="#4caf50" d="M17.204,19.122l-4.907,2.715C12.113,21.938,12,22.126,12,22.329l5.204,8.642 c0.183,0.101,0.41,0.101,0.593,0l4.907-2.717C22.887,28.152,23,27.965,23,27.762l-5.203-8.64c-0.092-0.051-0.195-0.076-0.297-0.076 c-0.103,0-0.205,0.025-0.297,0.076"/><path fill="#37474f" d="M47.703 21.791l-4.906-2.715C42.705 19.025 42.602 19 42.5 19c-.102 0-.205.025-.297.076h.001l-4.907 2.715C37.114 21.892 37 22.084 37 22.294v5.411c0 .209.114.402.297.503l4.908 2.717c.184.102.409.102.593 0l2.263-1.253c.207-.115.206-.412-.002-.526l-4.924-2.687C40.052 26.412 40 26.325 40 26.231v-2.466c0-.092.05-.177.13-.221l2.235-1.236h-.001c.042-.023.088-.034.135-.034.047 0 .093.012.135.034l2.235 1.237c.08.044.13.129.13.221v2.012c0 .086.046.166.121.209.075.042.167.042.242-.001l2.398-1.393c.148-.086.24-.245.24-.417v-1.88C48 22.085 47.886 21.892 47.703 21.791zM10.703 21.791l-4.906-2.715C5.705 19.025 5.602 19 5.5 19c-.102 0-.205.025-.297.076h.001l-4.907 2.715C.114 21.892 0 22.084 0 22.294v7.465c0 .086.046.166.121.209.075.042.167.042.242-.001l2.398-1.393C2.909 28.488 3 28.329 3 28.157v-4.393c0-.092.05-.177.13-.221l2.235-1.236H5.365c.042-.023.088-.034.135-.034.047 0 .093.012.135.034l2.235 1.237C7.95 23.588 8 23.673 8 23.765v4.393c0 .172.091.331.24.417l2.398 1.393c.075.043.167.043.242.001C10.954 29.925 11 29.845 11 29.759v-7.464C11 22.085 10.886 21.892 10.703 21.791z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><path fill="#fff" d="M44.083,29.79c-0.183-0.829-0.935-1.796-2.452-1.796c-0.31,0-0.649,0.039-1.035,0.119c-0.708,0.146-1.311,0.217-1.842,0.241c4.133-7.04,6.816-16.819,4.159-20.214c-3.501-4.473-8.214-5.141-10.711-5.141L31.967,3c-0.929,0.015-1.893,0.129-2.863,0.339l-3.583,0.774C25.033,4.052,24.536,4.009,24.018,4l-0.03,0l-0.016,0l-0.152-0.001c-1.593,0-3.046,0.338-4.341,0.973l-1.251-0.493c-1.72-0.678-4.308-1.485-6.868-1.485c-0.144,0-0.287,0.003-0.431,0.008C8.407,3.093,6.241,4.05,4.664,5.769C2.696,7.915,1.8,11.054,2.003,15.1C2.013,15.309,4.461,36,11.4,36h0.025l0.064-0.001c0.901-0.022,1.76-0.384,2.563-1.077c0.613,0.46,1.406,0.732,2.145,0.84c0.488,0.115,1.366,0.278,2.418,0.278c1.284,0,2.442-0.263,3.44-0.738c-0.001,0.88-0.006,1.994-0.016,3.418l-0.001,0.075l0.005,0.075c0.097,1.419,0.342,2.698,0.711,3.701c1.051,2.859,2.866,4.434,5.111,4.434c0.093,0,0.188-0.003,0.284-0.009c1.846-0.114,3.717-1.151,5.004-2.772c1.393-1.755,1.715-3.607,1.839-5.026L35,39.111v-0.088v-4.079l0.103,0.01l0.436,0.038l0.042,0.004l0.042,0.002c0.124,0.006,0.252,0.008,0.381,0.008c1.507,0,3.362-0.391,4.616-0.974C41.819,33.476,44.559,31.948,44.083,29.79z"/><path fill="#0277bd" d="M33,34c0-0.205,0.012-0.376,0.018-0.565C33.008,33.184,33,33,33,33s0.012-0.009,0.032-0.022c0.149-2.673,0.886-3.703,1.675-4.29c-0.11-0.153-0.237-0.318-0.356-0.475c-0.333-0.437-0.748-0.979-1.192-1.674l-0.082-0.158c-0.067-0.164-0.229-0.447-0.435-0.819c-1.183-2.14-3.645-6.592-1.96-9.404c0.738-1.232,2.122-1.942,4.121-2.117C33.986,11.718,30.925,6.115,23.985,6c-0.002,0-0.004,0-0.006,0c-6.041-0.098-8.026,5.392-8.672,8.672c0.89-0.377,1.906-0.606,2.836-0.606c0.014,0,0.029,0,0.043,0c2.29,0.017,3.865,1.239,4.323,3.354c0.335,1.552,0.496,2.91,0.492,4.153c-0.01,2.719-0.558,4.149-1.042,5.411l-0.154,0.408c-0.124,0.334-0.255,0.645-0.379,0.937c-0.126,0.298-0.237,0.563-0.318,0.802c0.484,0.11,0.864,0.265,1.125,0.38l0.151,0.066c0.047,0.02,0.094,0.043,0.137,0.069c0.848,0.516,1.376,1.309,1.489,2.233c0.061,0.498,0.051,3.893,0.03,6.855c0.087,1.285,0.305,2.364,0.593,3.146c0.409,1.114,1.431,3.241,3.394,3.119c1.37-0.085,2.687-0.919,3.561-2.019c0.938-1.181,1.284-2.487,1.414-3.958V34z"/><path fill="#0277bd" d="M15.114 28.917c-1.613-1.683-2.399-3.947-2.104-6.056.285-2.035.124-4.027.037-5.098-.029-.357-.048-.623-.047-.77 0-.008.002-.015.003-.023 0-.004-.002-.007-.002-.011.121-3.021 1.286-7.787 4.493-10.62C15.932 5.724 13.388 4.913 11 5 7.258 5.136 3.636 7.724 4 15c.137 2.73 3.222 19.103 7.44 19 .603-.015 1.229-.402 1.872-1.176 1.017-1.223 2.005-2.332 2.708-3.104C15.705 29.481 15.401 29.217 15.114 28.917zM37.023 14.731c.015.154.002.286-.022.408.031.92-.068 1.813-.169 2.677-.074.636-.15 1.293-.171 1.952-.021.645.07 1.282.166 1.956.225 1.578.459 3.359-.765 5.437.225.296.423.571.581.837 4.61-7.475 6.468-16.361 4.695-18.626C38.655 5.944 34.941 4.952 31.999 5c-.921.015-1.758.139-2.473.294C34.602 7.754 36.863 13.026 37.023 14.731zM41 30.071c-2.665.55-3.947.257-4.569-.126-.1.072-.2.133-.293.19-.372.225-.961.583-1.105 2.782.083.016.156.025.246.044L35.714 33c1.32.06 3.049-.31 4.063-.781C41.962 31.205 43.153 29.627 41 30.071zM22.023 32.119c-.037-.298-.198-.539-.492-.732l-.108-.047C21.062 31.181 20.653 31 20 31h-.004c-.127.01-.253.019-.38.019-.052 0-.103-.007-.155-.009-.474.365-1.148.647-2.816.99-2.98.759-1.221 1.655-.078 1.794 1.106.277 3.735.614 5.481-.809C22.043 32.537 22.035 32.229 22.023 32.119z"/><path fill="#0277bd" d="M20.681 18.501c-.292.302-.753.566-1.262.484-.828-.134-1.463-1.133-1.417-1.508h0c.044-.374.751-.569 1.578-.435.287.047.548.128.768.228-.32-.688-.899-1.085-1.782-1.182-1.565-.174-3.226.644-3.56 1.097.007.11.02.251.033.417.093 1.147.265 3.284-.05 5.537-.208 1.485.393 3.169 1.567 4.395.757.79 1.641 1.29 2.513 1.438.111-.478.309-.944.513-1.425.113-.265.233-.547.346-.852l.162-.427c.443-1.155.9-2.35.909-4.703C21.003 20.66 20.892 19.627 20.681 18.501zM34.847 22.007c-.104-.729-.211-1.484-.185-2.303.023-.742.105-1.442.184-2.119.062-.533.11-1.045.138-1.55-1.289.107-2.145.479-2.551 1.108.168-.057.358-.102.568-.129.892-.116 1.543.141 1.618.637.055.363-.253.705-.388.836-.277.269-.626.442-.981.488-.064.008-.129.012-.192.012-.353 0-.69-.121-.949-.3.112 1.973 1.567 4.612 2.283 5.907.153.277.271.498.369.688C35.154 24.163 35.009 23.143 34.847 22.007z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48px" height="48px"><path fill="#33c481" d="M24,30.571c-8.837,0-16,4.921-16,10.286V42c0,1.105,0.895,2,2,2h28c1.105,0,2-0.895,2-2v-1.143 C40,35.492,32.837,30.571,24,30.571z"/><path fill="#21a366" d="M30,32.6c0-0.37,0-0.788,0-1.232c-1.854-0.506-3.876-0.796-6-0.796s-4.146,0.29-6,0.796 c0,0.445,0,0.863,0,1.232c0,2.277,6,8.4,6,8.4S30,34.876,30,32.6z"/><path fill="#d6a121" d="M29,32c0,1.897-5,7-5,7s-5-5.103-5-7c0-2.637,0-8.035,0-8.035h10C29,23.965,29,29.363,29,32z"/><path fill="#fff" d="M29,32c0,1.897-5,7-5,7s-5-5.103-5-7c0,0,2,2,5,2S29,32,29,32z"/><linearGradient id="DVu_EwlVcyi3M2~gQlPREa" x1="32.917" x2="34.251" y1="20" y2="20" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#c48f0c"/><stop offset=".251" stop-color="#d19b16"/><stop offset=".619" stop-color="#dca51f"/><stop offset="1" stop-color="#e0a922"/></linearGradient><path fill="url(#DVu_EwlVcyi3M2~gQlPREa)" d="M32.916,18h-0.527v4h0.703c0.515,0,0.954-0.312,1.041-0.74l0.344-1.703 C34.642,18.743,33.897,18,32.916,18z"/><linearGradient id="DVu_EwlVcyi3M2~gQlPREb" x1="200.917" x2="202.251" y1="20" y2="20" gradientTransform="matrix(-1 0 0 1 216 0)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#c48f0c"/><stop offset=".251" stop-color="#d19b16"/><stop offset=".619" stop-color="#dca51f"/><stop offset="1" stop-color="#e0a922"/></linearGradient><path fill="url(#DVu_EwlVcyi3M2~gQlPREb)" d="M15.084,18h0.527v4h-0.703c-0.515,0-0.954-0.312-1.041-0.74l-0.344-1.703 C13.358,18.743,14.103,18,15.084,18z"/><radialGradient id="DVu_EwlVcyi3M2~gQlPREc" cx="-30.778" cy="-.539" r="12.224" gradientTransform="translate(51.135 19.175) scale(.8816)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#ffcf54"/><stop offset=".261" stop-color="#fdcb4d"/><stop offset=".639" stop-color="#f7c13a"/><stop offset="1" stop-color="#f0b421"/></radialGradient><path fill="url(#DVu_EwlVcyi3M2~gQlPREc)" d="M24,6.4c-4.441,0-9,0.675-9,10.275c0,0.768,0,5.877,0,6.698C15,26.8,20.4,31,24,31 s9-4.2,9-7.627c0-0.821,0-5.929,0-6.698C33,7.075,28.441,6.4,24,6.4z"/><radialGradient id="DVu_EwlVcyi3M2~gQlPREd" cx="-40.48" cy="-14.192" r="28.915" gradientTransform="translate(51.135 19.175) scale(.8816)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#c26715"/><stop offset=".508" stop-color="#b85515"/><stop offset="1" stop-color="#ad3f16"/></radialGradient><path fill="url(#DVu_EwlVcyi3M2~gQlPREd)" d="M24,5.545c-4.354,0-5,1.636-5,1.636c-1.77,0.261-5,2.854-5,5.818c0,1.654,0.265,2.876,1,7 c0.545-6.545,2.249-9,4-9c1.267,0,2.273,1,5,1c2.303,0,2.875-1,5-1c3,0,4,7.968,4,9c0.601-3.01,1-5.555,1-7 C34,9.57,30.209,5.545,24,5.545z"/><radialGradient id="DVu_EwlVcyi3M2~gQlPREe" cx="-53.966" cy="-12.256" r="33.398" gradientTransform="matrix(.8431 0 0 .8816 68.067 19.175)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#c26715"/><stop offset=".508" stop-color="#b85515"/><stop offset="1" stop-color="#ad3f16"/></radialGradient><path fill="url(#DVu_EwlVcyi3M2~gQlPREe)" d="M24.219,5c-4.164,0-5.216,2.182-5.216,2.182c-0.042,1.159,0.522,2.182,0.522,2.182 S20.285,11,24.625,11C27.245,11,31,9.365,31,5C31,5,30.157,5,24.219,5z"/><rect width="2" height="5" x="23" y="39" fill="#21a366"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><linearGradient id="iucqluk~4TSJfp3H4setfa" x1="30.123" x2="41.07" y1="36.377" y2="25.43" gradientUnits="userSpaceOnUse"><stop offset=".365" stop-color="#199ae0"/><stop offset=".699" stop-color="#1898de"/><stop offset=".819" stop-color="#1691d8"/><stop offset=".905" stop-color="#1186cc"/><stop offset=".974" stop-color="#0a75bc"/><stop offset="1" stop-color="#076cb3"/></linearGradient><path fill="url(#iucqluk~4TSJfp3H4setfa)" d="M45.516,25.667L33.668,37.516c-0.645,0.645-1.69,0.645-2.335,0l-2.349-2.349 c-0.645-0.645-0.645-1.69,0-2.335l11.849-11.849c0.645-0.645,1.69-0.645,2.335,0l2.349,2.349 C46.161,23.977,46.161,25.023,45.516,25.667z"/><linearGradient id="iucqluk~4TSJfp3H4setfb" x1="19.812" x2="38.111" y1="15.281" y2="33.58" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1ea2e4"/><stop offset="1" stop-color="#32bdef"/></linearGradient><path fill="url(#iucqluk~4TSJfp3H4setfb)" d="M45.516,23.332L32.667,10.484c-0.645-0.645-1.69-0.645-2.335,0l-2.349,2.349 c-0.645,0.645-0.645,1.69,0,2.335L32.816,20H15.5c-0.828,0-1.5,0.672-1.5,1.5v5c0,0.828,0.672,1.5,1.5,1.5h25.316l0,0h2.368 l2.333-2.333C46.161,25.023,46.161,23.977,45.516,23.332z"/><linearGradient id="iucqluk~4TSJfp3H4setfc" x1="145.334" x2="155.403" y1="-109.48" y2="-109.48" gradientTransform="rotate(-90 147.24 26.76)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1ea2e4"/><stop offset="1" stop-color="#32bdef"/></linearGradient><path fill="url(#iucqluk~4TSJfp3H4setfc)" d="M12,21v6c0,0.552-0.448,1-1,1h0c-0.552,0-1-0.448-1-1v-6c0-0.552,0.448-1,1-1h0 C11.552,20,12,20.448,12,21z"/><linearGradient id="iucqluk~4TSJfp3H4setfd" x1="145.334" x2="155.403" y1="-113.48" y2="-113.48" gradientTransform="rotate(-90 147.24 26.76)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1ea2e4"/><stop offset="1" stop-color="#32bdef"/></linearGradient><path fill="url(#iucqluk~4TSJfp3H4setfd)" d="M8,21v6c0,0.552-0.448,1-1,1h0c-0.552,0-1-0.448-1-1v-6c0-0.552,0.448-1,1-1h0 C7.552,20,8,20.448,8,21z"/><linearGradient id="iucqluk~4TSJfp3H4setfe" x1="145.334" x2="155.403" y1="-117.48" y2="-117.48" gradientTransform="rotate(-90 147.24 26.76)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1ea2e4"/><stop offset="1" stop-color="#32bdef"/></linearGradient><path fill="url(#iucqluk~4TSJfp3H4setfe)" d="M4,21v6c0,0.552-0.448,1-1,1h0c-0.552,0-1-0.448-1-1v-6c0-0.552,0.448-1,1-1h0 C3.552,20,4,20.448,4,21z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><linearGradient id="OhW_8EWeW2cETtZ_QU~4ka" x1="24" x2="24" y1="6.121" y2="42.039" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#33bef0"/><stop offset="1" stop-color="#0a85d9"/></linearGradient><path fill="url(#OhW_8EWeW2cETtZ_QU~4ka)" d="M40,42H8c-1.1,0-2-0.9-2-2V8c0-1.1,0.9-2,2-2h32c1.1,0,2,0.9,2,2v32C42,41.1,41.1,42,40,42z"/><path d="M37.02,20.243V19.5c0-0.827-0.673-1.5-1.5-1.5h-2.927c-0.827,0-1.5,0.673-1.5,1.5v0.529 C30.513,18.94,29.296,18,26.809,18H23.78c-0.827,0-1.5,0.673-1.5,1.5v7.729l-2.929-8.234C19.139,18.4,18.571,18,17.939,18h-1.969 c-0.627,0-1.193,0.396-1.409,0.987l-3.336,9.164c-0.154,0.422-0.093,0.893,0.165,1.261C11.647,29.78,12.069,30,12.519,30h1.537 c0.658,0,1.233-0.421,1.43-1.047l0.373-1.177h2.094l0.378,1.183C18.53,29.581,19.104,30,19.759,30h1.557 c0.446,0,0.866-0.218,1.124-0.582c0.029-0.041,0.046-0.087,0.07-0.13C22.775,29.714,23.243,30,23.78,30h1.252 c0.827,0,1.5-0.673,1.5-1.5v-1.945h0.074c1.449,0,2.643-0.395,3.549-1.172c0.95-0.816,1.433-1.892,1.433-3.196 c0-0.281-0.021-0.597-0.078-0.925c0.122,0.13,0.259,0.246,0.42,0.326v4.823c-0.495,0.245-0.837,0.756-0.837,1.345V28.5 c0,0.827,0.673,1.5,1.5,1.5h2.927c0.827,0,1.5-0.673,1.5-1.5v-0.743c0-0.589-0.342-1.1-0.837-1.345v-4.823 C36.678,21.343,37.02,20.833,37.02,20.243z M27.217,22.271c0,0.33,0,0.553-0.685,0.574v-1.114 C27.217,21.751,27.217,21.961,27.217,22.271z" opacity=".05"/><path d="M18.881,19.164c-0.142-0.397-0.521-0.664-0.941-0.664h-1.969c-0.418,0-0.796,0.264-0.939,0.658 l-3.336,9.165c-0.098,0.269-0.059,0.568,0.104,0.803c0.164,0.234,0.433,0.374,0.719,0.374h1.537c0.438,0,0.822-0.281,0.953-0.698 l0.483-1.526h2.825l0.488,1.53c0.134,0.416,0.517,0.695,0.953,0.695h1.557c0.284,0,0.552-0.139,0.716-0.371 c0.164-0.232,0.205-0.531,0.109-0.799L18.881,19.164z M17.481,24.546h-1.188l0.596-1.856L17.481,24.546z" opacity=".07"/><path d="M26.809,18.5H23.78c-0.552,0-1,0.449-1,1v9c0,0.551,0.448,1,1,1h1.252c0.552,0,1-0.449,1-1v-2.445 h0.574c1.326,0,2.41-0.354,3.224-1.052c0.835-0.717,1.258-1.665,1.258-2.816C31.088,20.505,30.346,18.5,26.809,18.5z M27.717,22.271 c0,0.559-0.157,1.076-1.299,1.076h-0.386v-2.117h0.386C27.56,21.229,27.717,21.73,27.717,22.271z" opacity=".07"/><path d="M36.52,20.243V19.5c0-0.551-0.448-1-1-1h-2.927c-0.552,0-1,0.449-1,1v0.743 c0,0.496,0.363,0.909,0.837,0.987v5.54c-0.474,0.078-0.837,0.491-0.837,0.987V28.5c0,0.551,0.448,1,1,1h2.927c0.552,0,1-0.449,1-1 v-0.743c0-0.496-0.363-0.909-0.837-0.987v-5.54C36.156,21.152,36.52,20.739,36.52,20.243z M36.019,19.5L36.019,19.5L36.019,19.5 L36.019,19.5z" opacity=".07"/><path fill="#fff" d="M21.315,29h-1.557c-0.217,0-0.41-0.141-0.476-0.348l-0.6-1.877h-3.556l-0.594,1.875 C14.466,28.859,14.273,29,14.055,29h-1.537c-0.261,0-0.443-0.26-0.354-0.505l3.337-9.166c0.072-0.198,0.26-0.329,0.47-0.329h1.968 c0.212,0,0.4,0.133,0.471,0.332l3.26,9.165C21.757,28.743,21.575,29,21.315,29z M18.166,25.046l-1.074-3.361 c-0.079-0.251-0.135-0.551-0.167-0.9h-0.056c-0.023,0.293-0.081,0.583-0.174,0.872l-1.088,3.389H18.166z"/><path fill="#fff" d="M25.532,25.555V28.5c0,0.276-0.224,0.5-0.5,0.5H23.78c-0.276,0-0.5-0.224-0.5-0.5v-9 c0-0.276,0.224-0.5,0.5-0.5h3.029c2.52,0,3.78,1.062,3.78,3.187c0,1.004-0.361,1.817-1.084,2.437s-1.689,0.931-2.897,0.931H25.532z M25.532,20.729v3.117h0.886c1.199,0,1.799-0.525,1.799-1.576c0-1.027-0.6-1.541-1.799-1.541H25.532z"/><path fill="#fff" d="M36.019,19.5v0.743c0,0.276-0.224,0.5-0.5,0.5h-0.337v6.513h0.337c0.276,0,0.5,0.224,0.5,0.5V28.5 c0,0.276-0.224,0.5-0.5,0.5h-2.926c-0.276,0-0.5-0.224-0.5-0.5v-0.743c0-0.276,0.224-0.5,0.5-0.5h0.337v-6.513h-0.337 c-0.276,0-0.5-0.224-0.5-0.5V19.5c0-0.276,0.224-0.5,0.5-0.5h2.926C35.795,19,36.019,19.224,36.019,19.5z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><linearGradient id="ldLw80Wb5w9tTRcKjgX8Ga" x1="2.252" x2="34.131" y1="12.996" y2="42.423" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#0077d2"/><stop offset="1" stop-color="#0b59a2"/></linearGradient><path fill="url(#ldLw80Wb5w9tTRcKjgX8Ga)" d="M23.008,22.387L6.256,31.181c-1.523,0.8-1.523,2.98,0,3.779l16.752,8.795 c0.621,0.326,1.363,0.326,1.984,0l16.752-8.795c1.523-0.8,1.523-2.98,0-3.779l-16.752-8.795 C24.371,22.06,23.629,22.06,23.008,22.387z"/><path d="M25.457,35.569L37.78,29.1l-12.787-6.713c-0.621-0.326-1.363-0.326-1.984,0L10.22,29.1l12.322,6.469 c0.447,0.235,0.952,0.36,1.458,0.36S25.011,35.805,25.457,35.569z" opacity=".05"/><path d="M25.225,35.127l12.017-6.309l-12.25-6.431c-0.621-0.326-1.363-0.326-1.984,0l-12.25,6.431 l12.017,6.309c0.376,0.198,0.8,0.303,1.225,0.303S24.849,35.325,25.225,35.127z" opacity=".07"/><linearGradient id="ldLw80Wb5w9tTRcKjgX8Gb" x1="6.773" x2="38.652" y1="8.098" y2="37.525" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#2aa4f4"/><stop offset="1" stop-color="#007ad9"/></linearGradient><path fill="url(#ldLw80Wb5w9tTRcKjgX8Gb)" d="M23.008,13.316L6.256,22.11c-1.523,0.8-1.523,2.98,0,3.779l16.752,8.795 c0.621,0.326,1.363,0.326,1.984,0l16.752-8.795c1.523-0.8,1.523-2.98,0-3.779l-16.752-8.795 C24.371,12.989,23.629,12.989,23.008,13.316z"/><path d="M25.457,26.498l12.322-6.469l-12.787-6.713c-0.621-0.326-1.363-0.326-1.984,0l-12.787,6.713 l12.321,6.469c0.447,0.235,0.952,0.36,1.458,0.36S25.011,26.733,25.457,26.498z" opacity=".05"/><path d="M25.225,26.056l12.017-6.309l-12.25-6.431c-0.621-0.326-1.363-0.326-1.984,0l-12.25,6.431 l12.017,6.309c0.376,0.198,0.8,0.303,1.225,0.303S24.849,26.254,25.225,26.056z" opacity=".07"/><linearGradient id="ldLw80Wb5w9tTRcKjgX8Gc" x1="11.294" x2="43.173" y1="3.201" y2="32.627" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#75daff"/><stop offset="1" stop-color="#1ea2e4"/></linearGradient><path fill="url(#ldLw80Wb5w9tTRcKjgX8Gc)" d="M23.008,4.245L6.256,13.039c-1.523,0.8-1.523,2.98,0,3.779l16.752,8.795 c0.621,0.326,1.363,0.326,1.984,0l16.752-8.795c1.523-0.8,1.523-2.98,0-3.779L24.992,4.245C24.371,3.918,23.629,3.918,23.008,4.245z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><path fill="#50e6ff" d="M44,8v33h-8V8c0-0.552,0.448-1,1-1h6C43.552,7,44,7.448,44,8z"/><path fill="#35c1f1" d="M36,15v26h-8V15H36z"/><path fill="#199be2" d="M28,13v28h-8V13c0-0.552,0.448-1,1-1h6C27.552,12,28,12.448,28,13z"/><path fill="#0078d4" d="M20,20v21h-8V20H20z"/><path fill="#0d62ab" d="M12,17v24H4V17c0-0.552,0.448-1,1-1h6C11.552,16,12,16.448,12,17z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><path fill="#e3a600" d="M20.834,29.595l-6.808,13.958c-0.136,0.279-0.33,0.518-0.579,0.708l-0.91,0.702 c-0.302,0.231-0.708,0.266-1.05,0.1l-2.481-1.21c-0.342-0.167-0.564-0.509-0.568-0.889l-0.007-1.149 c-0.003-0.313,0.065-0.613,0.201-0.892l0.671-1.375c0.609,0.074,1.271-0.326,1.556-0.91s0.192-1.353-0.241-1.787l0.877-1.798 c0.609,0.074,1.271-0.326,1.556-0.91s0.192-1.353-0.241-1.787l2.63-5.393L20.834,29.595z"/><path fill="#edbe00" d="M25.59,13c-4.967-2.423-10.949-0.363-13.372,4.604s-0.363,10.949,4.604,13.372 s10.949,0.363,13.372-4.604S30.557,15.423,25.59,13z"/><path fill="#edbe00" d="M25.59,13c-0.77-0.37-1.56-0.64-2.36-0.8c-0.31-0.07-0.62-0.12-0.93-0.15 c-2.337-0.258-4.68,0.321-6.613,1.595l-1.123-0.323l-0.461,1.62c-0.75,0.756-1.39,1.646-1.883,2.657 c-2.42,4.97-0.36,10.95,4.6,13.38c1.75,0.85,3.63,1.15,5.43,0.95c0.32-0.03,0.64-0.08,0.96-0.14c2.93-0.6,5.57-2.51,6.98-5.42 C32.62,21.4,30.56,15.42,25.59,13z"/><linearGradient id="bN0gXF350I4SeGvD0XhmSa" x1="27" x2="27" y1="18.098" y2="2.759" gradientTransform="matrix(1 0 0 -1 0 50)" gradientUnits="userSpaceOnUse"><stop offset=".014" stop-color="#e5a505"/><stop offset=".063" stop-color="#e9a804"/><stop offset=".128" stop-color="#f4b102"/><stop offset=".169" stop-color="#fbb600"/><stop offset=".323" stop-color="#fdb700"/></linearGradient><path fill="url(#bN0gXF350I4SeGvD0XhmSa)" d="M30,29v15.53c0,0.31-0.07,0.61-0.21,0.89l-0.51,1.03c-0.17,0.34-0.52,0.55-0.9,0.55h-2.76 c-0.38,0-0.73-0.21-0.9-0.55l-0.51-1.03C24.07,45.14,24,44.84,24,44.53V43c0.58-0.2,1-0.85,1-1.5s-0.42-1.3-1-1.5v-2 c0.58-0.2,1-0.85,1-1.5s-0.42-1.3-1-1.5v-6H30z"/><path d="M25.59,13c-0.77-0.37-1.56-0.64-2.36-0.8c-0.31-0.07-0.62-0.12-0.93-0.15 C18.58,13.82,16,17.61,16,22c0,4.37,2.56,8.15,6.25,9.93c0.32-0.03,0.64-0.08,0.96-0.14c2.93-0.6,5.57-2.51,6.98-5.42 C32.62,21.4,30.56,15.42,25.59,13z M27,20c-1.1,0-2-0.9-2-2s0.9-2,2-2s2,0.9,2,2S28.1,20,27,20z" opacity=".05"/><path d="M25.59,13c-0.77-0.37-1.56-0.64-2.36-0.8c-3.93,1.52-6.73,5.34-6.73,9.8 c0,4.45,2.79,8.27,6.71,9.79c2.93-0.6,5.57-2.51,6.98-5.42C32.62,21.4,30.56,15.42,25.59,13z M27,20.5c-1.38,0-2.5-1.12-2.5-2.5 s1.12-2.5,2.5-2.5s2.5,1.12,2.5,2.5S28.38,20.5,27,20.5z" opacity=".07"/><linearGradient id="bN0gXF350I4SeGvD0XhmSb" x1="22.304" x2="31.696" y1="36.832" y2="19.168" gradientTransform="matrix(1 0 0 -1 0 50)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fede00"/><stop offset="1" stop-color="#ffd000"/></linearGradient><path fill="url(#bN0gXF350I4SeGvD0XhmSb)" d="M27,12c-5.526,0-10,4.474-10,10s4.474,10,10,10s10-4.474,10-10S32.526,12,27,12z M27,21 c-1.656,0-3-1.344-3-3s1.344-3,3-3s3,1.344,3,3S28.656,21,27,21z"/><linearGradient id="bN0gXF350I4SeGvD0XhmSc" x1="15.816" x2="17.996" y1="63.86" y2="55.91" gradientTransform="matrix(1 0 0 -1 0 50)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fcfcfc"/><stop offset=".495" stop-color="#f4f4f4"/><stop offset=".946" stop-color="#e8e8e8"/><stop offset="1" stop-color="#e8e8e8"/></linearGradient><path fill="url(#bN0gXF350I4SeGvD0XhmSc)" d="M22.5,1C17.26,1,13,5.26,13,10.5c0,1.61,0.385,3.13,1.095,4.45 c0.48-0.5,1.022-0.935,1.592-1.305C15.237,12.685,15,11.62,15,10.5C15,6.36,18.36,3,22.5,3S30,6.36,30,10.5 c0,0.65-0.08,1.29-0.25,1.89c-0.25,0.99-0.7,1.9-1.31,2.68c-0.06,0.07-0.11,0.14-0.17,0.21c-1.06,1.29-2.56,2.22-4.26,2.57 C24,17.9,24,17.95,24,18c0,0.66,0.22,1.28,0.58,1.77c2.03-0.45,3.8-1.55,5.11-3.07l0.01-0.01c0.88-1.01,1.55-2.22,1.92-3.55 C31.87,12.3,32,11.42,32,10.5C32,5.26,27.74,1,22.5,1z"/><path d="M24.5,18c0-0.09,0.01-0.19,0.01-0.28c-0.16,0.05-0.33,0.1-0.5,0.13 C24,17.9,24,17.95,24,18c0,0.1,0.01,0.2,0.02,0.3c0.05,0.55,0.25,1.05,0.56,1.47c0.18-0.04,0.36-0.08,0.53-0.14 C24.73,19.2,24.5,18.62,24.5,18z" opacity=".07"/><path d="M25,18c0-0.16,0.02-0.31,0.05-0.46c-0.17,0.08-0.36,0.14-0.54,0.18 c-0.16,0.05-0.33,0.1-0.5,0.13C24,17.9,24,17.95,24,18c0,0.1,0.01,0.2,0.02,0.3c0.05,0.55,0.25,1.05,0.56,1.47 c0.18-0.04,0.36-0.08,0.53-0.14c0.18-0.05,0.36-0.1,0.53-0.17C25.25,19.09,25,18.57,25,18z" opacity=".05"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><path fill="#50e6ff" d="M6.673,11.767l24-8.308C31.322,3.235,32,3.717,32,4.404v18.884c0,0.426-0.27,0.806-0.673,0.945 l-24,8.308C6.678,32.765,6,32.283,6,31.596V12.712C6,12.286,6.27,11.906,6.673,11.767z"/><path d="M31.327,24.233C31.73,24.094,32,23.714,32,23.288V8.672l-20.653,7.149 C10.541,16.1,10,16.859,10,17.712v13.903L31.327,24.233z" opacity=".05"/><path d="M31.327,24.233C31.73,24.094,32,23.714,32,23.288V9.202l-20.49,7.093 c-0.604,0.208-1.01,0.778-1.01,1.417v13.73L31.327,24.233z" opacity=".05"/><path fill="#199be2" d="M11.673,16.767l24-8.308C36.322,8.235,37,8.717,37,9.404v18.884c0,0.426-0.27,0.806-0.673,0.945 l-24,8.308C11.678,37.765,11,37.283,11,36.596V17.712C11,17.286,11.27,16.906,11.673,16.767z"/><path d="M36.327,29.233C36.73,29.094,37,28.714,37,28.288V13.672l-20.653,7.149 C15.541,21.1,15,21.859,15,22.712v13.903L36.327,29.233z" opacity=".05"/><path d="M36.327,29.233C36.73,29.094,37,28.714,37,28.288V14.202l-20.49,7.093 c-0.604,0.208-1.01,0.778-1.01,1.417v13.73L36.327,29.233z" opacity=".05"/><path fill="#0d62ab" d="M16.673,21.767l24-8.308C41.322,13.235,42,13.717,42,14.404v18.884c0,0.426-0.27,0.806-0.673,0.945 l-24,8.308C16.678,42.765,16,42.283,16,41.596V22.712C16,22.286,16.27,21.906,16.673,21.767z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><path fill="#7b83eb" d="M24,13H3v24c0,1.105,0.895,2,2,2h19V13z"/><path fill="#5059c9" d="M45,13H24v26h19c1.105,0,2-0.895,2-2V13z"/><path fill="#3a41ac" d="M43,9H5c-1.105,0-2,0.895-2,2v2h42v-2C45,9.895,44.105,9,43,9z"/><circle cx="7" cy="18" r="1" fill="#3a41ac"/><circle cx="7" cy="22" r="1" fill="#3a41ac"/><circle cx="7" cy="26" r="1" fill="#3a41ac"/><circle cx="7" cy="34" r="1" fill="#3a41ac"/><path fill="#3a41ac" d="M20,19h-7c-0.552,0-1-0.448-1-1v0c0-0.552,0.448-1,1-1h7c0.552,0,1,0.448,1,1v0 C21,18.552,20.552,19,20,19z"/><path fill="#3a41ac" d="M20,27h-7c-0.552,0-1-0.448-1-1v0c0-0.552,0.448-1,1-1h7c0.552,0,1,0.448,1,1v0 C21,26.552,20.552,27,20,27z"/><path fill="#3a41ac" d="M20,23h-7c-0.552,0-1-0.448-1-1v0c0-0.552,0.448-1,1-1h7c0.552,0,1,0.448,1,1v0 C21,22.552,20.552,23,20,23z"/><path fill="#3a41ac" d="M20,35h-7c-0.552,0-1-0.448-1-1l0,0c0-0.552,0.448-1,1-1h7c0.552,0,1,0.448,1,1l0,0 C21,34.552,20.552,35,20,35z"/><path fill="#3a41ac" d="M20,31h-2c-0.552,0-1-0.448-1-1v0c0-0.552,0.448-1,1-1h2c0.552,0,1,0.448,1,1v0 C21,30.552,20.552,31,20,31z"/><circle cx="28" cy="18" r="1" fill="#7b83eb"/><circle cx="28" cy="22" r="1" fill="#7b83eb"/><circle cx="28" cy="26" r="1" fill="#7b83eb"/><circle cx="28" cy="34" r="1" fill="#7b83eb"/><path fill="#7b83eb" d="M41,19h-7c-0.552,0-1-0.448-1-1v0c0-0.552,0.448-1,1-1h7c0.552,0,1,0.448,1,1v0 C42,18.552,41.552,19,41,19z"/><path fill="#7b83eb" d="M41,27h-7c-0.552,0-1-0.448-1-1v0c0-0.552,0.448-1,1-1h7c0.552,0,1,0.448,1,1v0 C42,26.552,41.552,27,41,27z"/><path fill="#7b83eb" d="M41,23h-7c-0.552,0-1-0.448-1-1v0c0-0.552,0.448-1,1-1h7c0.552,0,1,0.448,1,1v0 C42,22.552,41.552,23,41,23z"/><path fill="#7b83eb" d="M41,35h-7c-0.552,0-1-0.448-1-1l0,0c0-0.552,0.448-1,1-1h7c0.552,0,1,0.448,1,1l0,0 C42,34.552,41.552,35,41,35z"/><path fill="#7b83eb" d="M41,31h-2c-0.552,0-1-0.448-1-1v0c0-0.552,0.448-1,1-1h2c0.552,0,1,0.448,1,1v0 C42,30.552,41.552,31,41,31z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><linearGradient id="Nc0B9TSPkzHlq4dNHwoWda" x1="7.793" x2="23.566" y1="8.207" y2="23.98" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#7dd8f3"/><stop offset="1" stop-color="#45b0d0"/></linearGradient><path fill="url(#Nc0B9TSPkzHlq4dNHwoWda)" d="M5,10h26v18H7c-1.105,0-2-0.895-2-2V10z"/><linearGradient id="Nc0B9TSPkzHlq4dNHwoWdb" x1="5" x2="31" y1="8" y2="8" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#0077d2"/><stop offset="1" stop-color="#0b59a2"/></linearGradient><path fill="url(#Nc0B9TSPkzHlq4dNHwoWdb)" d="M31,10V8c0-1.105-0.895-2-2-2H7C5.895,6,5,6.895,5,8v2H31z"/><linearGradient id="Nc0B9TSPkzHlq4dNHwoWdc" x1="12.5" x2="12.5" y1="15" y2="24.438" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#199ae0"/><stop offset="1" stop-color="#0782d8"/></linearGradient><path fill="url(#Nc0B9TSPkzHlq4dNHwoWdc)" d="M15,23h-5c-0.552,0-1-0.448-1-1v-6c0-0.552,0.448-1,1-1h5c0.552,0,1,0.448,1,1v6 C16,22.552,15.552,23,15,23z"/><linearGradient id="Nc0B9TSPkzHlq4dNHwoWdd" x1="23.5" x2="23.5" y1="15" y2="24.438" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#199ae0"/><stop offset="1" stop-color="#0782d8"/></linearGradient><path fill="url(#Nc0B9TSPkzHlq4dNHwoWdd)" d="M26,23h-5c-0.552,0-1-0.448-1-1v-6c0-0.552,0.448-1,1-1h5c0.552,0,1,0.448,1,1v6 C27,22.552,26.552,23,26,23z"/><path d="M31,28v-9H19c-1.654,0-3,1.346-3,3v6H31z" opacity=".05"/><path d="M31,28v-8.5H19c-1.378,0-2.5,1.122-2.5,2.5v6H31z" opacity=".07"/><linearGradient id="Nc0B9TSPkzHlq4dNHwoWde" x1="17" x2="43" y1="33" y2="33" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#9dffce"/><stop offset="1" stop-color="#50d18d"/></linearGradient><path fill="url(#Nc0B9TSPkzHlq4dNHwoWde)" d="M17,24h26v16c0,1.105-0.895,2-2,2H19c-1.105,0-2-0.895-2-2V24z"/><linearGradient id="Nc0B9TSPkzHlq4dNHwoWdf" x1="17" x2="43" y1="22" y2="22" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#21ad64"/><stop offset="1" stop-color="#088242"/></linearGradient><path fill="url(#Nc0B9TSPkzHlq4dNHwoWdf)" d="M43,24v-2c0-1.105-0.895-2-2-2H19c-1.105,0-2,0.895-2,2v2H43z"/><g><linearGradient id="Nc0B9TSPkzHlq4dNHwoWdg" x1="21" x2="28" y1="33" y2="33" gradientUnits="userSpaceOnUse"><stop offset=".824" stop-color="#135d36"/><stop offset=".931" stop-color="#125933"/><stop offset="1" stop-color="#11522f"/></linearGradient><path fill="url(#Nc0B9TSPkzHlq4dNHwoWdg)" d="M27,37h-5c-0.552,0-1-0.448-1-1v-6c0-0.552,0.448-1,1-1h5c0.552,0,1,0.448,1,1v6 C28,36.552,27.552,37,27,37z"/><linearGradient id="Nc0B9TSPkzHlq4dNHwoWdh" x1="32" x2="39" y1="33" y2="33" gradientUnits="userSpaceOnUse"><stop offset=".824" stop-color="#135d36"/><stop offset=".931" stop-color="#125933"/><stop offset="1" stop-color="#11522f"/></linearGradient><path fill="url(#Nc0B9TSPkzHlq4dNHwoWdh)" d="M38,37h-5c-0.552,0-1-0.448-1-1v-6c0-0.552,0.448-1,1-1h5c0.552,0,1,0.448,1,1v6 C39,36.552,38.552,37,38,37z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><linearGradient id="Y2MBg9lti7D0ov~adiJgUa" x1="16.758" x2="30.883" y1="3.118" y2="17.242" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#f44f5a"/><stop offset=".443" stop-color="#ee3d4a"/><stop offset="1" stop-color="#e52030"/></linearGradient><path fill="url(#Y2MBg9lti7D0ov~adiJgUa)" d="M24,4l-1,1v19h2.414L38.14,11.274V9.86C34.52,6.24,29.52,4,24,4z"/><linearGradient id="Y2MBg9lti7D0ov~adiJgUb" x1="-33.907" x2="-.208" y1="19.952" y2="53.652" gradientTransform="rotate(45.001 24.001 92)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fed100"/><stop offset="1" stop-color="#e36001"/></linearGradient><path fill="url(#Y2MBg9lti7D0ov~adiJgUb)" d="M38.142,9.858L24,24l1,1l17.997,0l1-1C43.997,18.881,42.045,13.761,38.142,9.858z"/><linearGradient id="Y2MBg9lti7D0ov~adiJgUc" x1="-46.93" x2="-36.223" y1="74.93" y2="85.637" gradientTransform="rotate(90 24 92)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#ffd747"/><stop offset=".482" stop-color="#ffd645"/><stop offset="1" stop-color="#f5bc00"/></linearGradient><path fill="url(#Y2MBg9lti7D0ov~adiJgUc)" d="M44,24H24v1.414L36.726,38.14h1.414C41.76,34.52,44,29.52,44,24z"/><linearGradient id="Y2MBg9lti7D0ov~adiJgUd" x1="-27.013" x2="-16.306" y1="123.013" y2="133.72" gradientTransform="rotate(134.999 24 92)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#33c481"/><stop offset="1" stop-color="#21a366"/></linearGradient><path fill="url(#Y2MBg9lti7D0ov~adiJgUd)" d="M38.142,38.142L24,24l-1,1l0,17.997l1,1C29.119,43.997,34.239,42.045,38.142,38.142z"/><linearGradient id="Y2MBg9lti7D0ov~adiJgUe" x1="21.07" x2="31.777" y1="142.93" y2="153.637" gradientTransform="rotate(180 24 92)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#28afea"/><stop offset="1" stop-color="#0b88da"/></linearGradient><path fill="url(#Y2MBg9lti7D0ov~adiJgUe)" d="M24,44V24h-1.414L9.86,36.726v1.414C13.48,41.76,18.48,44,24,44z"/><linearGradient id="Y2MBg9lti7D0ov~adiJgUf" x1="67.621" x2="78.328" y1="121.481" y2="132.188" gradientTransform="rotate(-134.999 24 92)" gradientUnits="userSpaceOnUse"><stop offset=".002" stop-color="#427fdb"/><stop offset=".397" stop-color="#2668cb"/><stop offset=".763" stop-color="#1358bf"/><stop offset="1" stop-color="#0c52bb"/></linearGradient><path fill="url(#Y2MBg9lti7D0ov~adiJgUf)" d="M9.858,38.142L24,24l-1-1L5.003,23l-1,1C4.003,29.119,5.955,34.239,9.858,38.142z"/><linearGradient id="Y2MBg9lti7D0ov~adiJgUg" x1="89.07" x2="99.777" y1="74.93" y2="85.637" gradientTransform="rotate(-90 24 92)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#a235d4"/><stop offset=".441" stop-color="#a033d1"/><stop offset=".702" stop-color="#982cc9"/><stop offset=".915" stop-color="#8b21bb"/><stop offset="1" stop-color="#831bb3"/></linearGradient><path fill="url(#Y2MBg9lti7D0ov~adiJgUg)" d="M4,24h20v-1.414L11.274,9.86H9.86C6.24,13.48,4,18.48,4,24z"/><linearGradient id="Y2MBg9lti7D0ov~adiJgUh" x1="69.153" x2="96.498" y1="26.847" y2="54.191" gradientTransform="rotate(-45.001 23.999 92)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#e83c67"/><stop offset=".423" stop-color="#c5214a"/><stop offset=".773" stop-color="#b01038"/><stop offset="1" stop-color="#a80a31"/></linearGradient><path fill="url(#Y2MBg9lti7D0ov~adiJgUh)" d="M9.858,9.858L24,24V4.003C18.881,4.003,13.761,5.955,9.858,9.858z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><linearGradient id="CrkWqRsuEmwpViPxws7A9a" x1="12.686" x2="35.58" y1="4.592" y2="41.841" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#737be6"/><stop offset="1" stop-color="#4750b3"/></linearGradient><path fill="url(#CrkWqRsuEmwpViPxws7A9a)" d="M42,8H6c-1.105,0-2,0.895-2,2v26c0,1.105,0.895,2,2,2h8v7.998 c0,0.891,1.077,1.337,1.707,0.707L24.412,38H42c1.105,0,2-0.895,2-2V10C44,8.895,43.105,8,42,8z"/><path d="M12,22h24c1.105,0,2-0.895,2-2v-2c0-1.105-0.895-2-2-2H12c-1.105,0-2,0.895-2,2v2 C10,21.105,10.895,22,12,22z" opacity=".05"/><path d="M12,21.5h24c0.828,0,1.5-0.672,1.5-1.5v-2c0-0.828-0.672-1.5-1.5-1.5H12c-0.828,0-1.5,0.672-1.5,1.5 v2C10.5,20.828,11.172,21.5,12,21.5z" opacity=".07"/><path d="M12,30h18c1.105,0,2-0.895,2-2v-2c0-1.105-0.895-2-2-2H12c-1.105,0-2,0.895-2,2v2 C10,29.105,10.895,30,12,30z" opacity=".05"/><path d="M12,29.5h18c0.828,0,1.5-0.672,1.5-1.5v-2c0-0.828-0.672-1.5-1.5-1.5H12c-0.828,0-1.5,0.672-1.5,1.5 v2C10.5,28.828,11.172,29.5,12,29.5z" opacity=".07"/><path fill="#fff" d="M31,26v2c0,0.552-0.448,1-1,1H12c-0.552,0-1-0.448-1-1v-2c0-0.552,0.448-1,1-1h18 C30.552,25,31,25.448,31,26z"/><path fill="#fff" d="M37,18v2c0,0.552-0.448,1-1,1H12c-0.552,0-1-0.448-1-1v-2c0-0.552,0.448-1,1-1h24 C36.552,17,37,17.448,37,18z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48px" height="48px"><linearGradient id="LkaBH78Qy0LlLxZFYVKUda" x1="8" x2="40" y1="35.5" y2="35.5" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#11408a"/><stop offset="1" stop-color="#103f8f"/></linearGradient><path fill="url(#LkaBH78Qy0LlLxZFYVKUda)" d="M40,28H8c0,0,0,10.271,0,11c0,2.209,7.163,4,16,4s16-1.791,16-4C40,38.271,40,28,40,28z"/><linearGradient id="LkaBH78Qy0LlLxZFYVKUdb" x1="8" x2="40" y1="25.5" y2="25.5" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1d59b3"/><stop offset="1" stop-color="#195bbc"/></linearGradient><path fill="url(#LkaBH78Qy0LlLxZFYVKUdb)" d="M40,18H8c0,0,0,10.271,0,11c0,2.209,7.163,4,16,4s16-1.791,16-4C40,28.271,40,18,40,18z"/><linearGradient id="LkaBH78Qy0LlLxZFYVKUdc" x1="8" x2="40" y1="15" y2="15" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#3079d6"/><stop offset="1" stop-color="#297cd2"/></linearGradient><path fill="url(#LkaBH78Qy0LlLxZFYVKUdc)" d="M40,8H8c0,0,0,9.756,0,10.5c0,1.933,7.163,3.5,16,3.5s16-1.567,16-3.5C40,17.756,40,8,40,8z"/><linearGradient id="LkaBH78Qy0LlLxZFYVKUdd" x1="8" x2="40" y1="8" y2="8" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#42a3f2"/><stop offset="1" stop-color="#42a4eb"/></linearGradient><ellipse cx="24" cy="8" fill="url(#LkaBH78Qy0LlLxZFYVKUdd)" rx="16" ry="3"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><linearGradient id="WxWrlTsssL_WlnpfbClFCa" x1="24" x2="24" y1="592.908" y2="650.553" gradientTransform="matrix(1 0 0 -1 0 662)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#f44f5a"/><stop offset=".443" stop-color="#ee3d4a"/><stop offset="1" stop-color="#e52030"/></linearGradient><path fill="url(#WxWrlTsssL_WlnpfbClFCa)" d="M39,10v31c0,1.105-0.895,2-2,2H11c-1.105,0-2-0.895-2-2V10H39z"/><linearGradient id="WxWrlTsssL_WlnpfbClFCb" x1="24" x2="24" y1="657.947" y2="648.199" gradientTransform="matrix(1 0 0 -1 0 662)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#f44f5a"/><stop offset=".443" stop-color="#ee3d4a"/><stop offset="1" stop-color="#e52030"/></linearGradient><path fill="url(#WxWrlTsssL_WlnpfbClFCb)" d="M28,4h-8c-1.105,0-2,0.895-2,2v2h12V6C30,4.895,29.105,4,28,4z"/><path fill="#ffa8a8" d="M8,11v-1c0-1.657,1.343-3,3-3h26c1.657,0,3,1.343,3,3v1H8z"/><path d="M32.395,30.153L28.243,26l4.191-4.191c0.781-0.781,0.781-2.047,0-2.828 l-1.414-1.414c-0.781-0.781-2.047-0.781-2.828,0L24,21.757l-4.191-4.191c-0.781-0.781-2.047-0.781-2.828,0l-1.414,1.414 c-0.781,0.781-0.781,2.047,0,2.828l4.191,4.191l-4.192,4.192c-0.781,0.781-0.781,2.047,0,2.828l1.414,1.414 c0.781,0.781,2.047,0.781,2.828,0L24,30.241l4.153,4.153c0.781,0.781,2.047,0.781,2.828,0l1.414-1.414 C33.176,32.2,33.176,30.934,32.395,30.153z" opacity=".05"/><path d="M32.042,30.506L27.536,26l4.544-4.544c0.586-0.586,0.586-1.536,0-2.121 l-1.414-1.414c-0.586-0.586-1.536-0.586-2.121,0L24,22.464l-4.544-4.544c-0.586-0.586-1.536-0.586-2.121,0l-1.414,1.414 c-0.586,0.586-0.586,1.536,0,2.121L20.464,26l-4.545,4.545c-0.586,0.586-0.586,1.536,0,2.121l1.414,1.414 c0.586,0.586,1.536,0.586,2.121,0L24,29.536l4.506,4.506c0.586,0.586,1.536,0.586,2.121,0l1.414-1.414 C32.628,32.042,32.628,31.092,32.042,30.506z" opacity=".07"/><path fill="#fff" d="M26.828,26l4.898-4.898c0.391-0.39,0.391-1.023,0-1.414l-1.414-1.414 c-0.39-0.391-1.024-0.391-1.414,0L24,23.172l-4.898-4.898c-0.39-0.391-1.023-0.391-1.414,0l-1.414,1.414 c-0.391,0.39-0.391,1.023,0,1.414L21.172,26l-4.899,4.899c-0.391,0.39-0.391,1.023,0,1.414l1.414,1.414 c0.39,0.391,1.023,0.391,1.414,0L24,28.828l4.86,4.86c0.39,0.391,1.023,0.391,1.414,0l1.414-1.414c0.391-0.39,0.391-1.024,0-1.414 L26.828,26z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48px" height="48px"><linearGradient id="YGGk5xCyNietrYbhNX6WKa" x1="13.25" x2="13.25" y1="42.071" y2="28.237" gradientTransform="rotate(-90 24 24)" gradientUnits="userSpaceOnUse"><stop offset=".365" stop-color="#199ae0"/><stop offset=".699" stop-color="#1898de"/><stop offset=".819" stop-color="#1691d8"/><stop offset=".905" stop-color="#1186cc"/><stop offset=".974" stop-color="#0a75bc"/><stop offset="1" stop-color="#076cb3"/></linearGradient><path fill="url(#YGGk5xCyNietrYbhNX6WKa)" d="M25.168,45.516l15.849-15.849c0.645-0.645,0.645-1.69,0-2.335l-3.349-3.349 c-0.645-0.645-1.69-0.645-2.335,0L19.484,39.832c-0.645,0.645-0.645,1.69,0,2.335l3.349,3.349 C23.477,46.161,24.523,46.161,25.168,45.516z"/><linearGradient id="YGGk5xCyNietrYbhNX6WKb" x1="11.984" x2="30.101" y1="2.622" y2="45.327" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#32bdef"/><stop offset="1" stop-color="#1ea2e4"/></linearGradient><path fill="url(#YGGk5xCyNietrYbhNX6WKb)" d="M27,2h-6c-1.105,0-2,0.895-2,2v26.316l-6.333-6.333c-0.645-0.645-1.69-0.645-2.335,0 l-3.349,3.349c-0.645,0.645-0.645,1.69,0,2.335l15.849,15.849c0.645,0.645,1.69,0.645,2.335,0l3.349-3.349 C28.839,41.845,29,41.423,29,41V4C29,2.895,28.105,2,27,2z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><linearGradient id="SVGID_1_" x1="8.268" x2="38.902" y1="110.689" y2="78.192" gradientTransform="matrix(1 0 0 -1 0 118)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#7dd8f3"/><stop offset="1" stop-color="#45b0d0"/></linearGradient><path fill="url(#SVGID_1_)" d="M37,42H11c-1.1,0-2-1-2-2.3V8.3C9,7,9.9,6,11,6h26c1.1,0,2,1,2,2.3v31.4C39,41,38.1,42,37,42z"/><path fill="#057093" d="M34.5,23h-18c-0.3,0-0.5-0.2-0.5-0.5v-1c0-0.3,0.2-0.5,0.5-0.5h18c0.3,0,0.5,0.2,0.5,0.5v1 C35,22.8,34.8,23,34.5,23z"/><path fill="#057093" d="M34.5,28h-18c-0.3,0-0.5-0.2-0.5-0.5v-1c0-0.3,0.2-0.5,0.5-0.5h18c0.3,0,0.5,0.2,0.5,0.5v1 C35,27.8,34.8,28,34.5,28z"/><path fill="#057093" d="M34.5,13h-18c-0.3,0-0.5-0.2-0.5-0.5v-1c0-0.3,0.2-0.5,0.5-0.5h18c0.3,0,0.5,0.2,0.5,0.5v1 C35,12.8,34.8,13,34.5,13z"/><path fill="#057093" d="M34.5,18h-18c-0.3,0-0.5-0.2-0.5-0.5v-1c0-0.3,0.2-0.5,0.5-0.5h18c0.3,0,0.5,0.2,0.5,0.5v1 C35,17.8,34.8,18,34.5,18z"/><path fill="#057093" d="M34.5,33H16.5c-0.3,0-0.5-0.2-0.5-0.5v-1c0-0.3,0.2-0.5,0.5-0.5h18.1c0.3,0,0.5,0.2,0.5,0.5v1 C35,32.8,34.8,33,34.5,33z"/><path fill="#057093" d="M34.5,38H16.5c-0.3,0-0.5-0.2-0.5-0.5v-1c0-0.3,0.2-0.5,0.5-0.5h18.1c0.3,0,0.5,0.2,0.5,0.5v1 C35,37.8,34.8,38,34.5,38z"/><path fill="#057093" d="M12,13.5L12,13.5c0,0.8-0.7,1.5-1.5,1.5h-2C7.7,15,7,14.3,7,13.5l0,0C7,12.7,7.7,12,8.5,12h2 C11.3,12,12,12.7,12,13.5z"/><path fill="#057093" d="M12,20.5L12,20.5c0,0.8-0.7,1.5-1.5,1.5h-2C7.7,22,7,21.3,7,20.5l0,0C7,19.7,7.7,19,8.5,19h2 C11.3,19,12,19.7,12,20.5z"/><path fill="#057093" d="M12,27.5L12,27.5c0,0.8-0.7,1.5-1.5,1.5h-2C7.7,29,7,28.3,7,27.5l0,0C7,26.7,7.7,26,8.5,26h2 C11.3,26,12,26.7,12,27.5z"/><path fill="#057093" d="M12,34.5L12,34.5c0,0.8-0.7,1.5-1.5,1.5h-2C7.7,36,7,35.3,7,34.5l0,0C7,33.7,7.7,33,8.5,33h2 C11.3,33,12,33.7,12,34.5z"/><path d="M37,6h-5.5l-6.1,9.7c-0.1,0.1-0.4,0.6-0.4,1.2c0,1.1,0.9,2,2,2h12V8.3C39,7,38.1,6,37,6z" opacity=".05"/><path d="M37,6h-4.9l-6.3,10c0,0-0.3,0.4-0.3,0.9c0,0.9,0.7,1.5,1.5,1.5h12V8.3C39,7,38.1,6,37,6z" opacity=".07"/><linearGradient id="SVGID_2_" x1="-137.298" x2="43.76" y1="303.225" y2="95.565" gradientTransform="matrix(1 0 0 -1 0 118)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#ffda1c"/><stop offset="1" stop-color="#feb705"/></linearGradient><path fill="url(#SVGID_2_)" d="M47.8,16.3L37.9,0.5c0,0-0.3-0.5-0.9-0.5s-0.9,0.6-0.9,0.6l-9.9,15.7c0,0-0.2,0.3-0.2,0.6c0,0.6,0.5,1,1,1H47 c0.6,0,1-0.5,1-1C48,16.6,47.8,16.3,47.8,16.3z"/><radialGradient id="SVGID_3_" cx="33.956" cy="112.739" r="11.714" gradientTransform="matrix(1 0 0 -1 0 118)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#4b4b4b"/><stop offset=".531" stop-color="#393939"/><stop offset="1" stop-color="#252525"/></radialGradient><path fill="url(#SVGID_3_)" d="M37,15.9c-0.4,0-0.7-0.1-0.9-0.3s-0.4-0.5-0.4-0.8c0-0.3,0.1-0.6,0.4-0.8c0.3-0.2,0.6-0.3,0.9-0.3 c0.4,0,0.7,0.1,0.9,0.3c0.2,0.2,0.4,0.5,0.4,0.8c0,0.3-0.1,0.6-0.4,0.9C37.7,15.7,37.4,15.9,37,15.9z M38.2,5.8l-0.3,6.4 c0,0.2-0.2,0.3-0.4,0.3h-1.1c-0.2,0-0.4-0.2-0.4-0.3l-0.2-6.4c0-0.2,0.2-0.4,0.4-0.4h1.6C38,5.4,38.2,5.5,38.2,5.8z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><radialGradient id="PrFtsSzfbx1AK_8CqmpOsa" cx="32" cy="34" r="10.654" gradientTransform="matrix(1 0 0 -1 0 48)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#9e17c2"/><stop offset=".378" stop-color="#b72cd4"/><stop offset="1" stop-color="#e756f7"/></radialGradient><path fill="url(#PrFtsSzfbx1AK_8CqmpOsa)" d="M32.598,3.592l1.149,1.138c0.36,0.357,0.882,0.497,1.373,0.368l1.564-0.411 c0.452-0.119,0.915,0.149,1.038,0.599l0.426,1.56c0.134,0.489,0.516,0.871,1.005,1.005l1.56,0.426 c0.45,0.123,0.718,0.586,0.599,1.038l-0.411,1.564c-0.129,0.491,0.011,1.013,0.368,1.373l1.138,1.149 c0.329,0.332,0.329,0.866,0,1.198l-1.138,1.149c-0.357,0.36-0.497,0.882-0.368,1.373l0.411,1.564 c0.119,0.452-0.149,0.915-0.599,1.038l-1.56,0.426c-0.489,0.134-0.871,0.516-1.005,1.005l-0.426,1.56 c-0.123,0.45-0.586,0.718-1.038,0.599l-1.564-0.411c-0.491-0.129-1.013,0.011-1.373,0.368l-1.149,1.138 c-0.332,0.329-0.866,0.329-1.198,0l-1.149-1.138c-0.36-0.357-0.882-0.497-1.373-0.368L26.5,23.525l-0.648-2.373 c-0.134-0.489-0.516-0.871-1.005-1.005l-2.373-0.648l0.625-2.379c0.129-0.491-0.011-1.013-0.368-1.373l-1.138-1.149 c-0.329-0.332-0.329-0.866,0-1.198l1.138-1.149c0.357-0.36,0.497-0.882,0.368-1.373l-0.411-1.564 c-0.119-0.452,0.149-0.915,0.599-1.038l1.56-0.426c0.489-0.134,0.871-0.516,1.005-1.005l0.426-1.56 c0.123-0.45,0.586-0.718,1.038-0.599l1.564,0.411c0.491,0.129,1.013-0.011,1.373-0.368l1.149-1.138 C31.733,3.264,32.266,3.264,32.598,3.592z"/><path fill="#e756f7" d="M39.482,33.348l1.043,3.128l3.128,1.043c0.463,0.154,0.463,0.81,0,0.964l-3.128,1.043l-1.043,3.128 c-0.154,0.463-0.81,0.463-0.964,0l-1.043-3.128l-3.128-1.043c-0.463-0.154-0.463-0.81,0-0.964l3.128-1.043l1.043-3.128 C38.672,32.884,39.328,32.884,39.482,33.348z"/><path fill="#e756f7" d="M30.289,29.209l0.626,1.876l1.876,0.626c0.278,0.093,0.278,0.486,0,0.579l-1.876,0.626l-0.626,1.876 c-0.093,0.278-0.486,0.278-0.579,0l-0.626-1.876l-1.876-0.626c-0.278-0.093-0.278-0.486,0-0.579l1.876-0.626l0.626-1.876 C29.804,28.93,30.197,28.93,30.289,29.209z"/><linearGradient id="PrFtsSzfbx1AK_8CqmpOsb" x1="9.062" x2="16.613" y1="24.272" y2="10.669" gradientTransform="matrix(1 0 0 -1 0 48)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#6d7479"/><stop offset="1" stop-color="#323538"/></linearGradient><path fill="url(#PrFtsSzfbx1AK_8CqmpOsb)" d="M5,42.414L3.586,41c-0.781-0.781-0.781-2.047,0-2.828l17.207-17.207l4.243,4.243L7.828,42.414 C7.047,43.195,5.781,43.195,5,42.414z"/><linearGradient id="PrFtsSzfbx1AK_8CqmpOsc" x1="25.773" x2="30.637" y1="34.945" y2="24.851" gradientTransform="matrix(1 0 0 -1 0 48)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#cfdbe6"/><stop offset="1" stop-color="#8f979e"/></linearGradient><path fill="url(#PrFtsSzfbx1AK_8CqmpOsc)" d="M33,11.586L34.414,13c0.781,0.781,0.781,2.047,0,2.828l-9.379,9.379l-4.243-4.243l9.379-9.379 C30.953,10.805,32.219,10.805,33,11.586z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><linearGradient id="TGbgz7YIIasADw2jo2LPPa" x1="24" x2="24" y1="44.346" y2="13.335" gradientTransform="matrix(1 0 0 -1 0 48)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#f44f5a"/><stop offset=".443" stop-color="#ee3d4a"/><stop offset=".651" stop-color="#ed3b48"/><stop offset=".726" stop-color="#eb3442"/><stop offset=".779" stop-color="#e82938"/><stop offset=".804" stop-color="#e52030"/></linearGradient><path fill="url(#TGbgz7YIIasADw2jo2LPPa)" d="M21.62,6.991c-0.013-0.046-0.02-0.126-0.02-0.186C21.6,6.36,21.958,6,22.4,6 c0.188,0,0.319,0.071,0.371,0.091c0.978,0.384,7.697,3.572,6.143,12.787C31.17,17.51,30.211,15,31.116,15 c0.277,0,0.39,0.104,0.56,0.348C34.144,18.892,36,22.973,36,26.927C36,33.595,30.628,39,24,39c-7.288,0-12-6.176-12-12.073 C12,17.118,23.49,15.307,21.62,6.991z"/><linearGradient id="TGbgz7YIIasADw2jo2LPPb" x1="23.5" x2="23.5" y1="30.346" y2="17.849" gradientTransform="matrix(1 0 0 -1 0 48)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fed100"/><stop offset=".353" stop-color="#fdcf00"/><stop offset=".523" stop-color="#fcc700"/><stop offset=".655" stop-color="#f9ba00"/><stop offset=".766" stop-color="#f4a800"/><stop offset=".865" stop-color="#ee9001"/><stop offset=".954" stop-color="#e77201"/><stop offset="1" stop-color="#e36001"/></linearGradient><path fill="url(#TGbgz7YIIasADw2jo2LPPb)" d="M23.225,18.152c0,0-0.182-0.152-0.446-0.152c-0.398,0-0.722,0.317-0.722,0.708 c0.722,4.25-4.329,5.667-4.329,10.625c0,3.13,2.584,5.667,5.772,5.667s5.772-2.537,5.772-5.667 C29.272,25.295,25.65,19.906,23.225,18.152z"/><path fill="#64717c" d="M30,42h-4l-5.5-1L15,42h-4l-5-5v-4l11.667-5H22l5,1l6-1h4l5,5v4L30,42z"/><linearGradient id="TGbgz7YIIasADw2jo2LPPc" x1="19.087" x2="29.046" y1="22.239" y2="3.511" gradientTransform="matrix(1 0 0 -1 0 48)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#bec5c8"/><stop offset=".968" stop-color="#b9c1c4"/></linearGradient><path fill="url(#TGbgz7YIIasADw2jo2LPPc)" d="M27,41c0,0.552-0.448,1-1,1H15c-0.552,0-1-0.448-1-1v-4c0-0.552,0.448-1,1-1h11 c0.552,0,1,0.448,1,1V41z M42,41c0,0.552-0.448,1-1,1H30c-0.552,0-1-0.448-1-1v-4c0-0.552,0.448-1,1-1h11c0.552,0,1,0.448,1,1V41z M33,33c0,0.552-0.448,1-1,1H21c-0.552,0-1-0.448-1-1v-4c0-0.552,0.448-1,1-1h11c0.552,0,1,0.448,1,1V33z M6,33c0,0.552,0.448,1,1,1 h10c0.552,0,1-0.448,1-1v-4c0-0.552-0.448-1-1-1H7c-0.552,0-1,0.448-1,1V33z M41,28h-5c-0.552,0-1,0.448-1,1v4c0,0.552,0.448,1,1,1 h6v-5C42,28.448,41.552,28,41,28z M11,36H6v5c0,0.552,0.448,1,1,1h4c0.552,0,1-0.448,1-1v-4C12,36.448,11.552,36,11,36z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><linearGradient id="g6m9hEw6~hyGkm4KdOogNa" x1="16.86" x2="29.576" y1="1.533" y2="41.546" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#c77740"/><stop offset="1" stop-color="#b0622b"/></linearGradient><path fill="url(#g6m9hEw6~hyGkm4KdOogNa)" d="M38,4H26c0,1.105-0.895,2-2,2s-2-0.895-2-2H10C8.895,4,8,4.895,8,6v36c0,1.105,0.895,2,2,2h28 c1.105,0,2-0.895,2-2V6C40,4.895,39.105,4,38,4z"/><linearGradient id="g6m9hEw6~hyGkm4KdOogNb" x1="24" x2="24" y1="36.966" y2="40.893" gradientUnits="userSpaceOnUse"><stop offset=".442" stop-color="#878786"/><stop offset=".594" stop-color="#9f9f9e"/><stop offset=".859" stop-color="#c3c3c3"/><stop offset="1" stop-color="#d1d1d1"/></linearGradient><path fill="url(#g6m9hEw6~hyGkm4KdOogNb)" d="M37,42H11c-0.552,0-1-0.448-1-1v-9h28v9C38,41.552,37.552,42,37,42z"/><path fill="#f3f3f3" d="M37,40H11c-0.552,0-1-0.448-1-1V7c0-0.552,0.448-1,1-1h26c0.552,0,1,0.448,1,1v32 C38,39.552,37.552,40,37,40z"/><linearGradient id="g6m9hEw6~hyGkm4KdOogNc" x1="-384.93" x2="-383.046" y1="275.072" y2="282.909" gradientTransform="rotate(180 -180 142.5)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#c3cdd9"/><stop offset="1" stop-color="#9fa7b0"/></linearGradient><path fill="url(#g6m9hEw6~hyGkm4KdOogNc)" d="M31,8V4h-4.184C26.403,2.837,25.304,2,24,2s-2.403,0.837-2.816,2H17v4c0,0.552,0.448,1,1,1h12 C30.552,9,31,8.552,31,8z M24,4c0.552,0,1,0.448,1,1c0,0.552-0.448,1-1,1s-1-0.448-1-1C23,4.448,23.448,4,24,4z"/><linearGradient id="g6m9hEw6~hyGkm4KdOogNd" x1="15" x2="34" y1="25.038" y2="25.038" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#3079d6"/><stop offset="1" stop-color="#297cd2"/></linearGradient><path fill="url(#g6m9hEw6~hyGkm4KdOogNd)" d="M21.594,31.74l-6.333-6.333c-0.347-0.347-0.347-0.91,0-1.257l1.257-1.257 c0.347-0.347,0.91-0.347,1.257,0l4.448,4.448l9.004-9.004c0.347-0.347,0.91-0.347,1.257,0l1.257,1.257 c0.347,0.347,0.347,0.91,0,1.257L22.851,31.74C22.504,32.087,21.941,32.087,21.594,31.74z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><linearGradient id="gCW9sGJUkBnBLRc40wQXGa" x1="25.447" x2="44.728" y1="4.921" y2="36.29" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#42a3f2"/><stop offset="1" stop-color="#42a4eb"/></linearGradient><path fill="url(#gCW9sGJUkBnBLRc40wQXGa)" d="M42,8H19l11,30h12c1.105,0,2-0.895,2-2V10C44,8.895,43.105,8,42,8z"/><linearGradient id="gCW9sGJUkBnBLRc40wQXGb" x1="3.865" x2="23.412" y1="9.86" y2="41.663" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1d59b3"/><stop offset="1" stop-color="#195bbc"/></linearGradient><path fill="url(#gCW9sGJUkBnBLRc40wQXGb)" d="M19,8H6c-1.105,0-2,0.895-2,2v26c0,1.105,0.895,2,2,2h8v7.998 c0,0.891,1.077,1.337,1.707,0.707L24.412,38H30L19,8z"/><path fill="#fff" d="M12,25h6v2h-6V25z"/><path fill="#fff" d="M12.109,29L15,20l2.906,9h2.11L16,17h-2l-4,12H12.109z"/><linearGradient id="gCW9sGJUkBnBLRc40wQXGc" x1="29.064" x2="38.79" y1="23.554" y2="23.554" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#11408a"/><stop offset="1" stop-color="#103f8f"/></linearGradient><path fill="url(#gCW9sGJUkBnBLRc40wQXGc)" d="M29.064,27.223c0.061-0.031,4.994-3.219,7.936-9.115L38.79,19 c-3.082,6.25-7.457,9.292-8.509,10L29.064,27.223z"/><linearGradient id="gCW9sGJUkBnBLRc40wQXGd" x1="28" x2="40" y1="23.5" y2="23.5" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#11408a"/><stop offset="1" stop-color="#103f8f"/></linearGradient><path fill="url(#gCW9sGJUkBnBLRc40wQXGd)" d="M38,29c0,0-5-2.583-7.769-6.998L32,21c2.333,3.833,6.981,6.26,6.981,6.26L38,29z M28,18h12v2 H28V18z"/><linearGradient id="gCW9sGJUkBnBLRc40wQXGe" x1="33" x2="35" y1="18" y2="18" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#11408a"/><stop offset="1" stop-color="#103f8f"/></linearGradient><path fill="url(#gCW9sGJUkBnBLRc40wQXGe)" d="M33,16h2v4h-2V16z"/></svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 96 96" width="96px" height="96px">
<defs>
<linearGradient id="linear0" gradientUnits="userSpaceOnUse" x1="53.879002" y1="85.043251" x2="121.141747" y2="85.043251" gradientTransform="matrix(0.55814,0,0,0.55814,0,0)">
<stop offset="0" style="stop-color:rgb(0%,46.27451%,81.568629%);stop-opacity:1;"/>
<stop offset="1" style="stop-color:rgb(20.392157%,59.607846%,85.882354%);stop-opacity:1;"/>
</linearGradient>
<linearGradient id="linear1" gradientUnits="userSpaceOnUse" x1="53.75" y1="86" x2="121.833328" y2="86" gradientTransform="matrix(0.55814,0,0,0.55814,0,0)">
<stop offset="0" style="stop-color:rgb(0%,46.27451%,81.568629%);stop-opacity:1;"/>
<stop offset="1" style="stop-color:rgb(20.392157%,59.607846%,85.882354%);stop-opacity:1;"/>
</linearGradient>
</defs>
<g id="surface7148703">
<path style=" stroke:none;fill-rule:nonzero;fill:url(#linear0);" d="M 57.914062 10.5625 L 56 8 L 38 8 L 36.03125 9.652344 L 30.070312 49.464844 L 32 52 L 49 52 L 42.039062 85.601562 L 45.769531 86.933594 L 67.613281 43.179688 L 66 40 L 51 40 Z M 57.914062 10.5625 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:url(#linear1);" d="M 56 8 C 54.894531 8 54 8.894531 54 10 C 54 11.105469 54.894531 12 56 12 C 57.105469 12 58 11.105469 58 10 C 58 8.894531 57.105469 8 56 8 Z M 38 8 C 36.894531 8 36 8.894531 36 10 C 36 11.105469 36.894531 12 38 12 C 39.105469 12 40 11.105469 40 10 C 40 8.894531 39.105469 8 38 8 Z M 32 48 C 30.894531 48 30 48.894531 30 50 C 30 51.105469 30.894531 52 32 52 C 33.105469 52 34 51.105469 34 50 C 34 48.894531 33.105469 48 32 48 Z M 64 42 C 64 43.105469 64.894531 44 66 44 C 67.105469 44 68 43.105469 68 42 C 68 40.894531 67.105469 40 66 40 C 64.894531 40 64 40.894531 64 42 Z M 44 84 C 42.894531 84 42 84.894531 42 86 C 42 87.105469 42.894531 88 44 88 C 45.105469 88 46 87.105469 46 86 C 46 84.894531 45.105469 84 44 84 Z M 44 84 "/>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><linearGradient id="SVGID_1_" x1=".308" x2="42.265" y1="8.778" y2="35.735" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#6e6e6e"/><stop offset=".999" stop-color="#4d4d4d"/></linearGradient><path fill="url(#SVGID_1_)" d="M45.8,36H2.2C1,36,0,35,0,33.8V14.2C0,13,1,12,2.2,12h43.6c1.2,0,2.2,1,2.2,2.2v19.6C48,35,47,36,45.8,36z"/><path d="M34,31.9c-0.4,0-0.9-0.2-1.2-0.5l-4.9-5.9c-0.4-0.5-0.5-1.1-0.2-1.6c0.3-0.5,0.8-0.9,1.4-0.9H31v-5.5 c0-0.8,0.7-1.5,1.5-1.5h3c0.8,0,1.5,0.7,1.5,1.5V23h1.9c0.6,0,1.1,0.3,1.4,0.9s0.2,1.1-0.2,1.6l-4.9,5.9 C34.9,31.7,34.4,31.9,34,31.9z" opacity=".05"/><path d="M34,31.4c-0.3,0-0.6-0.1-0.8-0.4l-4.9-5.9c-0.3-0.3-0.3-0.7-0.1-1.1s0.5-0.6,0.9-0.6h2.4v-6c0-0.6,0.4-1,1-1h3 c0.6,0,1,0.4,1,1v6h2.4c0.4,0,0.7,0.2,0.9,0.6s0.1,0.8-0.1,1.1l-4.9,5.9C34.6,31.3,34.3,31.4,34,31.4z" opacity=".07"/><path fill="#fff" d="M32,17.5V24h-2.9c-0.4,0-0.7,0.5-0.4,0.8l4.9,5.9c0.2,0.2,0.6,0.2,0.8,0l4.9-5.9c0.3-0.3,0-0.8-0.4-0.8H36 v-6.5c0-0.3-0.2-0.5-0.5-0.5h-3C32.2,17,32,17.2,32,17.5z"/><path d="M20.5,32c-0.8,0-1.5-0.7-1.5-1.5v-4.6l-1.8,2.3c-0.3,0.4-0.7,0.6-1.2,0.6s-0.9-0.2-1.2-0.6L13,25.9v4.6 c0,0.8-0.7,1.5-1.5,1.5h-3C7.7,32,7,31.3,7,30.5v-13C7,16.7,7.7,16,8.5,16h3.3c0.5,0,0.9,0.2,1.2,0.6l3.1,3.9l3.1-3.9 c0.3-0.4,0.7-0.6,1.2-0.6h3.3c0.8,0,1.5,0.7,1.5,1.5v13c0,0.8-0.7,1.5-1.5,1.5H20.5z" opacity=".05"/><path d="M20.5,31.5c-0.6,0-1-0.4-1-1v-6.1l-2.7,3.5c-0.2,0.2-0.5,0.4-0.8,0.4s-0.6-0.1-0.8-0.4l-2.7-3.5v6.1 c0,0.6-0.4,1-1,1h-3c-0.6,0-1-0.4-1-1v-13c0-0.6,0.4-1,1-1h3.3c0.3,0,0.6,0.1,0.8,0.4l3.5,4.4l3.5-4.4c0.2-0.2,0.5-0.4,0.8-0.4h3.3 c0.6,0,1,0.4,1,1v13c0,0.6-0.4,1-1,1H20.5z" opacity=".07"/><path fill="#fff" d="M24,30.5v-13c0-0.3-0.2-0.5-0.5-0.5h-3.3c-0.2,0-0.3,0.1-0.4,0.2l-3.8,5l-3.8-5c-0.1-0.1-0.2-0.2-0.4-0.2H8.5 C8.2,17,8,17.2,8,17.5v13C8,30.8,8.2,31,8.5,31h3c0.3,0,0.5-0.2,0.5-0.5V23l3.6,4.6c0.2,0.3,0.6,0.3,0.8,0L20,23v7.5 c0,0.3,0.2,0.5,0.5,0.5h3C23.8,31,24,30.8,24,30.5z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><linearGradient id="SVGID_1_" x1="18.921" x2="25.143" y1="-472.285" y2="-451.285" gradientTransform="translate(0 478)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#0078d3"/><stop offset="1" stop-color="#0858a1"/></linearGradient><path fill="url(#SVGID_1_)" d="M43,29.5H5V16.6c0-0.7,0.4-1.3,0.9-1.7L22.4,4.5c1-0.6,2.2-0.6,3.2,0l16.5,10.4c0.6,0.4,0.9,1,0.9,1.7V29.5z"/><linearGradient id="SVGID_2_" x1="24" x2="24" y1="-464.584" y2="-450.767" gradientTransform="translate(0 478)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset=".24" stop-color="#f8f8f7"/><stop offset="1" stop-color="#e3e3e1"/></linearGradient><path fill="url(#SVGID_2_)" d="M38,32H10V14c0-0.6,0.4-1,1-1h26c0.6,0,1,0.4,1,1V32z"/><linearGradient id="SVGID_3_" x1="25.886" x2="37.997" y1="-450.064" y2="-432.731" gradientTransform="translate(0 478)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#3ccbf4"/><stop offset="1" stop-color="#1fa0e5"/></linearGradient><path fill="url(#SVGID_3_)" d="M43,17v21.3c0,1-0.8,1.7-1.8,1.7H9.6l4.8-6.3L43,17z"/><linearGradient id="SVGID_4_" x1="3.074" x2="39.962" y1="-450.764" y2="-432.875" gradientTransform="translate(0 478)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#28afea"/><stop offset="1" stop-color="#0b88da"/></linearGradient><path fill="url(#SVGID_4_)" d="M5,17v21.3c0,1,0.8,1.7,1.8,1.7h34.5c0.6,0,1.1-0.3,1.4-0.7L5,17z"/><radialGradient id="SVGID_5_" cx="36.373" cy="37.908" r="11.628" gradientUnits="userSpaceOnUse"><stop offset="0"/><stop offset="1" stop-opacity="0"/></radialGradient><path fill="url(#SVGID_5_)" d="M37,26c-6.6,0-12,5.4-12,12c0,0.7,0.1,1.3,0.2,2h16c1,0,1.8-0.8,1.8-1.7V27.6C41.2,26.6,39.2,26,37,26z"/><linearGradient id="SVGID_6_" x1="30.189" x2="44.426" y1="1537.189" y2="1551.426" gradientTransform="translate(0 -1506)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#889097"/><stop offset=".331" stop-color="#848c94"/><stop offset=".669" stop-color="#78828b"/><stop offset="1" stop-color="#64717c"/></linearGradient><path fill="url(#SVGID_6_)" d="M46.7,35.7c-1.2,0.2-2.4-0.4-3.1-1.5c-0.6-1.1-0.5-2.4,0.2-3.4c-1.1-1.1-2.5-1.9-4-2.3 c-0.5,1.1-1.6,1.9-2.8,1.9s-2.4-0.8-2.8-1.9c-1.5,0.5-2.9,1.3-4,2.3c0.7,1,0.9,2.3,0.2,3.4c-0.6,1.1-1.9,1.7-3.1,1.5 C27.1,36.4,27,37.2,27,38s0.1,1.6,0.3,2.3c1.2-0.2,2.4,0.4,3.1,1.5c0.6,1.1,0.5,2.4-0.2,3.4c1.1,1.1,2.5,1.9,4,2.3 c0.5-1.1,1.6-1.9,2.8-1.9s2.4,0.8,2.8,1.9c1.5-0.5,2.9-1.3,4-2.3c-0.7-1-0.9-2.3-0.2-3.4c0.6-1.1,1.9-1.7,3.1-1.5 c0.2-0.7,0.3-1.5,0.3-2.3S46.9,36.4,46.7,35.7z"/><linearGradient id="SVGID_7_" x1="40.484" x2="33.47" y1="1547.484" y2="1540.47" gradientTransform="translate(0 -1506)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset=".242" stop-color="#f2f2f2"/><stop offset="1" stop-color="#ccc"/></linearGradient><circle cx="37" cy="38" r="5" fill="url(#SVGID_7_)"/><linearGradient id="SVGID_8_" x1="34.193" x2="39.117" y1="1541.193" y2="1546.117" gradientTransform="translate(0 -1506)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#0d61a9"/><stop offset=".363" stop-color="#0e5fa4"/><stop offset=".78" stop-color="#135796"/><stop offset="1" stop-color="#16528c"/></linearGradient><circle cx="37" cy="38" r="3" fill="url(#SVGID_8_)"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><linearGradient id="fQPhlwRPMUTWTWV5KNe4Ga" x1="5" x2="24" y1="28.581" y2="28.581" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#1d59b3"/><stop offset="1" stop-color="#195bbc"/></linearGradient><path fill="url(#fQPhlwRPMUTWTWV5KNe4Ga)" d="M5.307,12.161C5.111,12.563,5,13.008,5,13.472v20.237c0,1.114,0.617,2.136,1.603,2.655 l15.534,8.176C22.72,44.847,23.36,45,24,45V22L5.307,12.161z"/><linearGradient id="fQPhlwRPMUTWTWV5KNe4Gb" x1="24" x2="43" y1="28.581" y2="28.581" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#11408a"/><stop offset="1" stop-color="#103f8f"/></linearGradient><path fill="url(#fQPhlwRPMUTWTWV5KNe4Gb)" d="M24,22v23c0.64,0,1.28-0.153,1.863-0.46l15.534-8.176C42.383,35.845,43,34.823,43,33.709 V13.472c0-0.464-0.111-0.909-0.307-1.311L24,22z"/><linearGradient id="fQPhlwRPMUTWTWV5KNe4Gc" x1="5.307" x2="42.693" y1="12.5" y2="12.5" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#3079d6"/><stop offset="1" stop-color="#297cd2"/></linearGradient><path fill="url(#fQPhlwRPMUTWTWV5KNe4Gc)" d="M24,22l18.693-9.839c-0.293-0.602-0.781-1.103-1.409-1.4L25.712,3.385 c-1.084-0.513-2.341-0.513-3.425,0L6.716,10.761c-0.628,0.298-1.116,0.799-1.409,1.4L24,22z"/><path fill="#25a2e5" d="M13.178,16.306C13.064,16.538,13,16.796,13,17.065v11.716c0,0.645,0.357,1.237,0.928,1.537 l8.994,4.733c0.338,0.178,0.708,0.267,1.079,0.267V22.002L13.178,16.306z"/><path fill="#027ad4" d="M24,22.002v13.316c0.37,0,0.741-0.089,1.079-0.267l8.994-4.733c0.571-0.3,0.928-0.892,0.928-1.537 V17.065c0-0.269-0.064-0.526-0.178-0.759L24,22.002z"/><path fill="#54daff" d="M24,22.002l10.822-5.696c-0.17-0.348-0.452-0.638-0.816-0.811l-9.015-4.27 c-0.628-0.297-1.355-0.297-1.983,0l-9.015,4.27c-0.364,0.172-0.646,0.462-0.816,0.811L24,22.002z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><path fill="#50e6ff" d="M39,41c0,1.105-0.895,2-2,2H11c-1.105,0-2-0.895-2-2V7c0-1.105,0.895-2,2-2h26c1.105,0,2,0.895,2,2 V41z"/><path fill="#057093" d="M33.5,24h-19c-0.276,0-0.5-0.224-0.5-0.5v-1c0-0.276,0.224-0.5,0.5-0.5h19c0.276,0,0.5,0.224,0.5,0.5 v1C34,23.776,33.776,24,33.5,24z"/><path fill="#057093" d="M33.5,16h-19c-0.276,0-0.5-0.224-0.5-0.5v-3c0-0.276,0.224-0.5,0.5-0.5h19c0.276,0,0.5,0.224,0.5,0.5 v3C34,15.776,33.776,16,33.5,16z"/><path fill="#057093" d="M33.5,28h-19c-0.276,0-0.5-0.224-0.5-0.5v-1c0-0.276,0.224-0.5,0.5-0.5h19c0.276,0,0.5,0.224,0.5,0.5 v1C34,27.776,33.776,28,33.5,28z"/><path fill="#057093" d="M33.5,32h-19c-0.276,0-0.5-0.224-0.5-0.5v-1c0-0.276,0.224-0.5,0.5-0.5h19c0.276,0,0.5,0.224,0.5,0.5 v1C34,31.776,33.776,32,33.5,32z"/><path fill="#057093" d="M33.5,36h-19c-0.276,0-0.5-0.224-0.5-0.5v-1c0-0.276,0.224-0.5,0.5-0.5h19c0.276,0,0.5,0.224,0.5,0.5 v1C34,35.776,33.776,36,33.5,36z"/><path d="M34.605,20.574c-0.288-0.288-0.669-0.447-1.074-0.447c-0.196,0-0.386,0.036-0.563,0.106 C32.38,20.465,32,21.021,32,21.652l0,15.136c0,0.848,0.69,1.537,1.539,1.537c0.362,0,0.701-0.124,0.982-0.358l2.053-1.716 l1.617,4.104c0.149,0.378,0.44,0.655,0.791,0.815C38.988,41.114,39,41.059,39,41V24.969L34.605,20.574z" opacity=".05"/><path d="M39,25.677l-4.749-4.749c-0.194-0.194-0.45-0.301-0.72-0.301c-0.131,0-0.26,0.024-0.38,0.072 c-0.396,0.155-0.651,0.529-0.651,0.953l0,15.136c0,0.571,0.466,1.037,1.039,1.037c0.243,0,0.472-0.084,0.662-0.242l2.585-2.16 l1.871,4.749c0.072,0.183,0.194,0.331,0.343,0.443V25.677z" opacity=".07"/><path fill="#0078d4" d="M33.897,21.281L44.727,32.11c0.321,0.321,0.122,0.872-0.331,0.913l-4.585,0.415l2.142,5.436 c0.106,0.27-0.026,0.575-0.296,0.681l-0.945,0.372l-7.378-18.763C33.515,21.093,33.735,21.118,33.897,21.281z"/><path fill="#199be2" d="M39.123,39.99l-2.126-5.395l-3.117,2.604C33.531,37.491,33,37.243,33,36.788l0-15.135 c0-0.237,0.146-0.414,0.333-0.488l7.379,18.764l-0.908,0.358C39.534,40.393,39.229,40.26,39.123,39.99z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><path fill="#abb4be" d="M24,31c-0.552,0-1-0.448-1-1v-3.627c0-1.501,1.122-2.78,2.61-2.975l16.52-2.162 c0.496-0.065,0.87-0.491,0.87-0.992V13c0-0.551-0.449-1-1-1h-4c-0.552,0-1-0.448-1-1s0.448-1,1-1h4c1.654,0,3,1.346,3,3v7.245 c0,1.501-1.122,2.78-2.61,2.975l-16.52,2.162C25.374,25.447,25,25.873,25,26.373V30C25,30.552,24.552,31,24,31z"/><linearGradient id="Psn0qfw0zZI_2FiyraWIQa" x1="38.3" x2="40.42" y1="7.527" y2="14.85" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#ffd869"/><stop offset="1" stop-color="#fec52b"/></linearGradient><path fill="url(#Psn0qfw0zZI_2FiyraWIQa)" d="M39.434,17H38V5h1.434C40.295,5,41,5.705,41,6.566v8.868C41,16.295,40.295,17,39.434,17z"/><linearGradient id="Psn0qfw0zZI_2FiyraWIQb" x1="7.763" x2="9.883" y1="7.782" y2="15.105" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#ffd869"/><stop offset="1" stop-color="#fec52b"/></linearGradient><path fill="url(#Psn0qfw0zZI_2FiyraWIQb)" d="M10,17H8.565C7.701,17,7,16.299,7,15.435v-8.87C7,5.704,7.704,5,8.565,5H10V17z"/><linearGradient id="Psn0qfw0zZI_2FiyraWIQc" x1="21" x2="27" y1="36" y2="36" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#3079d6"/><stop offset="1" stop-color="#297cd2"/></linearGradient><path fill="url(#Psn0qfw0zZI_2FiyraWIQc)" d="M22,29h4c0.552,0,1,0.448,1,1v12c0,0.552-0.448,1-1,1h-4c-0.552,0-1-0.448-1-1V30 C21,29.448,21.448,29,22,29z"/><linearGradient id="Psn0qfw0zZI_2FiyraWIQd" x1="24" x2="24" y1="4.909" y2="23.577" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#d160f6"/><stop offset="1" stop-color="#c545ed"/></linearGradient><path fill="url(#Psn0qfw0zZI_2FiyraWIQd)" d="M10,4.999V23c0,0.552,0.448,1,1,1s1-0.448,1-1v-5c0-0.552,0.448-1,1-1s1,0.448,1,1v2 c0,0.552,0.448,1,1,1s1-0.448,1-1v-1c0-1.105,0.889-2,1.994-2C23.411,17,38,16.999,38,16.999V5L10,4.999z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><linearGradient id="7BDWD4ZdDeZm~8SgpcfAFa" x1="16.904" x2="33.664" y1="47.845" y2="16.325" gradientTransform="matrix(1 0 0 -1 0 48)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#0077d2"/><stop offset="1" stop-color="#0b59a2"/></linearGradient><path fill="url(#7BDWD4ZdDeZm~8SgpcfAFa)" d="M44.211,22H3.789C2.801,22,2,21.199,2,20.211V6.789C2,5.801,2.801,5,3.789,5h40.422 C45.199,5,46,5.801,46,6.789v13.422C46,21.199,45.199,22,44.211,22z"/><linearGradient id="7BDWD4ZdDeZm~8SgpcfAFb" x1="19.346" x2="29.122" y1="43.253" y2="24.866" gradientTransform="matrix(1 0 0 -1 0 48)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fcfcfc"/><stop offset=".495" stop-color="#f4f4f4"/><stop offset=".869" stop-color="#e8e8e8"/><stop offset="1" stop-color="#e8e8e8"/></linearGradient><polygon fill="url(#7BDWD4ZdDeZm~8SgpcfAFb)" points="4,20 4,7 44,7 44,20"/><circle cx="19.5" cy="13.5" r="2.5" fill="#0b5aa4"/><circle cx="10.5" cy="13.5" r="2.5" fill="#0b5aa4"/><circle cx="28.5" cy="13.5" r="2.5" fill="#0b5aa4"/><circle cx="37.5" cy="13.5" r="2.5" fill="#0b5aa4"/><linearGradient id="7BDWD4ZdDeZm~8SgpcfAFc" x1="19.786" x2="27.731" y1="4.075" y2="19.016" gradientTransform="matrix(1 0 0 -1 0 48)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#32bdef"/><stop offset="1" stop-color="#1ea2e4"/></linearGradient><path fill="url(#7BDWD4ZdDeZm~8SgpcfAFc)" d="M23.741,44.996c-4.692-0.132-8.603-4.043-8.737-8.735C14.859,31.18,18.95,27,24,27v4 c-3.109,0-5.564,2.852-4.887,6.077c0.397,1.887,1.922,3.413,3.809,3.809c3.06,0.643,5.784-1.534,6.055-4.414 C29.003,36.209,29.207,36,29.472,36h3.007c0.284,0,0.522,0.239,0.506,0.522C32.709,41.327,28.645,45.135,23.741,44.996z"/><linearGradient id="7BDWD4ZdDeZm~8SgpcfAFd" x1="22.302" x2="27.79" y1="24.041" y2="13.718" gradientTransform="matrix(1 0 0 -1 0 48)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#32bdef"/><stop offset="1" stop-color="#1ea2e4"/></linearGradient><path fill="url(#7BDWD4ZdDeZm~8SgpcfAFd)" d="M29.654,30.222l-5.239,4.567c-0.518,0.451-1.413,0.131-1.413-0.508l-0.009-9.561 c0-0.64,0.886-0.959,1.413-0.508l5.248,4.559C30.115,29.172,30.115,29.82,29.654,30.222z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48px" height="48px"><linearGradient id="DIL4YXqTpzKGN6Y0goToWa" x1="2.315" x2="27.991" y1="21.22" y2="46.895" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#f9f9f9"/><stop offset="1" stop-color="#c2c8cc"/></linearGradient><path fill="url(#DIL4YXqTpzKGN6Y0goToWa)" d="M12.16,21l-1.726,1.726c-0.511,0.511-0.874,1.151-1.051,1.852l-2.196,8.723L9.5,38.5 l5.183,2.304l8.727-2.197c0.701-0.177,1.341-0.54,1.853-1.051L27,35.81L12.16,21z"/><linearGradient id="DIL4YXqTpzKGN6Y0goToWb" x1="4.389" x2="11.881" y1="36.103" y2="43.595" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#787878"/><stop offset="1" stop-color="#666"/></linearGradient><path fill="url(#DIL4YXqTpzKGN6Y0goToWb)" d="M7.189,33.302l-2.117,8.396c-0.185,0.734,0.48,1.399,1.214,1.214l8.393-2.116L7.189,33.302z"/><path fill="#edbe00" d="M30.16,3L10.81,22.35C12.674,23.077,14,24.879,14,27c0,0,0,0.224,0,0.5c0,0.276,0.224,0.5,0.5,0.5 s0.5,0,0.5,0c2.761,0,5,2.239,5,5l0,0h0c0,0,0,0.224,0,0.5c0,0.276,0.224,0.5,0.5,0.5c0.276,0,0.5,0,0.5,0v0 c2.116,0,3.914,1.319,4.645,3.175L45,17.81L30.16,3z"/><linearGradient id="DIL4YXqTpzKGN6Y0goToWc" x1="25.22" x2="19.442" y1="18.489" y2="12.711" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fede00"/><stop offset="1" stop-color="#ffd000"/></linearGradient><path fill="url(#DIL4YXqTpzKGN6Y0goToWc)" d="M14.146,27.854L34.584,7.416L30.16,3L10.81,22.35C12.674,23.077,14,24.879,14,27 c0,0,0,0.224,0,0.5C14,27.638,14.056,27.763,14.146,27.854z"/><linearGradient id="DIL4YXqTpzKGN6Y0goToWd" x1="34.781" x2="14.864" y1="28.039" y2="8.123" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#eba601"/><stop offset="1" stop-color="#c18310"/></linearGradient><path fill="url(#DIL4YXqTpzKGN6Y0goToWd)" d="M20.146,33.854C20.237,33.944,20.362,34,20.5,34c0.276,0,0.5,0,0.5,0v0 c2.116,0,3.914,1.319,4.645,3.175L45,17.81l-4.409-4.401L20.146,33.854z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><linearGradient id="9_W9tVnDYTfgIF37M3F6la" x1="8.608" x2="15.584" y1="11.608" y2="18.584" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#199ae0"/><stop offset="1" stop-color="#0782d8"/></linearGradient><circle cx="12" cy="15" r="5" fill="url(#9_W9tVnDYTfgIF37M3F6la)"/><linearGradient id="9_W9tVnDYTfgIF37M3F6lb" x1="4.431" x2="19.998" y1="26.482" y2="42.048" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#199ae0"/><stop offset="1" stop-color="#0782d8"/></linearGradient><path fill="url(#9_W9tVnDYTfgIF37M3F6lb)" d="M12,22c-4.971,0-9,4.029-9,9v9c0,1.105,0.895,2,2,2h14c1.105,0,2-0.895,2-2v-9 C21,26.029,16.971,22,12,22z"/><linearGradient id="9_W9tVnDYTfgIF37M3F6lc" x1="32.608" x2="39.584" y1="11.608" y2="18.584" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#0d61a9"/><stop offset="1" stop-color="#16528c"/></linearGradient><circle cx="36" cy="15" r="5" fill="url(#9_W9tVnDYTfgIF37M3F6lc)"/><linearGradient id="9_W9tVnDYTfgIF37M3F6ld" x1="28.431" x2="43.998" y1="26.482" y2="42.048" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#0d61a9"/><stop offset="1" stop-color="#16528c"/></linearGradient><path fill="url(#9_W9tVnDYTfgIF37M3F6ld)" d="M36,22c-4.971,0-9,4.029-9,9v9c0,1.105,0.895,2,2,2h14c1.105,0,2-0.895,2-2v-9 C45,26.029,40.971,22,36,22z"/><linearGradient id="9_W9tVnDYTfgIF37M3F6le" x1="20.608" x2="27.584" y1="7.608" y2="14.584" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#32bdef"/><stop offset="1" stop-color="#1ea2e4"/></linearGradient><circle cx="24" cy="11" r="5" fill="url(#9_W9tVnDYTfgIF37M3F6le)"/><path d="M35,40V27c0-1.701-0.399-3.307-1.092-4.746C29.948,23.199,27,26.751,27,31v9c0,1.105,0.895,2,2,2 h5.444C34.788,41.409,35,40.732,35,40z" opacity=".05"/><path d="M34.333,40V27c0-1.621-0.385-3.15-1.053-4.517C29.649,23.602,27,26.987,27,31v9 c0,1.105,0.895,2,2,2h4.296C33.894,41.606,34.333,40.856,34.333,40z" opacity=".067"/><path d="M33.667,40V27c0-1.542-0.371-2.994-1.014-4.288C29.35,24.005,27,27.223,27,31v9c0,1.105,0.895,2,2,2 h3.148C32.999,41.803,33.667,40.98,33.667,40z" opacity=".09"/><path d="M13,40V27c0-1.701,0.399-3.307,1.092-4.746C18.052,23.199,21,26.751,21,31v9c0,1.105-0.895,2-2,2 h-5.444C13.212,41.409,13,40.732,13,40z" opacity=".05"/><path d="M13.667,40V27c0-1.621,0.385-3.15,1.053-4.517C18.351,23.602,21,26.987,21,31v9 c0,1.105-0.895,2-2,2h-4.296C14.106,41.606,13.667,40.856,13.667,40z" opacity=".067"/><path d="M14.333,40V27c0-1.542,0.371-2.994,1.014-4.288C18.65,24.005,21,27.223,21,31v9c0,1.105-0.895,2-2,2 h-3.148C15.001,41.803,14.333,40.98,14.333,40z" opacity=".09"/><linearGradient id="9_W9tVnDYTfgIF37M3F6lf" x1="21.181" x2="26.202" y1="19.057" y2="44.16" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#32bdef"/><stop offset="1" stop-color="#1ea2e4"/></linearGradient><path fill="url(#9_W9tVnDYTfgIF37M3F6lf)" d="M24,18c-4.971,0-9,4.029-9,9v13c0,1.105,0.895,2,2,2h14c1.105,0,2-0.895,2-2V27 C33,22.029,28.971,18,24,18z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><linearGradient id="dyoR47AMqzPbkc_5POASHa" x1="9.858" x2="38.142" y1="-27.858" y2="-56.142" gradientTransform="matrix(1 0 0 -1 0 -18)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#9dffce"/><stop offset="1" stop-color="#50d18d"/></linearGradient><path fill="url(#dyoR47AMqzPbkc_5POASHa)" d="M44,24c0,11.045-8.955,20-20,20S4,35.045,4,24S12.955,4,24,4S44,12.955,44,24z"/><path d="M34,21h-7v-7c0-1.105-0.895-2-2-2h-2c-1.105,0-2,0.895-2,2v7h-7 c-1.105,0-2,0.895-2,2v2c0,1.105,0.895,2,2,2h7v7c0,1.105,0.895,2,2,2h2c1.105,0,2-0.895,2-2v-7h7c1.105,0,2-0.895,2-2v-2 C36,21.895,35.105,21,34,21z" opacity=".05"/><path d="M34,21.5h-7.5V14c0-0.828-0.672-1.5-1.5-1.5h-2 c-0.828,0-1.5,0.672-1.5,1.5v7.5H14c-0.828,0-1.5,0.672-1.5,1.5v2c0,0.828,0.672,1.5,1.5,1.5h7.5V34c0,0.828,0.672,1.5,1.5,1.5h2 c0.828,0,1.5-0.672,1.5-1.5v-7.5H34c0.828,0,1.5-0.672,1.5-1.5v-2C35.5,22.172,34.828,21.5,34,21.5z" opacity=".07"/><linearGradient id="dyoR47AMqzPbkc_5POASHb" x1="22" x2="26" y1="24" y2="24" gradientUnits="userSpaceOnUse"><stop offset=".824" stop-color="#135d36"/><stop offset=".931" stop-color="#125933"/><stop offset="1" stop-color="#11522f"/></linearGradient><path fill="url(#dyoR47AMqzPbkc_5POASHb)" d="M23,13h2c0.552,0,1,0.448,1,1v20c0,0.552-0.448,1-1,1h-2c-0.552,0-1-0.448-1-1V14 C22,13.448,22.448,13,23,13z"/><linearGradient id="dyoR47AMqzPbkc_5POASHc" x1="13" x2="35" y1="24" y2="24" gradientUnits="userSpaceOnUse"><stop offset=".824" stop-color="#135d36"/><stop offset=".931" stop-color="#125933"/><stop offset="1" stop-color="#11522f"/></linearGradient><path fill="url(#dyoR47AMqzPbkc_5POASHc)" d="M35,23v2c0,0.552-0.448,1-1,1H14c-0.552,0-1-0.448-1-1v-2c0-0.552,0.448-1,1-1h20 C34.552,22,35,22.448,35,23z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><path fill="#e3a600" d="M13,9V6c0-0.552,0.448-1,1-1h0c0.552,0,1,0.448,1,1v3H13z"/><path fill="#e3a600" d="M17,9V6c0-0.552,0.448-1,1-1h0c0.552,0,1,0.448,1,1v3H17z"/><path fill="#e3a600" d="M21,9V6c0-0.552,0.448-1,1-1h0c0.552,0,1,0.448,1,1v3H21z"/><path fill="#e3a600" d="M25,9V6c0-0.552,0.448-1,1-1h0c0.552,0,1,0.448,1,1v3H25z"/><path fill="#e3a600" d="M29,9V6c0-0.552,0.448-1,1-1h0c0.552,0,1,0.448,1,1v3H29z"/><path fill="#e3a600" d="M33,9V6c0-0.552,0.448-1,1-1l0,0c0.552,0,1,0.448,1,1v3H33z"/><linearGradient id="qykBHthKC_SR9NwM248gla" x1="24.056" x2="23.957" y1="8.271" y2="36.062" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#899198"/><stop offset="1" stop-color="#787e85"/></linearGradient><path fill="url(#qykBHthKC_SR9NwM248gla)" d="M37,39H11c-1.105,0-2-0.895-2-2V11c0-1.105,0.895-2,2-2h26c1.105,0,2,0.895,2,2v26 C39,38.105,38.105,39,37,39z"/><path d="M32.36,36H15.637C13.628,36,12,34.372,12,32.363V15.64 c0-2.01,1.63-3.64,3.64-3.64h16.72c2.01,0,3.64,1.63,3.64,3.64v16.72C36,34.37,34.37,36,32.36,36z" opacity=".05"/><path d="M32.162,35H15.838C14.271,35,13,33.729,13,32.162V15.838 C13,14.271,14.271,13,15.838,13h16.324C33.729,13,35,14.271,35,15.838v16.324C35,33.729,33.729,35,32.162,35z" opacity=".07"/><linearGradient id="qykBHthKC_SR9NwM248glb" x1="23.902" x2="24.166" y1="14.123" y2="40.827" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#ccc"/><stop offset=".396" stop-color="#bbb"/><stop offset="1" stop-color="#999"/></linearGradient><path fill="url(#qykBHthKC_SR9NwM248glb)" d="M32,34H16c-1.105,0-2-0.895-2-2V16c0-1.105,0.895-2,2-2h16c1.105,0,2,0.895,2,2v16 C34,33.105,33.105,34,32,34z"/><path fill="#e3a600" d="M13,39v3c0,0.552,0.448,1,1,1h0c0.552,0,1-0.448,1-1v-3H13z"/><path fill="#e3a600" d="M17,39v3c0,0.552,0.448,1,1,1h0c0.552,0,1-0.448,1-1v-3H17z"/><path fill="#e3a600" d="M21,39v3c0,0.552,0.448,1,1,1h0c0.552,0,1-0.448,1-1v-3H21z"/><path fill="#e3a600" d="M25,39v3c0,0.552,0.448,1,1,1h0c0.552,0,1-0.448,1-1v-3H25z"/><path fill="#e3a600" d="M29,39v3c0,0.552,0.448,1,1,1h0c0.552,0,1-0.448,1-1v-3H29z"/><path fill="#e3a600" d="M33,39v3c0,0.552,0.448,1,1,1l0,0c0.552,0,1-0.448,1-1v-3H33z"/><path fill="#e3a600" d="M39,35h3c0.552,0,1-0.448,1-1l0,0c0-0.552-0.448-1-1-1h-3V35z"/><path fill="#e3a600" d="M39,31h3c0.552,0,1-0.448,1-1v0c0-0.552-0.448-1-1-1h-3V31z"/><path fill="#e3a600" d="M39,27h3c0.552,0,1-0.448,1-1v0c0-0.552-0.448-1-1-1h-3V27z"/><path fill="#e3a600" d="M39,23h3c0.552,0,1-0.448,1-1v0c0-0.552-0.448-1-1-1h-3V23z"/><path fill="#e3a600" d="M39,19h3c0.552,0,1-0.448,1-1v0c0-0.552-0.448-1-1-1h-3V19z"/><path fill="#e3a600" d="M39,15h3c0.552,0,1-0.448,1-1v0c0-0.552-0.448-1-1-1h-3V15z"/><path fill="#e3a600" d="M9,35H6c-0.552,0-1-0.448-1-1l0,0c0-0.552,0.448-1,1-1h3V35z"/><path fill="#e3a600" d="M9,31H6c-0.552,0-1-0.448-1-1v0c0-0.552,0.448-1,1-1h3V31z"/><path fill="#e3a600" d="M9,27H6c-0.552,0-1-0.448-1-1v0c0-0.552,0.448-1,1-1h3V27z"/><path fill="#e3a600" d="M9,23H6c-0.552,0-1-0.448-1-1v0c0-0.552,0.448-1,1-1h3V23z"/><path fill="#e3a600" d="M9,19H6c-0.552,0-1-0.448-1-1v0c0-0.552,0.448-1,1-1h3V19z"/><path fill="#e3a600" d="M9,15H6c-0.552,0-1-0.448-1-1v0c0-0.552,0.448-1,1-1h3V15z"/><linearGradient id="qykBHthKC_SR9NwM248glc" x1="36" x2="36" y1="10.989" y2="12.571" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#4c4c4c"/><stop offset="1" stop-color="#343434"/></linearGradient><circle cx="36" cy="12" r="1" fill="url(#qykBHthKC_SR9NwM248glc)"/><linearGradient id="qykBHthKC_SR9NwM248gld" x1="12" x2="12" y1="34.989" y2="36.571" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#4c4c4c"/><stop offset="1" stop-color="#343434"/></linearGradient><circle cx="12" cy="36" r="1" fill="url(#qykBHthKC_SR9NwM248gld)"/><linearGradient id="qykBHthKC_SR9NwM248gle" x1="36" x2="36" y1="34.989" y2="36.571" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#4c4c4c"/><stop offset="1" stop-color="#343434"/></linearGradient><circle cx="36" cy="36" r="1" fill="url(#qykBHthKC_SR9NwM248gle)"/><linearGradient id="qykBHthKC_SR9NwM248glf" x1="12" x2="12" y1="10.989" y2="12.571" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#4c4c4c"/><stop offset="1" stop-color="#343434"/></linearGradient><circle cx="12" cy="12" r="1" fill="url(#qykBHthKC_SR9NwM248glf)"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><path fill="#107c42" d="M24,44c-0.552,0-1-0.448-1-1s0.448-1,1-1V44z"/><path fill="#185c37" d="M25,43c0,0.552-0.448,1-1,1v-2C24.552,42,25,42.448,25,43z"/><circle cx="42" cy="11" r="1" fill="#21a366"/><circle cx="6" cy="11" r="1" fill="#33c481"/><path fill="#185c37" d="M24,43l0.427,0.907c0,0,15.144-7.9,18.08-19.907H24V43z"/><path fill="#21a366" d="M43,11l-1-1c-11.122,0-11.278-6-18-6v20h18.507C42.822,22.712,43,21.378,43,20C43,16.856,43,11,43,11 z"/><path fill="#107c42" d="M24,43l-0.427,0.907c0,0-15.144-7.9-18.08-19.907H24V43z"/><path fill="#33c481" d="M5,11l1-1c11.122,0,11.278-6,18-6v20H5.493C5.178,22.712,5,21.378,5,20C5,16.856,5,11,5,11z"/><path d="M32.172,16.172L22,26.344l-5.172-5.172c-0.781-0.781-2.047-0.781-2.828,0l-1.414,1.414 c-0.781,0.781-0.781,2.047,0,2.828l8,8c0.781,0.781,2.047,0.781,2.828,0l13-13c0.781-0.781,0.781-2.047,0-2.828L35,16.172 C34.219,15.391,32.953,15.391,32.172,16.172z" opacity=".05"/><path d="M20.939,33.061l-8-8c-0.586-0.586-0.586-1.536,0-2.121l1.414-1.414c0.586-0.586,1.536-0.586,2.121,0 L22,27.051l10.525-10.525c0.586-0.586,1.536-0.586,2.121,0l1.414,1.414c0.586,0.586,0.586,1.536,0,2.121l-13,13 C22.475,33.646,21.525,33.646,20.939,33.061z" opacity=".07"/><path fill="#fff" d="M21.293,32.707l-8-8c-0.391-0.391-0.391-1.024,0-1.414l1.414-1.414c0.391-0.391,1.024-0.391,1.414,0 L22,27.758l10.879-10.879c0.391-0.391,1.024-0.391,1.414,0l1.414,1.414c0.391,0.391,0.391,1.024,0,1.414l-13,13 C22.317,33.098,21.683,33.098,21.293,32.707z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><linearGradient id="SVGID_1_" x1="5.327" x2="38.083" y1="520.657" y2="487.901" gradientTransform="matrix(1 0 0 -1 0 526)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#889097"/><stop offset=".331" stop-color="#848c94"/><stop offset=".669" stop-color="#78828b"/><stop offset="1" stop-color="#64717c"/></linearGradient><path fill="url(#SVGID_1_)" d="M43.4,19.2c-2.4,0-4.7-1.3-6-3.5c-1.2-2.1-1.2-4.6-0.2-6.7c-2.1-1.9-4.6-3.3-7.4-4.2C28.6,6.8,26.4,8,24,8 s-4.6-1.2-5.8-3.1c-2.8,0.8-5.3,2.3-7.4,4.2c1,2,1.1,4.6-0.2,6.7c-1.3,2.2-3.6,3.5-6,3.5C4.2,20.8,4,22.4,4,24 c0,1.3,0.1,2.5,0.4,3.8c2.5-0.1,4.9,1.2,6.2,3.5c1.4,2.4,1.2,5.2-0.2,7.3c2.1,1.9,4.6,3.5,7.3,4.4c1.1-2.3,3.5-4,6.3-4 s5.2,1.6,6.3,4c2.8-0.9,5.3-2.4,7.3-4.4c-1.4-2.1-1.6-5-0.2-7.3c1.3-2.3,3.7-3.5,6.2-3.5c0.2-1.2,0.4-2.5,0.4-3.8 C44,22.4,43.8,20.8,43.4,19.2z"/><path d="M30,18.1v1.3c-0.6-0.7-1.6-1.3-3.4-1.3h-4v6.6l-2.3-6.6h-3.7l-3.8,10.4H17l0.6-1.9h1.5l0.6,1.9h6.7v-2.9 c1.2,0,2.2-0.4,3-1c0.2-0.2,0.3-0.3,0.5-0.5v4.4h3.9V18.1H30z M26.5,22.2v-0.6c0.3,0,0.3,0.1,0.3,0.3C26.7,22.1,26.7,22.2,26.5,22.2 z" opacity=".05"/><path d="M26.6,18.6h-3.5v9l-3.2-9H17L13.5,28h3.1l0.6-1.9h2.3l0.6,1.9H26v-2.9h0.4c1.1,0,2.1-0.3,2.8-0.9 c0.7-0.6,1.1-1.4,1.1-2.4C30.2,20.3,29.6,18.6,26.6,18.6z M18,23.7l0.4-1.2l0.4,1.2H18z M26.2,22.7H26v-1.6h0.2c0.9,0,1,0.4,1,0.8 C27.2,22.4,27.1,22.7,26.2,22.7z" opacity=".07"/><path fill="#fff" d="M22.5,27.5h-2.1l-0.6-1.9h-3l-0.6,1.9h-2.1l3.1-8.4h2.2L22.5,27.5z M19.5,24.2l-0.9-2.8 c-0.1-0.2-0.1-0.5-0.1-0.8h0c0,0.2-0.1,0.5-0.1,0.7l-0.9,2.8H19.5z"/><rect width="2.9" height="9.4" x="30.5" y="18.6" opacity=".07"/><path fill="#fff" d="M25.5,24.6v2.9h-1.9v-8.4h3c2.1,0,3.2,0.9,3.2,2.7c0,0.8-0.3,1.5-0.9,2s-1.4,0.8-2.4,0.8H25.5z M25.5,20.6v2.6 h0.7c1,0,1.5-0.4,1.5-1.3c0-0.9-0.5-1.3-1.5-1.3H25.5z"/><path fill="#fff" d="M32.9,27.5H31v-8.4h1.9V27.5z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><path fill="#50e6ff" d="M39,16v25c0,1.105-0.895,2-2,2H11c-1.105,0-2-0.895-2-2V7c0-1.105,0.895-2,2-2h17L39,16z"/><path fill="#057093" d="M32.5,21h-17c-0.276,0-0.5-0.224-0.5-0.5v-1c0-0.276,0.224-0.5,0.5-0.5h17c0.276,0,0.5,0.224,0.5,0.5 v1C33,20.776,32.776,21,32.5,21z"/><path fill="#057093" d="M30.5,25h-15c-0.276,0-0.5-0.224-0.5-0.5v-1c0-0.276,0.224-0.5,0.5-0.5h15c0.276,0,0.5,0.224,0.5,0.5 v1C31,24.776,30.776,25,30.5,25z"/><path fill="#057093" d="M32.5,29h-17c-0.276,0-0.5-0.224-0.5-0.5v-1c0-0.276,0.224-0.5,0.5-0.5h17c0.276,0,0.5,0.224,0.5,0.5 v1C33,28.776,32.776,29,32.5,29z"/><path fill="#057093" d="M27.5,33h-12c-0.276,0-0.5-0.224-0.5-0.5v-1c0-0.276,0.224-0.5,0.5-0.5h12c0.276,0,0.5,0.224,0.5,0.5 v1C28,32.776,27.776,33,27.5,33z"/><linearGradient id="yfMHI4HjB37yWV1npL5HQa" x1="22.5" x2="22.5" y1="26" y2="5" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#3079d6"/><stop offset="1" stop-color="#297cd2"/></linearGradient><path fill="url(#yfMHI4HjB37yWV1npL5HQa)" d="M28,5H11C9.895,5,9,5.895,9,7v6H6.455c-0.405,0-0.607,0.49-0.321,0.776l3.723,3.723 c0.355,0.355,0.931,0.355,1.286,0l3.723-3.723C15.152,13.49,14.95,13,14.545,13H12V8h16l8,8v9.5c0,0.276,0.224,0.5,0.5,0.5h2 c0.276,0,0.5-0.224,0.5-0.5V16L28,5z"/><linearGradient id="yfMHI4HjB37yWV1npL5HQb" x1="25.478" x2="25.478" y1="43" y2="22" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#3079d6"/><stop offset="1" stop-color="#297cd2"/></linearGradient><path fill="url(#yfMHI4HjB37yWV1npL5HQb)" d="M41.821,34.224l-3.723-3.723c-0.355-0.355-0.931-0.355-1.285,0l-3.723,3.723 C32.803,34.51,33.005,35,33.41,35H36v5H12V22.5c0-0.276-0.224-0.5-0.5-0.5h-2C9.224,22,9,22.224,9,22.5V41c0,1.105,0.895,2,2,2h26 c1.105,0,2-0.895,2-2v-6h2.5C41.905,35,42.107,34.51,41.821,34.224z"/><rect width="3" height="1" x="36" y="16" opacity=".05"/><rect width="3" height=".5" x="36" y="16" opacity=".05"/><rect width="3" height="1" x="26" y="6" opacity=".05" transform="rotate(90 27.5 6.5)"/><rect width="3" height=".5" x="26.25" y="6.25" opacity=".05" transform="rotate(90 27.75 6.5)"/><linearGradient id="yfMHI4HjB37yWV1npL5HQc" x1="28.529" x2="33.6" y1="-1251.471" y2="-1246.4" gradientTransform="matrix(1 0 0 -1 0 -1236)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#3079d6"/><stop offset="1" stop-color="#297cd2"/></linearGradient><path fill="url(#yfMHI4HjB37yWV1npL5HQc)" d="M28,5v9c0,1.105,0.895,2,2,2h9L28,5z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><linearGradient id="2xtIDvU2ySt~E0WlpAU5ia" x1="13.661" x2="34.486" y1="57.962" y2="3.712" gradientTransform="matrix(1 0 0 -1 0 48)" gradientUnits="userSpaceOnUse"><stop offset=".076" stop-color="#ffda1c"/><stop offset="1" stop-color="#feb705"/></linearGradient><path fill="url(#2xtIDvU2ySt~E0WlpAU5ia)" d="M42,10c-11.122,0-11.278-6-18-6s-6.878,6-18,6c-0.552,0-1,0.448-1,1c0,0,0,5.856,0,9 c0,1.378,0.178,2.712,0.493,4c2.936,12.007,18.08,19.907,18.08,19.907S23.784,44,24,44c0.203,0,0.427-0.093,0.427-0.093 s15.144-7.9,18.08-19.907C42.822,22.712,43,21.378,43,20c0-3.144,0-9,0-9C43,10.448,42.552,10,42,10z"/><path d="M24,33c-1.654,0-3-1.346-3-3v-2.91c-1.571-1.017-2.5-2.712-2.5-4.59 c0-3.033,2.468-5.5,5.5-5.5s5.5,2.467,5.5,5.5c0,1.877-0.929,3.573-2.5,4.59V30C27,31.654,25.654,33,24,33z" opacity=".05"/><path d="M24,32.5c-1.379,0-2.5-1.122-2.5-2.5v-3.19c-1.55-0.896-2.5-2.52-2.5-4.31 c0-2.757,2.243-5,5-5s5,2.243,5,5c0,1.79-0.95,3.415-2.5,4.31V30C26.5,31.378,25.379,32.5,24,32.5z" opacity=".07"/><radialGradient id="2xtIDvU2ySt~E0WlpAU5ib" cx="17.403" cy="30.919" r="17.37" gradientTransform="matrix(1 0 0 -1 0 48)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#4b4b4b"/><stop offset=".531" stop-color="#393939"/><stop offset="1" stop-color="#252525"/></radialGradient><path fill="url(#2xtIDvU2ySt~E0WlpAU5ib)" d="M28.5,22.5c0-2.485-2.015-4.5-4.5-4.5s-4.5,2.015-4.5,4.5c0,1.763,1.024,3.273,2.5,4.012V30 c0,1.105,0.895,2,2,2s2-0.895,2-2v-3.488C27.476,25.773,28.5,24.263,28.5,22.5z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><linearGradient id="5VgOgqi_6eF~SnlSy~llla" x1="16.197" x2="38.605" y1="45.133" y2="2.988" gradientTransform="matrix(1 0 0 -1 0 48)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#05acb3"/><stop offset="1" stop-color="#038387"/></linearGradient><path fill="url(#5VgOgqi_6eF~SnlSy~llla)" d="M42,10c-11.122,0-11.278-6-18-6s-6.878,6-18,6c-0.552,0-1,0.448-1,1c0,0,0,5.856,0,9 c0,1.378,0.178,2.712,0.493,4c2.936,12.007,18.08,19.907,18.08,19.907S23.784,44,24,44c0.203,0,0.427-0.093,0.427-0.093 s15.144-7.9,18.08-19.907C42.822,22.712,43,21.378,43,20c0-3.144,0-9,0-9C43,10.448,42.552,10,42,10z"/><path d="M14.931,28c-0.6,0-1.211-0.058-1.768-0.167 c-0.446-0.087-0.86-0.212-1.229-0.371c-0.54-0.23-0.891-0.771-0.891-1.375v-1.443c0-0.714,0.583-1.295,1.299-1.295 c0.262,0,0.516,0.078,0.733,0.226c0.517,0.349,0.979,0.442,1.132,0.473c0.231,0.048,0.443,0.071,0.65,0.071 c0.188,0,0.363-0.019,0.521-0.056c0.087-0.021,0.146-0.045,0.184-0.064c-0.034-0.016-0.093-0.072-0.207-0.156 c-0.309-0.216-0.742-0.405-1.201-0.604l-0.186-0.081c-0.947-0.412-1.677-0.939-2.168-1.568c-0.53-0.676-0.8-1.492-0.8-2.425 c-0.054-1.925,1.218-3.48,3.24-3.95C14.845,15.072,15.484,15,16.144,15c0.825,0,1.642,0.118,2.36,0.34 c0.616,0.189,1.047,0.78,1.047,1.437v1.014c0,0.823-0.67,1.493-1.494,1.493c-0.204,0-0.404-0.041-0.594-0.122 c-0.406-0.173-0.881-0.271-1.336-0.273c-0.32,0-0.548,0.057-0.657,0.107c0.124,0.103,0.387,0.249,0.513,0.318 c0.208,0.107,0.429,0.207,0.655,0.31c0.471,0.213,0.953,0.432,1.354,0.694c1.324,0.791,2.042,2.049,2.007,3.534 c0.064,1.949-1.26,3.554-3.293,3.966C16.181,27.936,15.563,28,14.931,28z" opacity=".05"/><path d="M14.931,27.5c-0.568,0-1.146-0.055-1.671-0.158 c-0.412-0.081-0.792-0.195-1.128-0.339c-0.356-0.152-0.588-0.512-0.588-0.916v-1.443c0-0.438,0.358-0.795,0.799-0.795 c0.162,0,0.318,0.048,0.453,0.14c0.601,0.406,1.137,0.514,1.313,0.549c0.268,0.055,0.513,0.081,0.749,0.081 c0.227,0,0.44-0.023,0.636-0.07c0.219-0.052,0.587-0.186,0.586-0.505c0-0.18-0.071-0.344-0.431-0.605 c-0.356-0.25-0.813-0.448-1.296-0.659l-0.186-0.081c-0.868-0.377-1.533-0.854-1.974-1.417c-0.46-0.586-0.693-1.299-0.693-2.117 c-0.047-1.685,1.073-3.05,2.854-3.463c0.567-0.133,1.17-0.201,1.789-0.201c0.775,0,1.541,0.11,2.213,0.318 c0.409,0.126,0.694,0.521,0.694,0.959v1.014c0,0.547-0.446,0.993-0.994,0.993c-0.136,0-0.271-0.028-0.397-0.082 c-0.466-0.199-1.009-0.31-1.529-0.313c-0.276,0-1.189,0.043-1.211,0.595c0.008,0.294,0.315,0.487,0.821,0.768 c0.229,0.118,0.457,0.222,0.691,0.328c0.45,0.204,0.916,0.415,1.286,0.657c1.174,0.702,1.812,1.807,1.78,3.103 c0.057,1.741-1.078,3.121-2.893,3.488C16.109,27.439,15.526,27.5,14.931,27.5z" opacity=".07"/><path fill="#fff" d="M12.33,26.544c-0.179-0.077-0.286-0.262-0.286-0.457v-1.443c0-0.242,0.271-0.377,0.471-0.242 c0.71,0.48,1.335,0.593,1.517,0.63c0.531,0.109,1.087,0.119,1.577,0.003c0.505-0.12,0.971-0.433,0.971-0.993 c0-0.455-0.281-0.749-0.636-1.008c-0.457-0.32-1.024-0.552-1.575-0.793c-0.796-0.346-1.391-0.769-1.781-1.268 c-0.392-0.499-0.587-1.102-0.587-1.809c-0.044-1.576,1.068-2.652,2.467-2.976c1.185-0.278,2.579-0.25,3.741,0.108 c0.207,0.064,0.342,0.265,0.342,0.481v1.014c0,0.36-0.365,0.592-0.696,0.451c-0.545-0.233-1.151-0.35-1.722-0.354 c-0.709,0.001-1.68,0.215-1.714,1.075c0.016,0.654,0.599,0.959,1.123,1.249c0.57,0.292,1.373,0.597,1.902,0.942 c0.964,0.576,1.583,1.473,1.554,2.672c0.052,1.629-1.04,2.716-2.493,3.01c-0.98,0.222-2.168,0.208-3.15,0.015 C12.975,26.777,12.633,26.675,12.33,26.544z"/><path d="M23.931,28c-0.6,0-1.211-0.058-1.768-0.167 c-0.446-0.087-0.86-0.212-1.229-0.371c-0.54-0.23-0.891-0.771-0.891-1.375v-1.443c0-0.714,0.583-1.295,1.299-1.295 c0.262,0,0.516,0.078,0.733,0.226c0.517,0.349,0.979,0.442,1.132,0.473c0.231,0.048,0.443,0.071,0.65,0.071 c0.188,0,0.363-0.019,0.521-0.056c0.087-0.021,0.146-0.045,0.184-0.064c-0.034-0.016-0.093-0.072-0.207-0.156 c-0.309-0.216-0.742-0.405-1.201-0.604l-0.186-0.081c-0.947-0.412-1.677-0.939-2.168-1.568c-0.53-0.676-0.8-1.492-0.8-2.425 c-0.054-1.925,1.218-3.48,3.24-3.95C23.845,15.072,24.484,15,25.144,15c0.825,0,1.642,0.118,2.36,0.34 c0.616,0.189,1.047,0.78,1.047,1.437v1.014c0,0.823-0.67,1.493-1.494,1.493c-0.204,0-0.404-0.041-0.594-0.122 c-0.406-0.173-0.881-0.271-1.336-0.273c-0.32,0-0.548,0.057-0.657,0.107c0.124,0.103,0.387,0.249,0.513,0.318 c0.208,0.107,0.429,0.207,0.655,0.31c0.471,0.213,0.953,0.432,1.354,0.694c1.324,0.791,2.042,2.049,2.007,3.534 c0.064,1.949-1.26,3.554-3.293,3.966C25.181,27.936,24.563,28,23.931,28z" opacity=".05"/><path d="M23.931,27.5c-0.568,0-1.146-0.055-1.671-0.158 c-0.412-0.081-0.792-0.195-1.128-0.339c-0.356-0.152-0.588-0.512-0.588-0.916v-1.443c0-0.438,0.358-0.795,0.799-0.795 c0.162,0,0.318,0.048,0.453,0.14c0.601,0.406,1.137,0.514,1.313,0.549c0.268,0.055,0.513,0.081,0.749,0.081 c0.227,0,0.44-0.023,0.636-0.07c0.219-0.052,0.587-0.186,0.586-0.505c0-0.18-0.071-0.344-0.431-0.605 c-0.356-0.25-0.813-0.448-1.296-0.659l-0.186-0.081c-0.868-0.377-1.533-0.854-1.974-1.417c-0.46-0.586-0.693-1.299-0.693-2.117 c-0.047-1.685,1.073-3.05,2.854-3.463c0.567-0.133,1.17-0.201,1.789-0.201c0.775,0,1.541,0.11,2.213,0.318 c0.409,0.126,0.694,0.521,0.694,0.959v1.014c0,0.547-0.446,0.993-0.994,0.993c-0.136,0-0.271-0.028-0.397-0.082 c-0.466-0.199-1.009-0.31-1.529-0.313c-0.276,0-1.189,0.043-1.211,0.595c0.008,0.294,0.315,0.487,0.821,0.768 c0.229,0.118,0.457,0.222,0.691,0.328c0.45,0.204,0.916,0.415,1.286,0.657c1.174,0.702,1.812,1.807,1.78,3.103 c0.057,1.741-1.078,3.121-2.893,3.488C25.109,27.439,24.526,27.5,23.931,27.5z" opacity=".07"/><path fill="#fff" d="M21.33,26.544c-0.179-0.077-0.286-0.262-0.286-0.457v-1.443c0-0.242,0.271-0.377,0.471-0.242 c0.71,0.48,1.335,0.593,1.517,0.63c0.531,0.109,1.087,0.119,1.577,0.003c0.505-0.12,0.971-0.433,0.971-0.993 c0-0.455-0.281-0.749-0.636-1.008c-0.457-0.32-1.024-0.552-1.575-0.793c-0.796-0.346-1.391-0.769-1.781-1.268 c-0.392-0.499-0.587-1.102-0.587-1.809c-0.044-1.576,1.068-2.652,2.467-2.976c1.185-0.278,2.579-0.25,3.741,0.108 c0.207,0.064,0.342,0.265,0.342,0.481v1.014c0,0.36-0.365,0.592-0.696,0.451c-0.545-0.233-1.151-0.35-1.722-0.354 c-0.709,0.001-1.68,0.215-1.714,1.075c0.016,0.654,0.599,0.959,1.123,1.249c0.57,0.292,1.373,0.597,1.902,0.942 c0.964,0.576,1.583,1.473,1.554,2.672c0.052,1.629-1.04,2.716-2.493,3.01c-0.98,0.222-2.168,0.208-3.15,0.015 C21.975,26.777,21.633,26.675,21.33,26.544z"/><path d="M30.5,28c-0.827,0-1.5-0.673-1.5-1.5v-10c0-0.827,0.673-1.5,1.5-1.5h1.269 c0.827,0,1.5,0.673,1.5,1.5v7.49H35.5c0.827,0,1.5,0.673,1.5,1.5v1.01c0,0.827-0.673,1.5-1.5,1.5H30.5z" opacity=".05"/><path d="M30.5,27.5c-0.552,0-1-0.449-1-1v-10c0-0.551,0.448-1,1-1h1.269 c0.552,0,1,0.449,1,1v7.99H35.5c0.552,0,1,0.449,1,1v1.01c0,0.551-0.448,1-1,1H30.5z" opacity=".07"/><path fill="#fff" d="M35.5,27h-5c-0.276,0-0.5-0.224-0.5-0.5v-10c0-0.276,0.224-0.5,0.5-0.5h1.269 c0.276,0,0.5,0.224,0.5,0.5v8.49H35.5c0.276,0,0.5,0.224,0.5,0.5v1.01C36,26.776,35.776,27,35.5,27z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><linearGradient id="9Zf~EdBnGkYjb06gomJKUa" x1="9.858" x2="38.142" y1="9.858" y2="38.142" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#f44f5a"/><stop offset=".443" stop-color="#ee3d4a"/><stop offset="1" stop-color="#e52030"/></linearGradient><path fill="url(#9Zf~EdBnGkYjb06gomJKUa)" d="M44,24c0,11.045-8.955,20-20,20S4,35.045,4,24S12.955,4,24,4S44,12.955,44,24z"/><path d="M29,13.61v4.722c0,0.445,0.129,0.889,0.411,1.233c1.262,1.536,1.884,3.616,1.452,5.838 c-0.531,2.732-2.731,4.933-5.463,5.463C20.92,31.732,17,28.324,17,24c0-1.686,0.598-3.232,1.592-4.44 C18.869,19.223,19,18.788,19,18.351V13.61c0-0.756-0.819-1.259-1.474-0.882c-4.407,2.536-7.188,7.579-6.389,13.183 c0.823,5.773,5.584,10.365,11.379,11.006C30.36,37.786,37,31.669,37,24c0-4.822-2.626-9.029-6.526-11.272 C29.818,12.35,29,12.853,29,13.61z" opacity=".05"/><path d="M29.5,14.067v4.282c0,0.337,0.107,0.668,0.32,0.929c1.287,1.582,1.945,3.695,1.576,5.963 c-0.502,3.158-3.079,5.697-6.24,6.166C20.501,32.098,16.5,28.521,16.5,24c0-1.792,0.632-3.434,1.681-4.724 c0.211-0.258,0.319-0.585,0.319-0.918v-4.29c0-0.582-0.639-0.949-1.134-0.644c-3.818,2.361-6.217,6.758-5.796,11.672 c0.515,6.008,5.432,10.918,11.453,11.358C30.366,37.019,36.5,31.226,36.5,24c0-4.462-2.336-8.388-5.865-10.576 C30.14,13.118,29.5,13.484,29.5,14.067z" opacity=".07"/><path fill="#fff" d="M30,14.556v3.817c0,0.229,0.084,0.446,0.228,0.624c1.439,1.786,2.135,4.193,1.583,6.758 c-0.657,3.052-3.14,5.488-6.204,6.088C20.495,32.844,16,28.937,16,24c0-1.894,0.667-3.631,1.771-5.002 C17.915,18.819,18,18.601,18,18.371v-3.814c0-0.418-0.471-0.654-0.815-0.416c-3.201,2.218-5.281,5.944-5.182,10.147 c0.147,6.243,5.28,11.459,11.52,11.703C30.356,36.257,36,30.775,36,24c0-4.084-2.057-7.691-5.184-9.858 C30.472,13.904,30,14.136,30,14.556z"/><path d="M23,22h2c1.105,0,2-0.895,2-2v-8c0-1.105-0.895-2-2-2h-2c-1.105,0-2,0.895-2,2v8 C21,21.105,21.895,22,23,22z" opacity=".05"/><path d="M23,21.5h2c0.828,0,1.5-0.672,1.5-1.5v-8c0-0.828-0.672-1.5-1.5-1.5h-2c-0.828,0-1.5,0.672-1.5,1.5v8 C21.5,20.828,22.172,21.5,23,21.5z" opacity=".07"/><path fill="#fff" d="M25,21h-2c-0.552,0-1-0.448-1-1v-8c0-0.552,0.448-1,1-1h2c0.552,0,1,0.448,1,1v8 C26,20.552,25.552,21,25,21z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px">
<linearGradient id="71jOKMe3jIEN7vuoamoZEa" x1="26.5" x2="26.5" y1="42.5" y2="35.874" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#737b80"/>
<stop offset="1" stop-color="#575c61"/>
</linearGradient>
<rect width="25" height="7" x="14" y="34" fill="url(#71jOKMe3jIEN7vuoamoZEa)"/>
<linearGradient id="71jOKMe3jIEN7vuoamoZEb" x1="18" x2="18" y1="38.094" y2="35.749" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#ffd869"/>
<stop offset="1" stop-color="#fec52b"/>
</linearGradient>
<path fill="url(#71jOKMe3jIEN7vuoamoZEb)" d="M18.5,39h-1c-0.276,0-0.5-0.224-0.5-0.5v-5c0-0.276,0.224-0.5,0.5-0.5h1 c0.276,0,0.5,0.224,0.5,0.5v5C19,38.776,18.776,39,18.5,39z"/>
<linearGradient id="71jOKMe3jIEN7vuoamoZEc" x1="22" x2="22" y1="38.094" y2="35.749" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#ffd869"/>
<stop offset="1" stop-color="#fec52b"/>
</linearGradient>
<path fill="url(#71jOKMe3jIEN7vuoamoZEc)" d="M22.5,39h-1c-0.276,0-0.5-0.224-0.5-0.5v-5c0-0.276,0.224-0.5,0.5-0.5h1 c0.276,0,0.5,0.224,0.5,0.5v5C23,38.776,22.776,39,22.5,39z"/>
<linearGradient id="71jOKMe3jIEN7vuoamoZEd" x1="27" x2="27" y1="38.094" y2="35.749" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#ffd869"/>
<stop offset="1" stop-color="#fec52b"/>
</linearGradient>
<path fill="url(#71jOKMe3jIEN7vuoamoZEd)" d="M27.5,39h-1c-0.276,0-0.5-0.224-0.5-0.5v-5c0-0.276,0.224-0.5,0.5-0.5h1 c0.276,0,0.5,0.224,0.5,0.5v5C28,38.776,27.776,39,27.5,39z"/>
<linearGradient id="71jOKMe3jIEN7vuoamoZEe" x1="31" x2="31" y1="38.094" y2="35.749" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#ffd869"/>
<stop offset="1" stop-color="#fec52b"/>
</linearGradient>
<path fill="url(#71jOKMe3jIEN7vuoamoZEe)" d="M31.5,39h-1c-0.276,0-0.5-0.224-0.5-0.5v-5c0-0.276,0.224-0.5,0.5-0.5h1 c0.276,0,0.5,0.224,0.5,0.5v5C32,38.776,31.776,39,31.5,39z"/>
<linearGradient id="71jOKMe3jIEN7vuoamoZEf" x1="35" x2="35" y1="38.094" y2="35.749" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#ffd869"/>
<stop offset="1" stop-color="#fec52b"/>
</linearGradient>
<path fill="url(#71jOKMe3jIEN7vuoamoZEf)" d="M35.5,39h-1c-0.276,0-0.5-0.224-0.5-0.5v-5c0-0.276,0.224-0.5,0.5-0.5h1 c0.276,0,0.5,0.224,0.5,0.5v5C36,38.776,35.776,39,35.5,39z"/>
<linearGradient id="71jOKMe3jIEN7vuoamoZEg" x1="24" x2="24" y1="30.333" y2="42.75" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#c3cdd9"/>
<stop offset="1" stop-color="#9fa7b0"/>
</linearGradient>
<path fill="url(#71jOKMe3jIEN7vuoamoZEg)" d="M42,30v10c0,1.1-0.9,2-2,2h-1.25c-0.44,0-0.83-0.3-0.96-0.73L37.71,41l-1.3-4.55 C36.17,35.59,35.38,35,34.49,35H18.51c-0.89,0-1.68,0.59-1.92,1.45L15.29,41l-0.08,0.27C15.08,41.7,14.69,42,14.25,42H8 c-1.1,0-2-0.9-2-2V30H42z"/>
<g>
<path d="M42,30v10c0,1.1-0.9,2-2,2h-1.25c-0.44,0-0.83-0.3-0.96-0.73L37.71,41h-1.04l-1.22-4.27 C35.33,36.3,34.94,36,34.49,36H18.51c-0.45,0-0.84,0.3-0.96,0.73L16.33,41h-1.04l-0.08,0.27C15.08,41.7,14.69,42,14.25,42H8 c-1.1,0-2-0.9-2-2V30H42z" opacity=".05"/>
<path d="M42,30v10c0,1.1-0.9,2-2,2h-1.25c-0.44,0-0.83-0.3-0.96-0.73L37.71,41h-0.52l-1.26-4.41 c-0.18-0.64-0.77-1.09-1.44-1.09H18.51c-0.67,0-1.26,0.45-1.44,1.09L15.81,41h-0.52l-0.08,0.27C15.08,41.7,14.69,42,14.25,42H8 c-1.1,0-2-0.9-2-2V30H42z" opacity=".07"/>
</g>
<linearGradient id="71jOKMe3jIEN7vuoamoZEh" x1="24" x2="24" y1="6.417" y2="31.933" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#737b80"/>
<stop offset="1" stop-color="#575c61"/>
</linearGradient>
<path fill="url(#71jOKMe3jIEN7vuoamoZEh)" d="M10.764,6h26.471c1.008,0,1.859,0.75,1.984,1.751l2.767,22.02C42.124,30.958,41.195,32,40,32 H8c-1.195,0-2.124-1.042-1.987-2.229L8.78,7.751C8.906,6.75,9.756,6,10.764,6z"/>
<g>
<path d="M11,35c1.105,0,2,0.895,2,2s-0.895,2-2,2s-2-0.895-2-2S9.895,35,11,35 M11,34c-1.654,0-3,1.346-3,3s1.346,3,3,3 s3-1.346,3-3S12.654,34,11,34L11,34z" opacity=".05"/>
<path d="M11,35c1.105,0,2,0.895,2,2s-0.895,2-2,2s-2-0.895-2-2S9.895,35,11,35 M11,34.5c-1.379,0-2.5,1.121-2.5,2.5 s1.121,2.5,2.5,2.5s2.5-1.121,2.5-2.5S12.379,34.5,11,34.5L11,34.5z" opacity=".07"/>
<linearGradient id="71jOKMe3jIEN7vuoamoZEi" x1="11" x2="11" y1="34.958" y2="39.052" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#75ff8a"/>
<stop offset="1" stop-color="#1ee446"/>
</linearGradient>
<circle cx="11" cy="37" r="2" fill="#666666" />
<circle cx="11" cy="37" r="2" fill="url(#71jOKMe3jIEN7vuoamoZEi)">
<animate attributeName="opacity" dur="2s" values="0;1;0" repeatCount="indefinite" begin="0.1" />
</circle>
</g>
<g>
<g opacity=".05">
<path d="M10.5,28c0.828,0,1.5,0.448,1.5,1s-0.672,1-1.5,1S9,29.552,9,29S9.672,28,10.5,28 M10.5,27C9.098,27,8,27.878,8,29 s1.098,2,2.5,2s2.5-0.878,2.5-2S11.902,27,10.5,27L10.5,27z"/>
<path d="M37.5,28c0.828,0,1.5,0.448,1.5,1s-0.672,1-1.5,1S36,29.552,36,29S36.672,28,37.5,28 M37.5,27c-1.402,0-2.5,0.878-2.5,2 s1.098,2,2.5,2s2.5-0.878,2.5-2S38.902,27,37.5,27L37.5,27z"/>
<path d="M12.5,8C13.328,8,14,8.448,14,9s-0.672,1-1.5,1S11,9.552,11,9S11.672,8,12.5,8 M12.5,7C11.098,7,10,7.878,10,9 s1.098,2,2.5,2S15,10.122,15,9S13.902,7,12.5,7L12.5,7z"/>
<path d="M35.5,8C36.328,8,37,8.448,37,9s-0.672,1-1.5,1S34,9.552,34,9S34.672,8,35.5,8 M35.5,7C34.098,7,33,7.878,33,9 s1.098,2,2.5,2S38,10.122,38,9S36.902,7,35.5,7L35.5,7z"/>
</g>
<g opacity=".07">
<path d="M10.5,28c0.828,0,1.5,0.448,1.5,1s-0.672,1-1.5,1S9,29.552,9,29S9.672,28,10.5,28 M10.5,27.5c-1.121,0-2,0.659-2,1.5 s0.879,1.5,2,1.5s2-0.659,2-1.5S11.621,27.5,10.5,27.5L10.5,27.5z"/>
<path d="M37.5,28c0.828,0,1.5,0.448,1.5,1s-0.672,1-1.5,1S36,29.552,36,29S36.672,28,37.5,28 M37.5,27.5c-1.121,0-2,0.659-2,1.5 s0.879,1.5,2,1.5s2-0.659,2-1.5S38.621,27.5,37.5,27.5L37.5,27.5z"/>
<path d="M12.5,8C13.328,8,14,8.448,14,9s-0.672,1-1.5,1S11,9.552,11,9S11.672,8,12.5,8 M12.5,7.5c-1.121,0-2,0.659-2,1.5 s0.879,1.5,2,1.5s2-0.659,2-1.5S13.621,7.5,12.5,7.5L12.5,7.5z"/>
<path d="M35.5,8C36.328,8,37,8.448,37,9s-0.672,1-1.5,1S34,9.552,34,9S34.672,8,35.5,8 M35.5,7.5c-1.121,0-2,0.659-2,1.5 s0.879,1.5,2,1.5s2-0.659,2-1.5S36.621,7.5,35.5,7.5L35.5,7.5z"/>
</g>
<ellipse cx="10.5" cy="29" fill="#ccc" rx="1.5" ry="1"/>
<ellipse cx="37.5" cy="29" fill="#ccc" rx="1.5" ry="1"/>
<ellipse cx="12.5" cy="9" fill="#ccc" rx="1.5" ry="1"/>
<ellipse cx="35.5" cy="9" fill="#ccc" rx="1.5" ry="1"/>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><defs><linearGradient id="q4ZcgI2I2xY6Kw_QGjTtla" x1="47.342" x2="24.972" y1="16.75" y2="16.75" data-name="Безымянный градиент 55" gradientUnits="userSpaceOnUse"><stop offset=".087" stop-color="#dfe9f2"/><stop offset=".291" stop-color="#d6e0e9"/><stop offset=".662" stop-color="#bfc8d1"/><stop offset=".741" stop-color="#889097"/></linearGradient><linearGradient id="q4ZcgI2I2xY6Kw_QGjTtlb" x1="5.412" x2="18" y1="17" y2="17" data-name="Безымянный градиент 56" gradientUnits="userSpaceOnUse"><stop offset=".024" stop-color="#dfe9f2"/><stop offset=".327" stop-color="#d6e0e9"/><stop offset=".798" stop-color="#bfc8d1"/><stop offset=".941" stop-color="#889097"/></linearGradient><linearGradient id="q4ZcgI2I2xY6Kw_QGjTtlc" x1="4.414" x2="18" y1="30.543" y2="30.543" data-name="Безымянный градиент 57" gradientUnits="userSpaceOnUse"><stop offset=".038" stop-color="#dfe9f2"/><stop offset=".488" stop-color="#d6e0e9"/><stop offset=".809" stop-color="#bfc8d1"/><stop offset=".956" stop-color="#889097"/></linearGradient><linearGradient id="q4ZcgI2I2xY6Kw_QGjTtld" x1="17.087" x2="31.387" y1="5.006" y2="44.294" data-name="Безымянный градиент 123" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#f44f5a"/><stop offset=".443" stop-color="#ee3d4a"/><stop offset="1" stop-color="#e52030"/></linearGradient></defs><path fill="url(#q4ZcgI2I2xY6Kw_QGjTtla)" d="M30,9,45,24a8.67909,8.67909,0,0,1-9-2L26,12l3-3Z"/><path fill="url(#q4ZcgI2I2xY6Kw_QGjTtlb)" d="M18,24,5.70711,11.70711A1,1,0,0,1,6.41421,10H10v2h2v2h2v2h2v2h2Z"/><path fill="url(#q4ZcgI2I2xY6Kw_QGjTtlc)" d="M14.11129,25.33513a1.62707,1.62707,0,0,1-.27677,1.82874,1.90889,1.90889,0,0,1-2.70188-.03127L9.882,25.882a1.07858,1.07858,0,0,1-.17486-1.58907L10.8043,23.1957a.50575.50575,0,0,0-.1902-.83335,4.96853,4.96853,0,0,0-5.14962,1.17317l-.75737.75737a1,1,0,0,0,0,1.41422L18,39V29l-3.7496-3.74959A.08377.08377,0,0,0,14.11129,25.33513Z"/><rect width="14" height="38" x="17" y="5" fill="url(#q4ZcgI2I2xY6Kw_QGjTtld)" rx="7"/><path d="M24.5,33a.5.5,0,0,1,.5.5V35h1.5a.5.5,0,0,1,.5.5v1a.5.5,0,0,1-.5.5H25v1.5a.5.5,0,0,1-.5.5h-1a.5.5,0,0,1-.5-.5V37H21.5a.5.5,0,0,1-.5-.5v-1a.5.5,0,0,1,.5-.5H23V33.5a.5.5,0,0,1,.5-.5h1m0-1h-1A1.5017,1.5017,0,0,0,22,33.5V34h-.5A1.5017,1.5017,0,0,0,20,35.5v1A1.5017,1.5017,0,0,0,21.5,38H22v.5A1.5017,1.5017,0,0,0,23.5,40h1A1.5017,1.5017,0,0,0,26,38.5V38h.5A1.5017,1.5017,0,0,0,28,36.5v-1A1.5017,1.5017,0,0,0,26.5,34H26v-.5A1.5017,1.5017,0,0,0,24.5,32Z" opacity=".05"/><path d="M24.5,33a.5.5,0,0,1,.5.5V35h1.5a.5.5,0,0,1,.5.5v1a.5.5,0,0,1-.5.5H25v1.5a.5.5,0,0,1-.5.5h-1a.5.5,0,0,1-.5-.5V37H21.5a.5.5,0,0,1-.5-.5v-1a.5.5,0,0,1,.5-.5H23V33.5a.5.5,0,0,1,.5-.5h1m0-.5h-1a1.00112,1.00112,0,0,0-1,1v1h-1a1.00112,1.00112,0,0,0-1,1v1a1.00112,1.00112,0,0,0,1,1h1v1a1.00112,1.00112,0,0,0,1,1h1a1.00112,1.00112,0,0,0,1-1v-1h1a1.00112,1.00112,0,0,0,1-1v-1a1.00112,1.00112,0,0,0-1-1h-1v-1a1.00112,1.00112,0,0,0-1-1Z" opacity=".07"/><path fill="#fff" d="M26.5,35H25V33.5a.5.5,0,0,0-.5-.5h-1a.5.5,0,0,0-.5.5V35H21.5a.5.5,0,0,0-.5.5v1a.5.5,0,0,0,.5.5H23v1.5a.5.5,0,0,0,.5.5h1a.5.5,0,0,0,.5-.5V37h1.5a.5.5,0,0,0,.5-.5v-1A.5.5,0,0,0,26.5,35Z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><path fill="#64717c" d="M16,6h-2v32c0,1.657,1.343,3,3,3h9v-2h-9c-0.552,0-1-0.448-1-1V25h10v-2H16V6z"/><linearGradient id="4RxtpKI4_WKe2V_J7J5Cfa" x1="711.5" x2="711.5" y1="409.459" y2="400" gradientTransform="translate(-696.5 -396.5)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#42a3f2"/><stop offset="1" stop-color="#42a4eb"/></linearGradient><path fill="url(#4RxtpKI4_WKe2V_J7J5Cfa)" d="M22,3H8C7.448,3,7,3.448,7,4v8c0,0.552,0.448,1,1,1h14c0.552,0,1-0.448,1-1V4 C23,3.448,22.552,3,22,3z"/><linearGradient id="4RxtpKI4_WKe2V_J7J5Cfb" x1="699.5" x2="699.5" y1="443.459" y2="434" gradientTransform="translate(-666.5 -414.5)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#3079d6"/><stop offset="1" stop-color="#297cd2"/></linearGradient><path fill="url(#4RxtpKI4_WKe2V_J7J5Cfb)" d="M40,19H26c-0.552,0-1,0.448-1,1v8c0,0.552,0.448,1,1,1h14c0.552,0,1-0.448,1-1v-8 C41,19.448,40.552,19,40,19z"/><linearGradient id="4RxtpKI4_WKe2V_J7J5Cfc" x1="699.5" x2="699.5" y1="459.459" y2="450" gradientTransform="translate(-666.5 -414.5)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#3079d6"/><stop offset="1" stop-color="#297cd2"/></linearGradient><path fill="url(#4RxtpKI4_WKe2V_J7J5Cfc)" d="M40,35H26c-0.552,0-1,0.448-1,1v8c0,0.552,0.448,1,1,1h14c0.552,0,1-0.448,1-1v-8 C41,35.448,40.552,35,40,35z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><linearGradient id="mSE1eGSRmh6PFhOj6Rylra" x1="13.48" x2="31.634" y1="650.407" y2="624.147" gradientTransform="matrix(1 0 0 -1 0 662)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#7dd8f3"/><stop offset="1" stop-color="#45b0d0"/></linearGradient><path fill="url(#mSE1eGSRmh6PFhOj6Rylra)" d="M4,38V15h40v23c0,1.1-0.9,2-2,2H6C4.9,40,4,39.1,4,38z"/><linearGradient id="mSE1eGSRmh6PFhOj6Rylrb" x1="4.614" x2="42.936" y1="654.259" y2="646.467" gradientTransform="matrix(1 0 0 -1 0 662)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#0077d2"/><stop offset="1" stop-color="#0b59a2"/></linearGradient><path fill="url(#mSE1eGSRmh6PFhOj6Rylrb)" d="M44,10v5H4v-5c0-1.1,0.9-2,2-2h36C43.1,8,44,8.9,44,10z"/><linearGradient id="mSE1eGSRmh6PFhOj6Rylrc" x1="16" x2="42" y1="650.5" y2="650.5" gradientTransform="matrix(1 0 0 -1 0 662)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#7dd8f3"/><stop offset="1" stop-color="#45b0d0"/></linearGradient><path fill="url(#mSE1eGSRmh6PFhOj6Rylrc)" d="M16.5,13h25c0.276,0,0.5-0.224,0.5-0.5v-2c0-0.276-0.224-0.5-0.5-0.5h-25 c-0.276,0-0.5,0.224-0.5,0.5v2C16,12.776,16.224,13,16.5,13z"/><linearGradient id="mSE1eGSRmh6PFhOj6Rylrd" x1="6.751" x2="8.032" y1="651.584" y2="649.731" gradientTransform="matrix(1 0 0 -1 0 662)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#75daff"/><stop offset="1" stop-color="#49bef1"/></linearGradient><circle cx="7.5" cy="11.5" r="1.5" fill="url(#mSE1eGSRmh6PFhOj6Rylrd)"/><linearGradient id="mSE1eGSRmh6PFhOj6Rylre" x1="11.751" x2="13.032" y1="651.584" y2="649.731" gradientTransform="matrix(1 0 0 -1 0 662)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#75daff"/><stop offset="1" stop-color="#49bef1"/></linearGradient><circle cx="12.5" cy="11.5" r="1.5" fill="url(#mSE1eGSRmh6PFhOj6Rylre)"/><path fill="#0d86ad" d="M40,37h-8c-0.552,0-1-0.448-1-1V19c0-0.552,0.448-1,1-1h8c0.552,0,1,0.448,1,1v17 C41,36.552,40.552,37,40,37z"/><path fill="#0d86ad" d="M27,26H8c-0.552,0-1-0.448-1-1v-6c0-0.552,0.448-1,1-1h19c0.552,0,1,0.448,1,1v6 C28,25.552,27.552,26,27,26z"/><path fill="#0d86ad" d="M27,37H8c-0.552,0-1-0.448-1-1v-6c0-0.552,0.448-1,1-1h19c0.552,0,1,0.448,1,1v6 C28,36.552,27.552,37,27,37z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="96px" height="96px"><path fill="#64717c" d="M17,19H7c-0.552,0-1-0.447-1-1s0.448-1,1-1h10c0.552,0,1,0.447,1,1S17.552,19,17,19z"/><path fill="#64717c" d="M7.001,17c-0.354,0-0.697-0.188-0.879-0.521c-0.265-0.484-0.086-1.092,0.399-1.356l11-6 c0.486-0.265,1.093-0.085,1.357,0.399c0.265,0.484,0.086,1.092-0.399,1.356l-11,6C7.327,16.961,7.163,17,7.001,17z"/><path fill="#64717c" d="M17.999,27c-0.162,0-0.326-0.039-0.478-0.122l-11-6c-0.485-0.265-0.664-0.872-0.399-1.356 s0.872-0.663,1.357-0.399l11,6c0.485,0.265,0.664,0.872,0.399,1.356C18.696,26.812,18.353,27,17.999,27z"/><path fill="#64717c" d="M7,44c-0.552,0-1-0.447-1-1V8c0-0.553,0.448-1,1-1s1,0.447,1,1v35C8,43.553,7.552,44,7,44z"/><linearGradient id="FLX5bOLQ980VwobKteXXKa" x1="5" x2="9" y1="18" y2="18" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#92a3b0"/><stop offset=".015" stop-color="#a3b5c4"/><stop offset=".032" stop-color="#aec2d1"/><stop offset=".046" stop-color="#b2c6d6"/></linearGradient><line x1="7" x2="7" y1="20" y2="16" fill="none" stroke="url(#FLX5bOLQ980VwobKteXXKa)" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-width="4"/><linearGradient id="FLX5bOLQ980VwobKteXXKb" x1="5.648" x2="8.44" y1="5.375" y2="10.796" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#f44f5a"/><stop offset=".443" stop-color="#ee3d4a"/><stop offset="1" stop-color="#e52030"/></linearGradient><circle cx="7" cy="8" r="3" fill="url(#FLX5bOLQ980VwobKteXXKb)"/><linearGradient id="FLX5bOLQ980VwobKteXXKc" x1="28.203" x2="30.596" y1="7.332" y2="24.394" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#f44f5a"/><stop offset=".443" stop-color="#ee3d4a"/><stop offset="1" stop-color="#e52030"/></linearGradient><path fill="url(#FLX5bOLQ980VwobKteXXKc)" d="M42.352,12.317l-24-4.286C17.126,7.813,16,8.755,16,10.001v15.999 c0,1.245,1.126,2.188,2.352,1.969l24-4.286c0.954-0.17,1.648-1,1.648-1.969v-7.427C44,13.317,43.305,12.488,42.352,12.317z"/><linearGradient id="FLX5bOLQ980VwobKteXXKd" x1="27.618" x2="31.169" y1="8.863" y2="24.613" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#f0f0f0"/><stop offset="1" stop-color="#bbc1c4"/></linearGradient><path fill="url(#FLX5bOLQ980VwobKteXXKd)" d="M22,8.683l5,0.893v16.848l-5,0.893V8.683z M33,10.647v14.705l5-0.893V11.54L33,10.647z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#4788c7" d="M20,16c2.206,0,4,1.794,4,4s-1.794,4-4,4s-4-1.794-4-4S17.794,16,20,16 M20,13 c-3.866,0-7,3.134-7,7s3.134,7,7,7s7-3.134,7-7S23.866,13,20,13L20,13z"/><path fill="#98ccfd" d="M20,9c6.065,0,11,4.935,11,11s-4.935,11-11,11S9,26.065,9,20S13.935,9,20,9 M20,7 C12.82,7,7,12.82,7,20s5.82,13,13,13s13-5.82,13-13S27.18,7,20,7L20,7z"/><path fill="#4788c7" d="M20 1A1 1 0 1 0 20 3 1 1 0 1 0 20 1zM20 37A1 1 0 1 0 20 39 1 1 0 1 0 20 37z"/><path fill="#4788c7" d="M20 1A1 1 0 1 0 20 3 1 1 0 1 0 20 1zM20 37A1 1 0 1 0 20 39 1 1 0 1 0 20 37zM38 19A1 1 0 1 0 38 21 1 1 0 1 0 38 19zM2 19A1 1 0 1 0 2 21 1 1 0 1 0 2 19z"/><path fill="#4788c7" d="M32.728 6.272A1 1 0 1 0 32.728 8.272A1 1 0 1 0 32.728 6.272Z" transform="rotate(-45.001 32.728 7.272)"/><path fill="#4788c7" d="M7.272 31.728A1 1 0 1 0 7.272 33.728A1 1 0 1 0 7.272 31.728Z" transform="rotate(-45.001 7.272 32.728)"/><path fill="#4788c7" d="M32.728 6.272A1 1 0 1 0 32.728 8.272A1 1 0 1 0 32.728 6.272Z" transform="rotate(-45.001 32.728 7.272)"/><path fill="#4788c7" d="M7.272 31.728A1 1 0 1 0 7.272 33.728A1 1 0 1 0 7.272 31.728Z" transform="rotate(-45.001 7.272 32.728)"/><path fill="#4788c7" d="M32.728 31.728A1 1 0 1 0 32.728 33.728A1 1 0 1 0 32.728 31.728Z" transform="rotate(-45.001 32.728 32.728)"/><path fill="#4788c7" d="M7.272 6.272A1 1 0 1 0 7.272 8.272A1 1 0 1 0 7.272 6.272Z" transform="rotate(-45.001 7.272 7.272)"/><path fill="#4788c7" d="M26.888 2.37A1 1 0 1 0 26.888 4.37A1 1 0 1 0 26.888 2.37Z" transform="rotate(-67.5 26.888 3.37)"/><path fill="#4788c7" d="M13.112 35.63A1 1 0 1 0 13.112 37.63A1 1 0 1 0 13.112 35.63Z" transform="rotate(-67.5 13.112 36.63)"/><path fill="#4788c7" d="M26.888 2.37A1 1 0 1 0 26.888 4.37A1 1 0 1 0 26.888 2.37Z" transform="rotate(-67.5 26.888 3.37)"/><path fill="#4788c7" d="M13.112 35.63A1 1 0 1 0 13.112 37.63A1 1 0 1 0 13.112 35.63Z" transform="rotate(-67.5 13.112 36.63)"/><path fill="#4788c7" d="M36.63 25.888A1 1 0 1 0 36.63 27.888A1 1 0 1 0 36.63 25.888Z" transform="rotate(-67.5 36.63 26.888)"/><path fill="#4788c7" d="M3.37 12.112A1 1 0 1 0 3.37 14.112A1 1 0 1 0 3.37 12.112Z" transform="rotate(-67.5 3.37 13.111)"/><path fill="#4788c7" d="M36.63 12.112A1 1 0 1 0 36.63 14.112A1 1 0 1 0 36.63 12.112Z" transform="rotate(-22.5 36.628 13.111)"/><path fill="#4788c7" d="M3.37 25.888A1 1 0 1 0 3.37 27.888A1 1 0 1 0 3.37 25.888Z" transform="rotate(-22.5 3.37 26.887)"/><path fill="#4788c7" d="M36.63 12.112A1 1 0 1 0 36.63 14.112A1 1 0 1 0 36.63 12.112Z" transform="rotate(-22.5 36.628 13.111)"/><path fill="#4788c7" d="M3.37 25.888A1 1 0 1 0 3.37 27.888A1 1 0 1 0 3.37 25.888Z" transform="rotate(-22.5 3.37 26.887)"/><path fill="#4788c7" d="M26.888 35.63A1 1 0 1 0 26.888 37.63A1 1 0 1 0 26.888 35.63Z" transform="rotate(-22.5 26.887 36.628)"/><path fill="#4788c7" d="M13.112 2.37A1 1 0 1 0 13.112 4.37A1 1 0 1 0 13.112 2.37Z" transform="rotate(-22.5 13.111 3.37)"/><path fill="#4788c7" d="M16.488 1.346A1 1 0 1 0 16.488 3.346A1 1 0 1 0 16.488 1.346Z" transform="rotate(-11.246 16.488 2.344)"/><path fill="#4788c7" d="M23.512 36.654A1 1 0 1 0 23.512 38.654A1 1 0 1 0 23.512 36.654Z" transform="rotate(-11.246 23.514 37.65)"/><path fill="#4788c7" d="M16.488 1.346A1 1 0 1 0 16.488 3.346A1 1 0 1 0 16.488 1.346Z" transform="rotate(-11.246 16.488 2.344)"/><path fill="#4788c7" d="M23.512 36.654A1 1 0 1 0 23.512 38.654A1 1 0 1 0 23.512 36.654Z" transform="rotate(-11.246 23.514 37.65)"/><path fill="#4788c7" d="M37.654 15.488A1 1 0 1 0 37.654 17.488A1 1 0 1 0 37.654 15.488Z" transform="rotate(-11.246 37.654 16.485)"/><path fill="#4788c7" d="M2.346 22.512A1 1 0 1 0 2.346 24.512A1 1 0 1 0 2.346 22.512Z" transform="rotate(-11.246 2.348 23.51)"/><path fill="#4788c7" d="M30 4.034A1 1 0 1 0 30 6.034A1 1 0 1 0 30 4.034Z" transform="rotate(-56.25 30 5.033)"/><path fill="#4788c7" d="M10 33.966A1 1 0 1 0 10 35.966A1 1 0 1 0 10 33.966Z" transform="rotate(-56.25 10 34.965)"/><path fill="#4788c7" d="M30 4.034A1 1 0 1 0 30 6.034A1 1 0 1 0 30 4.034Z" transform="rotate(-56.25 30 5.033)"/><path fill="#4788c7" d="M10 33.966A1 1 0 1 0 10 35.966A1 1 0 1 0 10 33.966Z" transform="rotate(-56.25 10 34.965)"/><path fill="#4788c7" d="M34.966 29A1 1 0 1 0 34.966 31A1 1 0 1 0 34.966 29Z" transform="rotate(-56.25 34.965 30)"/><path fill="#4788c7" d="M5.034 9A1 1 0 1 0 5.034 11A1 1 0 1 0 5.034 9Z" transform="rotate(-56.25 5.033 10)"/><path fill="#4788c7" d="M23.512 1.346A1 1 0 1 0 23.512 3.346A1 1 0 1 0 23.512 1.346Z" transform="rotate(-78.749 23.512 2.346)"/><path fill="#4788c7" d="M16.488 36.654A1 1 0 1 0 16.488 38.654A1 1 0 1 0 16.488 36.654Z" transform="rotate(-78.749 16.489 37.654)"/><path fill="#4788c7" d="M23.512 1.346A1 1 0 1 0 23.512 3.346A1 1 0 1 0 23.512 1.346Z" transform="rotate(-78.749 23.512 2.346)"/><path fill="#4788c7" d="M16.488 36.654A1 1 0 1 0 16.488 38.654A1 1 0 1 0 16.488 36.654Z" transform="rotate(-78.749 16.489 37.654)"/><path fill="#4788c7" d="M37.654 22.512A1 1 0 1 0 37.654 24.512A1 1 0 1 0 37.654 22.512Z" transform="rotate(-78.749 37.654 23.511)"/><path fill="#4788c7" d="M2.346 15.488A1 1 0 1 0 2.346 17.488A1 1 0 1 0 2.346 15.488Z" transform="rotate(-78.749 2.346 16.488)"/><path fill="#4788c7" d="M34.966 9A1 1 0 1 0 34.966 11A1 1 0 1 0 34.966 9Z" transform="rotate(-33.75 34.965 10)"/><path fill="#4788c7" d="M5.034 29A1 1 0 1 0 5.034 31A1 1 0 1 0 5.034 29Z" transform="rotate(-33.75 5.033 29.999)"/><path fill="#4788c7" d="M34.966 9A1 1 0 1 0 34.966 11A1 1 0 1 0 34.966 9Z" transform="rotate(-33.75 34.965 10)"/><path fill="#4788c7" d="M5.034 29A1 1 0 1 0 5.034 31A1 1 0 1 0 5.034 29Z" transform="rotate(-33.75 5.033 29.999)"/><path fill="#4788c7" d="M30 33.966A1 1 0 1 0 30 35.966A1 1 0 1 0 30 33.966Z" transform="rotate(-33.75 29.999 34.965)"/><path fill="#4788c7" d="M10 4.034A1 1 0 1 0 10 6.034A1 1 0 1 0 10 4.034Z" transform="rotate(-33.75 10 5.033)"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#b6dcfe" d="M19.5 8.5H39.5V17.5H19.5z"/><path fill="#4788c7" d="M39,9v8H20V9H39 M40,8H19v10h21V8L40,8z"/><path fill="#b6dcfe" d="M19.5 22.5H39.5V31.5H19.5z"/><path fill="#4788c7" d="M39,23v8H20v-8H39 M40,22H19v10h21V22L40,22z"/><path fill="#dff0fe" d="M7.268,35.5L5.5,32.849V17.5H4c-1.93,0-3.5-1.57-3.5-3.5V8c0-1.93,1.57-3.5,3.5-3.5h9 c1.93,0,3.5,1.57,3.5,3.5v6c0,1.93-1.57,3.5-3.5,3.5h-1.5v4.293l-1,1v1.414l1,1v1.586l-1,1v1.414l1,1v2.642L9.732,35.5H7.268z M5,7.5C4.173,7.5,3.5,8.173,3.5,9v1c0,0.827,0.673,1.5,1.5,1.5h7c0.827,0,1.5-0.673,1.5-1.5V9c0-0.827-0.673-1.5-1.5-1.5H5z"/><path fill="#4788c7" d="M13,5c1.654,0,3,1.346,3,3v6c0,1.654-1.346,3-3,3h-1h-1v1v3.586l-0.707,0.707L10,22.586V23v1v0.414 l0.293,0.293L11,25.414v1.172l-0.707,0.707L10,27.586V28v1v0.414l0.293,0.293L11,30.414v2.283L9.465,35h-1.93L6,32.697V18v-1H5H4 c-1.654,0-3-1.346-3-3V8c0-1.654,1.346-3,3-3H13 M5,12h7c1.103,0,2-0.897,2-2V9c0-1.103-0.897-2-2-2H5C3.897,7,3,7.897,3,9v1 C3,11.103,3.897,12,5,12 M13,4H4C1.791,4,0,5.791,0,8v6c0,2.209,1.791,4,4,4h1v15l2,3h3l2-3v-3l-1-1v-1l1-1v-2l-1-1v-1l1-1v-4h1 c2.209,0,4-1.791,4-4V8C17,5.791,15.209,4,13,4L13,4z M5,11c-0.552,0-1-0.448-1-1V9c0-0.552,0.448-1,1-1h7c0.552,0,1,0.448,1,1v1 c0,0.552-0.448,1-1,1H5L5,11z"/><path fill="#98ccfd" d="M8 35L8 18 7 18 7 34.197 7.535 35z"/><path fill="#98ccfd" d="M7.5,22L7.5,22C7.225,22,7,21.775,7,21.5v-4C7,17.225,7.225,17,7.5,17h0C7.775,17,8,17.225,8,17.5v4 C8,21.775,7.775,22,7.5,22z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#fff" d="M1.5,35.5v-31h37v28.031c0,1.637-1.332,2.969-2.969,2.969H1.5z"/><path fill="#4788c7" d="M38,5v27.531C38,33.893,36.893,35,35.531,35H2V5H38 M39,4H1v32h34.531 C37.447,36,39,34.447,39,32.531V4L39,4z"/><path fill="#b6dcfe" d="M6 9H34V26.875H6z"/><path fill="#dff0fe" d="M6 19H34V27H6zM6 27H34V31H6z"/><path fill="#dff0fe" d="M14.75 15A3.5 3.143 0 1 0 14.75 21.286A3.5 3.143 0 1 0 14.75 15Z"/><path fill="#dff0fe" d="M11.25 15.786000000000001A2.625 2.357 0 1 0 11.25 20.5 2.625 2.357 0 1 0 11.25 15.786000000000001zM20 16.570999999999998A3.5 3.143 0 1 0 20 22.857 3.5 3.143 0 1 0 20 16.570999999999998z"/><path fill="#dff0fe" d="M25.25 15A3.5 3.143 0 1 0 25.25 21.286 3.5 3.143 0 1 0 25.25 15zM32.25 16.572A1.75 1.571 0 1 0 32.25 19.714000000000002 1.75 1.571 0 1 0 32.25 16.572zM7.75 16.572A1.75 1.571 0 1 0 7.75 19.714000000000002 1.75 1.571 0 1 0 7.75 16.572z"/><path fill="#dff0fe" d="M28.75 15.786000000000001A2.625 2.357 0 1 0 28.75 20.5A2.625 2.357 0 1 0 28.75 15.786000000000001Z"/><path fill="#98ccfd" d="M6 27L34 27 34 25.384 25.25 20z"/><path fill="#b6dcfe" d="M27 27L6 27 6 23 14.75 19z"/><path fill="#98ccfd" d="M31 22.5A8.5 8.5 0 1 0 31 39.5A8.5 8.5 0 1 0 31 22.5Z"/><path fill="#4788c7" d="M31,23c4.411,0,8,3.589,8,8s-3.589,8-8,8s-8-3.589-8-8S26.589,23,31,23 M31,22 c-4.971,0-9,4.029-9,9s4.029,9,9,9s9-4.029,9-9S35.971,22,31,22L31,22z"/><path fill="none" stroke="#fff" stroke-miterlimit="10" stroke-width="2" d="M31 36L31 26M26 31L36 31"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><polygon fill="#dff0fe" points="33.865,23.5 6.135,23.5 1,38.5 39,38.5"/><path fill="#4788c7" d="M39,39H1c-0.162,0-0.313-0.078-0.407-0.209s-0.119-0.3-0.066-0.453l5.135-15 C5.731,23.136,5.921,23,6.135,23h27.729c0.214,0,0.404,0.136,0.473,0.338l5.135,15c0.052,0.153,0.027,0.321-0.066,0.453 S39.162,39,39,39z M1.7,38H38.3l-4.793-14H6.493L1.7,38z"/><rect width="22" height="1.5" x="9" y="23" fill="#dff0fe"/><path fill="#98ccfd" d="M19.999,35.311C18.064,33.124,8.5,21.858,8.5,13C8.5,6.658,13.658,1.5,20,1.5S31.5,6.658,31.5,13 C31.5,21.814,21.934,33.117,19.999,35.311z"/><path fill="#4788c7" d="M20,36.066l-0.375-0.424C17.684,33.448,8,22.043,8,13C8,6.383,13.383,1,20,1s12,5.383,12,12 c0,9.002-9.685,20.44-11.626,22.642L20,36.066z M20,2C13.935,2,9,6.935,9,13c0,8.209,8.47,18.625,10.999,21.551 C22.526,31.617,31,21.172,31,13C31,6.935,26.065,2,20,2z"/><path fill="#fff" d="M20,18.5c-3.032,0-5.5-2.467-5.5-5.5s2.468-5.5,5.5-5.5s5.5,2.467,5.5,5.5S23.032,18.5,20,18.5z"/><path fill="#4788c7" d="M20,19c-3.309,0-6-2.691-6-6s2.691-6,6-6s6,2.691,6,6S23.309,19,20,19z M20,8c-2.757,0-5,2.243-5,5 s2.243,5,5,5s5-2.243,5-5S22.757,8,20,8z"/><g><path fill="#4788c7" d="M9,24H8c-0.276,0-0.5-0.224-0.5-0.5S7.724,23,8,23h1c0.276,0,0.5,0.224,0.5,0.5S9.276,24,9,24z"/></g><g><path fill="#4788c7" d="M31.998,24h-1c-0.276,0-0.5-0.224-0.5-0.5s0.224-0.5,0.5-0.5h1c0.276,0,0.5,0.224,0.5,0.5 S32.274,24,31.998,24z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#b6dcfe" d="M4.511,38.5c0.263-6.11,5.316-11,11.489-11h8c6.173,0,11.227,4.89,11.489,11H4.511z"/><path fill="#4788c7" d="M24,28c5.729,0,10.448,4.401,10.955,10l-29.91,0C5.552,32.401,10.271,28,16,28H24 M24,27h-8 C9.373,27,4,32.373,4,39v0h32v0C36,32.373,30.627,27,24,27L24,27z"/><path fill="#b6dcfe" d="M20,30.266l-4.702,2.957l-1.567-5.485C14.5,27.58,15.261,27.5,16,27.5h8 c0.739,0,1.5,0.08,2.27,0.237l-1.567,5.485L20,30.266z"/><path fill="#4788c7" d="M24,28c0.535,0,1.083,0.044,1.637,0.131l-1.232,4.314l-3.872-2.435L20,29.675l-0.532,0.335 l-3.872,2.435l-1.232-4.314C14.917,28.044,15.465,28,16,28H24 M24,27h-8c-1,0-1.966,0.136-2.895,0.366L15,34l5-3.144L25,34 l1.895-6.634C25.966,27.136,25,27,24,27L24,27z"/><path fill="#fff" d="M15.5 27.819L15.5 22.5 24.5 22.5 24.5 27.819 20 31.364z"/><path fill="#4788c7" d="M24,23v4.577l-4,3.151l-4-3.151V23H24 M25,22H15v6.062L20,32l5-3.938V22L25,22z"/><path fill="#4788c7" d="M22.601 29.619L20 30.305 17.401 29.623 19 33 17 39 23 39 21 33z"/><g><path fill="#b6dcfe" d="M27.143,19.214c-1.3,0-2.357-1.058-2.357-2.357s1.058-2.357,2.357-2.357 c1.963,0,2.357,0.538,2.357,1.405C29.5,17.319,28.335,19.214,27.143,19.214z M12.857,19.214c-1.192,0-2.357-1.895-2.357-3.31 c0-0.867,0.394-1.405,2.357-1.405c1.3,0,2.357,1.057,2.357,2.357S14.157,19.214,12.857,19.214z"/><path fill="#4788c7" d="M27.143,15C29,15,29,15.481,29,15.905c0,1.234-1.041,2.81-1.857,2.81 c-1.024,0-1.857-0.833-1.857-1.857C25.286,15.833,26.119,15,27.143,15 M12.857,15c1.024,0,1.857,0.833,1.857,1.857 c0,1.024-0.833,1.857-1.857,1.857c-0.816,0-1.857-1.575-1.857-2.81C11,15.481,11,15,12.857,15 M27.143,14 c-1.578,0-2.857,1.279-2.857,2.857s1.279,2.857,2.857,2.857c1.578,0,2.857-2.232,2.857-3.81C30,14.327,28.721,14,27.143,14 L27.143,14z M12.857,14C11.279,14,10,14.327,10,15.905c0,1.578,1.279,3.81,2.857,3.81c1.578,0,2.857-1.279,2.857-2.857 S14.435,14,12.857,14L12.857,14z"/></g><g><path fill="#fff" d="M20,26.5c-0.604,0-1.172-0.218-1.641-0.63l-0.09-0.08l-0.117-0.03 C14.824,24.916,12.5,21.93,12.5,18.5V9.202c0-1.827,1.486-3.313,3.313-3.313h8.375c1.827,0,3.313,1.486,3.313,3.313V18.5 c0,3.43-2.324,6.416-5.652,7.26l-0.117,0.03l-0.09,0.08C21.172,26.282,20.604,26.5,20,26.5z"/><path fill="#4788c7" d="M24.187,6.389C25.738,6.389,27,7.651,27,9.202V18.5c0,3.201-2.169,5.987-5.275,6.776l-0.233,0.059 l-0.181,0.159C21.048,25.725,20.608,26,20,26s-1.048-0.275-1.311-0.506l-0.181-0.159l-0.233-0.059 C15.169,24.487,13,21.701,13,18.5V9.202c0-1.551,1.262-2.813,2.813-2.813H24.187 M24.187,5.389h-8.375 C13.707,5.389,12,7.096,12,9.202V18.5c0,3.737,2.566,6.866,6.029,7.745C18.557,26.709,19.242,27,20,27s1.443-0.291,1.971-0.755 C25.434,25.366,28,22.237,28,18.5V9.202C28,7.096,26.293,5.389,24.187,5.389L24.187,5.389z"/></g><g><path fill="#b6dcfe" d="M27.5,17.5V14c0-3.636-3.034-5.582-3.163-5.663l-0.398-0.25L23.664,8.47 c-0.084,0.118-2.119,2.887-6.514,2.887c-1.15,0-4.65,0-4.65,3.643v2.5h-0.179c-0.436-0.982-1.821-4.332-1.821-7.188 c0-5.271,3.617-8.812,9-8.812c3.839,0,4.992,2.585,5.04,2.695l0.13,0.303L25,4.5c2.076,0,4.5,1.444,4.5,5.515 c0,2.623-1.407,6.393-1.837,7.485H27.5z"/><path fill="#4788c7" d="M19.5,2c3.483,0,4.538,2.297,4.577,2.385L24.334,5H25c1.845,0,4,1.313,4,5.015 c0,1.536-0.507,3.498-1,5.043V14c0-3.909-3.258-5.999-3.397-6.087L23.802,7.41l-0.547,0.772c-0.019,0.027-1.941,2.674-6.105,2.674 C13.733,10.857,12,12.251,12,15v0.314c-0.491-1.422-1-3.305-1-5.003C11,5.34,14.416,2,19.5,2 M19.5,1C13.681,1,10,4.981,10,10.311 C10,13.842,12,18,12,18h1c0,0,0-2.029,0-3c0-2.668,2.024-3.143,4.15-3.143c4.73,0,6.922-3.097,6.922-3.097S27,10.599,27,14 c0,1.069,0,4,0,4h1c0,0,2-4.768,2-7.985C30,5.498,27.123,4,25,4C25,4,23.747,1,19.5,1L19.5,1z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M29.5 23.5L19.5 23.5 19.5 16.5 29.5 16.5 29.5 12.123 38.252 20 29.5 27.877z"/><path fill="#4788c7" d="M30,13.245L37.505,20L30,26.755V24v-1h-1h-9v-6h9h1v-1V13.245 M29,11v5H19v8h10v5l10-9L29,11L29,11z"/><path fill="#dff0fe" d="M7.5 16.5H10.5V23.5H7.5z"/><path fill="#4788c7" d="M10,17v6H8v-6H10 M11,16H7v8h4V16L11,16z"/><g><path fill="#dff0fe" d="M13.5 16.5H16.5V23.5H13.5z"/><path fill="#4788c7" d="M16,17v6h-2v-6H16 M17,16h-4v8h4V16L17,16z"/></g><g><path fill="#dff0fe" d="M1.5 16.5H4.5V23.5H1.5z"/><path fill="#4788c7" d="M4,17v6H2v-6H4 M5,16H1v8h4V16L5,16z"/></g></svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 96 96" width="96px" height="96px">
<g id="surface1650270">
<path style="fill-rule:nonzero;fill:rgb(87.450981%,94.117647%,99.607843%);fill-opacity:1;stroke-width:10;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(27.843139%,53.333336%,78.039217%);stroke-opacity:1;stroke-miterlimit:10;" d="M 48.473013 77.143901 C 48.473013 79.28363 48.703331 81.01473 49.10453 82.285195 C 49.557737 83.563089 50.129817 84.944997 50.932216 86.44578 C 51.221971 86.913845 51.333415 87.374482 51.333415 87.775681 C 51.333415 88.355191 50.991653 88.934701 50.248691 89.514211 L 46.645328 91.936266 C 46.125254 92.285458 45.612611 92.456339 45.159404 92.456339 C 44.587324 92.456339 44.015244 92.166584 43.443163 91.646511 C 42.640765 90.777246 41.95724 89.855973 41.37773 88.934701 C 40.805649 87.946562 40.233569 86.854408 39.609481 85.524507 C 35.144282 90.836683 29.534922 93.496485 22.788831 93.496485 C 17.98187 93.496485 14.148188 92.107147 11.347223 89.3359 C 8.546257 86.564653 7.112342 82.864705 7.112342 78.243484 C 7.112342 73.332508 8.828583 69.342804 12.320502 66.341239 C 15.812422 63.339674 20.441072 61.831462 26.332758 61.831462 C 28.279317 61.831462 30.285313 62.002343 32.395324 62.299528 C 34.512765 62.589283 36.689642 63.049919 38.977964 63.569992 L 38.977964 59.349971 C 38.977964 54.959068 38.064121 51.898066 36.288443 50.107529 C 34.460758 48.316991 31.370037 47.447726 26.964275 47.447726 C 24.958279 47.447726 22.907705 47.678044 20.790264 48.198117 C 18.672824 48.71819 16.61482 49.349708 14.608824 50.159536 C 13.694981 50.568165 13.004027 50.798483 12.602828 50.917357 C 12.201628 51.028801 11.919303 51.088238 11.688985 51.088238 C 10.886586 51.088238 10.492817 50.508728 10.492817 49.2977 L 10.492817 46.467017 C 10.492817 45.538315 10.604261 44.84736 10.894016 44.446161 C 11.176341 44.037532 11.696415 43.636333 12.491383 43.227704 C 14.49738 42.187558 16.897146 41.325723 19.70554 40.627339 C 22.506506 39.876947 25.478352 39.527756 28.628509 39.527756 C 35.434037 39.527756 40.41188 41.087975 43.614044 44.208414 C 46.764201 47.328852 48.361569 52.068947 48.361569 58.421269 L 48.361569 77.143901 Z M 25.248034 85.925706 C 27.135156 85.925706 29.081716 85.576515 31.13229 84.88556 C 33.197723 84.194606 35.025408 82.924142 36.570768 81.185612 C 37.484611 80.093458 38.175565 78.875001 38.517328 77.493093 C 38.85909 76.103754 39.089408 74.424661 39.089408 72.463243 L 39.089408 70.033758 C 37.432604 69.632559 35.656926 69.283367 33.82924 69.053049 C 31.994125 68.822731 30.218447 68.703857 28.450198 68.703857 C 24.616517 68.703857 21.808122 69.461678 19.920999 71.014467 C 18.033877 72.574687 17.120034 74.773853 17.120034 77.663974 C 17.120034 80.375783 17.810988 82.396639 19.237475 83.785977 C 20.611954 85.234752 22.61795 85.925706 25.248034 85.925706 Z M 71.185349 92.166584 C 70.152632 92.166584 69.469107 91.995703 69.008471 91.587074 C 68.547835 91.245311 68.154065 90.435483 67.804873 89.3359 L 54.364698 44.676479 C 54.015506 43.524889 53.844625 42.767068 53.844625 42.365869 C 53.844625 41.444596 54.305261 40.924523 55.219104 40.924523 L 60.828464 40.924523 C 61.913188 40.924523 62.65615 41.095404 63.057349 41.496604 C 63.517985 41.845796 63.859747 42.655624 64.20151 43.755207 L 73.815433 82.002869 L 82.738401 43.755207 C 83.020727 42.596187 83.369919 41.845796 83.823125 41.496604 C 84.276332 41.147412 85.07873 40.924523 86.111447 40.924523 L 90.68809 40.924523 C 91.772814 40.924523 92.515776 41.095404 92.976412 41.496604 C 93.437048 41.845796 93.830818 42.655624 94.061136 43.755207 L 103.102978 82.463506 L 112.999227 43.755207 C 113.340989 42.596187 113.742188 41.845796 114.143387 41.496604 C 114.596594 41.147412 115.339556 40.924523 116.372272 40.924523 L 121.691877 40.924523 C 122.60572 40.924523 123.125793 41.38516 123.125793 42.365869 C 123.125793 42.655624 123.066356 42.945379 123.006919 43.287141 C 122.954912 43.636333 122.836038 44.096969 122.60572 44.735916 L 108.823783 89.395337 C 108.474591 90.546928 108.073391 91.297319 107.620185 91.646511 C 107.166978 91.995703 106.424017 92.226021 105.443307 92.226021 L 100.524902 92.226021 C 99.440178 92.226021 98.697216 92.05514 98.23658 91.646511 C 97.775944 91.245311 97.382174 90.49492 97.151856 89.3359 L 88.288324 52.068947 L 79.4768 89.276463 C 79.194475 90.435483 78.845283 91.185875 78.392076 91.587074 C 77.93144 91.995703 77.136471 92.166584 76.103754 92.166584 Z M 144.693968 93.726803 C 141.714692 93.726803 138.742846 93.377611 135.882443 92.686657 C 133.022041 91.995703 130.793157 91.245311 129.307233 90.376046 C 128.393391 89.855973 127.761873 89.276463 127.531555 88.75639 C 127.301237 88.236317 127.189793 87.664237 127.189793 87.144163 L 127.189793 84.194606 C 127.189793 82.983579 127.642999 82.404069 128.504835 82.404069 C 128.846597 82.404069 129.18836 82.463506 129.530122 82.57495 C 129.871884 82.693824 130.384528 82.924142 130.956608 83.15446 C 132.903167 84.023725 135.020608 84.714679 137.249493 85.175315 C 139.545244 85.635951 141.774129 85.86627 144.06245 85.86627 C 147.665814 85.86627 150.466779 85.234752 152.413339 83.964288 C 154.359898 82.686394 155.385185 80.83642 155.385185 78.473802 C 155.385185 76.854146 154.872542 75.524244 153.839825 74.424661 C 152.814538 73.332508 150.867979 72.344369 148.067013 71.423096 L 139.768133 68.822731 C 135.600118 67.49283 132.509398 65.531411 130.622275 62.923616 C 128.727723 60.382687 127.761873 57.552004 127.761873 54.550439 C 127.761873 52.120954 128.274517 49.981225 129.307233 48.131251 C 130.33252 46.288706 131.706999 44.66905 133.423241 43.398585 C 135.139482 42.068684 137.086041 41.087975 139.366933 40.397021 C 141.662685 39.706066 144.06245 39.416311 146.58109 39.416311 C 147.836695 39.416311 149.151737 39.475748 150.414772 39.646629 C 151.729814 39.817511 152.925982 40.047829 154.13701 40.278147 C 155.273741 40.567902 156.365894 40.857657 157.391181 41.206849 C 158.423898 41.556041 159.226296 41.897803 159.798377 42.246995 C 160.600775 42.707631 161.172856 43.168267 161.514618 43.68834 C 161.85638 44.148977 162.034691 44.787924 162.034691 45.597752 L 162.034691 48.309561 C 162.034691 49.528018 161.574055 50.159536 160.719649 50.159536 C 160.259013 50.159536 159.516051 49.929218 158.542772 49.468582 C 155.28117 47.967799 151.61837 47.217408 147.5618 47.217408 C 144.300198 47.217408 141.722121 47.730051 139.953873 48.829635 C 138.178195 49.929218 137.264352 51.600881 137.264352 53.970929 C 137.264352 55.590585 137.836432 56.972494 138.980593 58.072077 C 140.124754 59.17166 142.242195 60.271243 145.273478 61.251952 L 153.394048 63.852318 C 157.510055 65.182219 160.489331 67.032193 162.25758 69.402241 C 164.033258 71.772288 164.887664 74.484098 164.887664 77.493093 C 164.887664 79.974584 164.37502 82.225758 163.401741 84.187176 C 162.376454 86.156025 161.001975 87.887125 159.226296 89.276463 C 157.458048 90.717809 155.340607 91.757955 152.881404 92.508346 C 150.295898 93.318174 147.606377 93.726803 144.693968 93.726803 Z M 144.693968 93.726803 " transform="matrix(0.525767,0,0,0.525767,2.784,2.784)"/>
<path style="fill-rule:nonzero;fill:rgb(87.450981%,94.117647%,99.607843%);fill-opacity:1;stroke-width:10;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(27.843139%,53.333336%,78.039217%);stroke-opacity:1;stroke-miterlimit:10;" d="M 155.504059 121.803321 C 136.684842 135.845295 109.336426 143.2972 85.821692 143.2972 C 52.878775 143.2972 23.182601 130.993756 0.76002 110.540024 C -1.015658 108.920368 0.589139 106.728631 2.706579 107.999095 C 26.964275 122.21195 56.875909 130.822875 87.827688 130.822875 C 108.704909 130.822875 131.647562 126.431972 152.755101 117.412418 C 155.905258 115.971073 158.594779 119.492711 155.504059 121.803321 Z M 163.342304 112.791197 C 160.935108 109.670759 147.435496 111.290415 141.313493 112.040806 C 139.485807 112.271124 139.196052 110.651468 140.860286 109.440441 C 151.61094 101.810225 169.285996 104.009391 171.351429 106.55032 C 173.409433 109.150686 170.771919 127.004053 160.71222 135.55554 C 159.166859 136.885442 157.680936 136.187058 158.364461 134.455957 C 160.652783 128.735153 165.74207 115.852199 163.342304 112.791197 Z M 163.342304 112.791197 " transform="matrix(0.525767,0,0,0.525767,2.784,2.784)"/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(87.450981%,94.117647%,99.607843%);fill-opacity:1;" d="M 28.269531 43.34375 C 28.269531 44.46875 28.390625 45.378906 28.601562 46.046875 C 28.839844 46.71875 29.140625 47.445312 29.5625 48.234375 C 29.714844 48.480469 29.773438 48.722656 29.773438 48.933594 C 29.773438 49.238281 29.59375 49.542969 29.203125 49.847656 L 27.308594 51.121094 C 27.035156 51.304688 26.765625 51.394531 26.527344 51.394531 C 26.226562 51.394531 25.925781 51.242188 25.625 50.96875 C 25.203125 50.511719 24.84375 50.027344 24.539062 49.542969 C 24.238281 49.023438 23.9375 48.449219 23.609375 47.75 C 21.261719 50.542969 18.3125 51.941406 14.765625 51.941406 C 12.238281 51.941406 10.222656 51.210938 8.75 49.753906 C 7.277344 48.296875 6.523438 46.351562 6.523438 43.921875 C 6.523438 41.339844 7.425781 39.242188 9.261719 37.664062 C 11.097656 36.085938 13.53125 35.292969 16.628906 35.292969 C 17.652344 35.292969 18.707031 35.382812 19.816406 35.539062 C 20.929688 35.691406 22.074219 35.933594 23.277344 36.207031 L 23.277344 33.988281 C 23.277344 31.679688 22.796875 30.070312 21.863281 29.128906 C 20.902344 28.1875 19.277344 27.730469 16.960938 27.730469 C 15.90625 27.730469 14.828125 27.851562 13.714844 28.125 C 12.601562 28.398438 11.519531 28.730469 10.464844 29.15625 C 9.984375 29.371094 9.621094 29.492188 9.410156 29.554688 C 9.199219 29.613281 9.050781 29.644531 8.929688 29.644531 C 8.507812 29.644531 8.300781 29.339844 8.300781 28.703125 L 8.300781 27.214844 C 8.300781 26.726562 8.359375 26.363281 8.511719 26.152344 C 8.660156 25.9375 8.933594 25.726562 9.351562 25.511719 C 10.40625 24.964844 11.667969 24.511719 13.144531 24.144531 C 14.617188 23.75 16.179688 23.566406 17.835938 23.566406 C 21.414062 23.566406 24.03125 24.386719 25.714844 26.027344 C 27.371094 27.667969 28.210938 30.160156 28.210938 33.5 L 28.210938 43.34375 Z M 16.058594 47.960938 C 17.050781 47.960938 18.074219 47.777344 19.152344 47.414062 C 20.238281 47.050781 21.199219 46.382812 22.011719 45.46875 C 22.492188 44.894531 22.855469 44.253906 23.035156 43.527344 C 23.214844 42.796875 23.335938 41.914062 23.335938 40.882812 L 23.335938 39.605469 C 22.464844 39.394531 21.53125 39.210938 20.570312 39.089844 C 19.605469 38.96875 18.671875 38.90625 17.742188 38.90625 C 15.726562 38.90625 14.25 39.304688 13.257812 40.121094 C 12.265625 40.941406 11.785156 42.097656 11.785156 43.617188 C 11.785156 45.042969 12.148438 46.105469 12.898438 46.835938 C 13.621094 47.597656 14.675781 47.960938 16.058594 47.960938 Z M 40.210938 51.242188 C 39.667969 51.242188 39.308594 51.152344 39.066406 50.9375 C 38.824219 50.757812 38.617188 50.332031 38.433594 49.753906 L 31.367188 26.273438 C 31.183594 25.667969 31.09375 25.269531 31.09375 25.058594 C 31.09375 24.574219 31.335938 24.300781 31.816406 24.300781 L 34.765625 24.300781 C 35.335938 24.300781 35.726562 24.390625 35.9375 24.601562 C 36.179688 24.785156 36.359375 25.210938 36.539062 25.789062 L 41.59375 45.898438 L 46.285156 25.789062 C 46.433594 25.179688 46.617188 24.785156 46.855469 24.601562 C 47.09375 24.417969 47.515625 24.300781 48.058594 24.300781 L 50.464844 24.300781 C 51.035156 24.300781 51.425781 24.390625 51.667969 24.601562 C 51.910156 24.785156 52.117188 25.210938 52.238281 25.789062 L 56.992188 46.140625 L 62.195312 25.789062 C 62.375 25.179688 62.585938 24.785156 62.796875 24.601562 C 63.035156 24.417969 63.425781 24.300781 63.96875 24.300781 L 66.765625 24.300781 C 67.246094 24.300781 67.519531 24.542969 67.519531 25.058594 C 67.519531 25.210938 67.488281 25.363281 67.457031 25.542969 C 67.429688 25.726562 67.367188 25.96875 67.246094 26.304688 L 60 49.785156 C 59.816406 50.390625 59.605469 50.785156 59.367188 50.96875 C 59.128906 51.152344 58.738281 51.273438 58.222656 51.273438 L 55.636719 51.273438 C 55.066406 51.273438 54.675781 51.183594 54.433594 50.96875 C 54.191406 50.757812 53.984375 50.363281 53.863281 49.753906 L 49.203125 30.160156 L 44.570312 49.722656 C 44.421875 50.332031 44.238281 50.726562 44 50.9375 C 43.757812 51.152344 43.339844 51.242188 42.796875 51.242188 Z M 78.859375 52.0625 C 77.292969 52.0625 75.730469 51.878906 74.226562 51.515625 C 72.722656 51.152344 71.550781 50.757812 70.769531 50.300781 C 70.289062 50.027344 69.957031 49.722656 69.835938 49.449219 C 69.714844 49.175781 69.65625 48.875 69.65625 48.601562 L 69.65625 47.050781 C 69.65625 46.414062 69.894531 46.109375 70.347656 46.109375 C 70.527344 46.109375 70.707031 46.140625 70.886719 46.199219 C 71.066406 46.261719 71.335938 46.382812 71.636719 46.503906 C 72.660156 46.960938 73.773438 47.324219 74.945312 47.566406 C 76.152344 47.808594 77.324219 47.929688 78.527344 47.929688 C 80.421875 47.929688 81.894531 47.597656 82.917969 46.929688 C 83.941406 46.257812 84.480469 45.285156 84.480469 44.042969 C 84.480469 43.191406 84.210938 42.492188 83.667969 41.914062 C 83.128906 41.339844 82.105469 40.820312 80.632812 40.335938 L 76.269531 38.96875 C 74.078125 38.269531 72.453125 37.238281 71.460938 35.867188 C 70.464844 34.53125 69.957031 33.042969 69.957031 31.464844 C 69.957031 30.1875 70.226562 29.0625 70.769531 28.089844 C 71.308594 27.121094 72.03125 26.269531 72.933594 25.601562 C 73.835938 24.902344 74.859375 24.386719 76.058594 24.023438 C 77.265625 23.660156 78.527344 23.507812 79.851562 23.507812 C 80.511719 23.507812 81.203125 23.539062 81.867188 23.628906 C 82.558594 23.71875 83.1875 23.839844 83.824219 23.960938 C 84.421875 24.113281 84.996094 24.265625 85.535156 24.449219 C 86.078125 24.632812 86.5 24.8125 86.800781 24.996094 C 87.222656 25.238281 87.523438 25.480469 87.703125 25.753906 C 87.882812 25.996094 87.976562 26.332031 87.976562 26.757812 L 87.976562 28.183594 C 87.976562 28.824219 87.734375 29.15625 87.285156 29.15625 C 87.042969 29.15625 86.652344 29.035156 86.140625 28.792969 C 84.425781 28.003906 82.5 27.609375 80.367188 27.609375 C 78.652344 27.609375 77.296875 27.878906 76.367188 28.457031 C 75.433594 29.035156 74.953125 29.914062 74.953125 31.160156 C 74.953125 32.011719 75.253906 32.738281 75.855469 33.316406 C 76.457031 33.894531 77.570312 34.472656 79.164062 34.988281 L 83.433594 36.355469 C 85.597656 37.054688 87.164062 38.027344 88.09375 39.273438 C 89.027344 40.519531 89.476562 41.945312 89.476562 43.527344 C 89.476562 44.832031 89.207031 46.015625 88.695312 47.046875 C 88.15625 48.082031 87.433594 48.992188 86.5 49.722656 C 85.570312 50.480469 84.457031 51.027344 83.164062 51.421875 C 81.804688 51.847656 80.390625 52.0625 78.859375 52.0625 Z M 78.859375 52.0625 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(87.450981%,94.117647%,99.607843%);fill-opacity:1;" d="M 84.542969 66.824219 C 74.648438 74.207031 60.269531 78.125 47.90625 78.125 C 30.585938 78.125 14.972656 71.65625 3.183594 60.902344 C 2.25 60.050781 3.09375 58.898438 4.207031 59.566406 C 16.960938 67.039062 32.6875 71.566406 48.960938 71.566406 C 59.9375 71.566406 72 69.257812 83.097656 64.515625 C 84.753906 63.757812 86.167969 65.609375 84.542969 66.824219 Z M 88.664062 62.085938 C 87.398438 60.445312 80.300781 61.296875 77.082031 61.691406 C 76.121094 61.8125 75.96875 60.960938 76.84375 60.324219 C 82.496094 56.3125 91.789062 57.46875 92.875 58.804688 C 93.957031 60.171875 92.570312 69.558594 87.28125 74.054688 C 86.46875 74.753906 85.6875 74.386719 86.046875 73.476562 C 87.25 70.46875 89.925781 63.695312 88.664062 62.085938 Z M 88.664062 62.085938 "/>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="40px" height="40px"><path fill="#98ccfd" d="M20.614,2.5c-4.851,0-9.926,1.849-11.06,7.782c-0.121,0.632,0.062,0.89,0.479,0.982l4.878,0.221 c0.463-0.025,0.832-0.454,0.921-0.91C16.256,8.531,17.979,7.5,19.921,7.5c1.049,0,2.236,0.725,2.856,1.654 c0.717,1.037,0.707,2.484,0.707,3.686v0.682c-2.955,0.329-6.919,0.492-9.682,1.695C10.609,16.582,8.5,19.404,8.5,23.5 c0,5.241,3.22,8,7.511,8c3.625,0,5.58-1.02,8.378-3.841c0.925,1.326,1.271,1.358,2.964,2.753c0.381,0.202,0.861,0.165,1.197-0.135 c0,0,2.707-1.841,3.745-2.708c0.414-0.338,0.325-0.864,0-1.324c-0.932-1.274-1.796-2.331-1.796-4.696v-7.84 c0-3.33,0.281-6.411-2.199-8.705C26.344,3.147,23.092,2.5,20.614,2.5z M21.994,17.537c0.46-0.03,1.044-0.037,1.506-0.037v1.13 c0.001,1.967-0.046,3.585-1.047,5.333c-0.811,1.419-2.113,2.537-3.544,2.537c-1.956,0-3.342-1.722-3.342-3.906 C15.568,18.837,18.778,17.747,21.994,17.537z"/><path fill="#4788c7" d="M16.011,32C11.145,32,8,28.664,8,23.5c0-4.092,1.991-7.197,5.605-8.744 c2.352-1.024,5.526-1.332,8.327-1.604c0.406-0.04,0.672-0.041,1.052-0.08v-0.233c0-0.979,0.052-2.432-0.618-3.401 C21.816,8.615,20.768,8,19.921,8c-1.843,0-3.251,1-3.599,2.676c-0.121,0.617-0.636,1.268-1.384,1.308l-4.932-0.221 c-0.497-0.103-1.163-0.429-0.943-1.576C10.061,4.965,14.237,2,20.614,2c1.231,0,5.45,0.19,8.032,2.642 C31.052,6.867,31.024,9.744,31,12.79v8.759c0,2.088,0.69,3.028,1.565,4.219l0.134,0.183c0.528,0.749,0.492,1.534-0.088,2.006 c-1.041,0.869-3.668,2.658-3.78,2.733c-0.383,0.353-1.149,0.463-1.713,0.163l-0.083-0.056c-0.463-0.381-0.825-0.66-1.125-0.891 c-0.669-0.516-1.064-0.82-1.582-1.484C21.547,31.12,19.458,32,16.011,32z M19.921,7c1.189,0,2.535,0.771,3.272,1.876 c0.825,1.193,0.791,2.85,0.791,3.963v1.129l-0.445,0.05c-0.517,0.057-0.938,0.073-1.511,0.129 c-2.727,0.265-5.817,0.565-8.027,1.527C10.775,17.055,9,19.833,9,23.5c0,4.626,2.687,7.5,7.011,7.5 c3.341,0,5.216-0.863,8.023-3.693l0.422-0.426l0.343,0.492c0.625,0.896,0.946,1.143,1.722,1.741 c0.297,0.229,0.653,0.503,1.105,0.875c0.159,0.07,0.361,0.12,0.591-0.085c0.079-0.059,2.75-1.877,3.758-2.719 c0.206-0.168,0.033-0.48-0.088-0.651l-0.127-0.174C30.854,25.128,30,23.965,30,21.549l0.005-8.767 c0.023-2.94,0.043-5.48-2.043-7.41C26.119,3.622,22.958,3,20.614,3c-3.438,0-9.337,0.932-10.569,7.375 c-0.052,0.27-0.016,0.357-0.012,0.364l0,0c0.001,0,0.028,0.019,0.108,0.037l4.797,0.21c0.142-0.011,0.351-0.243,0.403-0.507 C15.791,8.313,17.583,7,19.921,7z M18.909,27c-2.19,0-3.841-1.894-3.841-4.406c0-2.33,1.196-5.186,6.894-5.556 C22.431,17.008,23.028,17,23.5,17H24v1.63c0.001,2.127-0.077,3.772-1.113,5.582C21.89,25.958,20.403,27,18.909,27z M23,18.003 c-0.331,0.004-0.678,0.014-0.973,0.034c-4.01,0.26-5.959,1.751-5.959,4.558c0,1.941,1.222,3.406,2.841,3.406 c1.113,0,2.305-0.875,3.11-2.285c0.915-1.599,0.982-3.051,0.981-5.084V18.003z"/><g><path fill="#dff0fe" d="M35.955,29.5c-1.311,0.019-2.847,0.958-4.023,1.774c-0.361,0.251-0.308,0.605,0.093,0.558 c1.323-0.157,3.483-0.699,4.35,0.168c0.525,0.666-0.058,2.834-0.551,4.059c-0.15,0.369,0.175,0.512,0.513,0.231 c2.201-1.823,2.704-4.963,1.84-5.819C37.953,30.201,37.268,29.481,35.955,29.5z M1.67,31.26c-0.274,0.036-0.381,0.393-0.093,0.651 C6.47,36.284,12.729,38.5,19.909,38.5c5.122,0,10.164-1.09,14.267-4.088c0.678-0.498,0.265-1.147-0.429-0.854 c-4.6,1.933-8.937,1.942-13.485,1.942C13.52,35.5,7.277,34.393,2,31.353C1.883,31.287,1.76,31.248,1.67,31.26z"/><path fill="#4788c7" d="M19.909,39C12.51,39,6.23,36.74,1.245,32.283c-0.289-0.258-0.404-0.627-0.301-0.961 c0.094-0.303,0.347-0.516,0.662-0.558c0.321-0.004,0.514,0.081,0.642,0.154C7.015,33.666,12.907,35,20.263,35 c4.505,0,8.761,0,13.291-1.903c0.612-0.259,1.255-0.023,1.426,0.499c0.108,0.331,0.032,0.824-0.507,1.22 C30.672,37.592,25.772,39,19.909,39z M3.026,32.476C7.643,36.146,13.312,38,19.909,38c5.587,0,10.249-1.315,13.858-3.909 C29.117,36,24.815,36,20.263,36C13.366,36,7.708,34.845,3.026,32.476z M35.997,36.938L35.997,36.938 c-0.246,0-0.461-0.111-0.591-0.304c-0.083-0.123-0.199-0.386-0.045-0.764c0.652-1.62,0.87-3.245,0.622-3.561 c-0.182-0.177-0.608-0.289-1.226-0.289c-0.601,0-1.29,0.105-1.896,0.198c-0.277,0.042-0.539,0.082-0.775,0.11l-0.129,0.008 c-0.356,0-0.637-0.189-0.733-0.495c-0.107-0.34,0.06-0.724,0.424-0.978c1.234-0.857,2.838-1.843,4.302-1.864c0,0,0,0,0.001,0 c1.452,0,2.257,0.722,2.612,1.152c0.354,0.347,0.547,1.011,0.51,1.833c-0.058,1.288-0.725,3.288-2.417,4.69 C36.449,36.847,36.221,36.938,35.997,36.938z M34.756,31.021c0.906,0,1.551,0.205,1.972,0.626c0.635,0.803,0.238,2.555-0.108,3.659 c0.953-1.08,1.409-2.396,1.453-3.364c0.027-0.614-0.11-0.979-0.249-1.115C37.547,30.494,36.991,30,36.005,30 c-0.975,0.014-2.107,0.597-3.047,1.192C33.535,31.105,34.165,31.021,34.756,31.021z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#98ccfd" d="M3,33.5c-0.827,0-1.5-0.673-1.5-1.5V8c0-0.827,0.673-1.5,1.5-1.5h34c0.827,0,1.5,0.673,1.5,1.5v24 c0,0.827-0.673,1.5-1.5,1.5H3z"/><path fill="#4788c7" d="M37,7c0.551,0,1,0.449,1,1v24c0,0.551-0.449,1-1,1H3c-0.551,0-1-0.449-1-1V8c0-0.551,0.449-1,1-1 H37 M37,6H3C1.895,6,1,6.895,1,8v24c0,1.105,0.895,2,2,2h34c1.105,0,2-0.895,2-2V8C39,6.895,38.105,6,37,6L37,6z"/><path fill="#fff" d="M19 15.192C19.547 15.074 20.286 15 21.024 15c1.153 0 2.133.163 2.768.768.591.517.857 1.344.857 2.186 0 1.079-.324 1.846-.841 2.393-.62.665-1.61.96-2.423.96-.132 0-.251 0-.384-.015V25h-2V15.192zM21 19.727c.103.015.207.015.325.015.975 0 1.404-.695 1.404-1.625 0-.872-.355-1.551-1.256-1.551-.176 0-.354.029-.473.074V19.727zM26 15h2v10h-2V15zM15.952 25H18l-2.113-10h-2.532L11 25h2.048l.436-2h2.047L15.952 25zM14.532 16.839h.048c.097.653.242 1.662.355 2.27L15.256 21h-1.475l.365-1.89C14.258 18.531 14.419 17.507 14.532 16.839z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="40px" height="40px"><path fill="#dff0fe" d="M36.62,28.775c-0.879,1.901-1.299,2.751-2.427,4.428c-1.576,2.346-3.803,5.273-6.555,5.294 c-2.446,0.019-3.131-1.022-6.451-0.997c-3.32,0.017-3.96,1.026-6.41,0.999c-2.75-0.023-4.857-2.661-6.434-5 C5.759,29.652,4.529,25.419,4.5,21.749c-0.02-2.598,0.562-4.914,1.692-6.612c1.928-2.904,4.981-4.61,7.846-4.61 c2.919,0,4.754,1.91,7.166,1.91c2.344,0,3.769-1.913,7.145-1.913c2.553,0,5.253,1.36,7.181,3.704 C29.462,17.479,30.595,26.546,36.62,28.775z"/><path fill="#4788c7" d="M14.873,38.999c-0.002,0-0.1,0-0.102,0c-2.945-0.024-5.112-2.653-6.844-5.221 C5.426,30.053,4.031,25.783,4,21.753c-0.021-2.731,0.593-5.115,1.776-6.893c1.979-2.981,5.144-4.833,8.261-4.833 c1.631,0,2.958,0.565,4.129,1.063c1.023,0.436,1.99,0.847,3.037,0.847c0.958,0,1.761-0.362,2.69-0.782 c1.175-0.53,2.506-1.131,4.455-1.131c2.735,0,5.564,1.453,7.567,3.887c0.096,0.116,0.134,0.268,0.104,0.415 c-0.028,0.147-0.122,0.273-0.254,0.344c-2.551,1.366-3.951,3.969-3.745,6.963c0.211,3.059,2.084,5.679,4.772,6.673 c0.131,0.048,0.235,0.149,0.288,0.278c0.054,0.129,0.051,0.274-0.008,0.401c-0.89,1.925-1.333,2.812-2.466,4.498 c-1.824,2.715-4.078,5.493-6.966,5.515c-0.001,0-0.002,0-0.002,0c-1.232,0-2.011-0.225-2.836-0.462 C23.894,38.271,22.95,38,21.309,38l-0.117,0c-1.695,0.008-2.644,0.28-3.561,0.543C16.813,38.777,16.039,38.999,14.873,38.999z M14.037,11.027c-2.786,0-5.632,1.681-7.428,4.386C5.536,17.025,4.98,19.214,5,21.745c0.029,3.836,1.364,7.911,3.758,11.474 c1.585,2.352,3.541,4.759,6.023,4.779l0.092,0.5v-0.5c1.025,0,1.7-0.193,2.482-0.417c0.937-0.269,1.998-0.572,3.829-0.582l0.124,0 c1.783,0,2.841,0.305,3.773,0.574c0.788,0.228,1.469,0.424,2.492,0.424c2.483-0.019,4.525-2.575,6.204-5.073 c1.002-1.492,1.429-2.301,2.168-3.886c-2.787-1.256-4.698-4.078-4.923-7.338c-0.219-3.182,1.168-5.979,3.733-7.6 c-1.779-1.936-4.137-3.077-6.408-3.077c-1.734,0-2.908,0.53-4.044,1.042c-0.991,0.448-1.929,0.871-3.102,0.871 c-1.251,0-2.357-0.471-3.429-0.927C16.639,11.527,15.464,11.027,14.037,11.027z"/><g><path fill="#dff0fe" d="M26.342,7.491c1.313-1.634,2.452-3.641,2.09-5.991c-2.141,0.143-4.789,1.169-6.252,2.886 c-1.326,1.565-1.977,3.865-1.549,6.114C22.968,10.571,24.938,9.245,26.342,7.491z"/><path fill="#4788c7" d="M20.811,11.003L20.811,11.003L20.615,11c-0.233-0.007-0.432-0.176-0.476-0.406 c-0.439-2.303,0.196-4.806,1.658-6.531c1.637-1.92,4.494-2.921,6.601-3.062c0.26-0.015,0.487,0.167,0.527,0.423 c0.424,2.746-1.05,4.957-2.194,6.381C25.08,9.867,22.977,11.003,20.811,11.003z M27.989,2.046 c-1.791,0.232-4.111,1.118-5.429,2.665c-1.186,1.398-1.745,3.391-1.504,5.287c1.771-0.084,3.501-1.078,4.895-2.818 C27.44,5.327,28.096,3.682,27.989,2.046z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M1.512,35.5c0.268-5.559,4.982-10,10.738-10h7.5c5.756,0,10.47,4.441,10.738,10H1.512z"/><path fill="#4788c7" d="M19.75,26c5.306,0,9.683,3.954,10.199,9H2.051c0.516-5.046,4.893-9,10.199-9H19.75 M19.75,25h-7.5 C6.037,25,1,29.925,1,36h30C31,29.925,25.963,25,19.75,25L19.75,25z"/><path fill="#fff" d="M16,28.5c-3.076,0-4.297-2.626-4.5-3.123V19.91h9v5.468C20.297,25.874,19.076,28.5,16,28.5z"/><path fill="#4788c7" d="M20,20.41v4.865C19.737,25.865,18.607,28,16,28c-2.611,0-3.741-2.141-4-2.725V20.41H20 M21,19.41 H11v6.062c0,0,1.267,3.529,5,3.529c3.733,0,5-3.529,5-3.529V19.41L21,19.41z"/><path fill="#b6dcfe" d="M22.429,17.643c-1.143,0-2.072-0.929-2.072-2.071s0.929-2.071,2.072-2.071 c1.725,0,2.071,0.465,2.071,1.214C24.5,15.966,23.476,17.643,22.429,17.643z M9.571,17.643c-1.047,0-2.071-1.677-2.071-2.928 c0-0.75,0.347-1.214,2.071-1.214c1.143,0,2.072,0.929,2.072,2.071S10.714,17.643,9.571,17.643z"/><path fill="#4788c7" d="M22.429,14C24,14,24,14.363,24,14.714c0,1.044-0.896,2.429-1.571,2.429 c-0.867,0-1.571-0.705-1.571-1.571S21.562,14,22.429,14 M9.571,14c0.867,0,1.571,0.705,1.571,1.571s-0.705,1.571-1.571,1.571 C8.896,17.143,8,15.758,8,14.714C8,14.363,8,14,9.571,14 M22.429,13c-1.42,0-2.571,1.151-2.571,2.571s1.151,2.571,2.571,2.571 S25,16.134,25,14.714S23.849,13,22.429,13L22.429,13z M9.571,13C8.151,13,7,13.294,7,14.714s1.151,3.429,2.571,3.429 s2.571-1.151,2.571-2.571S10.992,13,9.571,13L9.571,13z"/><path fill="#fff" d="M16,24.5c-0.58,0-1.134-0.224-1.56-0.631l-0.09-0.086l-0.12-0.034 c-2.785-0.788-4.73-3.357-4.73-6.25V9.364c0-1.564,1.272-2.836,2.836-2.836h7.328c1.564,0,2.836,1.272,2.836,2.836V17.5 c0,2.893-1.945,5.462-4.73,6.25l-0.12,0.034l-0.09,0.086C17.134,24.276,16.58,24.5,16,24.5z"/><path fill="#4788c7" d="M19.664,7.028C20.952,7.028,22,8.076,22,9.364V17.5c0,2.67-1.796,5.042-4.367,5.768l-0.239,0.068 l-0.18,0.172C16.882,23.825,16.451,24,16,24s-0.882-0.175-1.214-0.492l-0.18-0.172l-0.239-0.068C11.796,22.542,10,20.17,10,17.5 V9.364c0-1.288,1.048-2.336,2.336-2.336H19.664 M19.664,6.028h-7.328C10.494,6.028,9,7.521,9,9.364V17.5 c0,3.205,2.156,5.9,5.095,6.731C14.591,24.705,15.26,25,16,25s1.409-0.295,1.905-0.769C20.844,23.4,23,20.705,23,17.5V9.364 C23,7.521,21.506,6.028,19.664,6.028L19.664,6.028z"/><g><path fill="#b6dcfe" d="M22.5,15.5V12c0-3.483-2.217-4.425-2.312-4.463l-0.343-0.139l-0.234,0.288 C19.589,7.713,17.283,10.5,14,10.5c-0.264,0-0.529-0.009-0.791-0.017c-0.265-0.008-0.526-0.017-0.778-0.017 c-0.877,0-2.931,0-2.931,2.534v2.5H9.286C8.845,14.727,7.5,12.151,7.5,9.576C7.5,4.821,10.995,1.5,16,1.5 c3.078,0,4.499,2.621,4.557,2.732l0.119,0.225l0.253,0.038C22.462,4.714,24.5,5.524,24.5,10c0,2.329-1.338,4.761-1.779,5.5H22.5z"/><path fill="#4788c7" d="M16,2c2.762,0,4.062,2.367,4.113,2.463l0.237,0.454l0.507,0.073C22.321,5.199,24,5.958,24,10 c0,1.395-0.515,2.842-1,3.894V12c0-3.816-2.516-4.883-2.623-4.926l-0.687-0.279l-0.467,0.577C19.201,7.397,17.06,10,14,10 c-0.259,0-0.519-0.008-0.775-0.017c-0.27-0.009-0.537-0.017-0.794-0.017C11.582,9.966,9,9.966,9,13v0.807 c-0.486-1.122-1-2.676-1-4.23C8,5.115,11.29,2,16,2 M16,1c-5.36,0-9,3.667-9,8.576C7,12.828,9,16,9,16h1c0,0,0-2.105,0-3 c0-1.791,1.085-2.034,2.431-2.034C12.932,10.966,13.469,11,14,11c3.573,0,6-3,6-3s2,0.813,2,4c0,0.984,0,4,0,4h1c0,0,2-3.037,2-6 c0-4.161-1.703-5.671-4-6C21,4,19.434,1,16,1L16,1z"/></g><g><path fill="#98ccfd" d="M24,39.5c-0.827,0-1.5-0.673-1.5-1.5V24c0-0.827,0.673-1.5,1.5-1.5h14c0.827,0,1.5,0.673,1.5,1.5v14 c0,0.827-0.673,1.5-1.5,1.5H24z"/><path fill="#4788c7" d="M38,23c0.551,0,1,0.449,1,1v14c0,0.551-0.449,1-1,1H24c-0.551,0-1-0.449-1-1V24 c0-0.551,0.449-1,1-1H38 M38,22H24c-1.105,0-2,0.895-2,2v14c0,1.105,0.895,2,2,2h14c1.105,0,2-0.895,2-2V24 C40,22.895,39.105,22,38,22L38,22z"/></g><path fill="none" stroke="#fff" stroke-miterlimit="10" stroke-width="2" d="M27 31.231L29.769 34 36 27.769"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#b6dcfe" d="M1.5 35.5L1.5 4.5 11.793 4.5 14.793 7.5 38.5 7.5 38.5 35.5z"/><path fill="#4788c7" d="M11.586,5l2.707,2.707L14.586,8H15h23v27H2V5H11.586 M12,4H1v32h38V7H15L12,4L12,4z"/><path fill="#dff0fe" d="M1.5 35.5L1.5 9.5 12.151 9.5 15.151 7.5 38.5 7.5 38.5 35.5z"/><path fill="#4788c7" d="M38,8v27H2V10h10h0.303l0.252-0.168L15.303,8H38 M39,7H15l-3,2H1v27h38V7L39,7z"/><path fill="#fff" d="M20,31.5c-1.93,0-3.5-1.57-3.5-3.5c0-0.548,0.354-2.489,0.973-5.325 c0.151-0.692,0.753-1.175,1.465-1.175h2.125c0.711,0,1.314,0.483,1.465,1.175C23.146,25.511,23.5,27.452,23.5,28 C23.5,29.93,21.93,31.5,20,31.5z"/><path fill="#4788c7" d="M21.063,22c0.474,0,0.876,0.321,0.976,0.782C22.931,26.874,23,27.81,23,28c0,1.654-1.346,3-3,3 s-3-1.346-3-3c0-0.19,0.069-1.126,0.961-5.218c0.1-0.46,0.502-0.782,0.976-0.782H21.063 M21.063,21h-2.125 c-0.941,0-1.753,0.65-1.953,1.569C16.589,24.381,16,27.216,16,28c0,2.209,1.791,4,4,4s4-1.791,4-4 c0-0.784-0.589-3.619-0.984-5.431C22.816,21.65,22.004,21,21.063,21L21.063,21z"/><path fill="#4788c7" d="M20 26.5A1.5 1.5 0 1 0 20 29.5 1.5 1.5 0 1 0 20 26.5zM22.5 20L20 20 19 19 22.5 19z"/><path fill="#4788c7" d="M22.5 19A.5.5 0 1 0 22.5 20 .5.5 0 1 0 22.5 19zM17.5 21L20 21 21 20 17.5 20z"/><path fill="#4788c7" d="M17.5 20A.5.5 0 1 0 17.5 21 .5.5 0 1 0 17.5 20zM22.5 18L20 18 19 17 22.5 17z"/><path fill="#4788c7" d="M22.5 17A.5.5 0 1 0 22.5 18 .5.5 0 1 0 22.5 17zM17.5 19L20 19 21 18 17.5 18z"/><path fill="#4788c7" d="M17.5 18A.5.5 0 1 0 17.5 19 .5.5 0 1 0 17.5 18zM22.5 16L20 16 19 15 22.5 15z"/><path fill="#4788c7" d="M22.5 15A.5.5 0 1 0 22.5 16 .5.5 0 1 0 22.5 15zM17.5 17L20 17 21 16 17.5 16z"/><path fill="#4788c7" d="M17.5 16A.5.5 0 1 0 17.5 17 .5.5 0 1 0 17.5 16zM22.5 14L20 14 19 13 22.5 13z"/><path fill="#4788c7" d="M22.5 13A.5.5 0 1 0 22.5 14 .5.5 0 1 0 22.5 13zM17.5 15L20 15 21 14 17.5 14z"/><path fill="#4788c7" d="M17.5 14A.5.5 0 1 0 17.5 15 .5.5 0 1 0 17.5 14zM22.5 12L20 12 19 11 22.5 11z"/><path fill="#4788c7" d="M22.5 11A.5.5 0 1 0 22.5 12 .5.5 0 1 0 22.5 11zM17.5 13L20 13 21 12 17.5 12z"/><path fill="#4788c7" d="M17.5 12A.5.5 0 1 0 17.5 13 .5.5 0 1 0 17.5 12zM22.5 10L20 10 19 9 22.5 9z"/><path fill="#4788c7" d="M22.5 9A.5.5 0 1 0 22.5 10 .5.5 0 1 0 22.5 9zM17.5 11L20 11 21 10 17.5 10z"/><g><path fill="#4788c7" d="M17.5 10A0.5 0.5 0 1 0 17.5 11A0.5 0.5 0 1 0 17.5 10Z"/></g><g><path fill="#4788c7" d="M17.5 9L20 9 21 8 17.5 8z"/></g><g><path fill="#4788c7" d="M17.5 8A0.5 0.5 0 1 0 17.5 9A0.5 0.5 0 1 0 17.5 8Z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M25.992,23.5l-0.457-3.241l-0.309-0.091c-1.183-0.35-2.288-0.987-3.197-1.843l-0.228-0.214 l-3.108,1.181l-1.49-2.581l2.583-2.087l-0.07-0.305C19.572,13.703,19.5,13.091,19.5,12.5c0-0.605,0.077-1.234,0.229-1.869 l0.074-0.312l-2.596-2.035l1.489-2.58l3.14,1.151l0.225-0.209c0.877-0.815,1.887-1.409,3.002-1.766l0.283-0.09L25.972,1.5h2.988 l0.483,3.237l0.307,0.09c1.169,0.342,2.267,0.966,3.174,1.804l0.224,0.207l3.105-1.135l1.5,2.599l-2.511,2.176l0.064,0.291 C35.435,11.35,35.5,11.933,35.5,12.5c0,0.594-0.074,1.209-0.22,1.831l-0.07,0.304l2.537,2.073l-1.494,2.588l-3.105-1.135 l-0.225,0.207c-0.906,0.838-2.004,1.462-3.173,1.805l-0.307,0.09L28.96,23.5H25.992z M27.5,8.5c-2.206,0-4,1.794-4,4s1.794,4,4,4 s4-1.794,4-4S29.706,8.5,27.5,8.5z"/><path fill="#4788c7" d="M28.529,2l0.373,2.495l0.094,0.632l0.614,0.18c1.095,0.321,2.124,0.906,2.974,1.692l0.448,0.415 l0.574-0.21l2.424-0.886l1.084,1.877l-1.973,1.71l-0.45,0.39l0.128,0.581C34.939,11.422,35,11.968,35,12.5 c0,0.556-0.069,1.134-0.206,1.717l-0.142,0.608l0.483,0.395l1.966,1.607l-1.071,1.856l-2.424-0.886l-0.574-0.21l-0.448,0.415 c-0.85,0.786-1.879,1.371-2.974,1.692l-0.614,0.18l-0.094,0.632L28.529,23h-2.103l-0.352-2.493l-0.09-0.637l-0.617-0.183 c-1.107-0.328-2.144-0.925-2.998-1.728l-0.456-0.428l-0.584,0.222l-2.417,0.918l-1.064-1.842l2.007-1.622l0.488-0.394l-0.142-0.611 C20.068,13.626,20,13.053,20,12.5c0-0.567,0.072-1.157,0.215-1.752l0.15-0.624l-0.505-0.396l-2.003-1.569l1.062-1.84l2.456,0.901 l0.576,0.211l0.449-0.418c0.822-0.764,1.769-1.321,2.814-1.656l0.567-0.181l0.111-0.585L26.386,2H28.529 M27.5,17 c2.481,0,4.5-2.019,4.5-4.5S29.981,8,27.5,8c-2.481,0-4.5,2.019-4.5,4.5S25.019,17,27.5,17 M29.391,1h-3.833l-0.647,3.405 C23.706,4.79,22.624,5.44,21.72,6.28l-3.246-1.19l-1.917,3.32l2.686,2.105C19.09,11.153,19,11.815,19,12.5 c0,0.665,0.084,1.31,0.229,1.931l-2.672,2.159l1.917,3.32l3.213-1.221c0.954,0.896,2.11,1.576,3.399,1.958L25.558,24h3.833 l0.5-3.347c1.275-0.373,2.422-1.039,3.372-1.917l3.213,1.174l1.917-3.32l-2.624-2.145C35.914,13.819,36,13.17,36,12.5 c0-0.632-0.074-1.246-0.205-1.839l2.597-2.251l-1.917-3.32l-3.213,1.174c-0.95-0.878-2.096-1.544-3.372-1.917L29.391,1L29.391,1z M27.5,16c-1.933,0-3.5-1.567-3.5-3.5S25.567,9,27.5,9s3.5,1.567,3.5,3.5S29.433,16,27.5,16L27.5,16z"/><g><path fill="#b6dcfe" d="M10.992,38.5l-0.457-3.241l-0.309-0.091c-1.183-0.35-2.288-0.987-3.197-1.843L6.802,33.11 l-3.108,1.181l-1.49-2.581l2.583-2.087l-0.07-0.305C4.572,28.703,4.5,28.091,4.5,27.5c0-0.605,0.077-1.234,0.229-1.869 l0.074-0.312l-2.596-2.035l1.489-2.58l3.14,1.151l0.225-0.209c0.877-0.815,1.887-1.409,3.002-1.766l0.283-0.09l0.626-3.291h2.988 l0.483,3.237l0.307,0.09c1.169,0.342,2.267,0.966,3.174,1.804l0.224,0.207l3.105-1.135l1.5,2.599l-2.511,2.176l0.064,0.291 C20.435,26.35,20.5,26.933,20.5,27.5c0,0.594-0.074,1.209-0.22,1.831l-0.07,0.304l2.537,2.073l-1.494,2.588l-3.105-1.135 l-0.225,0.207c-0.906,0.838-2.004,1.462-3.173,1.805l-0.307,0.09L13.96,38.5H10.992z M12.5,23.5c-2.206,0-4,1.794-4,4s1.794,4,4,4 s4-1.794,4-4S14.706,23.5,12.5,23.5z"/><path fill="#4788c7" d="M13.529,17l0.373,2.495l0.094,0.632l0.614,0.18c1.095,0.321,2.124,0.906,2.974,1.692l0.448,0.415 l0.574-0.21l2.424-0.886l1.084,1.877l-1.973,1.71l-0.45,0.39l0.128,0.581C19.939,26.422,20,26.968,20,27.5 c0,0.556-0.069,1.134-0.206,1.717l-0.142,0.608l0.483,0.395l1.966,1.607l-1.071,1.856l-2.424-0.886l-0.574-0.21l-0.448,0.415 c-0.85,0.786-1.879,1.371-2.974,1.692l-0.614,0.18l-0.094,0.632L13.529,38h-2.103l-0.352-2.493l-0.09-0.637l-0.617-0.183 c-1.107-0.328-2.144-0.925-2.998-1.728l-0.456-0.428l-0.584,0.222l-2.417,0.918L2.85,31.831l2.007-1.622l0.488-0.394l-0.142-0.611 C5.068,28.626,5,28.053,5,27.5c0-0.567,0.072-1.157,0.215-1.752l0.15-0.624l-0.505-0.396l-2.003-1.569l1.062-1.84l2.456,0.901 l0.576,0.211l0.449-0.418c0.822-0.764,1.769-1.321,2.814-1.656l0.567-0.181l0.111-0.585L11.386,17H13.529 M12.5,32 c2.481,0,4.5-2.019,4.5-4.5S14.981,23,12.5,23C10.019,23,8,25.019,8,27.5S10.019,32,12.5,32 M14.391,16h-3.833l-0.647,3.405 C8.706,19.79,7.624,20.44,6.72,21.28l-3.246-1.19l-1.917,3.32l2.686,2.105C4.09,26.153,4,26.815,4,27.5 c0,0.665,0.084,1.31,0.229,1.931L1.557,31.59l1.917,3.32l3.213-1.221c0.954,0.896,2.11,1.576,3.399,1.958L10.558,39h3.833 l0.5-3.347c1.275-0.373,2.422-1.039,3.372-1.917l3.213,1.174l1.917-3.32l-2.624-2.145C20.914,28.819,21,28.17,21,27.5 c0-0.632-0.074-1.246-0.205-1.839l2.597-2.251l-1.917-3.32l-3.213,1.174c-0.95-0.878-2.096-1.544-3.372-1.917L14.391,16L14.391,16 z M12.5,31C10.567,31,9,29.433,9,27.5s1.567-3.5,3.5-3.5s3.5,1.567,3.5,3.5S14.433,31,12.5,31L12.5,31z"/></g></svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 96 96" width="96px" height="96px">
<g id="surface1658587">
<path style="fill-rule:nonzero;fill:rgb(87.450981%,94.117647%,99.607843%);fill-opacity:1;stroke-width:10;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(27.843139%,53.333336%,78.039217%);stroke-opacity:1;stroke-miterlimit:10;" d="M 46.585111 142.100675 L 122.793156 133.443026 L 81.726722 85.859286 L 105.055715 38.88284 L 164.82978 143.330076 Z M 100.449164 20.345548 L 41.000965 128.806852 L 7.170222 132.213625 L 46.910976 65.152027 Z M 100.449164 20.345548 " transform="matrix(0.527442,0,0,0.527442,2.64,2.64)"/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(87.450981%,94.117647%,99.607843%);fill-opacity:1;" d="M 89.578125 78.238281 L 58.050781 23.148438 L 45.746094 47.925781 L 67.40625 73.023438 L 27.210938 77.589844 Z M 27.382812 37.003906 L 6.421875 72.375 L 24.265625 70.578125 L 55.621094 13.371094 Z M 27.382812 37.003906 "/>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="none" stroke="#4788c7" stroke-miterlimit="10" d="M19.5 13.5L19.5 4.5"/><path fill="#dff0fe" d="M19.5 1.5A3 3 0 1 0 19.5 7.5A3 3 0 1 0 19.5 1.5Z"/><path fill="#4788c7" d="M19.5,2C20.879,2,22,3.122,22,4.5S20.879,7,19.5,7S17,5.878,17,4.5S18.121,2,19.5,2 M19.5,1 C17.567,1,16,2.567,16,4.5S17.567,8,19.5,8S23,6.433,23,4.5S21.433,1,19.5,1L19.5,1z"/><path fill="#dff0fe" d="M19,38.5c-4.304,0-14.5-1.358-14.5-3.5v-8.139C4.5,19.077,11.141,12.5,19,12.5h1 c7.859,0,14.5,6.577,14.5,14.361V35c0,2.142-10.196,3.5-14.5,3.5H19z"/><path fill="#4788c7" d="M20,13c7.589,0,14,6.348,14,13.861V35c0,0.011-0.239,1.136-5.571,2.129 C25.202,37.73,21.558,38,20,38h-1c-1.558,0-5.202-0.27-8.429-0.871C5.239,36.136,5,35.011,5,35v-8.139C5,19.348,11.411,13,19,13H20 M20,12h-1c-8.154,0-15,6.707-15,14.861V35c0,2.965,12.035,4,15,4h1c2.965,0,15-1.035,15-4v-8.139C35,18.707,28.154,12,20,12L20,12 z"/><path fill="#fff" d="M12.5,30.5c-2.206,0-4-1.794-4-4s1.794-4,4-4h14c2.206,0,4,1.794,4,4s-1.794,4-4,4H12.5z"/><path fill="#4788c7" d="M26.5,23c1.93,0,3.5,1.57,3.5,3.5S28.43,30,26.5,30h-14C10.57,30,9,28.43,9,26.5s1.57-3.5,3.5-3.5 H26.5 M26.5,22h-14C10.025,22,8,24.025,8,26.5s2.025,4.5,4.5,4.5h14c2.475,0,4.5-2.025,4.5-4.5S28.975,22,26.5,22L26.5,22z"/><path fill="#98ccfd" d="M12.5 25.5A1 1 0 1 0 12.5 27.5A1 1 0 1 0 12.5 25.5Z"/><path fill="#4788c7" d="M12.5,26c0.276,0,0.5,0.224,0.5,0.5S12.776,27,12.5,27S12,26.776,12,26.5S12.224,26,12.5,26 M12.5,25c-0.828,0-1.5,0.672-1.5,1.5s0.672,1.5,1.5,1.5s1.5-0.672,1.5-1.5S13.328,25,12.5,25L12.5,25z"/><g><path fill="#98ccfd" d="M26.5 25.5A1 1 0 1 0 26.5 27.5A1 1 0 1 0 26.5 25.5Z"/><path fill="#4788c7" d="M26.5,26c0.276,0,0.5,0.224,0.5,0.5S26.776,27,26.5,27S26,26.776,26,26.5S26.224,26,26.5,26 M26.5,25c-0.828,0-1.5,0.672-1.5,1.5s0.672,1.5,1.5,1.5s1.5-0.672,1.5-1.5S27.328,25,26.5,25L26.5,25z"/></g><g><path fill="#dff0fe" d="M36,32.5c-0.827,0-1.5-0.673-1.5-1.5V19c0-0.827,0.673-1.5,1.5-1.5s1.5,0.673,1.5,1.5v12 C37.5,31.827,36.827,32.5,36,32.5z"/><path fill="#4788c7" d="M36,18c0.551,0,1,0.449,1,1v12c0,0.551-0.449,1-1,1s-1-0.449-1-1V19C35,18.449,35.449,18,36,18 M36,17c-1.105,0-2,0.895-2,2v12c0,1.105,0.895,2,2,2s2-0.895,2-2V19C38,17.895,37.105,17,36,17L36,17z"/></g><g><path fill="#dff0fe" d="M3,32.5c-0.827,0-1.5-0.673-1.5-1.5V19c0-0.827,0.673-1.5,1.5-1.5s1.5,0.673,1.5,1.5v12 C4.5,31.827,3.827,32.5,3,32.5z"/><path fill="#4788c7" d="M3,18c0.551,0,1,0.449,1,1v12c0,0.551-0.449,1-1,1s-1-0.449-1-1V19C2,18.449,2.449,18,3,18 M3,17 c-1.1,0-2,0.9-2,2v12c0,1.1,0.9,2,2,2s2-0.9,2-2V19C5,17.9,4.1,17,3,17L3,17z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#98ccfd" d="M3.5 32.926L3.5 13.675 20 9.516 36.5 13.675 36.5 32.926 20 38.473z"/><path fill="#4788c7" d="M20,10.031l16,4.034v18.502l-16,5.378L4,32.567V14.065L20,10.031 M20,9L3,13.286v20L20,39l17-5.714 v-20L20,9L20,9z"/><path fill="#b6dcfe" d="M36,32.567l-16,5.378V13.031l16,1.034V32.567z"/><path fill="#dff0fe" d="M20,18.231L4,14.065l16-4.034l16,4.034L20,18.231z"/><path fill="none" stroke="#4788c7" stroke-linecap="round" stroke-miterlimit="10" stroke-width="1.5" d="M26.788 21.154L30.806 19.815"/><path fill="#4788c7" d="M24 7.306L23 7.082 23 2 24 2zM30 8.653L29 8.429 29 4 30 4zM36 10L35 9.776 35 2 36 2zM16 7.306L17 7.082 17 2 16 2zM10 8.653L11 8.429 11 4 10 4zM4 10L5 9.776 5 2 4 2z"/><path fill="#4788c7" d="M4.5 3L4.5 3C4.225 3 4 2.775 4 2.5v-1C4 1.225 4.225 1 4.5 1h0C4.775 1 5 1.225 5 1.5v1C5 2.775 4.775 3 4.5 3zM16.5 3L16.5 3C16.225 3 16 2.775 16 2.5v-1C16 1.225 16.225 1 16.5 1l0 0C16.775 1 17 1.225 17 1.5v1C17 2.775 16.775 3 16.5 3zM10.5 5L10.5 5C10.225 5 10 4.775 10 4.5v-1C10 3.225 10.225 3 10.5 3h0C10.775 3 11 3.225 11 3.5v1C11 4.775 10.775 5 10.5 5zM29.5 5L29.5 5C29.225 5 29 4.775 29 4.5v-1C29 3.225 29.225 3 29.5 3l0 0C29.775 3 30 3.225 30 3.5v1C30 4.775 29.775 5 29.5 5zM23.5 3L23.5 3C23.225 3 23 2.775 23 2.5v-1C23 1.225 23.225 1 23.5 1l0 0C23.775 1 24 1.225 24 1.5v1C24 2.775 23.775 3 23.5 3zM35.5 3L35.5 3C35.225 3 35 2.775 35 2.5v-1C35 1.225 35.225 1 35.5 1l0 0C35.775 1 36 1.225 36 1.5v1C36 2.775 35.775 3 35.5 3z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M12.5 1.5H27.5V7.5H12.5z"/><path fill="#4788c7" d="M27,2v5H13V2H27 M28,1H12v7h16V1L28,1z"/><path fill="#dff0fe" d="M6.5 4.5H33.5V38.5H6.5z"/><path fill="#4788c7" d="M33,5v33H7V5H33 M34,4H6v35h28V4L34,4z"/><path fill="#98ccfd" d="M17.5 32.5H22.5V38.5H17.5z"/><path fill="#4788c7" d="M22,33v5h-4v-5H22 M23,32h-6v7h6V32L23,32z"/><path fill="#98ccfd" d="M17 26H23V29H17zM17 20H23V23H17zM17 14H23V17H17zM17 8H23V11H17zM25 26H31V29H25zM25 20H31V23H25zM25 14H31V17H25zM25 8H31V11H25zM9 26H15V29H9zM25 32H31V35H25zM9 32H15V35H9z"/><g><path fill="#98ccfd" d="M9 20H15V23H9z"/></g><g><path fill="#98ccfd" d="M9 14H15V17H9z"/></g><g><path fill="#98ccfd" d="M9 8H15V11H9z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="none" stroke="#4788c7" stroke-linecap="round" stroke-miterlimit="10" d="M20,13c0,0,2.799-10.5,7.5-10.5"/><path fill="#4788c7" d="M38,8c0,1.077,0,2.071,0,3c-0.311,7.904-1.843,11-6,11c2.271,1.026,3,2.469,3,5 c0,4.259-4.433,10-7.929,10c-3.321,0-7.071-5.021-7.103-7.736V16.902C20,12.518,29.563,4,34.4,4c0.913,0,1.813,0.154,2.52,0.759 C37.627,5.363,38,6.727,38,8z"/><path fill="#dff0fe" d="M27,35.5c-2.867,0-7.5-4.375-7.5-6.5v-7.475l0.475-0.024c0,0,0.65-0.033,1.663-0.033 c2.025,0,5.825,0.138,8.524,1.06C32.377,23.283,33.5,24.452,33.5,26C33.5,30.393,30.661,35.5,27,35.5z"/><path fill="#4788c7" d="M21.638,21.967c2.094,0,5.759,0.143,8.362,1.033c1.721,0.588,3,1.5,3,3c0,4.268-2.731,9-6,9 c-2.58,0-7-4.094-7-6v-7C20,22,20.64,21.967,21.638,21.967 M21.638,20.967c-1.011,0-1.661,0.032-1.688,0.034L19,21.049V22v7 c0,2.617,5.009,7,8,7c4.006,0,7-5.28,7-10c0-1.785-1.237-3.113-3.677-3.946C27.555,21.109,23.693,20.967,21.638,20.967 L21.638,20.967z"/><path fill="#dff0fe" d="M19.5,21.5v-5.127l0.061-0.112C20.765,14.054,27.664,5.5,32.634,5.5c1.012,0,1.925,0.26,2.64,0.753 C36.042,6.782,36.5,7.809,36.5,9c0,8.528-1.748,12.5-5.5,12.5H19.5z"/><path fill="#4788c7" d="M32.634,6c0.854,0,1.695,0.209,2.356,0.664C35.651,7.12,36,8.041,36,9c0,9.664-2.281,12-5,12 c-3.43,0-11,0-11,0v-4.5C21.359,14.009,28.11,6,32.634,6 M32.634,5c-5.162,0-12.112,8.454-13.512,11.021L19,16.245V16.5V21v1h1h11 c5.378,0,6-7.419,6-13c0-1.356-0.539-2.537-1.443-3.159C34.759,5.291,33.748,5,32.634,5L32.634,5z"/><path fill="#4788c7" d="M2,8c0,1.077,0,2.071,0,3c0.311,7.904,1.843,11,6,11c-2.271,1.026-3,2.469-3,5 c0,4.259,4.433,10,7.929,10c3.321,0,7.071-5.021,7.103-7.736V16.902C20,12.518,10.438,4,5.6,4C4.687,4,3.787,4.154,3.08,4.759 C2.373,5.363,2,6.727,2,8z"/><g><path fill="#dff0fe" d="M13,35.5c-3.661,0-6.5-5.107-6.5-9.5c0-1.548,1.123-2.717,3.338-3.473 c2.699-0.922,6.499-1.06,8.524-1.06c1.013,0,1.663,0.033,1.663,0.033l0.475,0.024V29C20.5,31.125,15.867,35.5,13,35.5z"/><path fill="#4788c7" d="M18.362,21.967C19.36,21.967,20,22,20,22v7c0,1.906-4.42,6-7,6c-3.269,0-6-4.732-6-9 c0-1.5,1.279-2.412,3-3C12.604,22.111,16.269,21.968,18.362,21.967 M18.363,20.967L18.363,20.967 c-2.511,0-6.057,0.188-8.686,1.086C7.237,22.887,6,24.215,6,26c0,4.72,2.994,10,7,10c2.991,0,8-4.383,8-7v-7v-0.95l-0.949-0.048 C20.024,21,19.374,20.967,18.363,20.967L18.363,20.967z"/><g><path fill="#dff0fe" d="M9,21.5c-3.752,0-5.5-3.972-5.5-12.5c0-1.191,0.458-2.218,1.226-2.747 C5.441,5.76,6.354,5.5,7.366,5.5c4.97,0,11.869,8.554,13.073,10.761l0.061,0.112V21.5H9z"/><path fill="#4788c7" d="M7.366,6C11.89,6,18.641,14.009,20,16.5V21c0,0-7.57,0-11,0c-2.719,0-5-2.336-5-12 c0-0.959,0.349-1.88,1.01-2.336C5.671,6.209,6.513,6,7.366,6 M7.366,5C6.252,5,5.241,5.291,4.443,5.841C3.539,6.463,3,7.644,3,9 c0,5.581,0.622,13,6,13h11h1v-1v-4.5v-0.255l-0.122-0.224C19.478,13.454,12.529,5,7.366,5L7.366,5z"/></g></g><path fill="none" stroke="#4788c7" stroke-linecap="round" stroke-miterlimit="10" d="M20,13c0,0-2.799-10.5-7.5-10.5"/><g><path fill="#98ccfd" d="M20,35.5c-0.708,0-1.5-1.497-1.5-3.5V14c0-2.003,0.792-3.5,1.5-3.5s1.5,1.497,1.5,3.5v18 C21.5,34.003,20.708,35.5,20,35.5z"/><path fill="#4788c7" d="M20,11c0.249,0,1,1.064,1,3v18c0,1.936-0.751,3-1,3s-1-1.064-1-3V14C19,12.064,19.751,11,20,11 M20,10c-1.105,0-2,1.791-2,4v18c0,2.209,0.895,4,2,4s2-1.791,2-4V14C22,11.791,21.105,10,20,10L20,10z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#fff" d="M2.5,37.5v-35h35V35c0,1.378-1.121,2.5-2.5,2.5H2.5z"/><path fill="#4788c7" d="M37,3v32c0,1.103-0.897,2-2,2H3V3H37 M38,2H2v36h33c1.657,0,3-1.343,3-3V2L38,2z"/><path fill="#b6dcfe" d="M2.5 2.5H37.5V7.5H2.5z"/><path fill="#4788c7" d="M37,3v4H3V3H37 M38,2H2v6h36V2L38,2z"/><path fill="#b6dcfe" d="M13 14H15V16H13zM21 14H23V16H21zM25 14H27V16H25zM29 14H31V16H29zM9 18H11V20H9zM13 18H15V20H13zM21 18H23V20H21zM25 18H27V20H25zM29 18H31V20H29zM9 26H11V28H9zM13 26H15V28H13zM21 26H23V28H21zM17 14H19V16H17zM17 18H19V20H17zM9 22H11V24H9zM13 22H15V24H13zM21 22H23V24H21zM25 22H27V24H25zM29 22H31V24H29zM17 22H19V24H17zM17 26H19V28H17zM25 26H27V28H25zM3 34H37V37H3z"/><path fill="#98ccfd" d="M31,39.5c-4.687,0-8.5-3.813-8.5-8.5s3.813-8.5,8.5-8.5s8.5,3.813,8.5,8.5S35.687,39.5,31,39.5z"/><path fill="#4788c7" d="M31,23c4.411,0,8,3.589,8,8s-3.589,8-8,8s-8-3.589-8-8S26.589,23,31,23 M31,22 c-4.971,0-9,4.029-9,9s4.029,9,9,9s9-4.029,9-9S35.971,22,31,22L31,22z"/><path fill="none" stroke="#fff" stroke-miterlimit="10" stroke-width="2" d="M31 36L31 26M26 31L36 31"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#fff" d="M2.5 2.5H37.5V37.5H2.5z"/><path fill="#4788c7" d="M37,3v34H3V3H37 M38,2H2v36h36V2L38,2z"/><path fill="#b6dcfe" d="M2.5 2.5H37.5V7.5H2.5z"/><path fill="#4788c7" d="M37,3v4H3V3H37 M38,2H2v6h36V2L38,2z"/><path fill="#b6dcfe" d="M13 14H15V16H13zM21 14H23V16H21zM25 14H27V16H25zM29 14H31V16H29zM9 18H11V20H9zM13 18H15V20H13zM21 18H23V20H21zM25 18H27V20H25zM29 18H31V20H29zM9 26H11V28H9zM13 26H15V28H13zM21 26H23V28H21zM17 14H19V16H17zM17 18H19V20H17zM9 22H11V24H9zM13 22H15V24H13zM21 22H23V24H21zM25 22H27V24H25zM29 22H31V24H29zM17 22H19V24H17zM17 26H19V28H17zM25 26H27V28H25zM3 34H37V37H3z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#98ccfd" d="M37.995,38.46c-2.113-0.165-4.481-0.831-6.779-1.917l-0.193-0.091l-0.199,0.076 C29.13,37.173,27.339,37.5,25.5,37.5c-7.168,0-13-4.935-13-11s5.832-11,13-11s13,4.935,13,11c0,2.53-1.042,5.001-2.935,6.958 l-0.242,0.25l0.151,0.314C36.292,35.724,37.138,37.211,37.995,38.46z"/><path fill="#4788c7" d="M25.5,16C32.393,16,38,20.71,38,26.5c0,2.4-0.992,4.748-2.794,6.611l-0.484,0.501l0.302,0.628 c0.641,1.333,1.3,2.537,1.968,3.602c-1.775-0.267-3.691-0.866-5.563-1.751l-0.385-0.182l-0.398,0.152 C29.009,36.684,27.278,37,25.5,37C18.607,37,13,32.29,13,26.5S18.607,16,25.5,16 M25.5,15C18.044,15,12,20.149,12,26.5 C12,32.851,18.044,38,25.5,38c1.961,0,3.82-0.364,5.501-1.005C33.547,38.198,36.405,39,39,39 c-1.176-1.549-2.201-3.377-3.075-5.194C37.846,31.82,39,29.275,39,26.5C39,20.149,32.956,15,25.5,15L25.5,15z"/><g><path fill="#dff0fe" d="M2.005,24.46c0.857-1.249,1.702-2.736,2.521-4.437l0.151-0.314l-0.242-0.25 C2.542,17.501,1.5,15.03,1.5,12.5c0-6.065,5.832-11,13-11s13,4.935,13,11s-5.832,11-13,11c-1.839,0-3.63-0.327-5.323-0.972 l-0.199-0.076l-0.193,0.091C6.487,23.629,4.119,24.295,2.005,24.46z"/><path fill="#4788c7" d="M14.5,2C21.393,2,27,6.71,27,12.5S21.393,23,14.5,23c-1.778,0-3.509-0.316-5.145-0.939 l-0.398-0.152l-0.385,0.182c-1.872,0.885-3.788,1.484-5.563,1.751c0.668-1.065,1.326-2.269,1.968-3.602l0.302-0.628l-0.484-0.501 C2.992,17.248,2,14.9,2,12.5C2,6.71,7.607,2,14.5,2 M14.5,1C7.044,1,1,6.149,1,12.5c0,2.775,1.154,5.32,3.075,7.306 C3.201,21.623,2.176,23.451,1,25c2.595,0,5.453-0.802,7.999-2.005C10.68,23.636,12.539,24,14.5,24C21.956,24,28,18.851,28,12.5 C28,6.149,21.956,1,14.5,1L14.5,1z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M7.032 38.5L21.637 20 7.032 1.5 18.758 1.5 33.363 20 18.758 38.5z"/><path fill="#4788c7" d="M18.515,2l14.211,18L18.515,38H8.064l13.721-17.38L22.274,20l-0.489-0.62L8.064,2H18.515 M19,1H6l15,19L6,39h13l15-19L19,1L19,1z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M20,38.5C9.799,38.5,1.5,30.201,1.5,20S9.799,1.5,20,1.5S38.5,9.799,38.5,20S30.201,38.5,20,38.5z"/><path fill="#4788c7" d="M20,2c9.925,0,18,8.075,18,18s-8.075,18-18,18S2,29.925,2,20S10.075,2,20,2 M20,1 C9.507,1,1,9.507,1,20s8.507,19,19,19s19-8.507,19-19S30.493,1,20,1L20,1z"/><path fill="#fff" d="M20,35.5c-8.547,0-15.5-6.953-15.5-15.5S11.453,4.5,20,4.5S35.5,11.453,35.5,20S28.547,35.5,20,35.5 z"/><path fill="#4788c7" d="M20,5c8.271,0,15,6.729,15,15s-6.729,15-15,15S5,28.271,5,20S11.729,5,20,5 M20,4 C11.163,4,4,11.163,4,20s7.163,16,16,16s16-7.163,16-16S28.837,4,20,4L20,4z"/><path fill="none" stroke="#4788c7" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M26.639 10.19L20 20 25 25"/><path fill="#4788c7" d="M20 18.5A1.5 1.5 0 1 0 20 21.5A1.5 1.5 0 1 0 20 18.5Z"/><path fill="#98ccfd" d="M20 7A1 1 0 1 0 20 9 1 1 0 1 0 20 7zM20 31A1 1 0 1 0 20 33 1 1 0 1 0 20 31z"/><g><path fill="#98ccfd" d="M32 19A1 1 0 1 0 32 21A1 1 0 1 0 32 19Z"/></g><g><path fill="#98ccfd" d="M8 19A1 1 0 1 0 8 21A1 1 0 1 0 8 19Z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M5.5,5.5h29c1.657,0,3,1.343,3,3v23c0,1.657-1.343,3-3,3h-29c-1.657,0-3-1.343-3-3v-23 C2.5,6.843,3.843,5.5,5.5,5.5z"/><path fill="#4788c7" d="M34.5,35h-29C3.57,35,2,33.43,2,31.5v-23C2,6.57,3.57,5,5.5,5h29C36.43,5,38,6.57,38,8.5v23 C38,33.43,36.43,35,34.5,35z M5.5,6C4.121,6,3,7.121,3,8.5v23C3,32.879,4.121,34,5.5,34h29c1.379,0,2.5-1.121,2.5-2.5v-23 C37,7.121,35.879,6,34.5,6H5.5z"/><path fill="#98ccfd" d="M18.5,26.713V21.5h-8v-3h8v-5.213L25.146,20L18.5,26.713z"/><path fill="#98ccfd" d="M18,27.93V22h-8v-4h8v-5.93L25.85,20L18,27.93z M11,21h8v4.498L24.443,20L19,14.502V19h-8V21z"/><g><path fill="#98ccfd" d="M27.5,5.5h7c1.657,0,3,1.343,3,3v23c0,1.657-1.343,3-3,3h-7V5.5z"/><path fill="#4788c7" d="M34.5,35H27V5h7.5C36.43,5,38,6.57,38,8.5v23C38,33.43,36.43,35,34.5,35z M28,34h6.5 c1.379,0,2.5-1.121,2.5-2.5v-23C37,7.121,35.879,6,34.5,6H28V34z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M6.537,32.5l-0.191-0.008C3.067,32.409,0.5,29.776,0.5,26.5c0-2.462,1.479-4.646,3.767-5.566 l0.367-0.147l-0.06-0.391C4.523,20.059,4.5,19.774,4.5,19.5c0-3.309,2.691-6,6-6c0.517,0,1.045,0.072,1.571,0.215l0.504,0.137 l0.114-0.509C13.467,9.903,16.473,7.5,20,7.5c2.698,0,5.2,1.464,6.53,3.82l0.166,0.293l0.334-0.043 c0.318-0.042,0.64-0.07,0.97-0.07c3.792,0,6.99,2.837,7.441,6.601l0.029,0.251l0.22,0.125c2.35,1.333,3.81,3.832,3.81,6.524 c0,4.136-3.364,7.5-7.5,7.5H6.537z"/><path fill="#4788c7" d="M20,8c2.517,0,4.853,1.366,6.095,3.566l0.331,0.586l0.668-0.086C27.443,12.021,27.73,12,28,12 c3.538,0,6.524,2.648,6.944,6.16l0.06,0.502l0.44,0.249C37.637,20.154,39,22.488,39,25c0,3.86-3.14,7-7,7H6.677l-0.319-0.008 C3.354,31.916,1,29.503,1,26.5c0-2.256,1.355-4.259,3.453-5.102l0.734-0.295l-0.117-0.782C5.022,20.008,5,19.747,5,19.5 c0-3.033,2.467-5.5,5.5-5.5c0.471,0,0.956,0.067,1.441,0.198l1.007,0.273l0.23-1.018C13.903,10.242,16.708,8,20,8 M20,7 c-3.81,0-6.992,2.666-7.798,6.233C11.659,13.086,11.09,13,10.5,13C6.91,13,4,15.91,4,19.5c0,0.331,0.033,0.653,0.08,0.97 C1.69,21.431,0,23.766,0,26.5c0,3.534,2.821,6.402,6.333,6.492V33H32c4.418,0,8-3.582,8-8c0-2.986-1.639-5.585-4.063-6.959 C35.462,14.076,32.093,11,28,11c-0.351,0-0.695,0.03-1.034,0.074C25.593,8.644,22.99,7,20,7L20,7z"/><path fill="none" stroke="#4788c7" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M14 23L18 27 27 18"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#fff" d="M6.5 37.5L6.5 2.5 24.793 2.5 33.5 11.207 33.5 37.5z"/><path fill="#4788c7" d="M24.586,3L33,11.414V37H7V3H24.586 M25,2H6v36h28V11L25,2L25,2z"/><path fill="#dff0fe" d="M24.5 11.5L24.5 2.5 24.793 2.5 33.5 11.207 33.5 11.5z"/><path fill="#4788c7" d="M25,3.414L32.586,11H25V3.414 M25,2h-1v10h10v-1L25,2L25,2z"/><path fill="none" stroke="#4788c7" stroke-linecap="round" stroke-miterlimit="10" d="M25.5 19.5L27.5 23.5 25.5 27.5M14.5 19.5L12.5 23.5 14.5 27.5M22.5 16.5L17.5 30.5"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="none" stroke="#4788c7" stroke-miterlimit="10" d="M6.5 35v-4.808c0-5.353 4.339-9.692 9.692-9.692h7.615c5.353 0 9.692-4.339 9.692-9.692V5.962M6.5 32.5L6.5 6.5"/><path fill="#dff0fe" d="M6.5 2.5A4 4 0 1 0 6.5 10.5A4 4 0 1 0 6.5 2.5Z"/><path fill="#4788c7" d="M6.5,3C8.43,3,10,4.57,10,6.5S8.43,10,6.5,10S3,8.43,3,6.5S4.57,3,6.5,3 M6.5,2 C4.015,2,2,4.014,2,6.5C2,8.985,4.015,11,6.5,11S11,8.985,11,6.5C11,4.014,8.985,2,6.5,2L6.5,2z"/><path fill="#dff0fe" d="M33.5 2.5A4 4 0 1 0 33.5 10.5A4 4 0 1 0 33.5 2.5Z"/><path fill="#4788c7" d="M33.5,3C35.43,3,37,4.57,37,6.5S35.43,10,33.5,10S30,8.43,30,6.5S31.57,3,33.5,3 M33.5,2 C31.015,2,29,4.014,29,6.5c0,2.485,2.015,4.5,4.5,4.5S38,8.985,38,6.5C38,4.014,35.985,2,33.5,2L33.5,2z"/><g><path fill="#dff0fe" d="M6.5 29.5A4 4 0 1 0 6.5 37.5A4 4 0 1 0 6.5 29.5Z"/><path fill="#4788c7" d="M6.5,30c1.93,0,3.5,1.57,3.5,3.5S8.43,37,6.5,37S3,35.43,3,33.5S4.57,30,6.5,30 M6.5,29 C4.015,29,2,31.014,2,33.5C2,35.985,4.015,38,6.5,38s4.5-2.015,4.5-4.5C11,31.014,8.985,29,6.5,29L6.5,29z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M4.893,36.471c0.79-1.355,1.714-3.006,2.561-4.577l0.198-0.369l-0.328-0.261 C3.568,28.296,1.5,24.295,1.5,20C1.5,11.453,9.799,4.5,20,4.5S38.5,11.453,38.5,20S30.201,35.5,20,35.5 c-2.174,0-4.34-0.331-6.437-0.985l-0.162-0.051l-0.16,0.06C10.296,35.617,7.255,36.322,4.893,36.471z"/><path fill="#4788c7" d="M20,5c9.925,0,18,6.729,18,15s-8.075,15-18,15c-2.123,0-4.239-0.324-6.287-0.962l-0.326-0.102 l-0.32,0.119c-2.521,0.936-5.108,1.583-7.26,1.831c0.671-1.171,1.402-2.487,2.086-3.756l0.398-0.739l-0.658-0.52 C4,28.001,2,24.14,2,20C2,11.729,10.075,5,20,5 M20,4C9.507,4,1,11.163,1,20c0,4.601,2.32,8.737,6.013,11.656 C5.947,33.635,4.837,35.596,4,37c2.597,0,6.172-0.803,9.415-2.007C15.47,35.633,17.681,36,20,36c10.493,0,19-7.163,19-16 S30.493,4,20,4L20,4z"/><path fill="#4788c7" d="M30.5 17h-21C9.225 17 9 16.775 9 16.5l0 0C9 16.225 9.225 16 9.5 16h21c.275 0 .5.225.5.5l0 0C31 16.775 30.775 17 30.5 17zM30.5 21h-21C9.225 21 9 20.775 9 20.5l0 0C9 20.225 9.225 20 9.5 20h21c.275 0 .5.225.5.5l0 0C31 20.775 30.775 21 30.5 21zM19.5 25h-10C9.225 25 9 24.775 9 24.5l0 0C9 24.225 9.225 24 9.5 24h10c.275 0 .5.225.5.5l0 0C20 24.775 19.775 25 19.5 25z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M4,27.5c-1.379,0-2.5-1.122-2.5-2.5V4c0-1.378,1.121-2.5,2.5-2.5h32c1.379,0,2.5,1.122,2.5,2.5v21 c0,1.378-1.121,2.5-2.5,2.5H4z"/><path fill="#4788c7" d="M36,2c1.103,0,2,0.897,2,2v21c0,1.103-0.897,2-2,2H4c-1.103,0-2-0.897-2-2V4c0-1.103,0.897-2,2-2 H36 M36,1H4C2.343,1,1,2.343,1,4v21c0,1.657,1.343,3,3,3h32c1.657,0,3-1.343,3-3V4C39,2.343,37.657,1,36,1L36,1z"/><path fill="#dff0fe" d="M4,38.5c-1.379,0-2.5-1.122-2.5-2.5v-6c0-1.378,1.121-2.5,2.5-2.5h32c1.379,0,2.5,1.122,2.5,2.5v6 c0,1.378-1.121,2.5-2.5,2.5H4z"/><path fill="#4788c7" d="M36,28c1.103,0,2,0.897,2,2v6c0,1.103-0.897,2-2,2H4c-1.103,0-2-0.897-2-2v-6c0-1.103,0.897-2,2-2 H36 M36,27H4c-1.657,0-3,1.343-3,3v6c0,1.657,1.343,3,3,3h32c1.657,0,3-1.343,3-3v-6C39,28.343,37.657,27,36,27L36,27z"/><path fill="#b6dcfe" d="M5.5 5.5H34.5V23.5H5.5z"/><path fill="#4788c7" d="M34 6v17H6V6H34M35 5H5v19h30V5L35 5zM20.5 33h-15C5.224 33 5 32.776 5 32.5l0 0C5 32.224 5.224 32 5.5 32h15c.276 0 .5.224.5.5l0 0C21 32.776 20.776 33 20.5 33z"/><path fill="#4788c7" d="M15,32.667c0,0-0.63,1.333-2.5,1.333S10,32.667,10,32.667L12.442,32L15,32.667z"/><g><path fill="#98ccfd" d="M33 31.5A1.5 1.5 0 1 0 33 34.5A1.5 1.5 0 1 0 33 31.5Z"/><path fill="#4788c7" d="M33,32c0.551,0,1,0.449,1,1s-0.449,1-1,1s-1-0.449-1-1S32.449,32,33,32 M33,31 c-1.105,0-2,0.895-2,2c0,1.105,0.895,2,2,2c1.105,0,2-0.895,2-2C35,31.895,34.105,31,33,31L33,31z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#98ccfd" d="M30.5,35.5v-0.274c0.61-0.353,1-1.008,1-1.726c0-1.103-0.897-2-2-2s-2,0.897-2,2v2h-15v-2 c0-1.103-0.897-2-2-2s-2,0.897-2,2c0,0.718,0.39,1.373,1,1.726V35.5h-8v-31h37v31H30.5z"/><path fill="#4788c7" d="M38,5v30h-6.505C31.815,34.576,32,34.053,32,33.5c0-1.379-1.121-2.5-2.5-2.5S27,32.121,27,33.5V35 H13v-1.5c0-1.379-1.121-2.5-2.5-2.5S8,32.121,8,33.5c0,0.553,0.185,1.076,0.505,1.5H2V5H38 M39,4H1v32h9v-1.092 c-0.581-0.207-1-0.756-1-1.408c0-0.828,0.672-1.5,1.5-1.5s1.5,0.672,1.5,1.5V36h16v-2.5c0-0.828,0.672-1.5,1.5-1.5 s1.5,0.672,1.5,1.5c0,0.652-0.419,1.202-1,1.408V36h9V4L39,4z"/><path fill="#fff" d="M12 11A4 4 0 1 0 12 19 4 4 0 1 0 12 11zM18 26H6c0-3.314 2.686-6 6-6S18 22.686 18 26zM33 16H23c-.552 0-1-.448-1-1v0c0-.552.448-1 1-1h10c.552 0 1 .448 1 1v0C34 15.552 33.552 16 33 16zM33 20H23c-.552 0-1-.448-1-1v0c0-.552.448-1 1-1h10c.552 0 1 .448 1 1v0C34 19.552 33.552 20 33 20zM33 24H23c-.552 0-1-.448-1-1v0c0-.552.448-1 1-1h10c.552 0 1 .448 1 1v0C34 23.552 33.552 24 33 24z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#b6dcfe" d="M24,30.5c-7.995,0-14.5-6.505-14.5-14.5S16.005,1.5,24,1.5S38.5,8.005,38.5,16S31.995,30.5,24,30.5z"/><path fill="#4788c7" d="M24,2c7.72,0,14,6.28,14,14s-6.28,14-14,14s-14-6.28-14-14S16.28,2,24,2 M24,1 C15.716,1,9,7.716,9,16s6.716,15,15,15s15-6.716,15-15S32.284,1,24,1L24,1z"/><path fill="#4788c7" d="M21 6A1 1 0 1 0 21 8 1 1 0 1 0 21 6zM29 9A2 2 0 1 0 29 13 2 2 0 1 0 29 9z"/><path fill="#dff0fe" d="M17,38.5C8.453,38.5,1.5,31.547,1.5,23S8.453,7.5,17,7.5S32.5,14.453,32.5,23S25.547,38.5,17,38.5z"/><path fill="#4788c7" d="M17,8c8.271,0,15,6.729,15,15s-6.729,15-15,15S2,31.271,2,23S8.729,8,17,8 M17,7 C8.163,7,1,14.163,1,23s7.163,16,16,16s16-7.163,16-16S25.837,7,17,7L17,7z"/><path fill="#4788c7" d="M21 15A1 1 0 1 0 21 17 1 1 0 1 0 21 15zM24.5 21A1.5 1.5 0 1 0 24.5 24 1.5 1.5 0 1 0 24.5 21zM35 15A1 1 0 1 0 35 17 1 1 0 1 0 35 15zM22.5 29A1.5 1.5 0 1 0 22.5 32 1.5 1.5 0 1 0 22.5 29zM8 17A2 2 0 1 0 8 21 2 2 0 1 0 8 17z"/><g><path fill="#4788c7" d="M11 13A1 1 0 1 0 11 15A1 1 0 1 0 11 13Z"/></g><g><path fill="#4788c7" d="M13 26A2 2 0 1 0 13 30A2 2 0 1 0 13 26Z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#98ccfd" d="M20,38.5C9.799,38.5,1.5,30.201,1.5,20S9.799,1.5,20,1.5S38.5,9.799,38.5,20S30.201,38.5,20,38.5z"/><path fill="#4788c7" d="M20,2c9.925,0,18,8.075,18,18s-8.075,18-18,18S2,29.925,2,20S10.075,2,20,2 M20,1 C9.507,1,1,9.507,1,20s8.507,19,19,19s19-8.507,19-19S30.493,1,20,1L20,1z"/><path fill="none" stroke="#fff" stroke-miterlimit="10" stroke-width="3" d="M25.5,16.813L25.5,16.813 c0-2.934-2.378-5.313-5.312-5.313h-0.375c-2.934,0-5.312,2.378-5.312,5.312v6.375c0,2.934,2.378,5.312,5.312,5.312h0.375 c2.934,0,5.312-2.378,5.312-5.312v0"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M4,33.5c-0.827,0-1.5-0.673-1.5-1.5V8c0-0.827,0.673-1.5,1.5-1.5h32c0.827,0,1.5,0.673,1.5,1.5v24 c0,0.827-0.673,1.5-1.5,1.5H4z"/><path fill="#4788c7" d="M36,7c0.551,0,1,0.449,1,1v24c0,0.551-0.449,1-1,1H4c-0.551,0-1-0.449-1-1V8c0-0.551,0.449-1,1-1 H36 M36,6H4C2.895,6,2,6.895,2,8v24c0,1.105,0.895,2,2,2h32c1.105,0,2-0.895,2-2V8C38,6.895,37.105,6,36,6L36,6z"/><path fill="#4788c7" d="M16.938 24.286c-.247.117-.728.208-1.313.208-2.249 0-3.315-1.833-3.315-4.329 0-3.302 1.833-4.589 3.536-4.589.598 0 1.014.117 1.183.234l-.285 1.43c-.195-.091-.416-.169-.793-.169-.963 0-1.834.832-1.834 3.003 0 2.093.794 2.912 1.834 2.912.285 0 .61-.065.818-.13L16.938 24.286zM18.005 22.673c.351.195.962.338 1.442.338.793 0 1.196-.416 1.196-.988 0-.637-.39-.949-1.131-1.43-1.196-.728-1.651-1.651-1.651-2.444 0-1.404.937-2.574 2.756-2.574.586 0 1.132.156 1.379.312l-.273 1.469c-.247-.156-.624-.299-1.105-.299-.728 0-1.078.442-1.078.91 0 .52.26.793 1.195 1.365 1.17.702 1.586 1.586 1.586 2.509 0 1.599-1.183 2.652-2.886 2.652-.702 0-1.378-.182-1.677-.351L18.005 22.673zM23.451 22.673c.352.195.962.338 1.443.338.793 0 1.196-.416 1.196-.988 0-.637-.391-.949-1.132-1.43-1.195-.728-1.65-1.651-1.65-2.444 0-1.404.936-2.574 2.756-2.574.585 0 1.131.156 1.378.312l-.272 1.469c-.247-.156-.624-.299-1.105-.299-.729 0-1.079.442-1.079.91 0 .52.26.793 1.196 1.365 1.17.702 1.586 1.586 1.586 2.509 0 1.599-1.184 2.652-2.886 2.652-.702 0-1.379-.182-1.678-.351L23.451 22.673z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M24.022,23.977c0.271,0.022,0.542,0.034,0.815,0.034C33.302,24.011,38.5,17.598,38.5,13 c0-4.393-3.192-7.46-7.763-7.46c-2.843,0-5.667,1.317-7.951,3.709c-1.852,1.94-3.205,4.437-3.884,7.033 c-2.538-2.004-5.102-4.795-7.36-7.253c-0.325-0.353-0.634-0.686-0.95-1.027L15.093,3.5H2.5v12.593l4.553-4.553 c0.269,0.292,0.531,0.572,0.807,0.872c3.274,3.564,6.836,7.44,10.682,9.688c1.049,8.736,8.001,15.381,16.399,15.381l2.56,0.02v-5 l-2.56-0.02C30.443,32.48,25.688,29.367,24.022,23.977z M23.486,18.83c0.289-2.209,1.354-4.491,2.916-6.128 c1.331-1.395,2.871-2.162,4.334-2.162c1.808,0,2.763,0.851,2.763,2.46c0,1.449-2.606,6.011-8.662,6.011 C24.397,19.011,23.946,18.947,23.486,18.83z"/><path fill="#4788c7" d="M37.5,38c-0.001,0-0.002,0-0.004,0l-2.56-0.02c-8.467,0-15.676-6.679-16.86-15.575 c-3.833-2.305-7.416-6.206-10.584-9.655l-0.453-0.489l-4.186,4.187c-0.144,0.144-0.358,0.185-0.545,0.108 C2.122,16.479,2,16.296,2,16.094V3.5C2,3.224,2.224,3,2.5,3h12.593c0.202,0,0.385,0.122,0.462,0.309 c0.078,0.187,0.035,0.402-0.108,0.545l-4.162,4.162l0.625,0.676c2.082,2.266,4.408,4.797,6.72,6.726 c0.762-2.439,2.092-4.729,3.794-6.514c2.379-2.491,5.332-3.863,8.313-3.863C35.602,5.04,39,8.313,39,13 c0,4.807-5.388,11.511-14.162,11.511c-0.035,0-0.07,0-0.105-0.001c1.664,4.433,6.013,7.539,10.453,7.539l2.563,0.02 C38.024,32.071,38,32.226,38,32.5v5c0,0.133-0.053,0.261-0.148,0.354C37.758,37.948,37.632,38,37.5,38z M7.053,11.04 c0.003,0,0.007,0,0.01,0c0.136,0.003,0.265,0.062,0.357,0.161l0.807,0.872c3.18,3.462,6.783,7.385,10.566,9.595 c0.135,0.079,0.225,0.217,0.244,0.372c1.023,8.518,7.859,14.94,15.902,14.972L37,37.027v-4.031l-2.063-0.016 c-5.094,0-9.78-3.642-11.392-8.856c-0.049-0.158-0.016-0.331,0.088-0.461c0.104-0.129,0.256-0.198,0.431-0.185 c0.257,0.021,0.515,0.032,0.774,0.032C32.993,23.511,38,17.389,38,13c0-4.098-2.987-6.96-7.263-6.96 c-2.705,0-5.4,1.263-7.589,3.555c-1.758,1.842-3.094,4.262-3.762,6.814c-0.043,0.163-0.165,0.294-0.325,0.347 c-0.16,0.054-0.336,0.023-0.469-0.081c-2.564-2.025-5.136-4.824-7.405-7.293l-0.962-1.04c-0.182-0.197-0.176-0.504,0.014-0.693 L13.886,4H3v10.887l3.7-3.7C6.793,11.093,6.921,11.04,7.053,11.04z M24.838,19.511c-0.468,0-0.964-0.066-1.475-0.196 c-0.245-0.063-0.405-0.298-0.372-0.549c0.304-2.331,1.445-4.728,3.05-6.409c1.426-1.493,3.094-2.316,4.696-2.316 C32.811,10.04,34,11.119,34,13C34,14.569,31.244,19.511,24.838,19.511z M24.053,18.44c0.272,0.047,0.535,0.07,0.785,0.07 C30.456,18.511,33,14.283,33,13c0-1.319-0.74-1.96-2.263-1.96c-1.326,0-2.737,0.713-3.973,2.008 C25.404,14.472,24.41,16.459,24.053,18.44z"/><path fill="#4788c7" d="M23.563,24.187c-0.536-1.978-0.708-3.766-0.563-5.421l0.979,0.11 c-0.135,1.536,0.044,3.188,0.548,5.049L23.563,24.187z"/><g><path fill="#4788c7" d="M18.013,22.315c-0.216-2.356-0.08-4.403,0.416-6.258l0.966,0.258 c-0.411,1.794-0.55,3.672-0.345,5.908L18.013,22.315z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M20,20.5c-5.238,0-9.5-4.262-9.5-9.5s4.262-9.5,9.5-9.5s9.5,4.262,9.5,9.5S25.238,20.5,20,20.5z"/><path fill="#4788c7" d="M20,2c4.963,0,9,4.037,9,9s-4.037,9-9,9s-9-4.037-9-9S15.037,2,20,2 M20,1c-5.523,0-10,4.477-10,10 c0,5.523,4.477,10,10,10s10-4.477,10-10C30,5.477,25.523,1,20,1L20,1z"/><g><path fill="#b6dcfe" d="M2.5,38.5v-2.299c0-7.608,11.157-10.49,12.021-10.701h10.959C26.343,25.711,37.5,28.592,37.5,36.201 V38.5H2.5z"/><path fill="#4788c7" d="M25.419,26C26.572,26.289,37,29.106,37,36.201V38H3v-1.799C3,29.106,13.428,26.289,14.581,26 H25.419 M25.538,25H14.462C14.462,25,2,27.827,2,36.201c0,0,0,1.204,0,2.799h36c0-1.595,0-2.799,0-2.799 C38,27.827,25.538,25,25.538,25L25.538,25z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M20,38.5c-7.859,0-14.5-2.748-14.5-6V7h29v25.5C34.5,35.752,27.859,38.5,20,38.5z"/><path fill="#4788c7" d="M34,7.5v25c0,2.601-5.75,5.5-14,5.5S6,35.101,6,32.5v-25H34 M35,6.5H5c0,1.29,0,24.71,0,26 c0,3.59,6.716,6.5,15,6.5s15-2.91,15-6.5C35,31.21,35,7.79,35,6.5L35,6.5z"/><path fill="#dff0fe" d="M20,11.5c-8.674,0-14.5-2.585-14.5-5s5.826-5,14.5-5s14.5,2.585,14.5,5S28.674,11.5,20,11.5z"/><path fill="#4788c7" d="M20,2c8.674,0,14,2.621,14,4.5S28.674,11,20,11S6,8.379,6,6.5S11.326,2,20,2 M20,1 C11.716,1,5,3.462,5,6.5S11.716,12,20,12s15-2.462,15-5.5S28.284,1,20,1L20,1z"/><path fill="#dff0fe" stroke="#4788c7" stroke-miterlimit="10" d="M34.5 15.183c0 2.936-6.492 5.317-14.5 5.317S5.5 18.12 5.5 15.183M5.5 23.217c0 3.47 6.492 6.283 14.5 6.283s14.5-2.813 14.5-6.283"/><g><path fill="#98ccfd" d="M31.999,39.468c-1.104-0.43-7.363-3.36-7.497-14.532L32,22.525l7.498,2.41 C39.364,36.079,33.104,39.033,31.999,39.468z"/><path fill="#4788c7" d="M32,23.05l6.991,2.247c-0.249,10.018-5.619,13.023-6.992,13.629 c-1.382-0.604-6.742-3.592-6.99-13.629L32,23.05 M32,22l-8,2.571C24,37.428,32,40,32,40s8-2.607,8-15.429L32,22L32,22z"/></g><path fill="#dff0fe" d="M31.994,36.648c-1.502-0.984-4.361-3.656-4.904-9.919L32,25.151l4.91,1.578 C36.369,32.981,33.526,35.649,31.994,36.648z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M20,38.5c-7.859,0-14.5-2.748-14.5-6V7h29v25.5C34.5,35.752,27.859,38.5,20,38.5z"/><path fill="#4788c7" d="M34,7.5v25c0,2.601-5.75,5.5-14,5.5S6,35.101,6,32.5v-25H34 M35,6.5H5c0,1.29,0,24.71,0,26 c0,3.59,6.716,6.5,15,6.5s15-2.91,15-6.5C35,31.21,35,7.79,35,6.5L35,6.5z"/><path fill="#dff0fe" d="M20,11.5c-8.674,0-14.5-2.585-14.5-5s5.826-5,14.5-5s14.5,2.585,14.5,5S28.674,11.5,20,11.5z"/><path fill="#4788c7" d="M20,2c8.674,0,14,2.621,14,4.5S28.674,11,20,11S6,8.379,6,6.5S11.326,2,20,2 M20,1 C11.716,1,5,3.462,5,6.5S11.716,12,20,12s15-2.462,15-5.5S28.284,1,20,1L20,1z"/><path fill="#4788c7" d="M20,30c-8.411,0-15-2.979-15-6.783h1C6,26.352,12.411,29,20,29s14-2.648,14-5.783h1 C35,27.021,28.411,30,20,30z M20,21c-8.411,0-15-2.556-15-5.817h1C6,17.509,11.626,20,20,20s14-2.491,14-4.817h1 C35,18.444,28.411,21,20,21z"/><path fill="#dff0fe" d="M24,30h5v-6h6c0-0.66,0-1.329,0-2h-3l-5,2v4h-7.161l7.958,10.063 c0.723-0.193,1.678-0.491,2.313-0.734L24,30z"/><path fill="#dff0fe" d="M18.898,1.021c1.254-0.068,9.856-0.003,16.102,0l0,20.812l-6.458-2.91h-9.644L18.898,1.021z"/><path fill="#fff" d="M21.5,16.5v-15h17v15H21.5z"/><path fill="#4788c7" d="M39,17H21V1h18V17z M22,16h16V2H22V16z"/><path fill="#b6dcfe" d="M21.5,1.5h17v3h-17V1.5z"/><path fill="#4788c7" d="M39,5H21V1h18V5z M22,4h16V2H22V4z"/><path fill="#b6dcfe" d="M22,15h16v1H22V15z"/><rect width="2" height="2" x="33" y="6" fill="#b6dcfe"/><rect width="2" height="2" x="29" y="6" fill="#b6dcfe"/><rect width="2" height="2" x="25" y="6" fill="#b6dcfe"/><rect width="2" height="2" x="33" y="9" fill="#b6dcfe"/><rect width="2" height="2" x="29" y="9" fill="#b6dcfe"/><rect width="2" height="2" x="25" y="9" fill="#b6dcfe"/><rect width="2" height="2" x="33" y="12" fill="#b6dcfe"/><rect width="2" height="2" x="29" y="12" fill="#b6dcfe"/><rect width="2" height="2" x="25" y="12" fill="#b6dcfe"/><rect width="1.313" height="6.504" x="33.681" y="18.369" fill="#dff0fe"/><path fill="#98ccfd" d="M25.04,30.5h4.46v-6h5v6h4.46L32,39.2L25.04,30.5z"/><path fill="#4788c7" d="M32,40.001L24,30h5v-6h6v6h5L32,40.001z M26.08,31L32,38.399L37.92,31H34v-6h-4v6H26.08z"/><path fill="#4788c7" d="M18.406,2.016c-0.272,0-0.496-0.219-0.5-0.493c-0.004-0.275,0.217-0.503,0.493-0.507L19.472,1 c0.002,0,0.005,0,0.007,0c0.272,0,0.496,0.219,0.5,0.493C19.982,1.769,19.762,1.996,19.485,2l-1.072,0.016 C18.411,2.016,18.408,2.016,18.406,2.016z"/><path fill="#4788c7" d="M19.338,12c-0.005,0-0.011,0-0.017,0l-0.479-0.016c-0.275-0.01-0.492-0.24-0.483-0.517 c0.01-0.275,0.201-0.47,0.517-0.483L19.354,11c0.275,0.01,0.492,0.24,0.483,0.517C19.829,11.787,19.606,12,19.338,12z"/><g><path fill="#4788c7" d="M26.797,38.29c-0.226,0-0.431-0.153-0.486-0.382c-0.064-0.269,0.1-0.539,0.368-0.604l0.938-0.228 c0.272-0.061,0.539,0.101,0.604,0.368c0.064,0.269-0.1,0.539-0.368,0.604l-0.938,0.228C26.875,38.285,26.836,38.29,26.797,38.29z"/></g><g><path fill="#4788c7" d="M21.516,30h-1.547c-0.276,0-0.5-0.224-0.5-0.5s0.224-0.5,0.5-0.5h1.547c0.276,0,0.5,0.224,0.5,0.5 S21.792,30,21.516,30z"/></g><g><path fill="#4788c7" d="M28.391,20.016c-0.224,0-0.427-0.15-0.484-0.377C27.838,19.371,28,19.1,28.268,19.031l1.656-0.422 c0.271-0.072,0.539,0.094,0.607,0.361s-0.094,0.539-0.361,0.607L28.514,20C28.473,20.011,28.431,20.016,28.391,20.016z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M20,38.5c-7.859,0-14.5-2.748-14.5-6V7h29v25.5C34.5,35.752,27.859,38.5,20,38.5z"/><path fill="#4788c7" d="M34,7.5v25c0,2.601-5.75,5.5-14,5.5S6,35.101,6,32.5v-25H34 M35,6.5H5c0,1.29,0,24.71,0,26 c0,3.59,6.716,6.5,15,6.5s15-2.91,15-6.5C35,31.21,35,7.79,35,6.5L35,6.5z"/><path fill="#dff0fe" d="M20,11.5c-8.674,0-14.5-2.585-14.5-5s5.826-5,14.5-5s14.5,2.585,14.5,5S28.674,11.5,20,11.5z"/><path fill="#4788c7" d="M20,2c8.674,0,14,2.621,14,4.5S28.674,11,20,11S6,8.379,6,6.5S11.326,2,20,2 M20,1 C11.716,1,5,3.462,5,6.5S11.716,12,20,12s15-2.462,15-5.5S28.284,1,20,1L20,1z"/><path fill="#4788c7" d="M20,30c-8.411,0-15-2.979-15-6.783h1C6,26.352,12.411,29,20,29s14-2.648,14-5.783h1 C35,27.021,28.411,30,20,30z M20,21c-8.411,0-15-2.556-15-5.817h1C6,17.509,11.626,20,20,20s14-2.491,14-4.817h1 C35,18.444,28.411,21,20,21z"/><path fill="#dff0fe" d="M35,36V20.851L32,22l-5,2v4h-5.563l5.092,10.357c1.033-0.169,2.946-0.786,3.58-1.029L35,36z"/><path fill="#dff0fe" d="M18.898,1.021c1.254-0.068,9.856-0.003,16.102,0l0,20.812l-6.458-2.91h-9.644L18.898,1.021z"/><path fill="#fff" d="M21.5,16.5v-15h17v15H21.5z"/><path fill="#4788c7" d="M39,17H21V1h18V17z M22,16h16V2H22V16z"/><path fill="#b6dcfe" d="M21.5,1.5h17v3h-17V1.5z"/><path fill="#4788c7" d="M39,5H21V1h18V5z M22,4h16V2H22V4z"/><path fill="#b6dcfe" d="M22,15h16v1H22V15z"/><rect width="2" height="2" x="33" y="6" fill="#b6dcfe"/><rect width="2" height="2" x="29" y="6" fill="#b6dcfe"/><rect width="2" height="2" x="25" y="6" fill="#b6dcfe"/><rect width="2" height="2" x="33" y="9" fill="#b6dcfe"/><rect width="2" height="2" x="29" y="9" fill="#b6dcfe"/><rect width="2" height="2" x="25" y="9" fill="#b6dcfe"/><rect width="2" height="2" x="33" y="12" fill="#b6dcfe"/><rect width="2" height="2" x="29" y="12" fill="#b6dcfe"/><rect width="2" height="2" x="25" y="12" fill="#b6dcfe"/><path fill="#98ccfd" d="M25.04,32.5h4.46v6h5v-6h4.46L32,23.8L25.04,32.5z"/><path fill="#4788c7" d="M35,39h-6v-6h-5l8-10.001L40,33h-5V39z M30,38h4v-6h3.92L32,24.601L26.08,32H30V38z"/><path fill="#4788c7" d="M18.406,2.016c-0.272,0-0.496-0.219-0.5-0.493c-0.004-0.275,0.217-0.503,0.493-0.507L19.472,1 c0.002,0,0.005,0,0.007,0c0.272,0,0.496,0.219,0.5,0.493C19.982,1.769,19.762,1.996,19.485,2l-1.072,0.016 C18.411,2.016,18.408,2.016,18.406,2.016z"/><path fill="#4788c7" d="M19.338,12c-0.005,0-0.011,0-0.017,0l-0.479-0.016c-0.275-0.01-0.492-0.24-0.483-0.517 c0.009-0.271,0.231-0.483,0.5-0.483c0.005,0,0.011,0,0.017,0L19.354,11c0.275,0.01,0.492,0.24,0.483,0.517 C19.829,11.787,19.606,12,19.338,12z"/><g><path fill="#4788c7" d="M25.202,38.594c-0.234,0-0.443-0.166-0.49-0.405c-0.052-0.271,0.125-0.533,0.396-0.586l1.375-0.266 c0.266-0.05,0.532,0.125,0.586,0.396c0.052,0.271-0.125,0.533-0.396,0.586l-1.375,0.266C25.266,38.591,25.234,38.594,25.202,38.594 z"/></g><g><path fill="#4788c7" d="M21.641,29.955c-0.269,0-0.491-0.214-0.5-0.484c-0.009-0.275,0.208-0.507,0.484-0.516 c0.489-0.016,0.992-0.068,1.425-0.114l0.117-0.012c0.27-0.031,0.521,0.171,0.549,0.445c0.029,0.274-0.171,0.521-0.445,0.549 l-0.116,0.013c-0.455,0.048-0.983,0.103-1.498,0.119C21.651,29.955,21.646,29.955,21.641,29.955z"/></g><g><path fill="#4788c7" d="M28.391,20.016c-0.224,0-0.427-0.15-0.484-0.377C27.838,19.371,28,19.1,28.268,19.031l1.656-0.422 c0.27-0.072,0.539,0.094,0.607,0.361s-0.094,0.539-0.361,0.607L28.514,20C28.473,20.011,28.431,20.016,28.391,20.016z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M20,38.5c-7.859,0-14.5-2.748-14.5-6V7h29v25.5C34.5,35.752,27.859,38.5,20,38.5z"/><path fill="#4788c7" d="M34,7.5v25c0,2.601-5.75,5.5-14,5.5S6,35.101,6,32.5v-25H34 M35,6.5H5c0,1.29,0,24.71,0,26c0,3.59,6.716,6.5,15,6.5s15-2.91,15-6.5C35,31.21,35,7.79,35,6.5L35,6.5z"/><path fill="#dff0fe" d="M20,11.5c-8.674,0-14.5-2.585-14.5-5s5.826-5,14.5-5s14.5,2.585,14.5,5S28.674,11.5,20,11.5z"/><path fill="#4788c7" d="M20,2c8.674,0,14,2.621,14,4.5S28.674,11,20,11S6,8.379,6,6.5S11.326,2,20,2 M20,1C11.716,1,5,3.462,5,6.5S11.716,12,20,12s15-2.462,15-5.5S28.284,1,20,1L20,1z"/><path fill="none" stroke="#4788c7" stroke-miterlimit="10" d="M34.5 15.183c0 2.936-6.492 5.317-14.5 5.317S5.5 18.12 5.5 15.183M5.5 23.217c0 3.47 6.492 6.283 14.5 6.283s14.5-2.813 14.5-6.283"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#b6dcfe" d="M1.512,35.5c0.269-5.559,4.982-10,10.738-10h7.5c5.756,0,10.47,4.441,10.738,10H1.512z"/><path fill="#4788c7" d="M19.75,26c5.306,0,9.683,3.954,10.199,9H2.051c0.516-5.046,4.893-9,10.199-9H19.75 M19.75,25h-7.5 C6.037,25,1,29.925,1,36h30C31,29.925,25.963,25,19.75,25L19.75,25z"/><path fill="#fff" d="M16,28.5c-3.055,0-4.3-2.645-4.5-3.124v-5.467h9v5.469C20.297,25.875,19.075,28.5,16,28.5z"/><path fill="#4788c7" d="M20,20.41v4.865C19.737,25.865,18.607,28,16,28c-2.611,0-3.741-2.141-4-2.725V20.41H20 M21,19.41 H11v6.062c0,0,1.267,3.529,5,3.529s5-3.529,5-3.529V19.41L21,19.41z"/><path fill="#dff0fe" d="M22.429,17.643c-1.143,0-2.071-0.929-2.071-2.071s0.929-2.071,2.071-2.071 c1.725,0,2.071,0.465,2.071,1.214C24.5,15.966,23.476,17.643,22.429,17.643z M9.571,17.643c-1.047,0-2.071-1.677-2.071-2.929 c0-0.749,0.347-1.214,2.071-1.214c1.143,0,2.071,0.929,2.071,2.071S10.714,17.643,9.571,17.643z"/><path fill="#4788c7" d="M22.429,14C24,14,24,14.363,24,14.714c0,1.044-0.896,2.429-1.571,2.429 c-0.867,0-1.571-0.705-1.571-1.571S21.562,14,22.429,14 M9.571,14c0.867,0,1.571,0.705,1.571,1.571s-0.705,1.571-1.571,1.571 C8.896,17.143,8,15.758,8,14.714C8,14.363,8,14,9.571,14 M22.429,13c-1.42,0-2.571,1.151-2.571,2.571s1.151,2.571,2.571,2.571 S25,16.134,25,14.714S23.849,13,22.429,13L22.429,13z M9.571,13C8.151,13,7,13.294,7,14.714s1.151,3.429,2.571,3.429 s2.571-1.151,2.571-2.571S10.992,13,9.571,13L9.571,13z"/><path fill="#fff" d="M16,24.5c-0.58,0-1.135-0.224-1.56-0.631l-0.09-0.086l-0.12-0.034 C11.445,22.963,9.5,20.393,9.5,17.5V9.364c0-1.564,1.272-2.837,2.836-2.837h7.328c1.563,0,2.836,1.272,2.836,2.837V17.5 c0,2.893-1.945,5.463-4.73,6.249l-0.12,0.034l-0.09,0.086C17.135,24.276,16.58,24.5,16,24.5z"/><path fill="#4788c7" d="M19.664,7.028C20.952,7.028,22,8.076,22,9.364V17.5c0,2.67-1.796,5.042-4.367,5.768l-0.239,0.068 l-0.18,0.172C16.882,23.825,16.451,24,16,24s-0.882-0.175-1.215-0.492l-0.18-0.172l-0.239-0.068C11.796,22.542,10,20.17,10,17.5 V9.364c0-1.288,1.048-2.336,2.336-2.336H19.664 M19.664,6.028h-7.328C10.494,6.028,9,7.521,9,9.364V17.5 c0,3.205,2.156,5.9,5.095,6.731C14.591,24.705,15.26,25,16,25s1.409-0.295,1.905-0.769C20.844,23.4,23,20.705,23,17.5V9.364 C23,7.521,21.506,6.028,19.664,6.028L19.664,6.028z"/><g><path fill="#b6dcfe" d="M22.5,15.5V12c0-3.484-2.218-4.425-2.312-4.463l-0.343-0.14l-0.234,0.287 C19.589,7.713,17.283,10.5,14,10.5c-2.005,0-4.5,0-4.5,2.5v2.5H9.285C8.845,14.727,7.5,12.151,7.5,9.576 C7.5,4.821,10.995,1.5,16,1.5c3.095,0,4.543,2.704,4.557,2.731l0.119,0.228l0.253,0.036C22.462,4.715,24.5,5.524,24.5,10 c0,2.334-1.338,4.763-1.778,5.5H22.5z"/><path fill="#4788c7" d="M16,2c2.762,0,4.062,2.367,4.113,2.463l0.237,0.454l0.507,0.073C22.321,5.199,24,5.958,24,10 c0,1.395-0.515,2.842-1,3.894V12c0-3.816-2.516-4.883-2.623-4.926l-0.687-0.279l-0.467,0.577C19.201,7.397,17.06,10,14,10 c-1.87,0-5,0-5,3v0.801c-0.486-1.124-1-2.679-1-4.225C8,5.115,11.29,2,16,2 M16,1c-5.36,0-9,3.667-9,8.576C7,12.828,9,16,9,16h1 c0,0,0-2.105,0-3c0-2,2.042-2,4-2c3.573,0,6-3,6-3s2,0.813,2,4c0,0.984,0,4,0,4h1c0,0,2-3.037,2-6c0-4.161-1.703-5.671-4-6 C21,4,19.434,1,16,1L16,1z"/></g><g><path fill="#98ccfd" d="M31,39.5c-4.687,0-8.5-3.813-8.5-8.5s3.813-8.5,8.5-8.5s8.5,3.813,8.5,8.5S35.687,39.5,31,39.5z"/><path fill="#4788c7" d="M31,23c4.411,0,8,3.589,8,8c0,4.411-3.589,8-8,8s-8-3.589-8-8C23,26.589,26.589,23,31,23 M31,22 c-4.971,0-9,4.029-9,9c0,4.971,4.029,9,9,9s9-4.029,9-9C40,26.029,35.971,22,31,22L31,22z"/></g><path fill="none" stroke="#fff" stroke-miterlimit="10" stroke-width="2" d="M27.5 34.5L34.5 27.5M27.5 27.5L34.5 34.5"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="40px" height="40px"><path fill="#98ccfd" d="M10,37.5c-4.136,0-7.5-3.364-7.5-7.5V10c0-4.136,3.364-7.5,7.5-7.5h20c4.136,0,7.5,3.364,7.5,7.5v20 c0,4.136-3.364,7.5-7.5,7.5H10z"/><path fill="#4788c7" d="M30,3c3.86,0,7,3.14,7,7v20c0,3.86-3.14,7-7,7H10c-3.86,0-7-3.14-7-7V10c0-3.86,3.14-7,7-7H30 M30,2H10c-4.418,0-8,3.582-8,8v20c0,4.418,3.582,8,8,8h20c4.418,0,8-3.582,8-8V10C38,5.582,34.418,2,30,2L30,2z"/><g><path fill="#fff" d="M30.909,11.909c0,0-3.126-2.446-6.818-2.727l-0.333,0.665c3.338,0.817,4.87,1.987,6.469,3.425 C27.469,11.865,24.746,11,20,11s-7.469,0.865-10.227,2.273c1.6-1.438,3.421-2.737,6.469-3.425l-0.333-0.665 c-3.873,0.366-6.818,2.727-6.818,2.727s-3.492,5.062-4.091,15C8.52,30.968,13.864,31,13.864,31l1.118-1.49 c-1.897-0.659-4.039-1.837-5.89-3.965C11.299,27.216,14.631,29,20,29s8.701-1.784,10.909-3.455 c-1.851,2.128-3.993,3.305-5.89,3.965L26.136,31c0,0,5.344-0.032,8.864-4.091C34.401,16.972,30.909,11.909,30.909,11.909z M15.541,24.3c-1.318,0-2.432-1.118-2.432-2.624s1.114-2.838,2.432-2.838s2.432,1.332,2.432,2.838S16.858,24.3,15.541,24.3z M24.459,24.3c-1.318,0-2.432-1.118-2.432-2.624s1.114-2.838,2.432-2.838c1.318,0,2.432,1.332,2.432,2.838S25.777,24.3,24.459,24.3 z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#98ccfd" d="M9,24.5c-0.275,0-0.5-0.224-0.5-0.5v-2.309L5.118,20L8.5,18.309V16c0-0.276,0.225-0.5,0.5-0.5h27 c0.275,0,0.5,0.224,0.5,0.5v8c0,0.276-0.225,0.5-0.5,0.5H9z"/><path fill="#4788c7" d="M36,16v8H9v-2v-0.618l-0.553-0.276L6.236,20l2.211-1.106L9,18.618V18v-2H36 M36,15H9 c-0.55,0-1,0.45-1,1v2l-4,2l4,2v2c0,0.55,0.45,1,1,1h27c0.55,0,1-0.45,1-1v-8C37,15.45,36.55,15,36,15L36,15z"/><path fill="#b6dcfe" d="M6,11.5c-0.275,0-0.5-0.224-0.5-0.5V8.691L2.118,7L5.5,5.309V3c0-0.276,0.225-0.5,0.5-0.5h27 c0.275,0,0.5,0.224,0.5,0.5v8c0,0.276-0.225,0.5-0.5,0.5H6z"/><path fill="#4788c7" d="M33,3v8H6V9V8.382L5.447,8.106L3.236,7l2.211-1.106L6,5.618V5V3H33 M33,2H6C5.45,2,5,2.45,5,3v2 L1,7l4,2v2c0,0.55,0.45,1,1,1h27c0.55,0,1-0.45,1-1V3C34,2.45,33.55,2,33,2L33,2z"/><g><path fill="#dff0fe" d="M11,37.5c-0.275,0-0.5-0.224-0.5-0.5v-2.309L7.118,33l3.382-1.691V29c0-0.276,0.225-0.5,0.5-0.5h27 c0.275,0,0.5,0.224,0.5,0.5v8c0,0.276-0.225,0.5-0.5,0.5H11z"/><path fill="#4788c7" d="M38,29v8H11v-2v-0.618l-0.553-0.276L8.236,33l2.211-1.106L11,31.618V31v-2H38 M38,28H11 c-0.55,0-1,0.45-1,1v2l-4,2l4,2v2c0,0.55,0.45,1,1,1h27c0.55,0,1-0.45,1-1v-8C39,28.45,38.55,28,38,28L38,28z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#b6dcfe" d="M39,20c0,10.578-8.618,19-19,19C9.619,39,1,30.578,1,20S9.422,1,20,1S39,9.422,39,20z"/><path fill="#dff0fe" d="M36.453,11.5H3.547C2.245,14.04,1.5,16.922,1.5,20s0.762,5.96,2.083,8.5h32.835 c1.32-2.54,2.083-5.422,2.083-8.5S37.755,14.04,36.453,11.5z"/><path fill="#dff0fe" d="M36.721,29H3.279l-0.14-0.27C1.72,26,1,23.063,1,20c0-3.07,0.707-6.007,2.102-8.729L3.241,11h33.518 l0.14,0.271C38.293,13.993,39,16.93,39,20c0,3.064-0.72,6.002-2.14,8.73L36.721,29z M3.89,28H36.11c1.254-2.509,1.89-5.198,1.89-8 c0-2.808-0.624-5.498-1.855-8H3.855C2.624,14.502,2,17.192,2,20C2,22.8,2.636,25.489,3.89,28z"/><path fill="#4788c7" d="M7.5,24.5v-9h2.796c2.803,0,4.204,1.463,4.204,4.387c0,1.402-0.383,2.521-1.147,3.358 c-0.765,0.837-1.784,1.255-3.057,1.255H7.5z M9.5,17.503v5h0.788c0.69,0,1.231-0.231,1.623-0.693 c0.393-0.462,0.589-1.091,0.589-1.887c0-0.751-0.195-1.343-0.584-1.774c-0.389-0.431-0.935-0.646-1.638-0.646H9.5z"/><path fill="#4788c7" d="M24.598,24.516h-2.1l-3.722-5.675l-0.199-0.347v6.021h-2.15v-9.032h2.192l3.584,5.499l0.246,0.308 v-5.806h2.15V24.516z"/><path fill="#4788c7" d="M27.088,24.125v-1.995c0.38,0.304,0.793,0.531,1.239,0.683c0.446,0.152,0.896,0.228,1.351,0.228 c0.267,0,0.499-0.023,0.698-0.069c0.199-0.046,0.365-0.109,0.498-0.19c0.133-0.081,0.233-0.177,0.298-0.287 c0.066-0.11,0.098-0.23,0.098-0.359c0-0.175-0.052-0.331-0.157-0.467c-0.105-0.138-0.248-0.264-0.43-0.381 c-0.181-0.117-0.397-0.229-0.646-0.337c-0.249-0.108-0.518-0.218-0.806-0.33c-0.734-0.291-1.282-0.647-1.642-1.066 c-0.36-0.42-0.541-0.927-0.541-1.521c0-0.466,0.098-0.866,0.295-1.2c0.197-0.335,0.464-0.61,0.803-0.826 c0.339-0.216,0.731-0.375,1.177-0.477c0.446-0.102,0.918-0.153,1.416-0.153c0.489,0,0.923,0.028,1.302,0.084 c0.378,0.056,0.727,0.142,1.046,0.258v1.865c-0.157-0.104-0.329-0.195-0.515-0.274c-0.186-0.079-0.377-0.144-0.574-0.197 c-0.197-0.052-0.392-0.09-0.587-0.115c-0.195-0.025-0.379-0.037-0.554-0.037c-0.24,0-0.459,0.022-0.656,0.065 c-0.197,0.044-0.363,0.105-0.498,0.184c-0.135,0.079-0.24,0.174-0.315,0.284c-0.074,0.11-0.111,0.234-0.111,0.371 c0,0.15,0.042,0.284,0.125,0.403c0.083,0.118,0.201,0.23,0.354,0.337c0.153,0.106,0.339,0.21,0.557,0.312 c0.219,0.102,0.465,0.207,0.741,0.315c0.376,0.15,0.714,0.309,1.013,0.477c0.299,0.169,0.556,0.359,0.77,0.571 c0.214,0.212,0.378,0.454,0.492,0.726s0.17,0.59,0.17,0.951c0,0.499-0.099,0.918-0.298,1.257c-0.199,0.339-0.469,0.613-0.81,0.823 s-0.738,0.361-1.19,0.452c-0.453,0.091-0.93,0.137-1.433,0.137c-0.516,0-1.006-0.041-1.472-0.125 C27.832,24.416,27.429,24.291,27.088,24.125z"/><rect width="25.5" height="1" x="7.25" y="6" fill="#4788c7"/><rect width="25.5" height="1" x="7.25" y="33" fill="#4788c7"/><path fill="#4788c7" d="M20,39C9.523,39,1,30.477,1,20C1,9.346,9.346,1,20,1s19,8.346,19,19C39,30.477,30.477,39,20,39z M20,2C9.906,2,2,9.906,2,20c0,9.925,8.075,18,18,18s18-8.075,18-18C38,9.906,30.094,2,20,2z"/><path fill="#4788c7" d="M20,39c-4.751,0-9.121-3.78-11.405-9.865c-0.098-0.259,0.033-0.547,0.292-0.644 c0.255-0.099,0.546,0.034,0.644,0.292C11.665,34.469,15.677,38,20,38c4.315,0,8.324-3.522,10.461-9.193 c0.097-0.259,0.383-0.391,0.645-0.291c0.258,0.098,0.389,0.386,0.291,0.645C29.109,35.229,24.742,39,20,39z"/><g><path fill="#4788c7" d="M9.041,11.525c-0.058,0-0.116-0.01-0.174-0.031c-0.259-0.096-0.391-0.384-0.295-0.643 C10.828,4.774,15.207,1,20,1c4.786,0,9.162,3.767,11.42,9.83c0.096,0.259-0.035,0.547-0.294,0.644 c-0.261,0.099-0.547-0.035-0.644-0.294C28.374,5.518,24.357,2,20,2c-4.364,0-8.384,3.525-10.49,9.199 C9.435,11.401,9.244,11.525,9.041,11.525z"/></g><g><path fill="#4788c7" d="M20,39c-2.773,0-4.019-6.936-4.425-9.918c-0.038-0.273,0.154-0.525,0.428-0.563 c0.269-0.05,0.525,0.153,0.563,0.428C17.414,35.167,18.94,38,20,38c1.063,0,2.591-2.841,3.438-9.077 c0.037-0.273,0.295-0.476,0.563-0.428c0.273,0.037,0.465,0.289,0.428,0.563C24.023,32.047,22.778,39,20,39z"/></g><g><path fill="#4788c7" d="M16.058,11.51c-0.022,0-0.045-0.001-0.067-0.005c-0.273-0.036-0.466-0.288-0.429-0.562 C15.962,7.954,17.197,1,20,1c2.799,0,4.033,6.931,4.434,9.91c0.037,0.273-0.154,0.525-0.429,0.562 c-0.272,0.044-0.525-0.155-0.562-0.429C22.607,4.83,21.072,2,20,2c-1.074,0-2.611,2.84-3.448,9.076 C16.519,11.327,16.304,11.51,16.058,11.51z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#b6dcfe" d="M31.438,13.266c-0.832,0-1.304,0.528-1.785,1.216l-0.466,0.667v-0.735 c0-1.422-1.317-2.956-2.729-2.956c-0.832,0-1.759,0.671-2.24,1.359l-0.466,0.667v-0.219c0-1.422-1.09-2.766-2.503-2.766 s-2.621,1.344-2.621,2.766l-0.025-9.916l-0.466-0.667c-0.481-0.688-1.264-1.099-2.096-1.099c-1.413,0-2.536,1.495-2.536,2.917 v21.203v0.486l-5.339-5.373c-1.121-1.128-2.945-1.128-4.066,0c-0.543,0.547-0.842,1.273-0.842,2.046 c0,0.773,0.299,1.499,0.842,2.046l10.94,11.009c1.004,1.02,2.343,1.583,3.767,1.583h2.146h5.105c4.379,0,8.567-3.554,8.567-7.961 V15.875C34.625,14.453,32.851,13.266,31.438,13.266z"/><path fill="#4788c7" d="M26.058,38h-7.251c-1.56,0-3.024-0.615-4.124-1.732L3.745,25.26 c-0.637-0.641-0.988-1.493-0.988-2.398s0.351-1.757,0.988-2.398c1.273-1.281,3.502-1.281,4.775,0l4.485,4.514V4.5 c0-1.616,1.247-3.417,3.036-3.417c1.688,0,3.062,1.381,3.062,3.078c0,1.176,0.01,4.477,0.018,6.763 C19.688,10.358,20.445,10,21.25,10c1.283,0,2.41,0.93,2.829,2.191c0.574-0.643,1.473-1.232,2.38-1.232 c1.426,0,2.829,1.311,3.157,2.807c0.631-0.601,1.571-1.016,2.384-1.016c1.694,0,3.125,1.431,3.125,3.125v13.664 C35.125,34.046,30.888,38,26.058,38z M6.133,20.47c-0.635,0-1.231,0.248-1.679,0.699c-0.449,0.452-0.697,1.054-0.697,1.693 s0.248,1.241,0.697,1.693l10.939,11.009C16.305,36.491,17.517,37,18.807,37h7.251c4.297,0,8.067-3.486,8.067-7.461V15.875 c0-1.132-0.993-2.125-2.125-2.125c-0.664,0-1.551,0.466-1.937,1.018l-1.375,1.971v-2.325c0-1.193-1.146-2.456-2.229-2.456 c-0.645,0-1.437,0.583-1.831,1.146l-1.375,1.971v-1.81c0-1.207-0.936-2.266-2.002-2.266c-1.11,0-2.121,1.08-2.121,2.266l-1,0.002 c0,0-0.025-7.236-0.025-9.106c0-1.146-0.925-2.078-2.062-2.078c-1.146,0-2.036,1.299-2.036,2.417v22.902l-6.194-6.233 C7.364,20.718,6.768,20.47,6.133,20.47z"/><path fill="#4788c7" d="M23.252 13.523H24.252V17.131999999999998H23.252zM18.129 12.524H19.129V17.131999999999998H18.129zM28.688 15.188H29.688V17.251H28.688z"/><path fill="#4788c7" d="M19.5 -4.042H20.5V44.041H19.5z" transform="rotate(-45.001 20 20)"/></svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 96 96" width="96px" height="96px">
<g id="surface37335734">
<path style="fill-rule:nonzero;fill:rgb(71.372551%,86.274511%,99.607843%);fill-opacity:1;stroke-width:10;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(27.843139%,53.333336%,78.039217%);stroke-opacity:1;stroke-miterlimit:10;" d="M 158.112511 139.752963 L 13.88749 139.752963 C 6.229656 139.752963 0.00118494 133.642989 0.00118494 126.133275 L 0.00118494 45.866726 C 0.00118494 38.357012 6.229656 32.247038 13.88749 32.247038 L 158.112511 32.247038 C 165.770345 32.247038 171.998816 38.357012 171.998816 45.866726 L 171.998816 126.133275 C 171.998816 133.642989 165.770345 139.752963 158.112511 139.752963 Z M 158.112511 139.752963 " transform="matrix(0.527442,0,0,0.527442,2.64,2.64)"/>
<path style="fill-rule:nonzero;fill:rgb(27.843139%,53.333336%,78.039217%);fill-opacity:1;stroke-width:10;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(27.843139%,53.333336%,78.039217%);stroke-opacity:1;stroke-miterlimit:10;" d="M 76.401786 118.25326 C 60.982433 118.25326 52.643243 112.498775 48.147783 105.781506 C 51.561963 106.544327 59.316076 107.558953 68.077409 103.685599 C 69.617863 115.853706 78.253294 117.453408 80.171455 118.119951 C 78.94946 118.201417 77.697841 118.25326 76.401786 118.25326 Z M 76.401786 118.25326 " transform="matrix(0.527442,0,0,0.527442,2.64,2.64)"/>
<path style="fill-rule:nonzero;fill:rgb(27.843139%,53.333336%,78.039217%);fill-opacity:1;stroke-width:10;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(27.843139%,53.333336%,78.039217%);stroke-opacity:1;stroke-miterlimit:10;" d="M 69.980759 104.929812 C 70.447338 105.974062 70.025195 107.344178 68.921696 107.670043 C 62.048901 109.691889 56.131483 109.958506 51.658241 109.958506 C 50.310344 108.677263 49.169815 107.299742 48.207032 105.877784 C 53.583809 105.877784 62.167397 105.625979 67.233122 103.863344 C 68.321808 103.493043 69.514179 103.87075 69.980759 104.929812 Z M 80.563975 101.604505 C 80.563975 103.900374 78.697655 105.766694 76.401786 105.766694 C 74.105917 105.766694 72.239598 103.900374 72.239598 101.604505 C 72.239598 99.308636 74.105917 97.442316 76.401786 97.442316 C 78.697655 97.442316 80.563975 99.308636 80.563975 101.604505 Z M 80.563975 101.604505 " transform="matrix(0.527442,0,0,0.527442,2.64,2.64)"/>
<path style="fill-rule:nonzero;fill:rgb(27.843139%,53.333336%,78.039217%);fill-opacity:1;stroke-width:10;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(27.843139%,53.333336%,78.039217%);stroke-opacity:1;stroke-miterlimit:10;" d="M 78.482881 101.604505 C 78.482881 102.75244 77.549721 103.685599 76.401786 103.685599 C 75.253852 103.685599 74.320692 102.75244 74.320692 101.604505 C 74.320692 100.45657 75.253852 99.523411 76.401786 99.523411 C 77.549721 99.523411 78.482881 100.45657 78.482881 101.604505 Z M 76.401786 118.25326 C 60.982433 118.25326 52.643243 112.498775 48.147783 105.781506 C 51.561963 106.544327 59.316076 107.558953 68.077409 103.685599 C 69.617863 115.853706 78.253294 117.453408 80.171455 118.119951 C 78.94946 118.201417 77.697841 118.25326 76.401786 118.25326 Z M 76.401786 118.25326 " transform="matrix(0.527442,0,0,0.527442,2.64,2.64)"/>
<path style="fill-rule:nonzero;fill:rgb(27.843139%,53.333336%,78.039217%);fill-opacity:1;stroke-width:10;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(27.843139%,53.333336%,78.039217%);stroke-opacity:1;stroke-miterlimit:10;" d="M 69.980759 104.929812 C 70.447338 105.974062 70.025195 107.344178 68.921696 107.670043 C 62.048901 109.691889 56.131483 109.958506 51.658241 109.958506 C 50.310344 108.677263 49.169815 107.299742 48.207032 105.877784 C 53.583809 105.877784 62.167397 105.625979 67.233122 103.863344 C 68.321808 103.493043 69.514179 103.87075 69.980759 104.929812 Z M 80.563975 101.604505 C 80.563975 103.900374 78.697655 105.766694 76.401786 105.766694 C 74.105917 105.766694 72.239598 103.900374 72.239598 101.604505 C 72.239598 99.308636 74.105917 97.442316 76.401786 97.442316 C 78.697655 97.442316 80.563975 99.308636 80.563975 101.604505 Z M 80.563975 101.604505 " transform="matrix(0.527442,0,0,0.527442,2.64,2.64)"/>
<path style="fill-rule:nonzero;fill:rgb(27.843139%,53.333336%,78.039217%);fill-opacity:1;stroke-width:10;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(27.843139%,53.333336%,78.039217%);stroke-opacity:1;stroke-miterlimit:10;" d="M 78.482881 101.604505 C 78.482881 102.75244 77.549721 103.685599 76.401786 103.685599 C 75.253852 103.685599 74.320692 102.75244 74.320692 101.604505 C 74.320692 100.45657 75.253852 99.523411 76.401786 99.523411 C 77.549721 99.523411 78.482881 100.45657 78.482881 101.604505 Z M 78.482881 101.604505 " transform="matrix(0.527442,0,0,0.527442,2.64,2.64)"/>
<path style="fill-rule:nonzero;fill:rgb(27.843139%,53.333336%,78.039217%);fill-opacity:1;stroke-width:10;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(27.843139%,53.333336%,78.039217%);stroke-opacity:1;stroke-miterlimit:10;" d="M 115.327878 96.753556 C 109.677077 106.418424 98.29401 118.25326 76.401786 118.25326 C 53.650463 118.25326 46.25184 106.129589 43.926346 96.753556 Z M 120.038113 85.844474 C 119.690029 87.110905 119.016081 89.162375 117.942206 91.621177 C 116.660963 92.576555 115.142727 93.169037 112.876482 93.169037 C 109.291964 93.169037 107.499705 91.82114 105.707445 89.584519 C 103.915186 91.82114 102.122927 93.169037 98.538409 93.169037 C 94.961296 93.169037 93.169037 91.82114 91.376778 89.584519 C 89.584519 91.82114 87.79226 93.169037 84.207741 93.169037 C 80.623223 93.169037 78.830964 91.82114 77.038705 89.584519 C 75.246446 91.82114 73.461593 93.169037 69.877074 93.169037 C 66.292556 93.169037 64.500297 91.82114 62.708038 89.584519 C 60.915778 91.82114 59.123519 93.169037 55.539001 93.169037 C 51.961889 93.169037 50.169629 91.82114 48.37737 89.584519 C 46.962819 91.35456 45.511237 92.532119 43.207962 92.961668 C 42.674727 88.903164 43.000593 86.000001 43.000593 86.000001 C 43.000593 86.000001 45.792666 86.000001 50.169629 86.000001 L 50.169629 75.246446 L 60.915778 75.246446 L 60.915778 64.500297 L 82.415482 64.500297 L 82.415482 53.746742 L 93.169037 53.746742 L 93.169037 75.246446 L 103.915186 75.246446 L 103.915186 86.000001 C 112.047007 86.000001 114.713177 82.741348 114.713177 82.741348 C 112.78761 80.675065 111.150877 77.742278 111.084223 74.357722 C 111.024975 71.343468 112.180315 67.966319 116.009233 64.500297 C 121.023115 69.121659 121.830372 73.461593 121.830372 77.490473 C 123.43748 76.261072 125.866658 75.246446 128.999408 75.246446 C 131.213811 75.246446 133.665207 75.727838 136.168445 76.594343 C 133.93923 85.563045 126.947938 85.96297 122.482102 86.000001 C 121.600785 86.007407 120.778716 85.940752 120.038113 85.844474 Z M 120.038113 85.844474 " transform="matrix(0.527442,0,0,0.527442,2.64,2.64)"/>
<path style="fill-rule:nonzero;fill:rgb(27.843139%,53.333336%,78.039217%);fill-opacity:1;stroke-width:10;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(27.843139%,53.333336%,78.039217%);stroke-opacity:1;stroke-miterlimit:10;" d="M 115.327878 96.753556 C 116.38694 94.931672 117.260852 93.191255 117.942206 91.621177 C 118.697621 91.058319 119.378976 90.406588 120.038113 89.584519 C 121.830372 91.82114 123.622631 93.169037 127.207149 93.169037 C 127.881098 93.169037 128.443956 93.072759 128.999408 92.983887 L 128.999408 96.753556 Z M 115.327878 96.753556 " transform="matrix(0.527442,0,0,0.527442,2.64,2.64)"/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(71.372551%,86.274511%,99.607843%);fill-opacity:1;" d="M 86.035156 76.351562 L 9.964844 76.351562 C 5.925781 76.351562 2.640625 73.128906 2.640625 69.167969 L 2.640625 26.832031 C 2.640625 22.871094 5.925781 19.648438 9.964844 19.648438 L 86.035156 19.648438 C 90.074219 19.648438 93.359375 22.871094 93.359375 26.832031 L 93.359375 69.167969 C 93.359375 73.128906 90.074219 76.351562 86.035156 76.351562 Z M 86.035156 76.351562 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(27.843139%,53.333336%,78.039217%);fill-opacity:1;" d="M 44.925781 64.941406 C 43.914062 64.589844 39.359375 63.746094 38.546875 57.328125 C 33.925781 59.371094 29.835938 58.835938 28.035156 58.433594 C 30.40625 61.976562 34.804688 65.011719 42.9375 65.011719 C 43.621094 65.011719 44.28125 64.984375 44.925781 64.941406 Z M 44.925781 64.941406 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(27.843139%,53.333336%,78.039217%);fill-opacity:1;" d="M 38.101562 57.421875 C 35.429688 58.351562 30.902344 58.484375 28.066406 58.484375 C 28.574219 59.234375 29.175781 59.960938 29.886719 60.636719 C 32.246094 60.636719 35.367188 60.496094 38.992188 59.429688 C 39.574219 59.257812 39.796875 58.535156 39.550781 57.984375 C 39.304688 57.425781 38.675781 57.226562 38.101562 57.421875 Z M 42.9375 54.035156 C 41.726562 54.035156 40.742188 55.019531 40.742188 56.230469 C 40.742188 57.441406 41.726562 58.425781 42.9375 58.425781 C 44.148438 58.425781 45.132812 57.441406 45.132812 56.230469 C 45.132812 55.019531 44.148438 54.035156 42.9375 54.035156 Z M 42.9375 54.035156 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(27.843139%,53.333336%,78.039217%);fill-opacity:1;" d="M 42.9375 55.132812 C 42.332031 55.132812 41.839844 55.625 41.839844 56.230469 C 41.839844 56.835938 42.332031 57.328125 42.9375 57.328125 C 43.542969 57.328125 44.035156 56.835938 44.035156 56.230469 C 44.035156 55.625 43.542969 55.132812 42.9375 55.132812 Z M 44.925781 64.941406 C 43.914062 64.589844 39.359375 63.746094 38.546875 57.328125 C 33.925781 59.371094 29.835938 58.835938 28.035156 58.433594 C 30.40625 61.976562 34.804688 65.011719 42.9375 65.011719 C 43.621094 65.011719 44.28125 64.984375 44.925781 64.941406 Z M 44.925781 64.941406 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(27.843139%,53.333336%,78.039217%);fill-opacity:1;" d="M 38.101562 57.421875 C 35.429688 58.351562 30.902344 58.484375 28.066406 58.484375 C 28.574219 59.234375 29.175781 59.960938 29.886719 60.636719 C 32.246094 60.636719 35.367188 60.496094 38.992188 59.429688 C 39.574219 59.257812 39.796875 58.535156 39.550781 57.984375 C 39.304688 57.425781 38.675781 57.226562 38.101562 57.421875 Z M 42.9375 54.035156 C 41.726562 54.035156 40.742188 55.019531 40.742188 56.230469 C 40.742188 57.441406 41.726562 58.425781 42.9375 58.425781 C 44.148438 58.425781 45.132812 57.441406 45.132812 56.230469 C 45.132812 55.019531 44.148438 54.035156 42.9375 54.035156 Z M 42.9375 54.035156 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(27.843139%,53.333336%,78.039217%);fill-opacity:1;" d="M 42.9375 55.132812 C 42.332031 55.132812 41.839844 55.625 41.839844 56.230469 C 41.839844 56.835938 42.332031 57.328125 42.9375 57.328125 C 43.542969 57.328125 44.035156 56.835938 44.035156 56.230469 C 44.035156 55.625 43.542969 55.132812 42.9375 55.132812 Z M 42.9375 55.132812 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(27.843139%,53.333336%,78.039217%);fill-opacity:1;" d="M 50.835938 53.671875 L 25.808594 53.671875 C 27.035156 58.617188 30.9375 65.011719 42.9375 65.011719 C 54.484375 65.011719 60.488281 58.769531 63.46875 53.671875 Z M 67.242188 48 C 69.597656 47.980469 73.285156 47.769531 74.460938 43.039062 C 73.140625 42.582031 71.847656 42.328125 70.679688 42.328125 C 69.027344 42.328125 67.746094 42.863281 66.898438 43.511719 C 66.898438 41.386719 66.472656 39.097656 63.828125 36.660156 C 61.808594 38.488281 61.199219 40.269531 61.230469 41.859375 C 61.265625 43.644531 62.128906 45.191406 63.144531 46.28125 C 63.144531 46.28125 61.738281 48 57.449219 48 L 57.449219 42.328125 L 51.78125 42.328125 L 51.78125 30.988281 L 46.109375 30.988281 L 46.109375 36.660156 L 34.769531 36.660156 L 34.769531 42.328125 L 29.101562 42.328125 L 29.101562 48 C 26.792969 48 25.320312 48 25.320312 48 C 25.320312 48 25.148438 49.53125 25.429688 51.671875 C 26.644531 51.445312 27.410156 50.824219 28.15625 49.890625 C 29.101562 51.070312 30.046875 51.78125 31.933594 51.78125 C 33.824219 51.78125 34.769531 51.070312 35.714844 49.890625 C 36.660156 51.070312 37.605469 51.78125 39.496094 51.78125 C 41.386719 51.78125 42.328125 51.070312 43.273438 49.890625 C 44.21875 51.070312 45.164062 51.78125 47.054688 51.78125 C 48.945312 51.78125 49.890625 51.070312 50.835938 49.890625 C 51.78125 51.070312 52.726562 51.78125 54.613281 51.78125 C 56.503906 51.78125 57.449219 51.070312 58.394531 49.890625 C 59.339844 51.070312 60.285156 51.78125 62.175781 51.78125 C 63.371094 51.78125 64.171875 51.46875 64.847656 50.964844 C 65.414062 49.667969 65.769531 48.585938 65.953125 47.917969 C 66.34375 47.96875 66.777344 48.003906 67.242188 48 Z M 67.242188 48 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(27.843139%,53.333336%,78.039217%);fill-opacity:1;" d="M 65.953125 53.671875 L 70.679688 53.671875 L 70.679688 51.683594 C 70.386719 51.730469 70.089844 51.78125 69.734375 51.78125 C 67.84375 51.78125 66.898438 51.070312 65.953125 49.890625 C 65.605469 50.324219 65.246094 50.667969 64.847656 50.964844 C 64.488281 51.792969 64.027344 52.710938 63.46875 53.671875 Z M 65.953125 53.671875 "/>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#b6dcfe" d="M8.5 2.5H31.5V37.5H8.5z"/><path fill="#4788c7" d="M31,3v34H9V3H31 M32,2H8v36h24V2L32,2z"/><path fill="#98ccfd" d="M20 3H25V37H20z"/><path fill="#dff0fe" d="M17.854 39.5L8.5 37.592 8.5 2.409 17.954 0.49 20.5 0.499 20.5 39.5z"/><path fill="#4788c7" d="M20,1v38h-2.046L9,37.183V2.817L17.954,1H20 M21,0h-3.146L8,2v36l9.854,2H21V0L21,0z"/><path fill="#fff" d="M18 1H20V39H18z"/><path fill="#4788c7" d="M16.5 19A0.5 1 0 1 0 16.5 21A0.5 1 0 1 0 16.5 19Z"/><g><path fill="none" stroke="#4788c7" stroke-linecap="round" stroke-miterlimit="10" d="M36.773 27.501c2.302-4.742 2.304-10.256-.005-15M3.232 12.501c-2.309 4.744-2.308 10.258-.005 15"/></g><g><path fill="none" stroke="#4788c7" stroke-linecap="round" stroke-miterlimit="10" d="M34.053 26.501c1.929-4.11 1.93-8.888-.004-13M5.951 13.501c-1.935 4.112-1.933 8.89-.004 13"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#b6dcfe" d="M6.697 36.543L18.695 20 6.697 3.457 9.107 1.699 22.38 20 9.107 38.301z"/><path fill="#4788c7" d="M8.997,2.399L21.762,20L8.997,37.601l-1.602-1.168l11.492-15.846L19.313,20l-0.426-0.587L7.395,3.567L8.997,2.399 M9.218,1L6,3.347L18.078,20L6,36.653L9.218,39l13.78-19L9.218,1L9.218,1z"/><path fill="#b6dcfe" d="M17.692 36.542L29.697 20 17.692 3.458 20.104 1.699 33.382 20 20.104 38.301z"/><path fill="#4788c7" d="M19.994,2.399L32.765,20L19.994,37.601l-1.603-1.169l11.497-15.845L30.314,20l-0.426-0.587L18.391,3.567L19.994,2.399 M20.215,1l-3.219,2.347L29.079,20L16.996,36.653L20.215,39L34,20L20.215,1L20.215,1z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M6.5,27.5c-3.309,0-6-2.691-6-6s2.691-6,6-6c0.499,0,1.013,0.069,1.529,0.204l0.495,0.13 l0.119-0.498c0.422-1.771,1.775-3.17,3.53-3.653l0.332-0.091l0.034-0.342C12.919,7.402,16.127,4.5,20,4.5 c2.859,0,5.43,1.596,6.709,4.165l0.203,0.408l0.425-0.165C28.039,8.638,28.766,8.5,29.5,8.5c3.309,0,6,2.691,6,6 c0,0.271-0.024,0.555-0.075,0.896l-0.058,0.391l0.366,0.147c2.288,0.919,3.767,3.104,3.767,5.566c0,3.309-2.691,6-6,6H6.5z"/><path fill="#4788c7" d="M20,5c2.668,0,5.068,1.49,6.262,3.888l0.406,0.816l0.85-0.329C28.161,9.126,28.828,9,29.5,9 c3.033,0,5.5,2.467,5.5,5.5c0,0.247-0.022,0.508-0.069,0.822l-0.117,0.782l0.734,0.295C37.645,17.241,39,19.244,39,21.5 c0,3.033-2.467,5.5-5.5,5.5h-27C3.467,27,1,24.533,1,21.5S3.467,16,6.5,16c0.455,0,0.927,0.063,1.401,0.188l0.99,0.26l0.237-0.995 c0.38-1.593,1.598-2.852,3.177-3.287l0.662-0.182l0.068-0.683C13.391,7.709,16.385,5,20,5 M20,4c-4.149,0-7.559,3.159-7.96,7.202 c-1.922,0.529-3.42,2.071-3.885,4.019C7.626,15.082,7.073,15,6.5,15C2.91,15,0,17.91,0,21.5S2.91,28,6.5,28c3.43,0,23.41,0,27,0 s6.5-2.91,6.5-6.5c0-2.734-1.69-5.069-4.08-6.03c0.048-0.317,0.08-0.64,0.08-0.97c0-3.59-2.91-6.5-6.5-6.5 c-0.827,0-1.615,0.161-2.343,0.442C25.847,5.812,23.138,4,20,4L20,4z"/><path fill="#dff0fe" d="M16 26H24V28H16z"/><path fill="#4788c7" d="M21,32V19c0-0.552-0.448-1-1-1h0c-0.552,0-1,0.448-1,1v13h-5l6,6l6-6H21z"/><path fill="#4788c7" d="M25.5 27h-2c-.275 0-.5.225-.5.5l0 0c0 .275.225.5.5.5h2c.275 0 .5-.225.5-.5l0 0C26 27.225 25.775 27 25.5 27zM16.5 27h-2c-.275 0-.5.225-.5.5l0 0c0 .275.225.5.5.5h2c.275 0 .5-.225.5-.5l0 0C17 27.225 16.775 27 16.5 27z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M4.5 21.5L4.5 13.088 8.351 2.5 31.649 2.5 35.5 13.088 35.5 21.5z"/><path fill="#4788c7" d="M31.3,3L35,13.176V21H5v-7.824L8.7,3H31.3 M32,2H8L4,13v9h32v-9L32,2L32,2z"/><path fill="#98ccfd" d="M7 19L33 19 33 13.529 29.899 5 10.101 5 7 13.529z"/><path fill="#dff0fe" d="M4.5,37.5v-24h10.022c0.253,2.799,2.613,5,5.478,5s5.225-2.201,5.478-5H35.5v24H4.5z"/><path fill="#4788c7" d="M35,14v23H5V14h9.083c0.477,2.834,2.949,5,5.917,5s5.439-2.166,5.917-5H35 M36,13H25 c0,2.761-2.239,5-5,5s-5-2.239-5-5H4v25h32V13L36,13z"/><g><path fill="#4788c7" d="M21,28v-4c0-0.552-0.448-1-1-1h0c-0.552,0-1,0.448-1,1v4h-3l4,5l4-5H21z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="40px" height="40px"><path fill="#98ccfd" d="M8.5,22.5v8.383L19.988,38.5L31.5,30.909V22.5H8.5z"/><path fill="#4788c7" d="M19.988,39c-0.096,0-0.192-0.028-0.276-0.083L8.224,31.3C8.084,31.208,8,31.051,8,30.883V22.5 C8,22.224,8.224,22,8.5,22h23c0.276,0,0.5,0.224,0.5,0.5v8.409c0,0.168-0.084,0.325-0.225,0.417l-11.512,7.591 C20.18,38.973,20.083,39,19.988,39z M9,30.615L19.989,37.9L31,30.64V23H9V30.615z"/><g><path fill="#98ccfd" d="M38.65,9.464L27.643,2.5L20,8.778l11.424,6.65L38.65,9.464z M1.35,21.556l11.328,6.639L20,22.578 L9.15,15.673L1.35,21.556z M12.678,2.5L1.35,9.801l7.8,5.873L20,8.778L12.678,2.5z M20,22.578l7.469,5.618l11.181-6.639 l-7.226-6.129L20,22.578z"/><path fill="#4788c7" d="M12.678,28.696c-0.087,0-0.174-0.022-0.253-0.069l-11.328-6.64 c-0.144-0.084-0.236-0.235-0.246-0.402c-0.01-0.167,0.064-0.327,0.198-0.428l7.271-5.483L1.049,10.2 c-0.13-0.098-0.205-0.254-0.199-0.417C0.856,9.619,0.941,9.469,1.079,9.38l11.328-7.3c0.186-0.119,0.428-0.104,0.596,0.041 l7.004,6.004l7.319-6.011c0.167-0.138,0.403-0.152,0.584-0.036l11.007,6.964c0.136,0.085,0.222,0.231,0.232,0.391 c0.01,0.16-0.057,0.315-0.181,0.417l-6.765,5.583l6.77,5.742c0.124,0.104,0.188,0.262,0.175,0.423 c-0.013,0.161-0.104,0.306-0.243,0.388l-11.181,6.64c-0.175,0.103-0.394,0.091-0.556-0.03l-7.166-5.389l-7.021,5.386 C12.893,28.661,12.786,28.696,12.678,28.696z M20.882,22.616l6.62,4.979l10.291-6.111l-6.413-5.438L20.882,22.616z M2.25,21.504 l10.391,6.09l6.489-4.978l-9.955-6.335L2.25,21.504z M10.082,15.674l9.921,6.313l10.455-6.543L20.011,9.363L10.082,15.674z M2.223,9.832l6.951,5.233l9.988-6.348l-6.527-5.596L2.223,9.832z M20.873,8.708l10.501,6.113L37.8,9.518L27.682,3.116 L20.873,8.708z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#fff" d="M1.5,37.5V15.521L17.981,4.132c0.596-0.412,1.294-0.63,2.019-0.63s1.423,0.218,2.019,0.63 L38.5,15.521V37.5H1.5z"/><path fill="#4788c7" d="M20,4.002c0.622,0,1.222,0.187,1.734,0.541L38,15.782V37H2V15.782L18.266,4.543 C18.778,4.189,19.378,4.002,20,4.002 M20,3.002c-0.805,0-1.61,0.239-2.302,0.718L1,15.258V38h38V15.258L22.302,3.72 C21.61,3.242,20.805,3.002,20,3.002L20,3.002z"/><path fill="#98ccfd" d="M25,25H15L2,15.782L18.266,4.543C18.778,4.189,19.378,4.002,20,4.002s1.222,0.187,1.734,0.541 L38,15.782L25,25z"/><rect width="25" height="19.5" x="7.5" y="6.5" fill="#fff" stroke="#4788c7" stroke-miterlimit="10"/><path fill="#dff0fe" d="M2,15.782V37h36V15.782l-13.213,8.707l-9.447,0.128L2,15.782z"/><path fill="#4788c7" d="M24.681,24h-9.362L2.876,15.177L2,15.782L15,25h10l13-9.218l-0.876-0.605L24.681,24z"/><path fill="#4788c7" d="M27.5,13h-15c-0.276,0-0.5-0.224-0.5-0.5l0,0c0-0.276,0.224-0.5,0.5-0.5h15 c0.276,0,0.5,0.224,0.5,0.5l0,0C28,12.776,27.776,13,27.5,13z"/><path fill="#4788c7" d="M23.5,16h-11c-0.276,0-0.5-0.224-0.5-0.5l0,0c0-0.276,0.224-0.5,0.5-0.5h11 c0.276,0,0.5,0.224,0.5,0.5l0,0C24,15.776,23.776,16,23.5,16z"/><path fill="#4788c7" d="M27.5,19h-15c-0.276,0-0.5-0.224-0.5-0.5l0,0c0-0.276,0.224-0.5,0.5-0.5h15 c0.276,0,0.5,0.224,0.5,0.5l0,0C28,18.776,27.776,19,27.5,19z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M20.022,38.5c-5.515,0-10.027-1.667-13.414-4.954C3.219,30.256,1.5,25.898,1.5,20.592 c0-5.459,1.799-10.055,5.346-13.659C10.395,3.328,14.985,1.5,20.49,1.5c14.246,0,18.01,10.782,18.01,16.483 c0,3.578-0.916,6.562-2.724,8.87C33.881,29.273,31.602,30.5,29,30.5c-2.891,0-4.668-1.361-5.218-3.963 c-1.297,2.601-3.409,3.963-6.188,3.963c-4.9,0-7.094-4.415-7.094-8.79c0-3.602,0.818-6.396,2.501-8.541 C14.913,10.734,17.32,9.5,20.156,9.5c1.966,0,3.357,1.054,4.164,2.042c0.034-0.494,0.077-1.05,0.127-1.589L24.49,9.5h3.785 l-0.047,0.543c-0.681,7.843-1.037,12.55-1.045,12.794c0,3.218,1.033,3.663,2.15,3.663c3.903,0,5.166-5.727,5.166-8.5 c0-3.761-1.243-6.812-3.801-9.329C28.441,6.448,25.335,5.5,20.312,5.5c-4.754,0-8.015,1.204-10.574,3.904 C6.926,12.37,5.5,16.09,5.5,20.46c0,4.295,1.352,7.832,4.017,10.511c2.428,2.44,5.736,3.528,10.729,3.528 c3.373,0,6.853-0.712,9.546-1.954l0.709-0.327v4.082l-0.266,0.141C27.663,37.808,24.227,38.5,20.022,38.5z M20.048,13.5 c-1.642,0-2.938,0.74-3.963,2.264c-1.052,1.564-1.585,3.546-1.585,5.889c0,1.535,0.342,2.748,1.018,3.606 c0.656,0.835,1.51,1.241,2.609,1.241c1.633,0,2.896-0.772,3.863-2.36c1.002-1.645,1.51-3.877,1.51-6.634 C23.5,14.773,22.403,13.5,20.048,13.5z"/><path fill="#4788c7" d="M20.49,2C33.937,2,38,12.063,38,17.983c0,3.479-0.872,6.333-2.618,8.562 C33.637,28.774,31.509,30,29,30c-3.253,0-4.887-1.851-4.901-5.33h-0.111C22.904,28.149,20.772,30,17.594,30 C12.625,30,11,25.208,11,21.71c0-3.303,0.679-6.047,2.395-8.233C15.11,11.293,17.363,10,20.156,10c2.703,0,4.241,2.232,4.478,3.05 h0.089c0.03-0.409,0.103-1.778,0.223-3.05h2.785c-0.699,8.054-1.047,12.683-1.047,12.828c0,3.026,0.883,4.172,2.651,4.172 C33.708,27,35,20.719,35,18c0-4.019-1.366-7.143-3.951-9.686S24.887,5,20.312,5c-4.411,0-8.056,1.02-10.938,4.06 C6.492,12.1,5,15.9,5,20.46c0,4.487,1.422,8.109,4.162,10.864C11.902,34.079,15.597,35,20.245,35c3.668,0,7.156-0.802,9.755-2v3 c-2.667,1.417-6.132,2-9.978,2c-5.405,0-9.761-1.604-13.066-4.812S2,25.781,2,20.592c0-5.35,1.734-9.785,5.202-13.308 C10.669,3.762,15.099,2,20.49,2 M18.127,27c1.804,0,3.235-0.866,4.29-2.6C23.473,22.667,24,20.368,24,17.505 C24,14.502,22.682,13,20.048,13c-1.804,0-3.264,0.829-4.378,2.484C14.557,17.141,14,19.197,14,21.653 c0,1.656,0.374,2.962,1.124,3.916C15.875,26.523,16.874,27,18.127,27 M20.49,1C14.846,1,10.136,2.878,6.489,6.582 C2.847,10.283,1,14.996,1,20.592c0,5.446,1.77,9.925,5.26,13.313C9.743,37.286,14.373,39,20.022,39 c4.288,0,7.803-0.712,10.447-2.117L31,36.601V36v-3v-1.562l-1.419,0.654C26.951,33.305,23.548,34,20.245,34 c-4.848,0-8.048-1.043-10.374-3.381C7.302,28.036,6,24.619,6,20.46c0-4.238,1.379-7.843,4.1-10.713 C12.557,7.156,15.706,6,20.312,6c4.879,0,7.88,0.905,10.036,3.027C32.805,11.445,34,14.381,34,18c0,2.506-1.175,8-4.666,8 c-0.657,0-1.651,0-1.651-3.172c0.012-0.269,0.366-4.934,1.043-12.742L28.821,9h-1.09h-2.785h-0.911L23.95,9.907 c-0.016,0.167-0.031,0.336-0.045,0.504C22.975,9.624,21.703,9,20.156,9c-2.955,0-5.565,1.335-7.548,3.86 C10.853,15.096,10,17.991,10,21.71c0,4.624,2.348,9.29,7.594,9.29c1.929,0,4.338-0.625,6.05-3.212C24.496,29.881,26.326,31,29,31 c2.763,0,5.175-1.292,7.17-3.839c1.878-2.398,2.83-5.486,2.83-9.178C39,11.156,34.071,1,20.49,1L20.49,1z M18.127,26 c-0.949,0-1.653-0.333-2.216-1.049C15.306,24.182,15,23.072,15,21.653c0-2.242,0.505-4.13,1.5-5.611 C17.424,14.668,18.585,14,20.048,14C21.508,14,23,14.416,23,17.505c0,2.665-0.483,4.809-1.437,6.374 C20.694,25.307,19.57,26,18.127,26L18.127,26z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M6 1H34V39H6z"/><path fill="none" stroke="#4788c7" stroke-linecap="round" stroke-miterlimit="10" d="M6.5 26.5L6.5 38.5 33.5 38.5 33.5 1.5 6.5 1.5 6.5 13.5"/><path fill="#98ccfd" d="M16.5 22.5L0.5 22.5 0.5 17.5 16.5 17.5 16.5 10.241 26.292 20 16.5 29.759z"/><path fill="#4788c7" d="M17,11.445L25.583,20L17,28.554V23v-1h-1H1v-4h15h1v-1V11.445 M16,9.037V17H0v6h16v7.963L27,20 L16,9.037L16,9.037z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#b6dcfe" d="M1.5 6.5H38.5V33.5H1.5z"/><path fill="#4788c7" d="M38,7v26H2V7H38 M39,6H1v28h38V6L39,6z"/><path fill="none" stroke="#4788c7" stroke-miterlimit="10" d="M1.679,12.372l15.748,8.48c1.607,0.865,3.541,0.865,5.147,0 l15.748-8.48"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M2.5 2.5H37.5V37.5H2.5z"/><path fill="#4788c7" d="M37,3v34H3V3H37 M38,2H2v36h36V2L38,2z"/><path fill="#98ccfd" d="M15.5 30.5L15.5 28.5 12.5 28.5 12.5 25.5 9.5 25.5 9.5 11.5 31.5 11.5 31.5 25.5 28.5 25.5 28.5 28.5 25.5 28.5 25.5 30.5z"/><path fill="#4788c7" d="M31,12v13h-2h-1v1v2h-2h-1v1v1h-9v-1v-1h-1h-2v-2v-1h-1h-2V12H31 M32,11H9v15h3v3h3v2h11v-2h3v-3h3 V11L32,11z"/><path fill="#fff" d="M14.5 18L14.5 18c-.275 0-.5-.225-.5-.5v-3c0-.275.225-.5.5-.5h0c.275 0 .5.225.5.5v3C15 17.775 14.775 18 14.5 18zM16.5 18L16.5 18c-.275 0-.5-.225-.5-.5v-3c0-.275.225-.5.5-.5l0 0c.275 0 .5.225.5.5v3C17 17.775 16.775 18 16.5 18zM18.5 18L18.5 18c-.275 0-.5-.225-.5-.5v-3c0-.275.225-.5.5-.5l0 0c.275 0 .5.225.5.5v3C19 17.775 18.775 18 18.5 18zM22.5 18L22.5 18c-.275 0-.5-.225-.5-.5v-3c0-.275.225-.5.5-.5l0 0c.275 0 .5.225.5.5v3C23 17.775 22.775 18 22.5 18zM24.5 18L24.5 18c-.275 0-.5-.225-.5-.5v-3c0-.275.225-.5.5-.5l0 0c.275 0 .5.225.5.5v3C25 17.775 24.775 18 24.5 18zM26.5 18L26.5 18c-.275 0-.5-.225-.5-.5v-3c0-.275.225-.5.5-.5l0 0c.275 0 .5.225.5.5v3C27 17.775 26.775 18 26.5 18z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M6 1H34V39H6z"/><path fill="none" stroke="#4788c7" stroke-linecap="round" stroke-miterlimit="10" d="M33.5 28.5L33.5 38.5 6.5 38.5 6.5 1.5 33.5 1.5 33.5 11.5"/><path fill="#98ccfd" d="M26.5 22.5L10.5 22.5 10.5 17.5 26.5 17.5 26.5 10.241 36.292 20 26.5 29.759z"/><path fill="#4788c7" d="M27,11.445L35.583,20L27,28.554V23v-1h-1H11v-4h15h1v-1V11.445 M26,9.037V17H10v6h16v7.963L37,20 L26,9.037L26,9.037z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#98ccfd" d="M12,22.5C6.21,22.5,1.5,17.79,1.5,12S6.21,1.5,12,1.5S22.5,6.21,22.5,12S17.79,22.5,12,22.5z"/><path fill="#4788c7" d="M12,2c5.514,0,10,4.486,10,10s-4.486,10-10,10S2,17.514,2,12S6.486,2,12,2 M12,1 C5.925,1,1,5.925,1,12s4.925,11,11,11s11-4.925,11-11S18.075,1,12,1L12,1z"/><path fill="#fff" d="M12 4A8 8 0 1 0 12 20A8 8 0 1 0 12 4Z"/><path fill="#4788c7" d="M12 10.625A1.375 1.375 0 1 0 12 13.375A1.375 1.375 0 1 0 12 10.625Z"/><path fill="none" stroke="#4788c7" stroke-linecap="round" stroke-miterlimit="10" d="M13.999 14.499L12 12 13.875 7.001"/><path fill="#98ccfd" d="M8.86,38.5c-0.49,0-0.93-0.254-1.176-0.679c-0.245-0.425-0.245-0.933,0-1.357l14.14-24.491 c0.246-0.425,0.686-0.679,1.176-0.679s0.93,0.254,1.176,0.679l14.14,24.491c0.245,0.425,0.245,0.933,0,1.357 C38.069,38.246,37.63,38.5,37.14,38.5H8.86z"/><path fill="#4788c7" d="M23,11.794c0.149,0,0.519,0.042,0.743,0.429l14.14,24.491c0.223,0.387,0.074,0.729,0,0.858 S37.587,38,37.14,38H8.86c-0.447,0-0.668-0.3-0.743-0.429s-0.223-0.471,0-0.858l14.14-24.491 C22.481,11.836,22.851,11.794,23,11.794 M23,10.794c-0.626,0-1.251,0.31-1.609,0.929L7.252,36.214C6.537,37.452,7.43,39,8.86,39 H37.14c1.43,0,2.324-1.548,1.609-2.786l-14.14-24.491C24.251,11.104,23.626,10.794,23,10.794L23,10.794z"/><path fill="#fff" d="M23 31.291A1.709 1.709 0 1 0 23 34.709 1.709 1.709 0 1 0 23 31.291zM22 20H24V29H22z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#b6dcfe" d="M12.109 35.5L1.384 30.584 11.653 27.317 6.053 12.384 16.315 19.848 19.561 5.941 23.702 19.746 36.814 12.253 29.299 27.284 38.777 30.602 29.872 35.5z"/><path fill="#4788c7" d="M19.621,7.883l3.421,11.404l0.362,1.205l1.092-0.624l11.132-6.361l-6.523,13.046l-0.508,1.016 l1.072,0.375l7.885,2.76L29.743,35H12.218l-9.45-4.331l8.535-2.716l1.003-0.319l-0.369-0.985l-4.83-12.881l8.306,6.041l1.219,0.887 l0.343-1.468L19.621,7.883 M19.5,4L16,19L5,11l6,16L0,30.5L12,36h18l10-5.5L30,27l8-16l-14,8L19.5,4L19.5,4z"/><path fill="#fff" d="M17 35L13 32 17 32 16 26 20 29 26 25 23 32 28 32 24 35z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="40px" height="40px"><path fill="#98ccfd" d="M2.5 2.5H37.5V37.5H2.5z"/><path fill="#4788c7" d="M37,3v34H3V3H37 M38,2H2v36h36V2L38,2z"/><g><path fill="#fff" d="M26,37V24h4.93l0.698-5H26v-3.384c0-1.568,0.702-2.636,2.95-2.636L32,12.979V8.225 c-0.496-0.066-2.381-0.213-4.361-0.213c-4.134,0-6.639,2.523-6.639,7.157V19h-5v5h5v13H26z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M17.604,34.5c-0.946,0-1.835-0.368-2.504-1.037L2.537,20.899C1.868,20.23,1.5,19.341,1.5,18.396 c0-0.946,0.368-1.835,1.037-2.504L14.724,3.705l17.569,17.572L20.108,33.463C19.439,34.132,18.551,34.5,17.604,34.5z"/><path fill="#4788c7" d="M14.723,4.412l16.863,16.864L19.755,33.109C19.181,33.684,18.417,34,17.605,34 c-0.812,0-1.576-0.316-2.15-0.891L2.891,20.546c-1.186-1.186-1.186-3.115,0-4.301L14.723,4.412 M14.723,2.998l-12.54,12.54 c-1.578,1.578-1.578,4.137,0,5.715l12.564,12.564C15.536,34.605,16.57,35,17.605,35c1.034,0,2.068-0.395,2.858-1.184L33,21.277 L14.723,2.998L14.723,2.998z"/><path fill="#4788c7" d="M2.184,21.253l12.564,12.564c1.578,1.578,4.137,1.578,5.715,0L33,21.277L31.725,20H1.34 C1.537,20.454,1.813,20.882,2.184,21.253z"/><path fill="#98ccfd" d="M30.311 20H2.465c.12.193.258.378.425.546l12.564 12.564C16.029 33.684 16.792 34 17.605 34c.812 0 1.576-.316 2.15-.891l11.833-11.833L30.311 20zM35 39.501c-1.93 0-3.5-1.57-3.5-3.5 0-1.511 2.229-6.01 3.5-8.395 1.271 2.386 3.5 6.884 3.5 8.395C38.5 37.931 36.93 39.501 35 39.501z"/><path fill="#4788c7" d="M35 28.676c1.402 2.701 3 6.159 3 7.324 0 1.654-1.346 3-3 3s-3-1.346-3-3C32 34.836 33.598 31.378 35 28.676M35 26.556c0 0-4 7.236-4 9.445s1.791 4 4 4 4-1.791 4-4S35 26.556 35 26.556L35 26.556zM14.793 4.5l-3.647-3.647c-.194-.194-.194-.513 0-.707l0 0c.194-.194.513-.194.707 0L15.5 3.793c.194.194.194.513 0 .707v0C15.306 4.694 14.987 4.694 14.793 4.5z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#4788c7" d="M36 21H3c-.552 0-1-.448-1-1v0c0-.552.448-1 1-1h33c.552 0 1 .448 1 1v0C37 20.552 36.552 21 36 21zM9 11L9 4 6 4 6 11 2 11 7.5 17 13 11zM21 11L21 4 18 4 18 11 14 11 19.5 17 25 11z"/><path fill="#dff0fe" d="M21.087 30.5L24.5 30.5 24.5 23.5 27.5 23.5 27.5 30.5 30.913 30.5 26 36.232z"/><path fill="#4788c7" d="M27,24v6v1h1h1.826L26,35.463L22.174,31H24h1v-1v-6H27 M28,23h-4v7h-4l6,7l6-7h-4V23L28,23z"/><path fill="#dff0fe" d="M8.087 30.5L11.5 30.5 11.5 23.5 14.5 23.5 14.5 30.5 17.913 30.5 13 36.232z"/><path fill="#4788c7" d="M14,24v6v1h1h1.826L13,35.463L9.174,31H11h1v-1v-6H14 M15,23h-4v7H7l6,7l6-7h-4V23L15,23z"/><g><path fill="#4788c7" d="M33 11L33 4 30 4 30 11 26 11 31.5 17 37 11z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="none" stroke="#4788c7" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M9.067 17.079c-1.059 2.016-1.602 4.257-1.586 6.59M18.644 7.823c-3.235.578-6.195 2.122-8.529 4.483-.257.246-1.793 1.766-2.841 3.887-1.208 2.445-1.811 4.966-1.793 7.492"/><path fill="#4788c7" d="M3 7L3 3 7 3 7 2 2 2 2 7zM37 7L38 7 38 2 33 2 33 3 37 3zM37 33L37 37 33 37 33 38 38 38 38 33zM3 33L2 33 2 38 7 38 7 37 3 37z"/><path fill="none" stroke="#4788c7" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M12.464 19.201c-.654 1.357-.994 2.856-.983 4.407M31.549 23.614c-.021-.09-.043-.22-.056-.401l-.077-.811c-.572-4.974-4.829-8.864-9.935-8.864l0 0h-.004c-2.719.019-5.242 1.077-7.118 2.979"/><path fill="none" stroke="#4788c7" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M24.674,12.004 c3.235,0.901,5.931,3.129,7.457,6.054c0.705,1.352,1.16,2.853,1.303,4.441"/><path fill="none" stroke="#4788c7" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M35.003 19.938c-.261-.964-.628-1.901-1.1-2.805-1.796-3.445-4.965-6.017-8.693-7.055M9.483 23.354c.044-2.558.874-4.973 2.41-7.007.316-.419.667-.825 1.042-1.205 2.252-2.284 5.281-3.554 8.529-3.576"/><path fill="none" stroke="#98ccfd" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M9.73 26.5c.227 1.492.658 3.398 1.473 5.476M7.482 23.669C7.49 24.56 7.6 26.946 8.433 29.968"/><path fill="none" stroke="#4788c7" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M30.516,12.903 c-2.448-2.079-5.613-3.336-9.052-3.336l0,0h-0.007l-0.007,0c-3.783,0.026-7.313,1.507-9.94,4.172"/><path fill="none" stroke="#98ccfd" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M5.481,23.684 c0.006,0.649,0.061,2.028,0.366,3.844"/><path fill="none" stroke="#4788c7" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M31.808,11.377 c-2.894-2.457-6.574-3.81-10.361-3.81l0,0h-0.005l-0.005,0"/><path fill="none" stroke="#4788c7" stroke-linecap="round" stroke-miterlimit="10" d="M5.481,15.306 c1.153-2.334,2.777-3.991,3.248-4.443C12.063,7.49,16.582,5.6,21.425,5.567c4.278,0,8.422,1.522,11.678,4.285"/><path fill="none" stroke="#98ccfd" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M28.498 33.185c-1.377-.344-2.483-.925-3.371-1.635M21.066 29.529c.951 1.874 2.479 3.748 4.934 4.891"/><path fill="none" stroke="#4788c7" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M23.5,23.509 c-0.012-1.092-0.909-1.981-2-1.981l0,0h-0.004c-0.545,0.004-1.046,0.215-1.421,0.596c-0.375,0.38-0.579,0.884-0.576,1.418"/><path fill="none" stroke="#98ccfd" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M29.498,23.354 c0.098,1.377,0.64,2.125,1.61,2.222c0.908,0.091,1.749,0.38,2.483,0.819"/><path fill="none" stroke="#4788c7" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M21.5 19.529L21.5 19.529h-.004c-1.089.008-2.095.431-2.845 1.192-.75.761-1.159 1.768-1.151 2.836M25.5 23.489c-.009-.892-.314-1.715-.82-2.378M15.705 21.964c-.139.517-.208 1.056-.204 1.606"/><path fill="none" stroke="#4788c7" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M27.5,23.469 c-0.035-3.276-2.726-5.94-6-5.94l0,0h-0.004c-1.633,0.011-3.144,0.646-4.269,1.787"/><path fill="none" stroke="#98ccfd" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M31.5 27.528c-2.627 0-3.973-1.366-4-4.059M15.006 30.633c.457 1.136 1.035 2.289 1.758 3.398"/><path fill="none" stroke="#4788c7" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M19.5 15.785c-1.398.358-2.669 1.084-3.697 2.127-1.5 1.521-2.318 3.536-2.303 5.673M25.448 16.58c-1.167-.668-2.516-1.051-3.948-1.051l0 0M29.5 23.449c-.015-1.41-.399-2.735-1.059-3.883M25.742 8.15c4.264 1.188 7.883 4.124 9.934 8.058"/><path fill="none" stroke="#98ccfd" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M11.481 23.608c.021 2.267.65 6.009 2.496 9.643M13.5 23.585c.012 1.272.236 3.059.805 5.018M17.5 23.557c.011 1.146.242 2.828.855 4.633.794 2.338 2.227 4.88 4.647 6.721M15.5 23.571c.024 2.6 1.046 7.625 4.499 11.345M23.789 30.203c-2.295-2.897-2.293-6.636-2.293-6.636s.003 0 .004 0M19.5 23.542c0 .047.037 1.828.749 4.003M30.512 31.546c-6.479-.648-7.004-7.294-7.012-8.037M31.5 29.528c-5.511 0-5.986-4.622-6-6.039M34.68 24.719c-.929-.569-1.988-.956-3.131-1.105"/><path fill="#4788c7" d="M37 25H3c-.552 0-1-.448-1-1v0c0-.552.448-1 1-1h34c.552 0 1 .448 1 1v0C38 24.552 37.552 25 37 25zM37.5 6L37.5 6C37.775 6 38 6.225 38 6.5v1C38 7.775 37.775 8 37.5 8l0 0C37.225 8 37 7.775 37 7.5v-1C37 6.225 37.225 6 37.5 6zM37.5 32L37.5 32c.275 0 .5.225.5.5v1c0 .275-.225.5-.5.5l0 0c-.275 0-.5-.225-.5-.5v-1C37 32.225 37.225 32 37.5 32zM2.5 32L2.5 32C2.775 32 3 32.225 3 32.5v1C3 33.775 2.775 34 2.5 34h0C2.225 34 2 33.775 2 33.5v-1C2 32.225 2.225 32 2.5 32zM2.5 6L2.5 6C2.775 6 3 6.225 3 6.5v1C3 7.775 2.775 8 2.5 8h0C2.225 8 2 7.775 2 7.5v-1C2 6.225 2.225 6 2.5 6zM6.5 2h1C7.775 2 8 2.225 8 2.5v0C8 2.775 7.775 3 7.5 3h-1C6.225 3 6 2.775 6 2.5v0C6 2.225 6.225 2 6.5 2zM32.5 2h1C33.775 2 34 2.225 34 2.5v0C34 2.775 33.775 3 33.5 3h-1C32.225 3 32 2.775 32 2.5v0C32 2.225 32.225 2 32.5 2zM6.5 37h1C7.775 37 8 37.225 8 37.5l0 0C8 37.775 7.775 38 7.5 38h-1C6.225 38 6 37.775 6 37.5l0 0C6 37.225 6.225 37 6.5 37zM32.5 37h1c.275 0 .5.225.5.5l0 0c0 .275-.225.5-.5.5h-1c-.275 0-.5-.225-.5-.5l0 0C32 37.225 32.225 37 32.5 37z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#98ccfd" d="M20,29.5c-5.691,0-10.5-4.809-10.5-10.5c0-4.111,2.14-8.003,3.249-9.743 c0.305,1.325,0.903,3.491,1.825,5.003l0.442,0.725l0.419-0.738c2.636-4.638,4.303-10.323,4.852-12.36 C22.55,3.824,30.5,11.187,30.5,19C30.5,24.888,25.888,29.5,20,29.5z"/><path fill="#4788c7" d="M20.559,2.789C23.323,5.26,30,11.961,30,19c0,5.607-4.393,10-10,10c-5.421,0-10-4.579-10-10 c0-3.316,1.451-6.505,2.559-8.456c0.35,1.27,0.875,2.807,1.587,3.977l0.884,1.451l0.839-1.477 C18.281,10.251,19.859,5.268,20.559,2.789 M20,1c0,0-1.741,7.265-5,13c-1.35-2.216-2-6-2-6s-4,5.246-4,11s4.882,11,11,11 s11-4.882,11-11C31,9.579,20,1,20,1L20,1z"/><path fill="#dff0fe" d="M14,24c0-5.231,6-5.464,6-13.077c2.61,3.913,6,7.294,6,13.077c0,3.926-2.941,6-6,6S14,27.981,14,24z"/><path fill="#fff" d="M17.231,26.154c0-1.529,2.769-5.538,2.769-5.538s2.769,4.009,2.769,5.538 c0,1.529-1.24,2.769-2.769,2.769C18.471,28.923,17.231,27.683,17.231,26.154z"/><path fill="#b6dcfe" d="M2.5 23.5H37.5V37.5H2.5z"/><path fill="#4788c7" d="M37,24v13H3V24H37 M38,23H2v15h36V23L38,23z"/><path fill="#b6dcfe" d="M16.5 23.5H30.5V30.5H16.5z"/><path fill="#4788c7" d="M30,24v6H17v-6H30 M31,23H16v8h15V23L31,23z"/><g><path fill="#b6dcfe" d="M2.5 23.5H16.5V30.5H2.5z"/><path fill="#4788c7" d="M16,24v6H3v-6H16 M17,23H2v8h15V23L17,23z"/></g><g><path fill="#b6dcfe" d="M23.5 30.5H37.5V37.5H23.5z"/><path fill="#4788c7" d="M37,31v6H24v-6H37 M38,30H23v8h15V30L38,30z"/></g><g><path fill="#b6dcfe" d="M9.5 30.5H23.5V37.5H9.5z"/><path fill="#4788c7" d="M23,31v6H10v-6H23 M24,30H9v8h15V30L24,30z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M5.5 1.5H8.5V38.5H5.5z"/><path fill="#4788c7" d="M8,2v36H6V2H8 M9,1H5v38h4V1L9,1z"/><g><path fill="#b6dcfe" d="M5.5 27.5L5.5 4.5 8.89 4.5 33.807 16.066 8.891 27.5z"/><path fill="#4788c7" d="M8.779,5l23.834,11.063L8.782,27H6V5H8.779 M9,4H5v24h4l26-11.931L9,4L9,4z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M1.5 4.5H38.5V35.5H1.5z"/><path fill="#4788c7" d="M38,5v30H2V5H38 M39,4H1v32h38V4L39,4z"/><path fill="#98ccfd" d="M27.45 19.612L20 25.437 30.247 35 38 35 38 29.112zM30 10A3 3 0 1 0 30 16 3 3 0 1 0 30 10z"/><path fill="#b6dcfe" d="M32.468 35L2 35 2 27.421 14 17.316z"/><g><path fill="#fff" d="M36,7v26H4V7H36 M38,5H2v30h36V5L38,5z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#b6dcfe" d="M20,38.5C9.799,38.5,1.5,30.201,1.5,20S9.799,1.5,20,1.5S38.5,9.799,38.5,20S30.201,38.5,20,38.5z M20,4.5C11.453,4.5,4.5,11.453,4.5,20S11.453,35.5,20,35.5S35.5,28.547,35.5,20S28.547,4.5,20,4.5z"/><path fill="#4788c7" d="M20,2c9.925,0,18,8.075,18,18s-8.075,18-18,18S2,29.925,2,20S10.075,2,20,2 M20,36 c8.822,0,16-7.178,16-16c0-8.822-7.178-16-16-16S4,11.178,4,20C4,28.822,11.178,36,20,36 M20,1C9.507,1,1,9.507,1,20 s8.507,19,19,19s19-8.507,19-19S30.493,1,20,1L20,1z M20,35c-8.284,0-15-6.716-15-15c0-8.284,6.716-15,15-15s15,6.716,15,15 C35,28.284,28.284,35,20,35L20,35z"/><path fill="#fff" d="M38.313,15c-0.487-1.786-1.225-3.464-2.179-5h-4.976C28.412,6.938,24.437,5,20,5 C11.716,5,5,11.716,5,20c0,8.284,6.716,15,15,15s15-6.716,15-15c0-1.756-0.317-3.434-0.872-5H38.313z"/><path fill="none" stroke="#4788c7" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M13 10L20 20 14 26"/><path fill="#4788c7" d="M20 18.5A1.5 1.5 0 1 0 20 21.5A1.5 1.5 0 1 0 20 18.5Z"/><path fill="#b6dcfe" d="M20 6A1 1 0 1 0 20 8 1 1 0 1 0 20 6zM20 32A1 1 0 1 0 20 34 1 1 0 1 0 20 32zM7 19A1 1 0 1 0 7 21 1 1 0 1 0 7 19zM33 19A1 1 0 1 0 33 21 1 1 0 1 0 33 19zM28.207 12.5L36.5 4.207 36.5 12.5z"/><path fill="#4788c7" d="M36,5.414V12h-6.586L36,5.414 M37,3L27,13h10V3L37,3z"/><path fill="none" stroke="#b6dcfe" stroke-miterlimit="10" stroke-width="2" d="M30.496,6.626c0.963,0.757,1.843,1.616,2.622,2.561"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#98ccfd" d="M6.758,35.414l-2.879,2.879l-2.172-2.172l2.879-2.879l-2.879-2.879l2.172-2.172l2.879,2.879 l3.384-3.385l-0.217-0.339C8.993,25.893,8.5,24.217,8.5,22.5c0-4.962,4.037-9,9-9s9,4.038,9,9s-4.037,9-9,9 c-1.717,0-3.393-0.493-4.848-1.425l-0.339-0.217L8.93,33.242l2.879,2.879l-2.172,2.172L6.758,35.414z M17.5,16.5 c-3.309,0-6,2.691-6,6s2.691,6,6,6s6-2.691,6-6S20.809,16.5,17.5,16.5z"/><path fill="#4788c7" d="M17.5,14c4.687,0,8.5,3.813,8.5,8.5S22.187,31,17.5,31c-1.621,0-3.204-0.465-4.577-1.346 l-0.678-0.435l-0.569,0.569L8.93,32.535l-0.707,0.707l0.707,0.707l2.172,2.172l-1.465,1.465l-2.172-2.172l-0.707-0.707 l-0.707,0.707l-2.172,2.172l-1.465-1.465l2.172-2.172l0.707-0.707l-0.707-0.707l-2.172-2.172l1.465-1.465l2.172,2.172l0.707,0.707 l0.707-0.707l2.746-2.746l0.569-0.569l-0.435-0.678C9.465,25.704,9,24.121,9,22.5C9,17.813,12.813,14,17.5,14 M17.5,29 c3.584,0,6.5-2.916,6.5-6.5S21.084,16,17.5,16S11,18.916,11,22.5S13.916,29,17.5,29 M17.5,13C12.253,13,8,17.253,8,22.5 c0,1.886,0.556,3.639,1.504,5.117l-2.746,2.746l-2.879-2.879L1,30.363l2.879,2.879L1,36.121L3.879,39l2.879-2.879L9.637,39 l2.879-2.879l-2.879-2.879l2.746-2.746C13.861,31.444,15.614,32,17.5,32c5.247,0,9.5-4.253,9.5-9.5S22.747,13,17.5,13L17.5,13z M17.5,28c-3.038,0-5.5-2.462-5.5-5.5c0-3.038,2.462-5.5,5.5-5.5s5.5,2.462,5.5,5.5C23,25.538,20.538,28,17.5,28L17.5,28z"/><g><path fill="#dff0fe" d="M21.97,26.474c-4.768-0.275-8.47-4.175-8.47-8.974c0-4.962,4.037-9,9-9 c1.716,0,3.393,0.493,4.848,1.425l0.339,0.217L33.328,4.5H27.5v-3h11v11h-3V6.672l-5.642,5.643l0.217,0.339 c0.932,1.454,1.425,3.13,1.425,4.847c0,3.718-2.28,7.006-5.668,8.352c0.439-1.076,0.668-2.216,0.668-3.352 c0-0.171-0.008-0.342-0.02-0.513c1.287-1.14,2.02-2.761,2.02-4.487c0-3.309-2.691-6-6-6s-6,2.691-6,6s2.691,6,6,6 c0.304,0,0.611-0.024,0.918-0.073C23.239,24.552,22.738,25.61,21.97,26.474z"/><path fill="#4788c7" d="M38,2v10h-2V7.879V5.465l-1.707,1.707l-4.504,4.504l-0.569,0.569l0.435,0.678 C30.535,14.296,31,15.879,31,17.5c0,3.117-1.698,5.915-4.318,7.393C26.892,24.108,27,23.303,27,22.5 c0-0.104-0.003-0.207-0.007-0.305C28.275,20.97,29,19.287,29,17.5c0-3.584-2.916-6.5-6.5-6.5S16,13.916,16,17.5s2.916,6.5,6.5,6.5 c0.093,0,0.187-0.002,0.281-0.006c-0.204,0.712-0.553,1.381-1.027,1.963C17.37,25.579,14,21.949,14,17.5 c0-4.687,3.813-8.5,8.5-8.5c1.621,0,3.204,0.465,4.577,1.346l0.678,0.435l0.569-0.569l4.504-4.504L34.535,4h-2.414H28V2H38 M39,1 H27v4h5.121l-4.504,4.504C26.139,8.556,24.386,8,22.5,8c-5.247,0-9.5,4.253-9.5,9.5c0,5.138,4.082,9.313,9.179,9.484 c1.063-1.11,1.732-2.585,1.805-4.192C23.511,22.924,23.015,23,22.5,23c-3.038,0-5.5-2.462-5.5-5.5c0-3.038,2.462-5.5,5.5-5.5 s5.5,2.462,5.5,5.5c0,1.725-0.795,3.263-2.038,4.271C25.984,22.013,26,22.256,26,22.5c0,1.478-0.406,2.917-1.131,4.19 C28.967,25.636,32,21.927,32,17.5c0-1.886-0.556-3.639-1.504-5.117L35,7.879V13h4V1L39,1z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M39,20c0,10.578-8.618,19-19,19C9.619,39,1,30.578,1,20S9.422,1,20,1S39,9.422,39,20z"/><path fill="#98ccfd" d="M27.124 26.951c.432.215.864.215 1.081.647.647.649.647 1.728.864 2.376.215.864.432 1.727.864 2.591.216 1.081.648 2.16.864 3.023.141-.11.306-.213.463-.318C35.927 31.822 39 26.302 39 20c0-5.597-2.373-10.575-6.161-14.037-.459-.151-.93-.165-1.396.042-.648.217-1.079 1.081-1.511 1.512-.432.648-.864 1.295-1.295 1.943-.217.216-.432.648-.217.864 0 .216.217.216.432.216.432.217.649.217 1.081.432.216 0 .432.217.216.432 0 0 0 .217-.216.217-1.081 1.08-2.159 1.943-3.239 3.022-.216.216-.432.648-.432.864 0 .216.216.216.216.432 0 .217-.216.217-.432.432-.432.217-.864.432-1.08.649-.216.432 0 1.08-.216 1.511-.216 1.079-.865 1.943-1.297 3.023-.432.647-.647 1.295-1.078 1.943 0 .864-.217 1.511.215 2.159C23.67 27.166 25.612 26.302 27.124 26.951zM26.725 2.21C24.638 1.432 22.375 1 20 1c-.391 0-.776.019-1.161.041-.27.419-.485.832-.566 1.078-.216 1.079.648.864 1.511 1.079 0 0 .216 1.727.216 1.943.216 1.081-.432 1.727-.432 2.807 0 .648 0 1.727.432 2.159h.216c.216 0 .432-.216.864-.432.648-.432 1.296-1.079 1.943-1.511.649-.432 1.296-1.079 1.728-1.511.648-.432 1.079-1.295 1.295-1.944.216-.432.956-1.704.739-2.351C26.769 2.323 26.746 2.263 26.725 2.21zM1.432 20.902c.648 1.295 1.943 2.592 3.239 3.454.864.648 2.591.648 3.454 1.727.648.865.432 1.943.432 3.023 0 1.295.864 2.375 1.295 3.453.216.649.432 1.512.648 2.16 0 .216.216 1.511.216 1.727.069.035.126.114.177.212 1.153.632 2.378 1.14 3.657 1.524.016.001.037-.012.053-.008.216 0 1.08-1.296 1.08-1.512.648-.648 1.079-1.511 1.727-1.943.432-.216.864-.432 1.295-.865.432-.432.648-1.295.864-1.943.216-.431.432-1.294.216-1.942-.137-.41-.216-.648-.648-.864-1.295-.432-2.591-.432-3.67-1.512-.216-.432-.216-.864-.432-1.295-.432-.432-1.511-.648-2.159-.864h-2.807H8.557c-.648-.216-1.079-1.08-1.511-1.727 0-.216 0-.649-.432-.649-.432-.215-.864.217-1.295 0-.216-.215-.216-.432-.216-.647 0-.649.432-1.296.864-1.728C6.614 20.253 7.262 20.9 7.909 20.9c.216 0 .216 0 .432.216.648.216.864 1.079.864 1.728v.432c0 .216.216.216.432.216.216-1.079.216-2.16.432-3.239 0-1.295 1.295-2.592 2.375-3.023.432-.215.648.217 1.079 0 1.295-.432 4.534-1.727 3.886-3.453-.432-1.512-1.727-3.022-3.454-2.807-.432.217-.648.432-1.079.649-.648.432-1.943 1.727-2.591 1.727-1.079-.216-1.079-1.727-.864-2.376.216-.864 2.159-3.669 3.454-3.238.216.216.648.648.864.864.432.216 1.08.216 1.727.216.216 0 .432 0 .648-.216.216-.216.216-.216.216-.432 0-.648-.648-1.296-1.079-1.728-.432-.432-1.08-.864-1.727-1.078-1.38-.415-4.295.076-6.672.878C3.24 9.685 1 14.553 1 20c0 .091.009.18.01.271C1.164 20.489 1.312 20.702 1.432 20.902z"/><path fill="#4788c7" d="M20,2c10.093,0,18,7.907,18,18c0,9.925-8.075,18-18,18S2,29.925,2,20C2,9.907,9.907,2,20,2 M20,1 C9.422,1,1,9.422,1,20s8.619,19,19,19c10.382,0,19-8.422,19-19S30.578,1,20,1L20,1z"/><path fill="#4788c7" d="M2 16H38V17H2zM2 23H38V24H2zM4.5 30H35.5V31H4.5zM5 9H35V10H5z"/><path fill="#4788c7" d="M19.996,2c1.358,0,4,6.353,4,18s-2.642,18-4,18s-4-6.353-4-18S18.638,2,19.996,2 M19.996,1 c-2.761,0-5,8.507-5,19s2.239,19,5,19c2.761,0,5-8.507,5-19S22.757,1,19.996,1L19.996,1z"/><path fill="#4788c7" d="M19.996,2c6.617,0,12,8.075,12,18s-5.383,18-12,18s-12-8.075-12-18S13.379,2,19.996,2 M19.996,1 c-7.18,0-13,8.507-13,19s5.82,19,13,19c7.18,0,13-8.507,13-19S27.175,1,19.996,1L19.996,1z"/></svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 264 264" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(2.26396,0,0,2.26396,2.66638,2.46404)">
<path d="M111.78,51.977L62.035,2.238C59.173,-0.627 54.527,-0.627 51.661,2.238L41.332,12.568L54.434,25.67C57.48,24.642 60.971,25.331 63.398,27.759C65.837,30.201 66.522,33.722 65.468,36.778L78.096,49.406C81.151,48.353 84.676,49.033 87.115,51.477C90.526,54.887 90.526,60.412 87.115,63.822C83.704,67.234 78.179,67.234 74.766,63.822C72.202,61.256 71.567,57.488 72.866,54.328L61.089,42.551L61.088,73.542C61.92,73.954 62.704,74.503 63.397,75.193C66.807,78.602 66.807,84.126 63.397,87.541C59.987,90.95 54.459,90.95 51.052,87.541C47.642,84.126 47.642,78.602 51.052,75.193C51.895,74.352 52.87,73.715 53.911,73.288L53.911,42.009C52.87,41.584 51.896,40.952 51.052,40.104C48.469,37.523 47.847,33.732 49.171,30.56L36.255,17.642L2.149,51.747C-0.716,54.614 -0.716,59.26 2.149,62.125L51.891,111.864C54.755,114.729 59.4,114.729 62.267,111.864L111.779,62.36C114.644,59.494 114.644,54.847 111.779,51.981" style="fill:rgb(223,240,254);fill-rule:nonzero;stroke:rgb(71,136,199);stroke-width:2.36px;"/>
</g>
</svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 280 274" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(2.26231,0,0,2.26231,139.89,270.846)">
<path d="M0,-118.274C-33.347,-118.274 -60.388,-91.239 -60.388,-57.886C-60.388,-31.206 -43.085,-8.57 -19.091,-0.585C-16.073,-0.026 -14.965,-1.895 -14.965,-3.49C-14.965,-4.929 -15.021,-9.687 -15.047,-14.733C-31.847,-11.08 -35.392,-21.858 -35.392,-21.858C-38.139,-28.837 -42.097,-30.694 -42.097,-30.694C-47.576,-34.442 -41.684,-34.365 -41.684,-34.365C-35.62,-33.939 -32.427,-28.141 -32.427,-28.141C-27.041,-18.91 -18.3,-21.579 -14.854,-23.122C-14.311,-27.024 -12.747,-29.689 -11.02,-31.197C-24.433,-32.723 -38.533,-37.902 -38.533,-61.041C-38.533,-67.633 -36.174,-73.021 -32.311,-77.25C-32.938,-78.771 -35.005,-84.913 -31.725,-93.231C-31.725,-93.231 -26.654,-94.853 -15.115,-87.04C-10.298,-88.378 -5.132,-89.049 0,-89.073C5.132,-89.049 10.302,-88.378 15.128,-87.04C26.654,-94.853 31.718,-93.231 31.718,-93.231C35.005,-84.913 32.938,-78.771 32.311,-77.25C36.183,-73.021 38.525,-67.633 38.525,-61.041C38.525,-37.846 24.398,-32.74 10.951,-31.245C13.117,-29.371 15.047,-25.696 15.047,-20.062C15.047,-11.982 14.978,-5.479 14.978,-3.49C14.978,-1.882 16.064,0 19.125,-0.592C43.107,-8.586 60.388,-31.214 60.388,-57.886C60.388,-91.239 33.351,-118.274 0,-118.274" style="fill:rgb(223,240,254);stroke:rgb(71,136,199);stroke-width:2.89px;"/>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="40px" height="40px"><path fill="#dff0fe" d="M13.833,3.5h12.333L38.5,25l-12.029,0.235l-0.304-0.402L13.833,3.5z"/><path fill="#98ccfd" d="M7.557,35.5L13.779,25H38.5l-6.167,10.5H7.557z"/><path fill="#b6dcfe" d="M1.5,24.944L7.557,35.5L20,14.167L13.833,3.5L1.5,24.944z"/><path fill="#4788c7" d="M32.333,36H7.557c-0.179,0-0.344-0.096-0.433-0.25l-6.057-10.5c-0.089-0.154-0.089-0.345,0-0.499 L13.4,3.251C13.489,3.096,13.654,3,13.833,3h12.333c0.179,0,0.345,0.096,0.434,0.251l12.333,21.5 c0.089,0.156,0.088,0.348-0.002,0.502l-6.167,10.5C32.675,35.906,32.511,36,32.333,36z M7.845,35h24.202l5.875-10.003L25.877,4 H14.123L2.077,24.999L7.845,35z"/><path fill="#4788c7" d="M7.529,35.617c-0.085,0-0.171-0.021-0.25-0.067c-0.239-0.139-0.32-0.445-0.181-0.684L18.509,15.22 c0.139-0.24,0.444-0.32,0.683-0.182c0.239,0.139,0.32,0.445,0.181,0.684L7.961,35.368C7.869,35.528,7.701,35.617,7.529,35.617z"/><path fill="#4788c7" d="M38,26H15.647c-0.276,0-0.5-0.224-0.5-0.5s0.224-0.5,0.5-0.5H38c0.276,0,0.5,0.224,0.5,0.5 S38.276,26,38,26z"/><path fill="#4788c7" d="M25.942,23.971c-0.172,0-0.34-0.089-0.433-0.249L14.097,4.074c-0.139-0.238-0.058-0.545,0.181-0.684 c0.238-0.139,0.544-0.059,0.683,0.182L26.374,23.22c0.139,0.238,0.058,0.545-0.181,0.684 C26.113,23.949,26.027,23.971,25.942,23.971z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="40px" height="40px"><path fill="#98ccfd" d="M31.186,21.769h0.01c0,0-3.586,5.26-6.601,9.17c-2.606,3.377-3.367,6.269-3.586,7.667 C20.923,39.12,20.504,39.5,20,39.5s-0.923-0.38-1.008-0.894c-0.219-1.398-0.98-4.29-3.586-7.667c-0.4-0.523-0.809-1.065-1.218-1.617 l9.845-11.7l7.924-9.398c0.875,1.836,1.36,3.89,1.36,6.069C33.317,17.051,32.528,19.61,31.186,21.769z"/><path fill="#fff" d="M24.033,17.622l-9.845,11.7c-2.682-3.596-5.384-7.553-5.384-7.553h0.01 c-0.285-0.457-0.542-0.923-0.761-1.408l7.914-9.398c-0.751,0.904-1.199,2.064-1.199,3.329c0,2.892,2.34,5.232,5.232,5.232 C21.627,19.524,23.082,18.782,24.033,17.622z"/><path fill="#98ccfd" d="M24.185,1.204l-8.152,9.683l-6.24-5.441C12.229,2.421,15.9,0.5,20,0.5 C21.465,0.5,22.873,0.747,24.185,1.204z"/><path fill="#dff0fe" d="M16.033,10.887l-0.067,0.076l-7.914,9.398c-0.875-1.836-1.37-3.89-1.37-6.069 c0-3.367,1.17-6.459,3.11-8.846L16.033,10.887z"/><path fill="#b6dcfe" d="M24.033,17.622c0.751-0.904,1.199-2.064,1.199-3.329c0-2.892-2.34-5.232-5.232-5.232 c-1.627,0-3.082,0.742-4.033,1.902l8.219-9.76c3.415,1.16,6.211,3.719,7.771,7.02L24.033,17.622z"/><path fill="#4788c7" d="M20,40c-0.75,0-1.387-0.552-1.515-1.312c-0.218-1.372-0.966-4.157-3.536-7.44 c-0.409-0.527-0.825-1.071-1.241-1.625c-2.693-3.563-5.442-7.529-5.469-7.569L7.785,21.27c-0.128-0.235-0.245-0.468-0.351-0.7 C6.484,18.604,6,16.489,6,14.293c0-3.353,1.16-6.607,3.268-9.165C11.927,1.87,15.839,0,20,0c1.51,0,2.993,0.246,4.405,0.731 c3.542,1.187,6.52,3.84,8.167,7.276C33.52,9.968,34,12.083,34,14.293c0,2.445-0.615,4.839-1.786,6.977h0.079l-0.532,0.784 c-0.036,0.053-3.679,5.316-6.709,9.193c-2.57,3.284-3.318,6.069-3.536,7.437C21.387,39.448,20.75,40,20,40z M9.178,21.652 c0.55,0.79,2.961,4.237,5.33,7.368c0.414,0.551,0.827,1.091,1.231,1.613c2.707,3.458,3.501,6.43,3.733,7.894 C19.518,38.799,19.74,39,20,39s0.482-0.201,0.529-0.478c0.232-1.459,1.026-4.431,3.735-7.892c2.74-3.504,5.986-8.154,6.579-9.008 l0.074-0.12C32.28,19.339,33,16.846,33,14.293c0-2.058-0.447-4.026-1.329-5.852c-1.531-3.196-4.296-5.66-7.587-6.764 C22.772,1.228,21.399,1,20,1c-3.859,0-7.489,1.736-9.959,4.763C8.08,8.143,7,11.172,7,14.293c0,2.044,0.451,4.013,1.339,5.851 c0.205,0.448,0.447,0.89,0.744,1.358L9.178,21.652z M20,20c-3.309,0-6-2.691-6-6c0-1.396,0.489-2.753,1.376-3.819 C16.51,8.796,18.197,8,20,8c3.309,0,6,2.691,6,6c0,1.396-0.489,2.753-1.376,3.819C23.49,19.204,21.803,20,20,20z M20,9 c-1.502,0-2.907,0.662-3.853,1.817C15.407,11.707,15,12.837,15,14c0,2.757,2.243,5,5,5c1.502,0,2.907-0.662,3.853-1.817 C24.593,16.293,25,15.163,25,14C25,11.243,22.757,9,20,9z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#fff" d="M6,36.5c-1.378,0-2.5-1.121-2.5-2.5V6c0-1.379,1.122-2.5,2.5-2.5h28c1.378,0,2.5,1.121,2.5,2.5v28 c0,1.379-1.122,2.5-2.5,2.5H6z"/><path fill="#4788c7" d="M34,4c1.103,0,2,0.897,2,2v28c0,1.103-0.897,2-2,2H6c-1.103,0-2-0.897-2-2V6c0-1.103,0.897-2,2-2 H34 M34,3H6C4.343,3,3,4.343,3,6v28c0,1.657,1.343,3,3,3h28c1.657,0,3-1.343,3-3V6C37,4.343,35.657,3,34,3L34,3z"/><path fill="#98ccfd" d="M14 13.5A6.5 6.5 0 1 0 14 26.5A6.5 6.5 0 1 0 14 13.5Z"/><path fill="#4788c7" d="M14,14c3.308,0,6,2.692,6,6s-2.692,6-6,6s-6-2.692-6-6S10.692,14,14,14 M14,13 c-3.866,0-7,3.134-7,7s3.134,7,7,7s7-3.134,7-7S17.866,13,14,13L14,13z"/><path fill="#dff0fe" d="M14.5,19.5v-5.981c3.187,0.244,5.737,2.795,5.981,5.981H14.5z"/><path fill="#4788c7" d="M15 14.083c2.509.423 4.494 2.408 4.917 4.917H15V14.083M14 13v7h7C21 16.134 17.866 13 14 13L14 13zM32.5 15h-9c-.275 0-.5-.225-.5-.5v0c0-.275.225-.5.5-.5h9c.275 0 .5.225.5.5v0C33 14.775 32.775 15 32.5 15zM32.5 19h-9c-.275 0-.5-.225-.5-.5l0 0c0-.275.225-.5.5-.5h9c.275 0 .5.225.5.5l0 0C33 18.775 32.775 19 32.5 19zM32.5 23h-9c-.275 0-.5-.225-.5-.5l0 0c0-.275.225-.5.5-.5h9c.275 0 .5.225.5.5l0 0C33 22.775 32.775 23 32.5 23zM28.5 27h-5c-.275 0-.5-.225-.5-.5l0 0c0-.275.225-.5.5-.5h5c.275 0 .5.225.5.5l0 0C29 26.775 28.775 27 28.5 27z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="40px" height="40px"><path fill="#98ccfd" d="M28.229,29.396c1.528-1.345,2.711-3.051,3.438-4.968c0.187-0.491,0.321-0.905,0.423-1.303l0.16-0.625 H20.5v-6h17.662c0.225,1.167,0.338,2.343,0.338,3.5c0,5.005-2.069,9.834-5.692,13.32L28.229,29.396z"/><path fill="#98ccfd" d="M32.828,22c-0.501,3.231-2.175,6.075-4.594,8.058l3.825,3.278c3.175-2.873,5.329-6.852,5.828-11.336 L32.828,22z"/><path fill="#b6dcfe" d="M20,38.5c-6.903,0-13.128-3.773-16.349-9.877l4.957-3.499C10.625,29.626,15.031,32.5,20,32.5 c2.713,0,5.277-0.851,7.439-2.465l4.624,3.963C28.695,36.906,24.434,38.5,20,38.5z"/><path fill="#b6dcfe" d="M28.234,30.058C25.992,31.896,23.125,33,20,33c-5.407,0-10.041-3.303-12-8l-4.13,2.95 C6.807,33.899,12.917,38,20,38c4.645,0,8.866-1.775,12.059-4.664L28.234,30.058z"/><path fill="#b6dcfe" d="M3.891,10.907C7.177,5.094,13.31,1.5,20,1.5c4.493,0,8.8,1.632,12.186,4.607l-4.212,4.212 C25.757,8.498,22.944,7.5,20,7.5c-4.84,0-9.196,2.763-11.271,7.093L3.891,10.907z"/><path fill="#b6dcfe" d="M20,7V2C13.07,2,7.064,5.922,4.056,11.662l4.056,3.09C10.13,10.189,14.689,7,20,7z"/><path fill="#fff" d="M3.235,27.789C2.083,25.324,1.5,22.707,1.5,20c0-2.838,0.661-5.66,1.917-8.197l4.905,3.737 C7.776,16.965,7.5,18.463,7.5,20c0,1.435,0.249,2.851,0.74,4.214L3.235,27.789z"/><path fill="#fff" d="M7,20c0-1.869,0.402-3.642,1.112-5.248l-4.056-3.09C2.749,14.156,2,16.989,2,20 c0,2.858,0.684,5.55,1.869,7.951L8,25C7.357,23.461,7,21.772,7,20z"/><path fill="#4788c7" d="M20,39c-7.056,0-13.489-3.887-16.792-10.144l-0.421-0.844C1.6,25.471,1,22.779,1,20 c0-2.906,0.681-5.817,1.969-8.419l0.48-0.908C6.824,4.702,13.163,1,20,1c4.599,0,9.043,1.68,12.516,4.731 c0.104,0.091,0.165,0.221,0.169,0.359c0.005,0.138-0.048,0.272-0.146,0.37l-4.212,4.212c-0.182,0.182-0.473,0.196-0.671,0.033 C25.532,8.961,22.813,8,20,8c-4.661,0-8.807,2.609-10.82,6.809l-0.398,0.928C8.266,17.084,8,18.525,8,20 c0,1.375,0.239,2.736,0.71,4.044l0.361,0.892C11.021,29.287,15.211,32,20,32c2.598,0,5.066-0.818,7.14-2.366l0.775-0.627 c1.449-1.276,2.591-2.926,3.285-4.757c0.178-0.469,0.307-0.866,0.406-1.25l0-0.001H20.5c-0.276,0-0.5-0.224-0.5-0.5v-6 c0-0.276,0.224-0.5,0.5-0.5h17.662c0.24,0,0.446,0.17,0.491,0.405C38.883,17.599,39,18.808,39,20c0,5.12-2.13,10.106-5.845,13.68 l-0.755,0.688C28.937,37.358,24.537,39,20,39z M20,2C13.523,2,7.518,5.507,4.326,11.153l-0.467,0.883C2.645,14.49,2,17.248,2,20 c0,2.631,0.568,5.181,1.688,7.577l0.41,0.823C7.221,34.317,13.316,38,20,38c4.297,0,8.465-1.556,11.736-4.38l0.735-0.669 C35.981,29.573,38,24.85,38,20c0-0.994-0.086-2.001-0.255-3H21v5h11.25c0.154,0,0.3,0.071,0.395,0.193s0.127,0.281,0.089,0.431 l-0.16,0.625c-0.108,0.422-0.248,0.853-0.44,1.357c-0.751,1.981-1.988,3.768-3.575,5.166l-0.806,0.652 C25.491,32.113,22.815,33,20,33c-5.188,0-9.728-2.939-11.848-7.671l-0.375-0.927C7.259,22.966,7,21.491,7,20 c0-1.598,0.288-3.159,0.855-4.639l0.414-0.965C10.459,9.827,14.951,7,20,7c2.889,0,5.689,0.938,7.935,2.65l3.515-3.514 C28.223,3.465,24.178,2,20,2z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#4788c7" d="M4.286,34.7c-0.128,0-0.256-0.049-0.354-0.146c-0.195-0.195-0.195-0.512,0-0.707l6.7-6.7 C10.727,27.053,10.854,27,10.986,27h17.027c0.133,0,0.26,0.053,0.354,0.146l6.658,6.658c0.195,0.195,0.195,0.512,0,0.707 s-0.512,0.195-0.707,0L27.807,28H11.193L4.64,34.554C4.542,34.651,4.414,34.7,4.286,34.7z"/><path fill="#4788c7" d="M34.228,25H3.471c-0.276,0-0.5-0.224-0.5-0.5s0.224-0.5,0.5-0.5h30.757c0.276,0,0.5,0.224,0.5,0.5 S34.504,25,34.228,25z"/><path fill="#4788c7" d="M28.014,22H10.986c-0.133,0-0.26-0.053-0.354-0.146l-6.7-6.7c-0.195-0.195-0.195-0.512,0-0.707 s0.512-0.195,0.707,0L11.193,21h16.613l6.512-6.512c0.195-0.195,0.512-0.195,0.707,0s0.195,0.512,0,0.707l-6.658,6.658 C28.273,21.947,28.146,22,28.014,22z"/><circle cx="4.5" cy="34.5" r="2" fill="#98ccfd"/><path fill="#4788c7" d="M4.5,37C3.121,37,2,35.879,2,34.5S3.121,32,4.5,32S7,33.121,7,34.5S5.879,37,4.5,37z M4.5,33 C3.673,33,3,33.673,3,34.5S3.673,36,4.5,36S6,35.327,6,34.5S5.327,33,4.5,33z"/><circle cx="34.5" cy="34.5" r="2" fill="#98ccfd"/><path fill="#4788c7" d="M34.5,37c-1.379,0-2.5-1.121-2.5-2.5s1.121-2.5,2.5-2.5s2.5,1.121,2.5,2.5S35.879,37,34.5,37z M34.5,33c-0.827,0-1.5,0.673-1.5,1.5s0.673,1.5,1.5,1.5s1.5-0.673,1.5-1.5S35.327,33,34.5,33z"/><circle cx="4.5" cy="24.5" r="2" fill="#98ccfd"/><path fill="#4788c7" d="M4.5,27C3.121,27,2,25.879,2,24.5S3.121,22,4.5,22S7,23.121,7,24.5S5.879,27,4.5,27z M4.5,23 C3.673,23,3,23.673,3,24.5S3.673,26,4.5,26S6,25.327,6,24.5S5.327,23,4.5,23z"/><circle cx="4.5" cy="14.5" r="2" fill="#98ccfd"/><path fill="#4788c7" d="M4.5,17C3.121,17,2,15.879,2,14.5S3.121,12,4.5,12S7,13.121,7,14.5S5.879,17,4.5,17z M4.5,13 C3.673,13,3,13.673,3,14.5S3.673,16,4.5,16S6,15.327,6,14.5S5.327,13,4.5,13z"/><circle cx="34.5" cy="14.5" r="2" fill="#98ccfd"/><path fill="#4788c7" d="M34.5,17c-1.379,0-2.5-1.121-2.5-2.5s1.121-2.5,2.5-2.5s2.5,1.121,2.5,2.5S35.879,17,34.5,17z M34.5,13c-0.827,0-1.5,0.673-1.5,1.5s0.673,1.5,1.5,1.5s1.5-0.673,1.5-1.5S35.327,13,34.5,13z"/><circle cx="34.5" cy="24.5" r="2" fill="#98ccfd"/><path fill="#4788c7" d="M34.5,27c-1.379,0-2.5-1.121-2.5-2.5s1.121-2.5,2.5-2.5s2.5,1.121,2.5,2.5S35.879,27,34.5,27z M34.5,23c-0.827,0-1.5,0.673-1.5,1.5s0.673,1.5,1.5,1.5s1.5-0.673,1.5-1.5S35.327,23,34.5,23z"/><rect width="11" height="1" x="14" y="21" fill="#b6dcfe"/><path fill="#4788c7" d="M13.957,22h-1.082c-0.276,0-0.5-0.224-0.5-0.5s0.224-0.5,0.5-0.5h1.082c0.276,0,0.5,0.224,0.5,0.5 S14.233,22,13.957,22z"/><path fill="#4788c7" d="M26.162,22H25.08c-0.276,0-0.5-0.224-0.5-0.5s0.224-0.5,0.5-0.5h1.082c0.276,0,0.5,0.224,0.5,0.5 S26.438,22,26.162,22z"/><rect width="11" height="1" x="14" y="24" fill="#b6dcfe"/><path fill="#4788c7" d="M13.957,25h-1.082c-0.276,0-0.5-0.224-0.5-0.5s0.224-0.5,0.5-0.5h1.082c0.276,0,0.5,0.224,0.5,0.5 S14.233,25,13.957,25z"/><path fill="#4788c7" d="M26.162,25H25.08c-0.276,0-0.5-0.224-0.5-0.5s0.224-0.5,0.5-0.5h1.082c0.276,0,0.5,0.224,0.5,0.5 S26.438,25,26.162,25z"/><g><rect width="11" height="1" x="14" y="26.996" fill="#b6dcfe"/></g><g><path fill="#4788c7" d="M13.957,27.996h-1.082c-0.276,0-0.5-0.224-0.5-0.5s0.224-0.5,0.5-0.5h1.082 c0.276,0,0.5,0.224,0.5,0.5S14.233,27.996,13.957,27.996z"/></g><g><path fill="#4788c7" d="M26.162,27.996H25.08c-0.276,0-0.5-0.224-0.5-0.5s0.224-0.5,0.5-0.5h1.082 c0.276,0,0.5,0.224,0.5,0.5S26.438,27.996,26.162,27.996z"/></g><path fill="#dff0fe" d="M18.268,35.5L16.5,32.849V17.5H15c-1.93,0-3.5-1.57-3.5-3.5V8c0-1.93,1.57-3.5,3.5-3.5h9 c1.93,0,3.5,1.57,3.5,3.5v6c0,1.93-1.57,3.5-3.5,3.5h-1.5v4.293l-1,1v1.414l1,1v1.586l-1,1v1.414l1,1v2.642L20.732,35.5H18.268z M16,7.5c-0.827,0-1.5,0.673-1.5,1.5v1c0,0.827,0.673,1.5,1.5,1.5h7c0.827,0,1.5-0.673,1.5-1.5V9c0-0.827-0.673-1.5-1.5-1.5H16z"/><path fill="#4788c7" d="M24,5c1.654,0,3,1.346,3,3v6c0,1.654-1.346,3-3,3h-1h-1v1v3.586l-0.707,0.707L21,22.586V23v1v0.414 l0.293,0.293L22,25.414v1.172l-0.707,0.707L21,27.586V28v1v0.414l0.293,0.293L22,30.414v2.283L20.465,35h-1.93L17,32.697V18v-1h-1 h-1c-1.654,0-3-1.346-3-3V8c0-1.654,1.346-3,3-3H24 M16,12h7c1.103,0,2-0.897,2-2V9c0-1.103-0.897-2-2-2h-7c-1.103,0-2,0.897-2,2v1 C14,11.103,14.897,12,16,12 M24,4h-9c-2.209,0-4,1.791-4,4v6c0,2.209,1.791,4,4,4h1v15l2,3h3l2-3v-3l-1-1v-1l1-1v-2l-1-1v-1l1-1v-4 h1c2.209,0,4-1.791,4-4V8C28,5.791,26.209,4,24,4L24,4z M16,11c-0.552,0-1-0.448-1-1V9c0-0.552,0.448-1,1-1h7c0.552,0,1,0.448,1,1v1 c0,0.552-0.448,1-1,1H16L16,11z"/><path fill="#98ccfd" d="M19,35V17h-1v17.197L18.535,35H19z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#98ccfd" d="M4,38.5c-1.378,0-2.5-1.122-2.5-2.5v-8L5.494,3.411C5.65,2.317,6.592,1.5,7.687,1.5h24.626 c1.095,0,2.037,0.817,2.192,1.901l4.001,24.679L38.5,36c0,1.378-1.122,2.5-2.5,2.5H4z"/><path fill="#4788c7" d="M32.313,2c0.848,0,1.577,0.633,1.7,1.49L38,28.081V36c0,1.103-0.897,2-2,2H4c-1.103,0-2-0.897-2-2 v-7.919L5.99,3.472C6.11,2.633,6.839,2,7.687,2H32.313 M32.313,1H7.687C6.336,1,5.191,1.993,5,3.33L1,28v8c0,1.657,1.343,3,3,3h32 c1.657,0,3-1.343,3-3v-8L35,3.33C34.809,1.993,33.664,1,32.313,1L32.313,1z"/><path fill="#dff0fe" d="M7.687,2C6.839,2,6.11,2.633,5.99,3.472L2.013,28h35.974L34.013,3.49C33.89,2.633,33.161,2,32.313,2 H7.687z"/><path fill="#fff" d="M33,31c-1.105,0-2,0.895-2,2c0,1.105,0.895,2,2,2s2-0.895,2-2C35,31.895,34.105,31,33,31L33,31z"/><path fill="#98ccfd" d="M20,22.5c-6.341,0-11.5-3.364-11.5-7.5S13.659,7.5,20,7.5s11.5,3.364,11.5,7.5S26.341,22.5,20,22.5z"/><path fill="#4788c7" d="M20,8c6.065,0,11,3.14,11,7s-4.935,7-11,7c-6.065,0-11-3.14-11-7S13.935,8,20,8 M20,7 c-6.627,0-12,3.582-12,8s5.373,8,12,8s12-3.582,12-8S26.627,7,20,7L20,7z"/><path fill="#4788c7" d="M20 14A3 1 0 1 0 20 16A3 1 0 1 0 20 14Z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M20.023,35.377C17.729,33.522,2.5,20.933,2.5,13.739C2.5,8.645,6.624,4.5,11.692,4.5 c3.251,0,6.197,1.682,7.878,4.498L20,9.717l0.429-0.719C22.111,6.182,25.056,4.5,28.308,4.5c5.069,0,9.192,4.145,9.192,9.239 C37.5,22.858,22.364,33.749,20.023,35.377z"/><path fill="#4788c7" d="M28.308,5C33.101,5,37,8.92,37,13.739c0,8.548-13.881,18.839-16.958,21.015 C14.791,30.513,3,19.734,3,13.739C3,8.92,6.899,5,11.692,5c3.074,0,5.858,1.59,7.449,4.254L20,10.692l0.859-1.438 C22.449,6.59,25.234,5,28.308,5 M28.308,4C24.776,4,21.694,5.905,20,8.742C18.306,5.905,15.224,4,11.692,4C6.339,4,2,8.36,2,13.739 C2,21.814,20,36,20,36s18-12.043,18-22.261C38,8.36,33.661,4,28.308,4L28.308,4z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#98ccfd" d="M16.5 28.5H23.5V34.5H16.5z"/><path fill="#4788c7" d="M23,29v5h-6v-5H23 M24,28h-8v7h8V28L24,28z"/><path fill="#fff" d="M1.5 4.5H38.5V30.5H1.5z"/><path fill="#4788c7" d="M38,5v25H2V5H38 M39,4H1v27h38V4L39,4z"/><path fill="#98ccfd" d="M1.5 26.5H38.5V30.5H1.5z"/><path fill="#4788c7" d="M38,27v3H2v-3H38 M39,26H1v5h38V26L39,26z"/><path fill="#98ccfd" d="M9.5,36.5V36c0-1.378,1.122-2.5,2.5-2.5h16c1.378,0,2.5,1.122,2.5,2.5v0.5H9.5z"/><path fill="#4788c7" d="M28,34c1.103,0,2,0.897,2,2H10c0-1.103,0.897-2,2-2H28 M28,33H12c-1.657,0-3,1.343-3,3v1h22v-1 C31,34.343,29.657,33,28,33L28,33z"/><path fill="#fff" d="M36.5,29h-2c-0.276,0-0.5-0.224-0.5-0.5v0c0-0.276,0.224-0.5,0.5-0.5h2c0.276,0,0.5,0.224,0.5,0.5v0 C37,28.776,36.776,29,36.5,29z"/><g><path fill="#dff0fe" d="M19.999,22.46c-1.056-0.461-6.369-3.221-6.497-12.131L20,7.544l6.498,2.785 C26.369,19.213,21.018,22.008,19.999,22.46z"/><path fill="#4788c7" d="M20,8.088l5.99,2.567c-0.235,7.926-4.697,10.636-5.987,11.255 c-1.297-0.631-5.759-3.371-5.994-11.255L20,8.088 M20,7l-7,3c0,10.46,7,13,7,13s7-2.486,7-13L20,7L20,7z"/></g><path fill="#98ccfd" d="M20,10.264l-3.9,1.671c0.483,4.491,2.6,6.692,3.912,7.643c1.292-0.934,3.408-3.124,3.889-7.643 L20,10.264z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#fff" d="M9.5,34.625V30c0-4.093,2.412-7.839,6.145-9.545L16.64,20l-0.995-0.455 C11.912,17.839,9.5,14.093,9.5,10V5.375h21V10c0,4.093-2.412,7.839-6.145,9.545L23.36,20l0.995,0.455 C28.088,22.161,30.5,25.907,30.5,30v4.625H9.5z"/><path fill="#4788c7" d="M30,5.875V10c0,3.897-2.297,7.465-5.853,9.091L22.158,20l1.989,0.909 C27.703,22.535,30,26.103,30,30v4.125H10V30c0-3.897,2.297-7.465,5.853-9.091L17.842,20l-1.989-0.909 C12.297,17.465,10,13.897,10,10V5.875H30 M31,4.875H9V10c0,4.445,2.642,8.265,6.437,10C11.642,21.735,9,25.555,9,30v5.125h22V30 c0-4.445-2.642-8.265-6.437-10C28.358,18.265,31,14.445,31,10V4.875L31,4.875z"/><path fill="#dff0fe" d="M9.5,7.5v-3H9c-1.183,0-2.5-0.88-2.5-2.143V1.5h27V2c0,1.215-1.285,2.5-2.5,2.5h-0.5v3H9.5z"/><path fill="#4788c7" d="M33,2c0,0.953-1.047,2-2,2h-1v1v2H10V5V4H9C8.056,4,7,3.297,7,2.357V2H33 M34,1H6v1.357 C6,3.856,7.501,5,9,5v3h22V5c1.499,0,3-1.501,3-3V1L34,1z"/><path fill="#98ccfd" d="M11,33h18c0-6.028-9-9-9-9S11,26.918,11,33z"/><path fill="#dff0fe" d="M6.5,38.5V38c0-1.215,1.285-2.5,2.5-2.5h0.5v-3h21v3H31c1.215,0,2.5,1.285,2.5,2.5v0.5H6.5z"/><path fill="#4788c7" d="M30,33v2v1h1c0.953,0,2,1.047,2,2H7c0-0.953,1.047-2,2-2h1v-1v-2H30 M31,32H9v3 c-1.499,0-3,1.501-3,3v1h28v-1c0-1.499-1.501-3-3-3V32L31,32z"/><g><path fill="#98ccfd" d="M12.955,14c1.408,2.431,4.032,4,7.045,4s5.592-1.569,7-4H12.955z"/></g><path fill="#b6dcfe" d="M10 4H30V7H10zM10 33H30V36H10z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M3.5 38.5L3.5 13.286 19.998 3.58 36.5 13.286 36.5 38.5z"/><path fill="#4788c7" d="M19.998,4.16L36,13.572V38H4V13.572L19.998,4.16 M19.998,3L3,13v26h34V13L19.998,3L19.998,3z"/><path fill="#b6dcfe" d="M19.998 4.645L1.5 15.955 1.5 12.896 19.998 1.586 38.5 12.896 38.5 15.955z"/><path fill="#4788c7" d="M19.998,2.172L38,13.176v1.887L20.519,4.378l-0.522-0.319l-0.522,0.319L2,15.063v-1.887 L19.998,2.172 M19.998,1L1,12.615v4.231L19.998,5.231L39,16.846v-4.231L19.998,1L19.998,1z"/><g><path fill="#b6dcfe" d="M14.5 21.5H25.5V38.5H14.5z"/><path fill="#4788c7" d="M25,22v16H15V22H25 M26,21H14v18h12V21L26,21z"/></g><path fill="#4788c7" d="M23 30A1 1 0 1 0 23 32A1 1 0 1 0 23 30Z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M4,33.5c-0.827,0-1.5-0.673-1.5-1.5V8c0-0.827,0.673-1.5,1.5-1.5h32c0.827,0,1.5,0.673,1.5,1.5v24 c0,0.827-0.673,1.5-1.5,1.5H4z"/><path fill="#4788c7" d="M36,7c0.551,0,1,0.449,1,1v24c0,0.551-0.449,1-1,1H4c-0.551,0-1-0.449-1-1V8c0-0.551,0.449-1,1-1 H36 M36,6H4C2.895,6,2,6.895,2,8v24c0,1.105,0.895,2,2,2h32c1.105,0,2-0.895,2-2V8C38,6.895,37.105,6,36,6L36,6z"/><path fill="#4788c7" d="M9.92 15.8v3.511h1.781V15.8h1.703v8.763h-1.703v-3.666H9.92v3.666H8.217V15.8H9.92zM16.187 17.373h-1.547V15.8h4.811v1.573h-1.56v7.189h-1.703V17.373zM26.028 21.494c-.052-.832-.104-1.963-.091-2.898h-.026c-.156.936-.39 2.015-.559 2.69l-.767 3.134h-1.196l-.728-3.082c-.169-.701-.403-1.794-.546-2.742h-.026c-.026.948-.091 2.054-.13 2.925l-.156 3.042h-1.456l.624-8.763h1.807l.702 3.173c.234 1.104.455 2.08.611 3.067h.039c.13-.975.325-1.963.546-3.067l.702-3.173h1.794l.533 8.763h-1.521L26.028 21.494zM29.277 15.8h1.703v7.319h2.236v1.443h-3.939V15.8z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M1.5 30.167L1.5 22.72 5.474 4.5 34.526 4.5 38.5 22.72 38.5 30.167z"/><path fill="#4788c7" d="M34.123,5L38,22.774v6.892H2v-6.892L5.877,5H34.123 M34.929,4H5.071L1,22.666v8h38v-8L34.929,4L34.929,4z"/><path fill="#b6dcfe" d="M34.929,32H5.071v-8.91L8.363,8h23.274l3.291,15.09L34.929,32L34.929,32z"/><path fill="#dff0fe" d="M1.5,35.5v-13h13.022C14.508,22.667,14.5,22.833,14.5,23c0,3.033,2.468,5.5,5.5,5.5s5.5-2.467,5.5-5.5c0-0.167-0.008-0.333-0.022-0.5H38.5v13H1.5z"/><path fill="#4788c7" d="M38,23v12H2V23h12c0,3.308,2.692,6,6,6s6-2.692,6-6H38 M38,22H24.899C24.965,22.323,25,22.657,25,23c0,2.761-2.239,5-5,5s-5-2.239-5-5c0-0.343,0.035-0.677,0.101-1H2l-1,1v13h38V23L38,22z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#4788c7" d="M38.5 8h-29C9.224 8 9 7.776 9 7.5v0C9 7.224 9.224 7 9.5 7h29C38.776 7 39 7.224 39 7.5v0C39 7.776 38.776 8 38.5 8zM31.5 12h-22C9.224 12 9 11.776 9 11.5v0C9 11.224 9.224 11 9.5 11h22c.276 0 .5.224.5.5v0C32 11.776 31.776 12 31.5 12z"/><path fill="#dff0fe" d="M1.5 7.5H5.5V11.5H1.5z"/><path fill="#4788c7" d="M5 8v3H2V8H5M6 7H1v5h5V7L6 7zM38.5 19h-29C9.224 19 9 18.776 9 18.5l0 0C9 18.224 9.224 18 9.5 18h29c.276 0 .5.224.5.5l0 0C39 18.776 38.776 19 38.5 19zM31.5 23h-22C9.224 23 9 22.776 9 22.5l0 0C9 22.224 9.224 22 9.5 22h22c.276 0 .5.224.5.5l0 0C32 22.776 31.776 23 31.5 23z"/><path fill="#dff0fe" d="M1.5 18.5H5.5V22.5H1.5z"/><path fill="#4788c7" d="M5 19v3H2v-3H5M6 18H1v5h5V18L6 18zM38.5 30h-29C9.224 30 9 29.776 9 29.5l0 0C9 29.224 9.224 29 9.5 29h29c.276 0 .5.224.5.5l0 0C39 29.776 38.776 30 38.5 30zM31.5 34h-22C9.224 34 9 33.776 9 33.5l0 0C9 33.224 9.224 33 9.5 33h22c.276 0 .5.224.5.5l0 0C32 33.776 31.776 34 31.5 34z"/><g><path fill="#dff0fe" d="M1.5 29.5H5.5V33.5H1.5z"/><path fill="#4788c7" d="M5,30v3H2v-3H5 M6,29H1v5h5V29L6,29z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#98ccfd" d="M16.13 35.5L5.5 35.5 5.5 2.5 34.5 2.5 34.5 35.5 23.716 35.5 19.994 39.293z"/><path fill="#4788c7" d="M34,3v32H23.926h-0.42l-0.294,0.3l-3.225,3.286l-3.36-3.299L16.335,35h-0.409H6V3H34 M35,2H5v34 h10.926L20,40l3.926-4H35V2L35,2z"/><path fill="#fff" d="M20 9A2 2 0 1 0 20 13A2 2 0 1 0 20 9Z"/><g><path fill="#fff" d="M22 27L22 15 17 15 17 16 18 16 18 27 17 27 17 28 23 28 23 27z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M12.5 37.5L12.5 34.5 16.5 34.5 16.5 17.5 12.5 17.5 12.5 14.5 23.5 14.5 23.5 34.5 27.5 34.5 27.5 37.5z"/><path fill="#4788c7" d="M23,15v19v1h1h3v2H13v-2h3h1v-1V18v-1h-1h-3v-2h3h4H23 M24,14h-4h-4h-4v4h4v16h-4v4h16v-4h-4V14 L24,14z"/><g><path fill="#dff0fe" d="M20 2.5A4.5 4.5 0 1 0 20 11.5A4.5 4.5 0 1 0 20 2.5Z"/><path fill="#4788c7" d="M20,3c2.206,0,4,1.794,4,4s-1.794,4-4,4s-4-1.794-4-4S17.794,3,20,3 M20,2c-2.761,0-5,2.239-5,5 s2.239,5,5,5s5-2.239,5-5S22.761,2,20,2L20,2z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#c1e3f7" d="M39,20c0,10.6-8.6,19-19,19C9.6,39,1,30.6,1,20S9.4,1,20,1S39,9.4,39,20z"/><path fill="#7290bb" d="M20,1C20,1,20,1,20,1C20,1,20,1,20,1C20,1,20,1,20,1C9.4,1,1,9.4,1,20c0,4.1,1.3,7.9,3.5,11v0h0 c3.5,4.8,9.1,8,15.5,8c0,0,0,0,0,0c0,0,0,0,0,0c0,0,0,0,0,0c0.7,0,1.3,0,2-0.1c0.4,0,0.7-0.1,1.1-0.1c2.3-0.4,4.4-1.2,6.3-2.3 l-0.7-0.7c-0.9,0.5-1.9,1-3,1.3c-1.3,0.4-2.8,0.7-3.9,0.7c0.1-0.1,0.2-0.3,0.3-0.4V35c-0.7,2-1.5,3-2,3c0,0,0,0,0,0 c-0.8,0-2.2-2.4-3.1-7H22v-1h-5.2c-0.3-1.7-0.5-3.7-0.7-6H22v-1h-5.9c0-1-0.1-2-0.1-3s0-2,0.1-3h7.9c0,1,0.1,2,0.1,3 c0,0.7,0,1.4,0,2h1c0-0.7,0-1.3,0-2c0-1,0-2-0.1-3h6.9c0.1,1,0.2,2,0.2,3c0,0.7,0,1.3-0.1,2h1c0.1-0.7,0.1-1.3,0.1-2 c0-1-0.1-2-0.2-3h4.9c0.2,1,0.3,2,0.3,3c0,0.7-0.1,1.3-0.1,2c0,0.3-0.1,0.7-0.1,1l-0.2,1c0,0.1-0.1,0.3-0.1,0.4 c-0.4,1.5-0.9,2.9-1.7,4.3l0.7,0.7c1.1-1.9,1.9-4.1,2.3-6.3c0.1-0.4,0.1-0.7,0.1-1.1c0.1-0.7,0.1-1.3,0.1-2C39,9.4,30.6,1,20,1z M34.3,9h-3.7c-1.3-2.6-3-4.7-5-6.1C29.1,4,32.1,6.1,34.3,9z M20,2L20,2c0.8,0,2.2,2.4,3.1,7h-6.1C17.8,4.4,19.2,2,20,2z M14.4,2.9 c-2,1.4-3.7,3.5-5,6.1H5.7C7.9,6.1,10.9,4,14.4,2.9z M15.1,23H8.2C8.1,22,8,21,8,20s0.1-2,0.2-3h6.9c0,1-0.1,2-0.1,3S15,22,15.1,23 z M15.1,24c0.1,2.2,0.3,4.2,0.6,6H10c-0.8-1.8-1.4-3.8-1.7-6H15.1z M15.1,16H8.3c0.3-2.2,0.9-4.2,1.7-6h5.7 C15.5,11.8,15.2,13.8,15.1,16z M5,9.9L5,9.9L9,10c-0.8,1.8-1.3,3.8-1.7,6H2.4C2.9,13.8,3.8,11.7,5,9.9z M2,20c0-1,0.1-2,0.3-3h4.9 C7.1,18,7,19,7,20s0.1,2,0.2,3H2.3C2.1,22,2,21,2,20z M2.5,24h4.8c0.3,2.2,0.9,4.2,1.7,6H5C3.8,28.2,3,26.2,2.5,24z M5.8,31h3.6 c1.3,2.6,2.9,4.7,4.9,6.1C10.9,35.9,7.9,33.8,5.8,31z M18.3,37.8c-3.1-0.7-5.9-3.2-7.7-6.8h5.4C16.5,34.1,17.3,36.5,18.3,37.8z M15.9,9h-5.4c1.9-3.6,4.6-6.1,7.7-6.8C17.3,3.5,16.5,5.9,15.9,9z M16.1,16c0.1-2.3,0.4-4.3,0.7-6h6.5c0.3,1.7,0.5,3.7,0.7,6H16.1z M21.7,2.2c3.1,0.7,5.9,3.2,7.7,6.8h-5.4C23.5,5.9,22.7,3.5,21.7,2.2z M24.9,16c-0.1-2.2-0.3-4.2-0.6-6H30c0.8,1.8,1.4,3.8,1.7,6 H24.9z M32.7,16c-0.3-2.2-0.9-4.2-1.7-6h4V9.9c1.2,1.8,2.1,3.9,2.6,6.1H32.7z"/><path fill="#dff0fe" d="M39,20c0,10.6-8.6,19-19,19C9.6,39,1,30.6,1,20S9.4,1,20,1S39,9.4,39,20z"/><path fill="#4788c7" d="M2 16H38V17H2zM2 23H22V24H2zM4.5 30H22V31H4.5zM5 9H35V10H5z"/><path fill="#4788c7" d="M28.7,35.8C26.1,37.2,23.1,38,20,38c-9.9,0-18-8.1-18-18C2,9.9,9.9,2,20,2s18,7.9,18,18c0,3.1-0.8,6.1-2.2,8.7 l0.7,0.7c1.6-2.8,2.5-6,2.5-9.4C39,9.4,30.6,1,20,1S1,9.4,1,20s8.6,19,19,19c3.4,0,6.6-0.9,9.4-2.5L28.7,35.8z"/><path fill="#98ccfd" d="M40.1 35.9L31.6 27.4 35 24 24 24 24 35 27.4 31.6 35.9 40.1z"/><path fill="#4788c7" d="M32.6,25l-1.7,1.7l-0.7,0.7l0.7,0.7l7.8,7.8l-2.8,2.8l-7.8-7.8l-0.7-0.7l-0.7,0.7L25,32.6V25H32.6 M35,24H24 v11l3.4-3.4l8.5,8.5l4.2-4.2l-8.5-8.5L35,24L35,24z"/><path fill="#4788c7" d="M20,1C12.8,1,7,9.5,7,20s5.8,19,13,19c0.1,0,0.2,0,0.3,0c0.6,0,1.1-0.1,1.7-0.2v-1v0V35c-0.7,2-1.5,3-2,3 c-1.4,0-4-6.4-4-18s2.6-18,4-18s4,6.4,4,18c0,0.7,0,1.4,0,2h1c0-0.7,0-1.3,0-2c0-8.2-1.4-15.1-3.3-17.8C27.5,3.5,32,11,32,20 c0,0.7,0,1.3-0.1,2h1c0-0.7,0.1-1.3,0.1-2C33,9.5,27.2,1,20,1z M15,20c0,8.2,1.4,15.1,3.3,17.8C12.5,36.5,8,29,8,20 S12.5,3.5,18.3,2.2C16.4,4.9,15,11.8,15,20z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#98ccfd" d="M1.517,26.5c0.258-3.903,3.516-7,7.483-7h6c3.968,0,7.226,3.097,7.483,7H1.517z"/><path fill="#4788c7" d="M15,20c3.52,0,6.442,2.612,6.929,6H2.071C2.558,22.612,5.48,20,9,20H15 M15,19H9 c-4.418,0-8,3.582-8,8h22C23,22.582,19.418,19,15,19L15,19z"/><path fill="#dff0fe" d="M12,21.745c-2.668,0-3.381-1.462-3.5-1.765V16.5h7v3.48C15.38,20.288,14.667,21.745,12,21.745z"/><path fill="#4788c7" d="M15,17v2.873c-0.167,0.34-0.852,1.373-3,1.373c-2.166,0-2.844-1.049-3-1.368V17H15 M16,16H8v4.064 c0,0,0.628,2.181,4,2.181s4-2.181,4-2.181V16L16,16z"/><path fill="#dff0fe" d="M12,18.5c-0.399,0-0.78-0.182-1.044-0.498l-0.105-0.126l-0.159-0.039 C8.224,17.232,6.5,15.037,6.5,12.5V7.243c0-1.301,1.059-2.359,2.359-2.359h6.281c1.301,0,2.359,1.059,2.359,2.359V12.5 c0,2.537-1.724,4.732-4.191,5.337l-0.159,0.039l-0.105,0.126C12.78,18.318,12.399,18.5,12,18.5z"/><path fill="#4788c7" d="M15.141,5.384c1.025,0,1.859,0.834,1.859,1.86V12.5c0,2.307-1.567,4.302-3.81,4.85l-0.32,0.078 l-0.211,0.253C12.561,17.801,12.343,18,12,18s-0.561-0.199-0.66-0.318l-0.211-0.253l-0.32-0.078C8.567,16.802,7,14.807,7,12.5 V7.243c0-1.025,0.834-1.86,1.859-1.86H15.141 M15.141,4.384H8.859C7.28,4.384,6,5.664,6,7.243V12.5 c0,2.821,1.949,5.18,4.572,5.822C10.914,18.733,11.423,19,12,19s1.086-0.267,1.428-0.678C16.051,17.68,18,15.321,18,12.5V7.243 C18,5.664,16.72,4.384,15.141,4.384L15.141,4.384z"/><path fill="#98ccfd" d="M18.154,18.73c-1.377,0-2.799-1.02-3.483-1.588c0.688-0.646,1.829-2.093,1.829-4.565v-1.64 c0-1.808-0.946-3.521-0.986-3.594l-0.33-0.591l-0.469,0.49c-0.015,0.016-1.553,1.595-4.52,2.27C8.437,9.911,7.5,11.5,7.5,12.494 c0,2.521,1.024,3.942,1.635,4.566c-0.595,0.58-1.897,1.67-3.288,1.67c-1.26,0-2.388-0.614-3.009-1.033 c0.707-0.588,1.806-1.767,1.806-3.412c0-0.69-0.031-1.218-0.065-1.778C4.54,11.875,4.5,11.221,4.5,10.23 c0-5.731,3.579-8.73,7.115-8.73c2.851,0,3.766,1.99,3.774,2.01l0.132,0.298h0.325c3.02,0,3.653,3.074,3.653,5.653 c0,1.044-0.083,1.926-0.162,2.779c-0.075,0.797-0.146,1.55-0.146,2.375c0,1.4,1.041,2.198,1.951,2.571 C20.575,17.804,19.5,18.73,18.154,18.73z"/><path fill="#4788c7" d="M11.616,2c2.477,0,3.288,1.653,3.316,1.712l0.263,0.595h0.651C17.939,4.308,19,6.042,19,9.461 c0,1.02-0.082,1.89-0.16,2.732c-0.076,0.809-0.147,1.572-0.147,2.421c0,1.319,0.763,2.182,1.604,2.698 c-0.535,0.461-1.283,0.917-2.142,0.917c-0.947,0-2.002-0.598-2.745-1.142C16.136,16.251,17,14.79,17,12.577v-1.64 c0-1.936-1.007-3.76-1.05-3.837l-0.66-1.169l-0.935,0.966c-0.014,0.015-1.469,1.491-4.27,2.128C8.072,9.482,7,11.334,7,12.495 c0,2.258,0.787,3.711,1.44,4.528c-0.66,0.565-1.644,1.208-2.594,1.208c-0.828,0-1.605-0.306-2.184-0.619 c0.708-0.726,1.481-1.856,1.481-3.326c0-0.709-0.032-1.243-0.066-1.809C5.039,11.852,5,11.206,5,10.231C5,4.827,8.328,2,11.616,2 M11.616,1C7.921,1,4,4.146,4,10.231c0,1.887,0.143,2.601,0.143,4.055c0,2.12-2.143,3.407-2.143,3.407s1.734,1.538,3.846,1.538 c2.149,0,4.009-2.201,4.009-2.201S8,15.783,8,12.495c0-0.71,0.748-2.141,2.306-2.495c3.17-0.721,4.771-2.411,4.771-2.411 S16,9.239,16,10.937c0,0.803,0,0.321,0,1.64c0,3.226-2.101,4.549-2.101,4.549s2.121,2.104,4.255,2.104 c2.312,0,3.846-2.308,3.846-2.308s-2.308-0.412-2.308-2.308c0-1.685,0.308-3.117,0.308-5.154c0-4.431-1.784-6.154-4.154-6.154 C15.846,3.308,14.825,1,11.616,1L11.616,1z"/><path fill="#dff0fe" d="M9.517,32.5c0.258-3.903,3.516-7,7.483-7h6c3.968,0,7.226,3.097,7.483,7H9.517z"/><path fill="#4788c7" d="M23,26c3.52,0,6.442,2.612,6.929,6H10.071c0.487-3.388,3.408-6,6.929-6H23 M23,25h-6 c-4.418,0-8,3.582-8,8h22C31,28.582,27.418,25,23,25L23,25z"/><path fill="#fff" d="M20,27.745c-2.668,0-3.381-1.462-3.5-1.765V22.5h7v3.48C23.38,26.288,22.667,27.745,20,27.745z"/><path fill="#4788c7" d="M23,23v2.873c-0.167,0.34-0.852,1.373-3,1.373c-2.166,0-2.844-1.049-3-1.368V23H23 M24,22h-8v4.064 c0,0,0.628,2.181,4,2.181s4-2.181,4-2.181V22L24,22z"/><g><path fill="#fff" d="M20,24.5c-0.399,0-0.78-0.182-1.044-0.498l-0.105-0.126l-0.159-0.039 c-2.468-0.604-4.191-2.8-4.191-5.337v-5.257c0-1.301,1.059-2.359,2.359-2.359h6.281c1.301,0,2.359,1.059,2.359,2.359V18.5 c0,2.537-1.724,4.732-4.191,5.337l-0.159,0.039l-0.105,0.126C20.78,24.318,20.399,24.5,20,24.5z"/><path fill="#4788c7" d="M23.141,11.384c1.025,0,1.859,0.834,1.859,1.86V18.5c0,2.307-1.567,4.302-3.81,4.85l-0.32,0.078 l-0.211,0.253C20.561,23.801,20.343,24,20,24s-0.561-0.199-0.66-0.318l-0.211-0.253l-0.32-0.078C16.567,22.802,15,20.807,15,18.5 v-5.257c0-1.025,0.834-1.86,1.859-1.86H23.141 M23.141,10.384h-6.281c-1.579,0-2.859,1.28-2.859,2.86V18.5 c0,2.821,1.949,5.18,4.572,5.822C18.914,24.733,19.423,25,20,25s1.086-0.267,1.428-0.678C24.051,23.68,26,21.321,26,18.5v-5.257 C26,11.664,24.72,10.384,23.141,10.384L23.141,10.384z"/></g><g><path fill="#b6dcfe" d="M26.154,24.73c-1.377,0-2.799-1.02-3.483-1.588c0.688-0.646,1.829-2.093,1.829-4.565v-1.64 c0-1.808-0.946-3.521-0.986-3.594l-0.33-0.591l-0.469,0.49c-0.015,0.016-1.553,1.595-4.52,2.27 C16.437,15.911,15.5,17.5,15.5,18.494c0,2.521,1.024,3.942,1.635,4.566c-0.595,0.58-1.897,1.67-3.288,1.67 c-1.26,0-2.388-0.614-3.009-1.033c0.707-0.588,1.806-1.767,1.806-3.412c0-0.69-0.031-1.218-0.065-1.778 C12.54,17.875,12.5,17.221,12.5,16.23c0-5.731,3.579-8.73,7.115-8.73c2.851,0,3.766,1.99,3.774,2.01l0.132,0.298h0.325 c3.02,0,3.653,3.074,3.653,5.653c0,1.044-0.083,1.926-0.162,2.779c-0.075,0.797-0.146,1.55-0.146,2.375 c0,1.4,1.041,2.198,1.951,2.571C28.575,23.804,27.5,24.73,26.154,24.73z"/><path fill="#4788c7" d="M19.616,8c2.477,0,3.288,1.653,3.316,1.712l0.263,0.595h0.651c2.093,0,3.154,1.734,3.154,5.154 c0,1.02-0.082,1.89-0.16,2.732c-0.076,0.809-0.147,1.572-0.147,2.421c0,1.319,0.763,2.182,1.604,2.698 c-0.535,0.461-1.283,0.917-2.142,0.917c-0.947,0-2.002-0.598-2.745-1.142C24.136,22.251,25,20.79,25,18.577v-1.64 c0-1.936-1.007-3.76-1.05-3.837l-0.66-1.169l-0.935,0.966c-0.014,0.015-1.469,1.491-4.27,2.128C16.072,15.482,15,17.334,15,18.495 c0,2.258,0.787,3.711,1.44,4.528c-0.66,0.565-1.644,1.208-2.594,1.208c-0.828,0-1.605-0.306-2.184-0.619 c0.708-0.726,1.481-1.856,1.481-3.326c0-0.709-0.032-1.243-0.066-1.809C13.039,17.852,13,17.206,13,16.231 C13,10.827,16.328,8,19.616,8 M19.616,7C15.921,7,12,10.146,12,16.231c0,1.887,0.143,2.601,0.143,4.055 c0,2.12-2.143,3.407-2.143,3.407s1.734,1.538,3.846,1.538c2.149,0,4.009-2.201,4.009-2.201S16,21.783,16,18.495 c0-0.71,0.748-2.141,2.306-2.495c3.17-0.721,4.771-2.411,4.771-2.411S24,15.239,24,16.937c0,0.803,0,0.321,0,1.64 c0,3.226-2.101,4.549-2.101,4.549s2.121,2.104,4.255,2.104c2.312,0,3.846-2.308,3.846-2.308s-2.308-0.412-2.308-2.308 c0-1.685,0.308-3.117,0.308-5.154c0-4.431-1.784-6.154-4.154-6.154C23.846,9.308,22.825,7,19.616,7L19.616,7z"/></g><g><path fill="#98ccfd" d="M31,39.5c-4.687,0-8.5-3.813-8.5-8.5s3.813-8.5,8.5-8.5s8.5,3.813,8.5,8.5S35.687,39.5,31,39.5z"/><path fill="#4788c7" d="M31,23c4.411,0,8,3.589,8,8s-3.589,8-8,8s-8-3.589-8-8S26.589,23,31,23 M31,22 c-4.971,0-9,4.029-9,9s4.029,9,9,9s9-4.029,9-9S35.971,22,31,22L31,22z"/></g><path fill="none" stroke="#fff" stroke-miterlimit="10" stroke-width="2" d="M31 36L31 26M26 31L36 31"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M1.566,35.793l1.408-4.564l11.824-11.825l-0.592-0.591c-0.419-0.418-0.648-0.974-0.648-1.565 s0.229-1.147,0.648-1.566l0.961-0.962l-0.025-0.238c-0.048-0.444-0.071-0.859-0.071-1.267c0-6.459,5.255-11.714,11.714-11.714 l0.333,0.005c6.104,0.168,11.208,5.272,11.377,11.376c0.089,3.195-1.087,6.213-3.312,8.5c-2.225,2.288-5.207,3.547-8.397,3.547 c-0.408,0-0.822-0.023-1.268-0.071l-0.238-0.026l-0.961,0.961c-0.419,0.418-0.975,0.648-1.566,0.648 c-0.591,0-1.147-0.23-1.565-0.648l-0.592-0.592L18.297,27.5H14.5v3.797L13.297,32.5H9.5v3.797l-0.738,0.738l-4.553,1.398 L1.566,35.793z M26.971,5.5c-2.012,0-3.902,0.783-5.324,2.206l-0.354,0.354l10.648,10.648l0.354-0.354 c1.422-1.422,2.205-3.313,2.205-5.324s-0.783-3.902-2.205-5.324C30.873,6.283,28.982,5.5,26.971,5.5z"/><path fill="#4788c7" d="M26.786,2c0.106,0,0.212,0.001,0.318,0.004c5.844,0.162,10.73,5.047,10.891,10.891 c0.085,3.058-1.041,5.948-3.17,8.137c-2.13,2.19-4.985,3.396-8.039,3.396c-0.39,0-0.787-0.022-1.214-0.068l-0.476-0.051 l-0.338,0.338l-0.792,0.792c-0.324,0.324-0.754,0.502-1.212,0.502c-0.458,0-0.888-0.178-1.212-0.502l-0.238-0.238l-0.707-0.707 l-0.707,0.707L18.09,27H15h-1v1v3.09L13.09,32H10H9v1v3.09l-0.504,0.504l-4.147,1.274l-2.216-2.215l1.282-4.158l11.383-11.383 l0.707-0.707l-0.707-0.707l-0.238-0.238c-0.324-0.324-0.502-0.754-0.502-1.212s0.178-0.888,0.502-1.212l0.792-0.792l0.338-0.338 l-0.051-0.476c-0.046-0.427-0.068-0.824-0.068-1.214C15.571,7.031,20.602,2,26.786,2 M31.941,19.414l0.707-0.707 C34.165,17.191,35,15.174,35,13.029s-0.835-4.161-2.352-5.678C31.132,5.835,29.115,5,26.971,5s-4.161,0.835-5.678,2.352 l-0.707,0.707l0.707,0.707l9.941,9.941L31.941,19.414 M26.786,1C20.04,1,14.571,6.468,14.571,13.214 c0,0.447,0.027,0.887,0.074,1.321l-0.792,0.792c-1.06,1.06-1.06,2.779,0,3.839l0.238,0.238L2.533,30.963L1,35.933L4.068,39 l4.96-1.524L10,36.504V33h3.504L15,31.504V28h3.504l2.091-2.091l0.238,0.238c0.53,0.53,1.225,0.795,1.919,0.795 c0.695,0,1.389-0.265,1.919-0.795l0.792-0.792c0.434,0.047,0.874,0.074,1.321,0.074c6.861,0,12.401-5.657,12.209-12.561 c-0.177-6.374-5.49-11.687-11.863-11.863C27.016,1.002,26.9,1,26.786,1L26.786,1z M31.941,18L22,8.059 C23.373,6.686,25.172,6,26.971,6s3.598,0.686,4.971,2.059C34.686,10.804,34.686,15.255,31.941,18L31.941,18z"/><path fill="#98ccfd" d="M16.953,21.754l-11.1,11.1c-0.195,0.195-0.512,0.195-0.707,0h0c-0.195-0.195-0.195-0.512,0-0.707 l11.1-11.1c0.195-0.195,0.512-0.195,0.707,0l0,0C17.148,21.242,17.148,21.559,16.953,21.754z"/><path fill="#4788c7" d="M17.114 18.465H18.114V25.991H17.114z" transform="rotate(-45.001 17.613 22.229)"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"><path fill="none" stroke="#4788c7" stroke-linecap="round" d="M34.25 13L35.607 13M4.393 13L5.75 13M34.25 13L35.607 13M4.393 13L5.75 13M34.25 13L35.607 13M4.393 13L5.75 13M30.076 23.076L31.036 24.036M8.964 1.964L9.924 2.924M30.076 2.924L31.036 1.964M8.964 24.036L9.924 23.076M33.165 7.547L34.419 7.027M5.581 18.973L6.835 18.453M33.165 18.453L34.419 18.973M5.581 7.027L6.835 7.547"/><path fill="#b6dcfe" d="M14.5,29.833V28c0-1.914-1.168-3.76-2.52-5.897C10.349,19.525,8.5,16.603,8.5,13 C8.5,6.659,13.659,1.5,20,1.5S31.5,6.659,31.5,13c0,3.603-1.849,6.525-3.48,9.103C26.668,24.24,25.5,26.086,25.5,28v1.833H14.5z"/><path fill="#4788c7" d="M20,2c6.065,0,11,4.935,11,11c0,3.458-1.808,6.315-3.402,8.835C26.262,23.947,25,25.941,25,28 v1.333h-5h-5V28c0-2.059-1.262-4.053-2.598-6.165C10.808,19.315,9,16.458,9,13C9,6.935,13.935,2,20,2 M20,1C13.373,1,8,6.373,8,13 c0,6.667,6,10.958,6,15v2.333h6h6V28c0-4.042,6-8.333,6-15C32,6.373,26.627,1,20,1L20,1z"/><path fill="#fff" d="M22.714,11.335c0.502,0,0.974,0.195,1.329,0.55c0.733,0.733,0.733,1.925,0,2.657l-1.75,1.75 L22,16.586V17v12h-4V17v-0.414l-0.293-0.293l-1.75-1.75c-0.733-0.733-0.733-1.925,0-2.657c0.355-0.355,0.827-0.55,1.329-0.55 c0.502,0,0.974,0.195,1.329,0.55l0.679,0.679L20,13.271l0.707-0.707l0.679-0.679C21.741,11.531,22.212,11.335,22.714,11.335 M22.714,10.335c-0.737,0-1.474,0.281-2.036,0.843L20,11.857l-0.679-0.679c-0.562-0.562-1.299-0.843-2.036-0.843 c-0.737,0-1.474,0.281-2.036,0.843c-1.124,1.124-1.124,2.947,0,4.071L17,17v13h6V17l1.75-1.75c1.124-1.124,1.124-2.947,0-4.071 C24.188,10.616,23.451,10.335,22.714,10.335L22.714,10.335z"/><path fill="#4788c7" d="M20 32A3.5 3.5 0 1 0 20 39A3.5 3.5 0 1 0 20 32Z"/><path fill="#dff0fe" d="M17,36.5c-1.378,0-2.5-1.122-2.5-2.5v-5.5h11V34c0,1.378-1.122,2.5-2.5,2.5H17z"/><path fill="#4788c7" d="M25,29v5c0,1.103-0.897,2-2,2h-6c-1.103,0-2-0.897-2-2v-5H25 M26,28H14v6c0,1.657,1.343,3,3,3h6 c1.657,0,3-1.343,3-3V28L26,28z"/><g><path fill="#4788c7" d="M25.5 31h-6c-.275 0-.5-.225-.5-.5l0 0c0-.275.225-.5.5-.5h6c.275 0 .5.225.5.5l0 0C26 30.775 25.775 31 25.5 31zM25.5 33h-6c-.275 0-.5-.225-.5-.5l0 0c0-.275.225-.5.5-.5h6c.275 0 .5.225.5.5l0 0C26 32.775 25.775 33 25.5 33zM24.988 35H19.5c-.275 0-.5-.225-.5-.5l0 0c0-.275.225-.5.5-.5h5.488c.275 0 .5.225.5.5l0 0C25.488 34.775 25.263 35 24.988 35zM14.5 31h2c.275 0 .5-.225.5-.5l0 0c0-.275-.225-.5-.5-.5h-2c-.275 0-.5.225-.5.5l0 0C14 30.775 14.225 31 14.5 31zM14.5 33h2c.275 0 .5-.225.5-.5l0 0c0-.275-.225-.5-.5-.5h-2c-.275 0-.5.225-.5.5l0 0C14 32.775 14.225 33 14.5 33zM14.907 35H16.5c.275 0 .5-.225.5-.5l0 0c0-.275-.225-.5-.5-.5h-1.593c-.275 0-.5.225-.5.5l0 0C14.407 34.775 14.632 35 14.907 35z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#b6dcfe" d="M10.747 39.5L17.747 22.5 8.732 22.5 17.341 0.5 31.167 0.5 23.167 15.5 31.894 15.5 10.774 39.5z"/><path fill="#4788c7" d="M30.333,1l-7.216,13.529L22.333,16H24h6.788L12.325,36.981l5.6-13.6L18.493,22H17H9.465l8.217-21 H30.333 M32,0H17L8,23h9l-7,17h1l22-25h-9L32,0L32,0z"/><path fill="#fff" d="M19.167 1.37L19.178 1.343 19.187 1.315 19.292 1 17.678 1 9.475 22 11.112 22zM19.431 23.761L19.999 22.381 20.156 22 18.493 22 17.925 23.381 12.325 36.981 15.45 33.43z"/></svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 128 128" width="128px" height="128px">
<g id="surface38439588">
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 58.425781 50.175781 C 64.011719 50.175781 69.84375 45.566406 69.84375 45.566406 C 69.84375 45.566406 80.898438 59.136719 82.457031 65.03125 C 84.011719 70.925781 86.195312 77.609375 86.105469 82.265625 C 86.015625 86.925781 85.015625 90.183594 85.015625 90.183594 C 85.015625 90.183594 81.796875 83.488281 80.90625 92.207031 C 80.015625 100.921875 78.015625 111.558594 64.015625 111.558594 C 50.015625 111.558594 48.359375 103.3125 48.359375 103.3125 C 48.359375 103.3125 56.871094 99.457031 54.023438 96.609375 C 51.175781 93.761719 40.015625 90.921875 40.015625 78.921875 C 40.015625 66.921875 47.878906 60.066406 48.949219 56.492188 C 50.015625 52.921875 52.96875 48.542969 52.96875 48.542969 Z M 58.425781 50.175781 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(71.372551%,86.274511%,99.607843%);fill-opacity:1;" d="M 100.226562 88.652344 C 100.226562 84.925781 100.828125 82.824219 100.828125 79.652344 C 100.828125 72.890625 96.722656 65.484375 91.964844 58.644531 C 87.203125 51.804688 83.339844 47.636719 81.253906 39.011719 C 79.171875 30.386719 80.523438 33.09375 78.738281 25.652344 C 77.054688 17.761719 75.140625 10.925781 61.554688 10.925781 C 49.09375 10.925781 46.828125 22.234375 46.828125 33.015625 C 46.828125 36.582031 46.828125 39.808594 46.828125 45.289062 C 46.828125 46.476562 46.53125 47.964844 45.933594 49.152344 C 44.746094 51.832031 32.101562 65.058594 32.101562 84.558594 C 32.101562 84.558594 36.007812 102.066406 47.5 102.066406 C 50.011719 102.066406 52.363281 101.246094 53.734375 99.289062 C 54.628906 97.800781 54.03125 96.3125 53.4375 95.421875 C 52.84375 94.53125 47.34375 91.957031 45.261719 90.171875 C 43.179688 88.386719 39.460938 83.859375 39.460938 79.652344 C 39.460938 68.097656 51.4375 54.957031 51.734375 50.199219 C 51.734375 49.671875 51.734375 48.78125 51.734375 47.742188 C 51.734375 47.742188 54.835938 50.175781 58.421875 50.175781 C 62.007812 50.175781 69.839844 45.566406 69.839844 45.566406 C 69.839844 45.566406 72.007812 50.925781 76.007812 54.925781 C 80.007812 58.925781 86.007812 72.925781 86.007812 80.925781 C 86.007812 88.925781 86.007812 94.925781 86.007812 94.925781 C 86.007812 94.925781 86.007812 96.925781 90.007812 96.925781 C 94.007812 96.925781 100.226562 88.652344 100.226562 88.652344 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 50.140625 42.289062 C 50.140625 36.925781 59.1875 35.21875 59.363281 35.21875 C 60.046875 35.21875 60.757812 35.328125 61.464844 35.496094 C 61.527344 34.699219 61.554688 33.867188 61.554688 33.015625 C 61.554688 24.117188 59.699219 20.742188 54.191406 20.742188 C 48.6875 20.742188 44.375 26.132812 44.375 33.015625 C 44.375 38.542969 47.179688 43.054688 51.125 44.636719 C 50.527344 43.957031 50.140625 43.203125 50.140625 42.289062 Z M 50.140625 42.289062 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 66.464844 20.742188 C 60.960938 20.742188 59.101562 23.964844 59.101562 33.015625 C 59.101562 33.78125 59.132812 34.515625 59.183594 35.238281 C 59.246094 35.234375 59.304688 35.21875 59.363281 35.21875 C 60.183594 35.21875 72.40625 39.691406 72.214844 41.105469 C 72.125 42.054688 72.027344 42.746094 71.851562 43.3125 C 74.535156 41.148438 76.285156 37.390625 76.285156 33.015625 C 76.285156 26.132812 71.96875 20.742188 66.464844 20.742188 Z M 66.464844 20.742188 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(27.843139%,53.333336%,78.039217%);fill-opacity:1;" d="M 66.464844 37.925781 C 65.113281 37.925781 64.011719 36.277344 64.011719 34.242188 C 64.011719 32.210938 65.113281 30.5625 66.464844 30.5625 C 67.820312 30.5625 68.921875 32.210938 68.921875 34.242188 C 68.921875 36.277344 67.820312 37.925781 66.464844 37.925781 Z M 54.191406 37.925781 C 52.839844 37.925781 51.738281 36.277344 51.738281 34.242188 C 51.738281 32.210938 52.839844 30.5625 54.191406 30.5625 C 55.546875 30.5625 56.644531 32.210938 56.644531 34.242188 C 56.648438 36.277344 55.546875 37.925781 54.191406 37.925781 Z M 54.191406 37.925781 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 90.011719 96.925781 C 86.011719 96.925781 86.160156 88.214844 86.160156 88.214844 C 85.6875 87.925781 85.109375 87.707031 84.382812 87.707031 C 82.933594 87.707031 82.351562 88.289062 81.769531 89.449219 C 81.1875 90.609375 81.191406 91.476562 81.191406 94.378906 C 81.191406 96.699219 81.191406 99.3125 80.898438 101.34375 C 80.316406 106.273438 78.734375 108.480469 78.734375 111.382812 C 78.734375 114.574219 79.609375 116.605469 80.765625 117.476562 C 81.636719 118.347656 83.089844 118.925781 86.277344 118.925781 C 89.46875 118.925781 91.496094 117.765625 93.53125 115.734375 C 94.980469 114.285156 96.144531 113.707031 100.203125 110.804688 C 103.394531 108.773438 108.324219 106.160156 109.199219 105.292969 C 109.773438 104.710938 110.644531 104.421875 110.644531 102.683594 C 110.644531 101.230469 109.484375 100.652344 108.617188 100.363281 C 107.457031 99.78125 105.425781 98.910156 103.683594 96.300781 C 102.8125 94.851562 103.105469 90.789062 101.652344 89.046875 C 100.78125 87.886719 99.625 88.464844 99.335938 88.464844 C 98.683594 88.609375 97.863281 89.015625 96.929688 89.46875 C 94.011719 92.925781 94.484375 96.925781 90.011719 96.925781 Z M 46.878906 101.003906 C 44.035156 96.464844 43.746094 95.617188 41.757812 92.78125 C 40.050781 89.949219 36.351562 84.5625 34.074219 84.5625 C 32.367188 84.5625 31.515625 85.410156 30.375 86.546875 C 29.238281 87.679688 28.027344 89.445312 26.035156 90.863281 C 24.285156 93.148438 19.035156 90.949219 17.527344 94.382812 C 16.699219 96.257812 19.558594 98.734375 19.558594 102.984375 C 19.558594 104.6875 18.136719 105.820312 17.851562 106.953125 C 17.566406 108.371094 17.28125 109.222656 17.851562 110.355469 C 18.988281 112.054688 20.410156 112.625 30.089844 114.609375 C 35.210938 115.742188 40.046875 118.574219 43.179688 118.859375 C 46.308594 119.140625 51.714844 118.859375 51.714844 111.207031 C 52 106.671875 49.441406 105.535156 46.878906 101.003906 Z M 52.355469 46.664062 C 50.679688 45.484375 49.28125 44.308594 49.28125 42.539062 C 49.28125 40.773438 50.398438 40.183594 52.074219 38.710938 C 52.355469 38.414062 55.429688 35.46875 58.503906 35.46875 C 61.574219 35.46875 65.207031 37.53125 66.605469 38.121094 C 69.117188 38.710938 71.632812 39.296875 71.355469 41.359375 C 71.074219 44.304688 70.792969 44.894531 68.003906 46.367188 C 66.046875 46.957031 62.414062 50.199219 59.898438 50.199219 C 58.785156 50.199219 57.105469 50.199219 55.988281 49.902344 C 55.148438 49.609375 53.753906 48.136719 52.355469 46.664062 Z M 52.355469 46.664062 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(27.843139%,53.333336%,78.039217%);fill-opacity:1;" d="M 34.101562 84.5625 L 30.101562 84.5625 C 30.101562 68.046875 38.867188 55.789062 42.613281 50.554688 C 43.246094 49.664062 43.96875 48.65625 44.109375 48.34375 C 44.5625 47.433594 44.828125 46.265625 44.828125 45.289062 L 44.828125 41.164062 L 48.828125 41.164062 L 48.828125 45.289062 C 48.828125 46.890625 48.414062 48.671875 47.722656 50.050781 C 47.460938 50.652344 46.859375 51.492188 45.863281 52.882812 C 42.046875 58.21875 34.101562 69.328125 34.101562 84.5625 Z M 102.363281 87.570312 L 98.386719 87.136719 C 98.679688 84.492188 98.828125 81.902344 98.828125 79.652344 C 98.828125 72.804688 93.972656 65.03125 90.320312 59.785156 C 89.511719 58.617188 88.726562 57.53125 87.972656 56.484375 C 84.300781 51.398438 81.128906 47.007812 79.3125 39.476562 C 78.199219 34.871094 78.035156 33.382812 77.878906 31.941406 C 77.746094 30.71875 77.621094 29.566406 76.792969 26.117188 C 75.171875 18.5 73.777344 11.964844 61.558594 11.964844 C 55.070312 11.964844 51.140625 15.984375 49.539062 24.257812 L 45.613281 23.496094 C 47.578125 13.339844 53.09375 7.964844 61.558594 7.964844 C 77.015625 7.964844 79.054688 17.539062 80.695312 25.234375 C 81.570312 28.878906 81.714844 30.21875 81.855469 31.511719 C 81.996094 32.824219 82.148438 34.183594 83.199219 38.542969 C 84.832031 45.304688 87.648438 49.207031 91.214844 54.144531 C 91.980469 55.210938 92.78125 56.316406 93.605469 57.503906 C 97.5625 63.195312 102.828125 71.683594 102.828125 79.652344 C 102.828125 82.042969 102.667969 84.785156 102.363281 87.570312 Z M 102.363281 87.570312 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(27.843139%,53.333336%,78.039217%);fill-opacity:1;" d="M 84.015625 86.988281 C 83.445312 69.054688 77.667969 61.101562 73.027344 54.707031 C 71.003906 51.914062 69.089844 49.28125 67.96875 46.261719 L 71.71875 44.871094 C 72.648438 47.375 74.324219 49.683594 76.265625 52.359375 C 80.964844 58.832031 87.402344 67.699219 88.011719 86.863281 Z M 47.5 104.070312 C 46.542969 104.070312 45.699219 103.378906 45.53125 102.40625 C 45.347656 101.316406 46.078125 100.285156 47.164062 100.097656 C 49.082031 99.773438 51.574219 98.886719 52.097656 98.140625 C 52.292969 97.804688 52.230469 97.269531 51.851562 96.648438 C 51.429688 96.304688 50.039062 95.511719 49.007812 94.921875 C 47.207031 93.890625 45.164062 92.722656 43.964844 91.691406 C 41.714844 89.765625 37.464844 84.769531 37.464844 79.652344 C 37.464844 71.910156 42.175781 63.988281 45.957031 57.621094 C 47.777344 54.554688 49.660156 51.390625 49.742188 50.074219 L 49.738281 47.742188 C 49.738281 46.636719 50.632812 45.742188 51.738281 45.742188 C 52.847656 45.742188 53.738281 46.636719 53.738281 47.742188 L 53.738281 50.199219 C 53.59375 52.605469 51.835938 55.566406 49.398438 59.664062 C 45.863281 65.613281 41.464844 73.011719 41.464844 79.652344 C 41.464844 82.847656 44.449219 86.839844 46.566406 88.65625 C 47.480469 89.441406 49.429688 90.550781 50.992188 91.449219 C 53.460938 92.859375 54.574219 93.515625 55.109375 94.316406 C 56.425781 96.292969 56.554688 98.484375 55.453125 100.316406 C 53.617188 102.953125 48.789062 103.878906 47.839844 104.042969 C 47.722656 104.058594 47.609375 104.070312 47.5 104.070312 Z M 52 110 L 78 110 L 78 114 L 52 114 Z M 52 110 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(27.843139%,53.333336%,78.039217%);fill-opacity:1;" d="M 86.28125 121.964844 C 82.40625 121.964844 80.425781 119.96875 79.472656 119.007812 C 77.742188 117.699219 76.738281 114.96875 76.738281 111.382812 C 76.738281 109.648438 77.195312 108.160156 77.679688 106.585938 C 78.132812 105.101562 78.644531 103.421875 78.917969 101.109375 C 79.195312 99.167969 79.195312 96.625 79.195312 94.382812 C 79.195312 93.414062 79.328125 84.925781 84.015625 84.925781 C 89.105469 84.925781 89.589844 89.234375 89.820312 91.304688 C 89.878906 91.820312 89.960938 92.5625 90.085938 92.925781 C 91.246094 92.871094 92.453125 91.488281 93.621094 90.15625 C 95.09375 88.472656 96.753906 86.570312 99.144531 86.46875 C 101.339844 85.988281 102.585938 86.949219 103.261719 87.847656 C 104.390625 89.199219 104.695312 91.28125 104.964844 93.117188 C 105.074219 93.851562 105.234375 94.96875 105.40625 95.269531 C 106.683594 97.179688 108.175781 97.910156 109.265625 98.445312 L 109.390625 98.511719 C 112.222656 99.511719 112.652344 101.546875 112.652344 102.679688 C 112.652344 105.019531 111.476562 105.984375 110.847656 106.507812 C 110.773438 106.570312 110.695312 106.628906 110.628906 106.699219 C 109.953125 107.371094 108.449219 108.257812 105.621094 109.898438 C 104.152344 110.757812 102.574219 111.671875 101.285156 112.488281 C 100.027344 113.390625 98.996094 114.105469 98.164062 114.675781 C 96.539062 115.792969 95.796875 116.304688 94.953125 117.148438 L 94.652344 117.449219 C 92.640625 119.460938 90.144531 121.964844 86.28125 121.964844 Z M 84.285156 88.929688 C 83.816406 89.570312 83.195312 91.847656 83.195312 94.382812 C 83.195312 96.757812 83.195312 99.453125 82.882812 101.625 C 82.574219 104.246094 81.980469 106.191406 81.503906 107.757812 C 81.074219 109.144531 80.738281 110.246094 80.738281 111.382812 C 80.738281 114.015625 81.402344 115.449219 81.96875 115.875 L 82.183594 116.058594 C 83.097656 116.980469 84.070312 117.964844 86.28125 117.964844 C 88.484375 117.964844 90.027344 116.417969 91.816406 114.625 L 92.121094 114.320312 C 93.222656 113.214844 94.171875 112.5625 95.894531 111.378906 C 96.707031 110.816406 97.71875 110.121094 99.042969 109.175781 C 100.464844 108.269531 102.089844 107.320312 103.609375 106.441406 C 105.199219 105.515625 107.378906 104.253906 107.796875 103.867188 C 107.941406 103.722656 108.113281 103.574219 108.296875 103.425781 C 108.648438 103.132812 108.648438 103.132812 108.648438 102.679688 C 108.640625 102.59375 108.535156 102.441406 107.988281 102.257812 L 107.496094 102.039062 C 106.257812 101.429688 103.949219 100.296875 102.023438 97.40625 C 101.398438 96.367188 101.207031 95.070312 101.003906 93.695312 C 100.832031 92.527344 100.601562 90.929688 100.136719 90.347656 C 100.101562 90.355469 100.066406 90.363281 100.039062 90.371094 C 99.855469 90.410156 99.625 90.46875 99.335938 90.46875 C 98.65625 90.46875 97.535156 91.757812 96.628906 92.789062 C 95.015625 94.632812 93.011719 96.925781 90.011719 96.925781 C 86.425781 96.925781 86.03125 93.433594 85.84375 91.753906 C 85.570312 89.332031 85.335938 88.96875 84.285156 88.929688 Z M 43.941406 122 C 43.628906 122 43.3125 121.984375 42.996094 121.957031 C 41.089844 121.785156 39.042969 120.722656 36.671875 119.492188 C 34.5 118.367188 32.042969 117.089844 29.652344 116.558594 C 20.0625 114.597656 17.847656 113.9375 16.191406 111.46875 L 16.066406 111.257812 C 15.246094 109.625 15.527344 108.296875 15.796875 107.011719 L 15.890625 106.558594 C 16.101562 105.707031 16.511719 105.074219 16.867188 104.515625 C 17.238281 103.9375 17.558594 103.4375 17.558594 102.984375 C 17.558594 101.214844 16.914062 99.757812 16.347656 98.46875 C 15.65625 96.90625 14.941406 95.289062 15.699219 93.574219 C 17.007812 90.589844 20.058594 90.324219 22.074219 90.148438 C 22.921875 90.074219 24.203125 89.960938 24.449219 89.640625 L 24.878906 89.230469 C 26.066406 88.382812 26.980469 87.34375 27.78125 86.421875 C 28.199219 85.945312 28.585938 85.507812 28.964844 85.128906 C 30.175781 83.921875 31.542969 82.5625 34.074219 82.5625 C 37.269531 82.5625 40.949219 87.558594 43.472656 91.75 C 44.605469 93.355469 45.222656 94.394531 46.078125 95.839844 C 46.679688 96.847656 47.410156 98.078125 48.574219 99.941406 L 48.621094 100.019531 C 49.378906 101.359375 50.125 102.363281 50.847656 103.332031 C 52.445312 105.484375 53.953125 107.515625 53.710938 111.332031 C 53.714844 114.832031 52.648438 117.644531 50.546875 119.566406 C 48.84375 121.121094 46.429688 122 43.941406 122 Z M 19.589844 109.355469 C 20.269531 110.277344 21.582031 110.824219 30.488281 112.648438 C 33.417969 113.296875 36.125 114.703125 38.515625 115.941406 C 40.429688 116.933594 42.234375 117.871094 43.359375 117.972656 C 44.003906 118.035156 46.21875 118.105469 47.847656 116.613281 C 49.085938 115.480469 49.714844 113.660156 49.714844 111.203125 C 49.867188 108.722656 49.121094 107.71875 47.636719 105.71875 C 46.882812 104.707031 46.035156 103.5625 45.160156 102.027344 C 43.984375 100.148438 43.242188 98.898438 42.636719 97.878906 C 41.796875 96.464844 41.242188 95.527344 40.121094 93.929688 C 37.238281 89.148438 34.78125 86.726562 34.003906 86.554688 C 33.226562 86.558594 32.878906 86.871094 31.785156 87.957031 C 31.464844 88.277344 31.144531 88.648438 30.792969 89.050781 C 29.933594 90.035156 28.871094 91.25 27.410156 92.332031 C 26.082031 93.8125 24.0625 93.988281 22.421875 94.132812 C 20.390625 94.308594 19.664062 94.484375 19.359375 95.179688 C 19.359375 95.386719 19.734375 96.230469 20.007812 96.847656 C 20.660156 98.335938 21.558594 100.367188 21.558594 102.980469 C 21.558594 104.605469 20.792969 105.800781 20.234375 106.671875 C 20.074219 106.921875 19.835938 107.296875 19.792969 107.4375 L 19.710938 107.832031 C 19.503906 108.820312 19.472656 109.070312 19.589844 109.355469 Z M 47.617188 44.882812 C 44.335938 42.28125 42.375 37.84375 42.375 33.015625 C 42.375 25.011719 47.566406 18.742188 54.195312 18.742188 C 58.425781 18.742188 62 22.980469 62 28 L 58 28 C 58 24.992188 55.988281 22.742188 54.195312 22.742188 C 49.808594 22.742188 46.375 27.257812 46.375 33.019531 C 46.375 36.636719 47.769531 39.898438 50.101562 41.746094 Z M 47.617188 44.882812 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(27.843139%,53.333336%,78.039217%);fill-opacity:1;" d="M 70.90625 46.714844 L 69.117188 43.136719 C 72.351562 41.519531 74.28125 36.722656 74.28125 33.015625 C 74.28125 27.253906 70.847656 22.742188 66.464844 22.742188 C 62.125 22.742188 62 27.460938 62 28 L 61.992188 29.199219 C 61.984375 30.875 61.960938 35.328125 61.996094 35.867188 L 58.003906 36.136719 C 57.96875 35.605469 57.972656 33.082031 57.992188 29.179688 L 58 28 C 58 24.796875 59.769531 18.742188 66.464844 18.742188 C 73.089844 18.742188 78.28125 25.015625 78.28125 33.019531 C 78.285156 37.988281 75.75 44.292969 70.90625 46.714844 Z M 70.90625 46.714844 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(27.843139%,53.333336%,78.039217%);fill-opacity:1;" d="M 59.898438 52.199219 C 58.683594 52.199219 56.847656 52.199219 55.476562 51.839844 C 54.125 51.371094 52.902344 50.144531 51.042969 48.1875 C 49.5625 47.144531 47.28125 45.4375 47.28125 42.542969 C 47.28125 40.132812 48.671875 38.96875 50.015625 37.839844 C 50.242188 37.644531 50.488281 37.441406 50.753906 37.210938 C 50.742188 37.210938 54.398438 33.472656 58.5 33.472656 C 61.453125 33.472656 64.59375 34.964844 66.46875 35.859375 C 66.761719 35.996094 67.019531 36.121094 67.234375 36.214844 C 69.941406 36.851562 73.847656 37.851562 73.335938 41.632812 C 73.007812 45.085938 72.421875 46.300781 68.933594 48.140625 L 68.578125 48.285156 C 68.070312 48.4375 67.070312 49.058594 66.1875 49.605469 C 64.226562 50.820312 62.007812 52.199219 59.898438 52.199219 Z M 56.636719 48.003906 C 57.527344 48.199219 59 48.199219 59.898438 48.199219 C 60.867188 48.199219 62.722656 47.046875 64.078125 46.207031 C 65.246094 45.484375 66.269531 44.851562 67.21875 44.523438 C 69.140625 43.507812 69.144531 43.449219 69.363281 41.171875 C 69.085938 40.757812 67.175781 40.308594 66.148438 40.066406 L 65.828125 39.964844 C 65.546875 39.84375 65.183594 39.671875 64.753906 39.46875 C 63.183594 38.71875 60.550781 37.46875 58.503906 37.46875 C 56.5 37.46875 54.027344 39.570312 53.523438 40.09375 C 53.109375 40.464844 52.839844 40.695312 52.585938 40.90625 C 51.320312 41.960938 51.285156 42.082031 51.285156 42.539062 C 51.285156 43.214844 51.886719 43.886719 53.507812 45.027344 L 53.808594 45.285156 C 54.660156 46.191406 56.070312 47.675781 56.636719 48.003906 Z M 56.636719 48.003906 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(27.843139%,53.333336%,78.039217%);fill-opacity:1;" d="M 47.5 104.070312 C 46.542969 104.070312 45.699219 103.378906 45.53125 102.40625 C 45.347656 101.316406 46.078125 100.285156 47.164062 100.097656 C 49.082031 99.773438 51.574219 98.886719 52.097656 98.140625 C 52.292969 97.804688 52.230469 97.269531 51.851562 96.648438 C 51.429688 96.304688 50.039062 95.511719 49.007812 94.921875 C 47.207031 93.890625 45.164062 92.722656 43.964844 91.691406 C 41.714844 89.765625 37.464844 84.769531 37.464844 79.652344 C 37.464844 71.910156 42.175781 63.988281 45.957031 57.621094 C 47.777344 54.554688 49.660156 51.390625 49.742188 50.074219 L 49.738281 47.742188 C 49.738281 46.636719 50.632812 45.742188 51.738281 45.742188 C 52.847656 45.742188 53.738281 46.636719 53.738281 47.742188 L 53.738281 50.199219 C 53.59375 52.605469 51.835938 55.566406 49.398438 59.664062 C 45.863281 65.613281 41.464844 73.011719 41.464844 79.652344 C 41.464844 82.847656 44.449219 86.839844 46.566406 88.65625 C 47.480469 89.441406 49.429688 90.550781 50.992188 91.449219 C 53.460938 92.859375 54.574219 93.515625 55.109375 94.316406 C 56.425781 96.292969 56.554688 98.484375 55.453125 100.316406 C 53.617188 102.953125 48.789062 103.878906 47.839844 104.042969 C 47.722656 104.058594 47.609375 104.070312 47.5 104.070312 Z M 47.5 104.070312 "/>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#98ccfd" d="M2.633,32.5c-1.176,0-2.133-0.957-2.133-2.133V9.633C0.5,8.457,1.457,7.5,2.633,7.5h34.733 c1.176,0,2.133,0.957,2.133,2.133v20.733c0,1.176-0.957,2.133-2.133,2.133H2.633z"/><path fill="#4788c7" d="M37.367,8C38.267,8,39,8.733,39,9.633v20.734C39,31.267,38.267,32,37.367,32H2.633 C1.733,32,1,31.267,1,30.367V9.633C1,8.733,1.733,8,2.633,8H37.367 M37.367,7H2.633C1.185,7,0,8.185,0,9.633v20.734 C0,31.815,1.185,33,2.633,33h34.734C38.815,33,40,31.815,40,30.367V9.633C40,8.185,38.815,7,37.367,7L37.367,7z"/><path fill="#fff" d="M17 13L13 18.6 9 13 5 13 5 27 9 27 9 18.111 13 23.667 17 17.944 17 27 21 27 21 13z"/><g><path fill="#fff" d="M32 20L32 13 28 13 28 20 24.25 20 30 27 36 20z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#b6dcfe" d="M19,8c0.319,1.994-1.947,4-3.537,4C12.338,12,13.875,4,7,4c3.124,9.706-6,11.415-6,22.375 C1,30.591,5.614,36,12,36s11-4.371,11-9.625C23,18.21,19,8,19,8z"/><path fill="#fff" d="M12.039,35C7.701,35,5,30.488,5,28.041C5,22.258,10.794,20.604,9.552,15 c6.43,2.652,1.347,5.533,3.014,7.426c1.308,1.486,3.473-0.631,2.74-2.74C17.717,22.098,19,25.222,19,28.007 C19,31.119,16.383,35,12.039,35z"/><path fill="#dff0fe" d="M8.101 17.849H41.753V20.583H8.101z" transform="rotate(-42.297 24.925 19.215)"/><path fill="#4788c7" d="M36.42,7.589l1.167,1.283L13.435,30.844l-1.167-1.283L36.42,7.589 M36.487,6.176L10.855,29.495 l2.513,2.762L39,8.938L36.487,6.176L36.487,6.176z"/><path fill="#98ccfd" d="M12.249,32.5c-0.492,0-0.963-0.208-1.294-0.572c-0.649-0.713-0.596-1.822,0.117-2.471l1.053-0.958 c0.208-0.189,0.479-0.294,0.76-0.294c0.318,0,0.623,0.135,0.836,0.369l0.833,0.916c0.204,0.224,0.308,0.513,0.293,0.814 c-0.014,0.301-0.145,0.578-0.368,0.781l-1.053,0.958C13.104,32.338,12.686,32.5,12.249,32.5z"/><path fill="#4788c7" d="M12.885,28.705c0.104,0,0.303,0.027,0.466,0.206l0.834,0.917c0.234,0.257,0.215,0.656-0.042,0.889 l-1.053,0.958C12.86,31.884,12.561,32,12.25,32c-0.357,0-0.685-0.145-0.925-0.409c-0.464-0.51-0.426-1.301,0.083-1.765 l1.053-0.958C12.578,28.763,12.728,28.705,12.885,28.705 M12.885,27.705c-0.391,0-0.784,0.14-1.096,0.424l-1.053,0.958 c-0.919,0.836-0.986,2.259-0.15,3.178C11.029,32.752,11.639,33,12.25,33c0.54,0,1.082-0.193,1.513-0.586l1.053-0.958 c0.666-0.606,0.714-1.636,0.109-2.302l-0.834-0.917C13.769,27.884,13.328,27.705,12.885,27.705L12.885,27.705z"/><path fill="none" stroke="#4788c7" stroke-linecap="round" stroke-miterlimit="10" d="M21.376,17.674 c-0.72-3.192-1.625-6.044-2.219-7.768c-0.161,0.326-0.373,0.646-0.633,0.951c-0.851,0.998-2.052,1.643-3.06,1.643 c-1.602,0-2.197-1.538-2.828-3.167c-0.822-2.122-1.747-4.51-4.956-4.803c1.375,5.007-0.509,7.975-2.5,11.108 c-1.809,2.85-3.68,5.797-3.68,10.736C1.5,30.096,5.59,35.5,12,35.5c5.825,0,10.395-3.925,10.491-8.965"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#98ccfd" d="M2.5 2.5H37.5V37.5H2.5z"/><path fill="#4788c7" d="M37,3v34H3V3H37 M38,2H2v36h36V2L38,2z"/><path fill="#fff" d="M28,13v14H12V13H28 M30,11H10v18h20V11L30,11z"/><path fill="#fff" d="M10 11H30V16H10z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M1.5,27.5V7c0-0.827,0.673-1.5,1.5-1.5h34c0.827,0,1.5,0.673,1.5,1.5v20.5H1.5z"/><path fill="#4788c7" d="M37,6c0.551,0,1,0.449,1,1v20H2V7c0-0.551,0.449-1,1-1H37 M37,5H3C1.895,5,1,5.895,1,7v21h38V7 C39,5.895,38.105,5,37,5L37,5z"/><path fill="#98ccfd" d="M21.5,34.5V31c0.001-0.052,0.006-0.646-0.417-1.081C20.897,29.728,20.559,29.5,20,29.5 s-0.897,0.228-1.083,0.419c-0.423,0.436-0.418,1.029-0.417,1.095V34.5h-17v-7h37v7H21.5z"/><path fill="#4788c7" d="M38,28v6H22l0-2.972c0.004-0.143-0.004-0.888-0.558-1.458C21.188,29.31,20.733,29,20,29 s-1.188,0.31-1.441,0.57C18.004,30.141,17.996,30.885,18,31v3H2v-6H38 M39,27H1v8h18v-4c0,0-0.028-1,1-1s1,1,1,1v4h18V27L39,27z"/><path fill="#98ccfd" d="M30 10H35V23H30zM22 10H27V23H22zM13 10H18V23H13zM5 10H10V23H5z"/><path fill="#fff" d="M32 34h2v-3c0-.55-.45-1-1-1l0 0c-.55 0-1 .45-1 1V34zM35 34h2v-3c0-.55-.45-1-1-1l0 0c-.55 0-1 .45-1 1V34zM29 34h2v-3c0-.55-.45-1-1-1h0c-.55 0-1 .45-1 1V34zM26 34h2v-3c0-.55-.45-1-1-1h0c-.55 0-1 .45-1 1V34zM23 34h2v-3c0-.55-.45-1-1-1h0c-.55 0-1 .45-1 1V34zM12 34h2v-3c0-.55-.45-1-1-1h0c-.55 0-1 .45-1 1V34zM15 34h2v-3c0-.55-.45-1-1-1h0c-.55 0-1 .45-1 1V34zM9 34h2v-3c0-.55-.45-1-1-1h0c-.55 0-1 .45-1 1V34zM6 34h2v-3c0-.55-.45-1-1-1h0c-.55 0-1 .45-1 1V34zM3 34h2v-3c0-.55-.45-1-1-1h0c-.55 0-1 .45-1 1V34z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#98ccfd" d="M5,37.5c-1.378,0-2.5-1.121-2.5-2.5V5c0-1.379,1.122-2.5,2.5-2.5h30c1.378,0,2.5,1.121,2.5,2.5v30 c0,1.379-1.122,2.5-2.5,2.5H5z"/><path fill="#4788c7" d="M35,3c1.103,0,2,0.897,2,2v30c0,1.103-0.897,2-2,2H5c-1.103,0-2-0.897-2-2V5c0-1.103,0.897-2,2-2 H35 M35,2H5C3.343,2,2,3.343,2,5v30c0,1.657,1.343,3,3,3h30c1.657,0,3-1.343,3-3V5C38,3.343,36.657,2,35,2L35,2z"/><path fill="#dff0fe" d="M26,12H14c-1.105,0-2,0.895-2,2v12c0,1.105,0.895,2,2,2h12c1.105,0,2-0.895,2-2V14 C28,12.895,27.105,12,26,12z"/><path fill="#fff" d="M14 5A1 1 0 1 0 14 7 1 1 0 1 0 14 5zM18 5A1 1 0 1 0 18 7 1 1 0 1 0 18 5zM22 5A1 1 0 1 0 22 7 1 1 0 1 0 22 5zM26 5A1 1 0 1 0 26 7 1 1 0 1 0 26 5zM14 33A1 1 0 1 0 14 35 1 1 0 1 0 14 33zM18 33A1 1 0 1 0 18 35 1 1 0 1 0 18 33zM22 33A1 1 0 1 0 22 35 1 1 0 1 0 22 33zM26 33A1 1 0 1 0 26 35 1 1 0 1 0 26 33zM34 13A1 1 0 1 0 34 15 1 1 0 1 0 34 13zM34 17A1 1 0 1 0 34 19 1 1 0 1 0 34 17zM34 21A1 1 0 1 0 34 23 1 1 0 1 0 34 21zM34 25A1 1 0 1 0 34 27 1 1 0 1 0 34 25zM6 13A1 1 0 1 0 6 15 1 1 0 1 0 6 13zM6 17A1 1 0 1 0 6 19 1 1 0 1 0 6 17zM6 21A1 1 0 1 0 6 23 1 1 0 1 0 6 21zM6 25A1 1 0 1 0 6 27 1 1 0 1 0 6 25z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="40px" height="40px"><rect width="17" height="17" x="1.5" y="2.5" fill="#dff0fe" stroke="#4788c7" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10"/><rect width="17" height="17" x="20.5" y="2.5" fill="#dff0fe" stroke="#4788c7" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10"/><rect width="17" height="17" x="1.5" y="21.5" fill="#dff0fe" stroke="#4788c7" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10"/><rect width="17" height="17" x="20.5" y="21.5" fill="#dff0fe" stroke="#4788c7" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="none" stroke="#4788c7" stroke-miterlimit="10" d="M14.05 9.918l-6.78 3.767c-1.092.607-1.77 1.758-1.77 3.007v7.476M25.95 9.918l6.78 3.767c1.092.607 1.77 1.758 1.77 3.007v7.476M29.5 32.359l-7.811 4.687c-1.046.628-2.346.654-3.417.07L9.55 32.359"/><path fill="#dff0fe" d="M13.5 13.359L13.5 6.641 20 2.589 26.5 6.641 26.5 13.359 20 17.411z"/><path fill="#4788c7" d="M20,3.178l6,3.74v6.163l-6,3.74l-6-3.74V6.919L20,3.178 M20,2l-7,4.364v7.273L20,18l7-4.364V6.364 L20,2L20,2z"/><path fill="#98ccfd" d="M20 10.312L14 6.924 14 13.081 20 16.822z"/><path fill="#fff" d="M26 6.924L20 10.312 20 16.822 26 13.081z"/><path fill="#dff0fe" d="M25.5 31.359L25.5 24.641 32 20.589 38.5 24.641 38.5 31.359 32 35.411z"/><path fill="#4788c7" d="M32,21.178l6,3.74v6.163l-6,3.74l-6-3.74v-6.163L32,21.178 M32,20l-7,4.364v7.273L32,36l7-4.364 v-7.273L32,20L32,20z"/><path fill="#98ccfd" d="M32 28.312L26 24.924 26 31.081 32 34.822z"/><path fill="#fff" d="M38 24.924L32 28.312 32 34.822 38 31.081z"/><path fill="#dff0fe" d="M1.5 31.359L1.5 24.641 8 20.589 14.5 24.641 14.5 31.359 8 35.411z"/><path fill="#4788c7" d="M8,21.178l6,3.74v6.163l-6,3.74l-6-3.74v-6.163L8,21.178 M8,20l-7,4.364v7.273L8,36l7-4.364v-7.273 L8,20L8,20z"/><path fill="#98ccfd" d="M8 28.312L2 24.924 2 31.081 8 34.822z"/><path fill="#fff" d="M14 24.924L8 28.312 8 34.822 14 31.081z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M2.5 2.5H37.5V37.5H2.5z"/><path fill="#4788c7" d="M37,3v34H3V3H37 M38,2H2v36h36V2L38,2z"/><path fill="#b6dcfe" d="M9 14.5A2.5 2.5 0 1 0 9 19.5A2.5 2.5 0 1 0 9 14.5Z"/><path fill="#4788c7" d="M9,15c1.103,0,2,0.897,2,2s-0.897,2-2,2s-2-0.897-2-2S7.897,15,9,15 M9,14c-1.657,0-3,1.343-3,3 s1.343,3,3,3s3-1.343,3-3S10.657,14,9,14L9,14z"/><path fill="#98ccfd" d="M9 6.5A2.5 2.5 0 1 0 9 11.5A2.5 2.5 0 1 0 9 6.5Z"/><path fill="#4788c7" d="M9,7c1.103,0,2,0.897,2,2s-0.897,2-2,2s-2-0.897-2-2S7.897,7,9,7 M9,6C7.343,6,6,7.343,6,9 s1.343,3,3,3s3-1.343,3-3S10.657,6,9,6L9,6z"/><path fill="#98ccfd" d="M15.5 6.5H33.5V33.5H15.5z"/><path fill="#4788c7" d="M33,7v26H16V7H33 M34,6H15v28h19V6L34,6z"/><path fill="#4788c7" d="M27 6.308H28V34H27zM21 6H22V33.692H21z"/><path fill="#fff" d="M30.5 12L30.5 12c-.276 0-.5-.224-.5-.5v-2C30 9.224 30.224 9 30.5 9h0C30.776 9 31 9.224 31 9.5v2C31 11.776 30.776 12 30.5 12zM24.5 12L24.5 12c-.276 0-.5-.224-.5-.5v-2C24 9.224 24.224 9 24.5 9h0C24.776 9 25 9.224 25 9.5v2C25 11.776 24.776 12 24.5 12zM18.5 12L18.5 12c-.276 0-.5-.224-.5-.5v-2C18 9.224 18.224 9 18.5 9h0C18.776 9 19 9.224 19 9.5v2C19 11.776 18.776 12 18.5 12z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#fff" d="M2.5 2.5H37.5V37.5H2.5z"/><path fill="#4788c7" d="M37,3v34H3V3H37 M38,2H2v36h36V2L38,2z"/><path fill="#98ccfd" d="M3 3H37V11H3z"/><path fill="#fff" d="M17 5H35V9H17z"/><path fill="#dff0fe" d="M7 5A2 2 0 1 0 7 9 2 2 0 1 0 7 5zM13 5A2 2 0 1 0 13 9 2 2 0 1 0 13 5z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#4788c7" d="M24,2c0.551,0,1,0.449,1,1v3H14V3c0-0.551,0.449-1,1-1H24 M24,1h-9c-1.105,0-2,0.895-2,2v4h13V3C26,1.895,25.105,1,24,1L24,1z"/><path fill="#dff0fe" d="M1.5 14.5H37.5V31.5H1.5z"/><path fill="#4788c7" d="M37,15v16H2V15H37 M38,14H1v18h37V14L38,14z"/><path fill="#dff0fe" d="M5,20.5c-1.93,0-3.5-1.57-3.5-3.5V4.5h36V17c0,1.93-1.57,3.5-3.5,3.5H5z"/><path fill="#4788c7" d="M37,5v12c0,1.654-1.346,3-3,3H5c-1.654,0-3-1.346-3-3V5H37 M38,4H1v13c0,2.209,1.791,4,4,4h29c2.209,0,4-1.791,4-4V4L38,4z"/><path fill="#4788c7" d="M19.5 15A1.5 1.5 0 1 0 19.5 18 1.5 1.5 0 1 0 19.5 15zM27 5h-3V4.5C24 3.672 24.672 3 25.5 3l0 0C26.328 3 27 3.672 27 4.5V5zM15 5h-3V4.5C12 3.672 12.672 3 13.5 3l0 0C14.328 3 15 3.672 15 4.5V5z"/><path fill="#98ccfd" d="M29.045 37.318L26.217 37.718 25.723 34.905 23.2 33.566 24.455 31 23.2 28.434 25.723 27.095 26.217 24.282 29.045 24.682 31.098 22.696 33.151 24.682 35.979 24.282 36.473 27.095 38.996 28.434 37.741 31 38.996 33.566 36.473 34.905 35.979 37.718 33.151 37.318 31.098 39.304z"/><path fill="#4788c7" d="M31.098,23.391l1.53,1.48l0.351,0.34l0.484-0.068l2.107-0.298l0.368,2.096l0.084,0.481l0.432,0.229l1.88,0.997l-0.935,1.912L37.185,31l0.215,0.439l0.935,1.912l-1.88,0.997l-0.432,0.229l-0.084,0.481l-0.368,2.096l-2.107-0.298l-0.484-0.068l-0.351,0.34l-1.53,1.48l-1.53-1.48l-0.351-0.34l-0.484,0.068l-2.107,0.298l-0.368-2.096l-0.084-0.481l-0.432-0.229l-1.88-0.997l0.935-1.912L25.011,31l-0.215-0.439l-0.935-1.912l1.88-0.997l0.432-0.229l0.084-0.481l0.368-2.096l2.107,0.298l0.484,0.068l0.351-0.34L31.098,23.391 M31.098,22l-2.225,2.152l-3.065-0.434l-0.535,3.049l-2.735,1.451L23.898,31l-1.36,2.781l2.735,1.451l0.535,3.049l3.065-0.434L31.098,40l2.225-2.152l3.065,0.434l0.535-3.049l2.735-1.451L38.298,31l1.36-2.781l-2.735-1.451l-0.535-3.049l-3.065,0.434L31.098,22L31.098,22z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#fff" d="M1.5 3.5H38.5V36.5H1.5z"/><path fill="#4788c7" d="M38,4v32H2V4H38 M39,3H1v34h38V3L39,3z"/><path fill="#98ccfd" d="M2 4H38V10H2z"/><g><path fill="#98ccfd" d="M20,32.5c-5.238,0-9.5-4.262-9.5-9.5s4.262-9.5,9.5-9.5s9.5,4.262,9.5,9.5S25.238,32.5,20,32.5z M16.706,28.647l0.667,0.295C18.208,29.313,19.092,29.5,20,29.5c3.584,0,6.5-2.916,6.5-6.5c0-0.909-0.188-1.793-0.558-2.627 l-0.295-0.666L16.706,28.647z M20,16.5c-3.584,0-6.5,2.916-6.5,6.5c0,0.922,0.194,1.821,0.578,2.671l0.298,0.66l8.955-8.955 l-0.659-0.298C21.822,16.695,20.924,16.5,20,16.5z"/><path fill="#4788c7" d="M20,14c4.963,0,9,4.037,9,9s-4.037,9-9,9s-9-4.037-9-9S15.037,14,20,14 M14.219,27.196l1.023-1.023 l7.932-7.932l1.023-1.023l-1.318-0.596C21.963,16.21,20.995,16,20,16c-3.86,0-7,3.14-7,7c0,0.995,0.21,1.963,0.623,2.878 L14.219,27.196 M20,30c3.86,0,7-3.14,7-7c0-0.978-0.202-1.93-0.6-2.83l-0.59-1.333l-1.031,1.031l-7.91,7.91l-1.031,1.031 l1.333,0.59C18.07,29.798,19.022,30,20,30 M20,13c-5.523,0-10,4.477-10,10c0,5.523,4.477,10,10,10s10-4.477,10-10 C30,17.477,25.523,13,20,13L20,13z M14.534,25.466C14.194,24.713,14,23.88,14,23c0-3.314,2.686-6,6-6 c0.88,0,1.713,0.194,2.466,0.534L14.534,25.466L14.534,25.466z M20,29c-0.864,0-1.683-0.186-2.425-0.515l7.91-7.91 C25.814,21.317,26,22.136,26,23C26,26.314,23.314,29,20,29L20,29z"/></g></svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 96 96" width="96px" height="96px">
<g id="surface46010398">
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(87.450981%,94.117647%,99.607843%);fill-opacity:1;" d="M 34.40625 38.242188 L 24.59375 43.675781 C 24.226562 43.875 24 44.253906 24 44.65625 L 24 55.523438 C 24 55.929688 24.226562 56.304688 24.59375 56.507812 L 34.410156 61.941406 C 34.777344 62.144531 35.230469 62.144531 35.597656 61.941406 L 45.410156 56.507812 C 45.773438 56.304688 46 55.929688 46 55.523438 L 46 44.65625 C 46 44.253906 45.773438 43.878906 45.40625 43.675781 L 35.59375 38.242188 C 35.410156 38.140625 35.203125 38.09375 35 38.09375 C 34.792969 38.09375 34.589844 38.140625 34.40625 38.242188 M 84.902344 48.027344 L 83.265625 48.929688 C 83.203125 48.964844 83.167969 49.027344 83.167969 49.09375 L 83.167969 50.90625 C 83.167969 50.972656 83.207031 51.035156 83.265625 51.070312 L 84.902344 51.976562 C 84.964844 52.011719 85.039062 52.011719 85.101562 51.976562 L 86.734375 51.070312 C 86.796875 51.035156 86.835938 50.972656 86.835938 50.90625 L 86.835938 49.09375 C 86.835938 49.027344 86.796875 48.964844 86.734375 48.929688 L 85.097656 48.027344 C 85.066406 48.007812 85.035156 48 85 48 C 84.964844 48 84.933594 48.007812 84.902344 48.027344 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(59.607846%,80.000001%,99.215686%);fill-opacity:1;" d="M 71.503906 26.726562 L 66.722656 24.0625 C 66.574219 23.976562 66.390625 23.980469 66.242188 24.066406 C 66.09375 24.15625 66.003906 24.3125 66.003906 24.484375 L 66 40.589844 L 61.59375 38.152344 C 61.410156 38.050781 61.203125 38 61 38 C 60.796875 38 60.589844 38.050781 60.40625 38.152344 L 50.59375 43.582031 C 50.226562 43.785156 50 44.160156 50 44.5625 L 50 55.429688 C 50 55.835938 50.226562 56.210938 50.59375 56.414062 L 60.410156 61.847656 C 60.777344 62.050781 61.230469 62.050781 61.597656 61.847656 L 71.410156 56.414062 C 71.773438 56.210938 72 55.835938 72 55.429688 L 72 27.574219 C 72 27.222656 71.808594 26.898438 71.503906 26.726562 Z M 65.730469 52.914062 L 61.273438 55.386719 C 61.105469 55.476562 60.898438 55.476562 60.734375 55.386719 L 56.273438 52.914062 C 56.101562 52.824219 56 52.652344 56 52.46875 L 56 47.527344 C 56 47.34375 56.101562 47.175781 56.269531 47.078125 L 60.730469 44.613281 C 60.8125 44.566406 60.90625 44.542969 61 44.542969 C 61.09375 44.542969 61.1875 44.566406 61.269531 44.613281 L 65.730469 47.078125 C 65.898438 47.175781 66 47.347656 66 47.53125 L 66 52.46875 C 66 52.652344 65.898438 52.824219 65.730469 52.914062 Z M 65.730469 52.914062 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(27.843139%,53.333336%,78.039217%);fill-opacity:1;" d="M 34.40625 38.242188 L 24 55.523438 C 24 55.929688 24.226562 56.304688 24.59375 56.507812 L 34.410156 61.941406 C 34.777344 62.144531 35.230469 62.144531 35.597656 61.941406 L 46 44.65625 C 46 44.253906 45.773438 43.878906 45.40625 43.675781 L 35.59375 38.242188 C 35.410156 38.140625 35.203125 38.09375 35 38.09375 C 34.792969 38.09375 34.589844 38.140625 34.40625 38.242188 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(59.607846%,80.000001%,99.215686%);fill-opacity:1;" d="M 34.40625 38.242188 L 24.59375 43.675781 C 24.226562 43.875 24 44.253906 24 44.65625 L 34.40625 61.941406 C 34.773438 62.144531 35.226562 62.144531 35.59375 61.941406 L 45.40625 56.507812 C 45.773438 56.304688 46 55.929688 46 55.523438 L 35.59375 38.242188 C 35.410156 38.140625 35.203125 38.09375 35 38.09375 C 34.792969 38.09375 34.589844 38.140625 34.40625 38.242188 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(59.607846%,80.000001%,99.215686%);fill-opacity:1;" d="M 95.40625 43.582031 L 85.59375 38.152344 C 85.410156 38.050781 85.203125 38 85 38 C 84.796875 38 84.589844 38.050781 84.40625 38.152344 L 74.59375 43.582031 C 74.226562 43.785156 74 44.167969 74 44.589844 L 74 55.410156 C 74 55.828125 74.226562 56.214844 74.59375 56.414062 L 84.410156 61.851562 C 84.777344 62.054688 85.226562 62.054688 85.597656 61.851562 L 90.121094 59.34375 C 90.535156 59.113281 90.535156 58.519531 90.117188 58.292969 L 80.269531 52.917969 C 80.105469 52.824219 80 52.648438 80 52.460938 L 80 47.53125 C 80 47.347656 80.101562 47.175781 80.261719 47.089844 L 84.730469 44.617188 L 84.726562 44.617188 C 84.8125 44.570312 84.902344 44.546875 84.996094 44.546875 C 85.09375 44.546875 85.183594 44.570312 85.269531 44.617188 L 89.738281 47.089844 C 89.898438 47.179688 89.996094 47.347656 89.996094 47.53125 L 89.996094 51.554688 C 89.996094 51.726562 90.089844 51.886719 90.238281 51.972656 C 90.390625 52.058594 90.574219 52.058594 90.722656 51.972656 L 95.519531 49.1875 C 95.816406 49.015625 96 48.695312 96 48.351562 L 96 44.59375 C 96 44.171875 95.773438 43.785156 95.40625 43.582031 Z M 21.40625 43.582031 L 11.59375 38.152344 C 11.410156 38.050781 11.203125 38 11 38 C 10.796875 38 10.589844 38.050781 10.40625 38.152344 L 0.59375 43.582031 C 0.226562 43.785156 0 44.167969 0 44.589844 L 0 59.519531 C 0 59.691406 0.09375 59.851562 0.242188 59.9375 C 0.390625 60.019531 0.574219 60.019531 0.726562 59.933594 L 5.523438 57.148438 C 5.816406 56.976562 6 56.65625 6 56.3125 L 6 47.527344 C 6 47.34375 6.101562 47.175781 6.261719 47.085938 L 10.730469 44.613281 C 10.8125 44.566406 10.90625 44.546875 11 44.546875 C 11.09375 44.546875 11.1875 44.570312 11.269531 44.613281 L 15.738281 47.089844 C 15.898438 47.175781 16 47.347656 16 47.53125 L 16 56.316406 C 16 56.660156 16.183594 56.976562 16.480469 57.148438 L 21.277344 59.9375 C 21.425781 60.023438 21.609375 60.023438 21.761719 59.9375 C 21.90625 59.851562 22 59.691406 22 59.519531 L 22 44.589844 C 22 44.171875 21.773438 43.785156 21.40625 43.582031 Z M 21.40625 43.582031 "/>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M2.5 37.5L2.5 8.175 6.24 3.5 33.759 3.5 37.5 8.175 37.5 37.5z"/><path fill="#4788c7" d="M33.519,4L37,8.351V37H3V8.351L6.48,4H33.519 M33.999,3H6L2,8v30h36V8L33.999,3L33.999,3z"/><path fill="#98ccfd" d="M2.5 8.5L2.5 8.175 6.24 3.5 33.759 3.5 37.5 8.175 37.5 8.5z"/><path fill="#4788c7" d="M33.519,4l3.2,4H3.281l3.2-4H33.519 M33.999,3H6L2,8v1h36V8L33.999,3L33.999,3z"/><path fill="#dff0fe" d="M5.954 8.5L16.432 1.597 27.156 8.5z"/><path fill="#4788c7" d="M16.435,2.193L25.456,8H7.621L16.435,2.193 M16.429,1L4.286,9h24.571L16.429,1L16.429,1z"/><g><path fill="#fff" d="M11.514 8.5L22.983 1.594 33.096 8.5z"/><path fill="#4788c7" d="M22.966,2.188L31.477,8H13.314L22.966,2.188 M23,1L9.714,9h25L23,1L23,1z"/></g><path fill="#ffc49c" stroke="#4788c7" stroke-miterlimit="10" d="M2 8.5L38 8.5"/><g><path fill="#4788c7" d="M24,13h-4h-4c-0.552,0-1,0.448-1,1c0,0.552,0.448,1,1,1h4h4c0.552,0,1-0.448,1-1 C25,13.448,24.552,13,24,13z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#b6dcfe" d="M1.5 35.5L1.5 4.5 11.793 4.5 14.793 7.5 35.5 7.5 35.5 35.5z"/><path fill="#4788c7" d="M11.586,5l2.707,2.707L14.586,8H15h20v27H2V5H11.586 M12,4H1v32h35V7H15L12,4L12,4z"/><g><path fill="#dff0fe" d="M1.599 35.5L5.417 14.5 16.151 14.5 19.151 12.5 39.41 12.5 35.577 35.5z"/><path fill="#4788c7" d="M38.82,13l-3.667,22H2.198l3.636-20H16h0.303l0.252-0.168L19.303,13H38.82 M40,12H19l-3,2H5L1,36 h35L40,12L40,12z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#98ccfd" d="M0.5 2.5H39.5V19.5H0.5z"/><path fill="#4788c7" d="M39,3v16H1V3H39 M40,2H0v18h40V2L40,2z"/><path fill="#fff" d="M18 11c0 1.133-.867 2-2 2s-2-.867-2-2 .867-2 2-2S18 9.867 18 11zM8 9c-1.133 0-2 .867-2 2s.867 2 2 2 2-.867 2-2S9.133 9 8 9zM32 9c-1.133 0-2 .867-2 2s.867 2 2 2c1.133 0 2-.867 2-2S33.133 9 32 9zM24 9c-1.133 0-2 .867-2 2s.867 2 2 2 2-.867 2-2S25.133 9 24 9z"/><g><path fill="#dff0fe" d="M20,37.5c-4.136,0-7.5-3.364-7.5-7.5s3.364-7.5,7.5-7.5c1.752,0,3.459,0.624,4.805,1.756 l0.352,0.295l2.344-2.344V28.5h-6.293l1.838-1.838L22.56,26.32C21.8,25.784,20.914,25.5,20,25.5c-2.481,0-4.5,2.019-4.5,4.5 s2.019,4.5,4.5,4.5c1.911,0,3.598-1.215,4.228-3h3.115C26.642,34.958,23.579,37.5,20,37.5z"/><path fill="#4788c7" d="M20,23c1.634,0,3.226,0.582,4.484,1.638l0.702,0.59l0.648-0.648L27,23.414V28h-4.586l0.565-0.564 l0.84-0.84l-0.97-0.685C22.003,25.315,21.018,25,20,25c-2.757,0-5,2.243-5,5s2.243,5,5,5c2.003,0,3.784-1.201,4.568-3h2.135 c-0.867,2.917-3.573,5-6.703,5c-3.86,0-7-3.14-7-7S16.14,23,20,23 M28,21l-2.873,2.873C23.74,22.707,21.955,22,20,22 c-4.418,0-8,3.582-8,8s3.582,8,8,8c4.079,0,7.438-3.055,7.931-7h-4.072c-0.446,1.722-1.997,3-3.859,3c-2.209,0-4-1.791-4-4 c0-2.209,1.791-4,4-4c0.85,0,1.628,0.274,2.272,0.728L20,29h8V21L28,21z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="none" stroke="#4788c7" stroke-miterlimit="10" stroke-width="2" d="M30,17.714c0,0,0-5.306,0-5.714 c0-5.523-4.477-10-10-10S10,6.477,10,12c0,0.408,0,5.714,0,5.714"/><path fill="#98ccfd" d="M2.5,37.5V19c0-1.93,1.57-3.5,3.5-3.5h28c1.93,0,3.5,1.57,3.5,3.5v18.5H2.5z"/><path fill="#4788c7" d="M34,16c1.654,0,3,1.346,3,3v18H3V19c0-1.654,1.346-3,3-3H34 M34,15H6c-2.209,0-4,1.791-4,4v19h36 V19C38,16.791,36.209,15,34,15L34,15z"/><path fill="#fff" d="M14 27c0 1.133-.867 2-2 2s-2-.867-2-2 .867-2 2-2S14 25.867 14 27zM28 25c-1.133 0-2 .867-2 2s.867 2 2 2 2-.867 2-2S29.133 25 28 25zM20 25c-1.133 0-2 .867-2 2s.867 2 2 2 2-.867 2-2S21.133 25 20 25z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#b6dcfe" d="M17.817,16.396L30.482,3.73c0.793-0.794,1.821-1.23,2.894-1.23c1.073,0,2.1,0.437,2.894,1.23 c0.793,0.793,1.23,1.82,1.23,2.894s-0.437,2.101-1.23,2.894L23.604,22.184L17.817,16.396z"/><path fill="#4788c7" d="M33.376,3c0.939,0,1.841,0.385,2.54,1.084C36.615,4.783,37,5.685,37,6.624 c0,0.939-0.385,1.841-1.084,2.54L23.604,21.476l-5.08-5.08L30.836,4.084C31.535,3.385,32.437,3,33.376,3 M33.376,2 c-1.165,0-2.33,0.459-3.247,1.377L17.11,16.396l6.495,6.495L36.623,9.871c1.835-1.835,1.835-4.659,0-6.495 C35.706,2.459,34.541,2,33.376,2L33.376,2z"/><path fill="#dff0fe" d="M4.604 23.916L13.801 20.411 18.444 15.769 24.231 21.557 19.588 26.199 16.084 35.397 2.594 37.406z"/><path fill="#4788c7" d="M18.444,16.476l5.08,5.08L19.31,25.77l-0.151,0.151l-0.076,0.2l-3.362,8.824L3.188,36.812 l1.867-12.533l8.824-3.362l0.2-0.076l0.151-0.151L18.444,16.476 M18.444,15.062l-4.921,4.921l-9.371,3.57L2,38l14.448-2.152 l3.57-9.371l4.921-4.921L18.444,15.062L18.444,15.062z"/><path fill="#4788c7" d="M11.5 26.5A2 2 0 1 0 11.5 30.5A2 2 0 1 0 11.5 26.5Z"/><path fill="none" stroke="#4788c7" stroke-miterlimit="10" d="M2.922 37.078L11.349 28.651"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#b6dcfe" d="M4.511,38.5c0.263-6.11,5.315-11,11.489-11h8c6.174,0,11.227,4.89,11.489,11H4.511z"/><path fill="#4788c7" d="M24,28c5.729,0,10.448,4.401,10.955,10H5.045C5.552,32.401,10.271,28,16,28H24 M24,27h-8 C9.373,27,4,32.373,4,39h32C36,32.373,30.627,27,24,27L24,27z"/><path fill="#fff" d="M20,30.5c-3.219,0-4.309-2.102-4.5-2.537V22.5h9v5.464C24.312,28.394,23.223,30.5,20,30.5z"/><path fill="#4788c7" d="M24,23v4.854C23.759,28.343,22.738,30,20,30c-2.73,0-3.756-1.657-4-2.147V23H24 M25,22H15v6.062 c0,0,1.066,2.938,5,2.938s5-2.938,5-2.938V22L25,22z"/><path fill="#b6dcfe" d="M27.143,19.214c-1.3,0-2.356-1.057-2.356-2.356s1.057-2.357,2.356-2.357 c1.963,0,2.357,0.537,2.357,1.404C29.5,17.318,28.335,19.214,27.143,19.214z M12.857,19.214c-1.192,0-2.357-1.896-2.357-3.31 c0-0.867,0.395-1.404,2.357-1.404c1.3,0,2.356,1.058,2.356,2.357S14.157,19.214,12.857,19.214z"/><path fill="#4788c7" d="M27.143,15C29,15,29,15.481,29,15.905c0,1.234-1.041,2.81-1.857,2.81 c-1.024,0-1.857-0.833-1.857-1.857S26.119,15,27.143,15 M12.857,15c1.024,0,1.857,0.833,1.857,1.857s-0.833,1.857-1.857,1.857 c-0.816,0-1.857-1.575-1.857-2.81C11,15.481,11,15,12.857,15 M27.143,14c-1.578,0-2.857,1.279-2.857,2.857 s1.279,2.857,2.857,2.857c1.578,0,2.857-2.232,2.857-3.81C30,14.327,28.721,14,27.143,14L27.143,14z M12.857,14 C11.279,14,10,14.327,10,15.905c0,1.578,1.279,3.81,2.857,3.81c1.578,0,2.857-1.279,2.857-2.857S14.435,14,12.857,14L12.857,14z"/><g><path fill="#fff" d="M20,26.5c-0.604,0-1.172-0.218-1.642-0.631l-0.091-0.079l-0.116-0.029 c-3.327-0.845-5.651-3.83-5.651-7.261V9.201c0-1.826,1.486-3.313,3.312-3.313h8.375c1.826,0,3.313,1.486,3.313,3.313V18.5 c0,3.431-2.324,6.416-5.651,7.261l-0.116,0.029l-0.091,0.079C21.172,26.282,20.604,26.5,20,26.5z"/><path fill="#4788c7" d="M24.187,6.389C25.738,6.389,27,7.651,27,9.202V18.5c0,3.201-2.169,5.987-5.275,6.776l-0.233,0.059 l-0.181,0.159C21.048,25.725,20.608,26,20,26s-1.048-0.275-1.311-0.506l-0.181-0.159l-0.233-0.059 C15.169,24.487,13,21.701,13,18.5V9.202c0-1.551,1.262-2.813,2.813-2.813H24.187 M24.187,5.389h-8.375 C13.707,5.389,12,7.096,12,9.202V18.5c0,3.737,2.566,6.866,6.029,7.745C18.557,26.709,19.242,27,20,27s1.443-0.291,1.971-0.755 C25.434,25.366,28,22.237,28,18.5V9.202C28,7.096,26.293,5.389,24.187,5.389L24.187,5.389z"/></g><g><path fill="#b6dcfe" d="M27.5,17.5V14c0-3.635-3.033-5.582-3.163-5.663l-0.398-0.25l-0.274,0.384 c-0.085,0.118-2.119,2.886-6.514,2.886c-1.15,0-4.65,0-4.65,3.644v2.5h-0.179c-0.436-0.981-1.821-4.332-1.821-7.188 c0-5.271,3.617-8.812,9-8.812c3.839,0,4.992,2.585,5.039,2.695l0.131,0.303L25,4.5c1.671,0,4.5,1.161,4.5,5.515 c0,2.621-1.407,6.394-1.838,7.485H27.5z"/><path fill="#4788c7" d="M19.5,2c3.483,0,4.538,2.297,4.577,2.385L24.334,5H25c1.845,0,4,1.313,4,5.015 c0,1.536-0.507,3.498-1,5.043V14c0-3.909-3.258-5.999-3.397-6.086L23.802,7.41l-0.547,0.772c-0.019,0.027-1.941,2.674-6.105,2.674 C13.733,10.857,12,12.251,12,15v0.314c-0.491-1.422-1-3.305-1-5.003C11,5.34,14.416,2,19.5,2 M19.5,1C13.681,1,10,4.981,10,10.311 C10,13.842,12,18,12,18h1c0,0,0-2.029,0-3c0-2.668,2.024-3.143,4.15-3.143c4.73,0,6.922-3.096,6.922-3.096S27,10.599,27,14 c0,1.069,0,4,0,4h1c0,0,2-4.768,2-7.985C30,5.498,27.123,4,25,4C25,4,23.747,1,19.5,1L19.5,1z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="none" stroke="#4788c7" stroke-miterlimit="10" d="M36.5 3.5L28.5 11.5 15.5 6.5 21.5 27.5 9.533 25.643 3.5 36.5"/><path fill="#dff0fe" d="M36.5 1.5A2 2 0 1 0 36.5 5.5A2 2 0 1 0 36.5 1.5Z"/><path fill="#4788c7" d="M36.5,2C37.327,2,38,2.673,38,3.5S37.327,5,36.5,5S35,4.327,35,3.5S35.673,2,36.5,2 M36.5,1 C35.119,1,34,2.119,34,3.5S35.119,6,36.5,6S39,4.881,39,3.5S37.881,1,36.5,1L36.5,1z"/><path fill="#dff0fe" d="M28.5 9.5A2 2 0 1 0 28.5 13.5A2 2 0 1 0 28.5 9.5Z"/><path fill="#4788c7" d="M28.5,10c0.827,0,1.5,0.673,1.5,1.5S29.327,13,28.5,13S27,12.327,27,11.5S27.673,10,28.5,10 M28.5,9c-1.381,0-2.5,1.119-2.5,2.5s1.119,2.5,2.5,2.5s2.5-1.119,2.5-2.5S29.881,9,28.5,9L28.5,9z"/><path fill="#dff0fe" d="M15.5 4.5A2 2 0 1 0 15.5 8.5A2 2 0 1 0 15.5 4.5Z"/><path fill="#4788c7" d="M15.5,5C16.327,5,17,5.673,17,6.5S16.327,8,15.5,8S14,7.327,14,6.5S14.673,5,15.5,5 M15.5,4 C14.119,4,13,5.119,13,6.5S14.119,9,15.5,9S18,7.881,18,6.5S16.881,4,15.5,4L15.5,4z"/><g><path fill="#dff0fe" d="M21.5 25.5A2 2 0 1 0 21.5 29.5A2 2 0 1 0 21.5 25.5Z"/><path fill="#4788c7" d="M21.5,26c0.827,0,1.5,0.673,1.5,1.5S22.327,29,21.5,29S20,28.327,20,27.5S20.673,26,21.5,26 M21.5,25c-1.381,0-2.5,1.119-2.5,2.5s1.119,2.5,2.5,2.5s2.5-1.119,2.5-2.5S22.881,25,21.5,25L21.5,25z"/></g><g><path fill="#dff0fe" d="M3.5 34.5A2 2 0 1 0 3.5 38.5A2 2 0 1 0 3.5 34.5Z"/><path fill="#4788c7" d="M3.5,35C4.327,35,5,35.673,5,36.5S4.327,38,3.5,38S2,37.327,2,36.5S2.673,35,3.5,35 M3.5,34 C2.119,34,1,35.119,1,36.5S2.119,39,3.5,39S6,37.881,6,36.5S4.881,34,3.5,34L3.5,34z"/></g><g><path fill="#dff0fe" d="M9.5 23.5A2 2 0 1 0 9.5 27.5A2 2 0 1 0 9.5 23.5Z"/><path fill="#4788c7" d="M9.5,24c0.827,0,1.5,0.673,1.5,1.5S10.327,27,9.5,27S8,26.327,8,25.5S8.673,24,9.5,24 M9.5,23 C8.119,23,7,24.119,7,25.5S8.119,28,9.5,28s2.5-1.119,2.5-2.5S10.881,23,9.5,23L9.5,23z"/></g></svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 96 96" width="96px" height="96px">
<g id="surface46008244">
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(27.843139%,53.333336%,78.039217%);fill-opacity:1;" d="M 88.164062 59.578125 C 87.800781 57.921875 86.296875 55.988281 83.261719 55.988281 C 82.640625 55.988281 81.964844 56.066406 81.191406 56.226562 C 79.777344 56.519531 78.570312 56.660156 77.507812 56.707031 C 85.773438 42.628906 91.140625 23.070312 85.824219 16.28125 C 78.824219 7.335938 69.398438 5.996094 64.402344 5.996094 L 63.933594 6 C 62.074219 6.03125 60.148438 6.257812 58.207031 6.679688 L 51.042969 8.226562 C 50.066406 8.105469 49.070312 8.019531 48.035156 8 L 47.945312 8 L 47.640625 7.996094 C 44.453125 7.996094 41.546875 8.675781 38.957031 9.945312 L 36.457031 8.957031 C 33.015625 7.601562 27.839844 5.988281 22.71875 5.988281 C 22.433594 5.988281 22.144531 5.992188 21.859375 6.003906 C 16.8125 6.1875 12.480469 8.101562 9.328125 11.539062 C 5.390625 15.828125 3.601562 22.109375 4.007812 30.199219 C 4.027344 30.617188 8.921875 72 22.800781 72 L 22.851562 72 L 22.976562 71.996094 C 24.78125 71.953125 26.496094 71.230469 28.105469 69.84375 C 29.328125 70.765625 30.914062 71.308594 32.394531 71.523438 C 33.371094 71.753906 35.125 72.078125 37.230469 72.078125 C 39.796875 72.078125 42.113281 71.554688 44.109375 70.605469 C 44.109375 72.363281 44.097656 74.59375 44.078125 77.441406 L 44.074219 77.589844 L 44.085938 77.738281 C 44.28125 80.578125 44.769531 83.136719 45.507812 85.140625 C 47.609375 90.859375 51.238281 94.011719 55.730469 94.011719 C 55.914062 94.011719 56.105469 94.003906 56.296875 93.992188 C 59.988281 93.765625 63.730469 91.691406 66.304688 88.449219 C 69.09375 84.9375 69.734375 81.234375 69.984375 78.394531 L 70 78.222656 L 70 69.886719 L 70.207031 69.90625 L 71.078125 69.984375 L 71.160156 69.992188 L 71.246094 69.996094 C 71.492188 70.007812 71.75 70.011719 72.007812 70.011719 C 75.023438 70.011719 78.730469 69.230469 81.238281 68.0625 C 83.636719 66.953125 89.117188 63.894531 88.164062 59.578125 Z M 88.164062 59.578125 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(59.607846%,80.000001%,99.215686%);fill-opacity:1;" d="M 66 68 C 66 67.589844 66.023438 67.246094 66.035156 66.871094 C 66.015625 66.367188 66 66 66 66 C 66 66 66.023438 65.980469 66.0625 65.957031 C 66.363281 60.609375 67.835938 58.550781 69.414062 57.375 C 69.195312 57.070312 68.941406 56.738281 68.703125 56.425781 C 68.035156 55.550781 67.207031 54.46875 66.316406 53.078125 L 66.152344 52.761719 C 66.019531 52.433594 65.695312 51.867188 65.285156 51.125 C 62.917969 46.84375 57.992188 37.941406 61.363281 32.316406 C 62.839844 29.851562 65.609375 28.433594 69.605469 28.082031 C 67.972656 23.4375 61.851562 12.230469 47.96875 12 C 47.964844 12 47.960938 12 47.957031 12 C 35.875 11.804688 31.90625 22.785156 30.613281 29.34375 C 32.394531 28.589844 34.425781 28.132812 36.285156 28.132812 C 36.3125 28.132812 36.34375 28.132812 36.371094 28.132812 C 40.953125 28.164062 44.101562 30.609375 45.019531 34.839844 C 45.6875 37.945312 46.011719 40.660156 46.003906 43.144531 C 45.980469 48.585938 44.886719 51.445312 43.917969 53.96875 L 43.609375 54.785156 C 43.363281 55.453125 43.101562 56.074219 42.851562 56.65625 C 42.601562 57.253906 42.378906 57.785156 42.214844 58.261719 C 43.183594 58.480469 43.945312 58.792969 44.464844 59.023438 L 44.769531 59.152344 C 44.863281 59.195312 44.957031 59.238281 45.042969 59.292969 C 46.738281 60.324219 47.792969 61.910156 48.019531 63.757812 C 48.140625 64.753906 48.121094 71.542969 48.078125 77.46875 C 48.253906 80.039062 48.691406 82.195312 49.265625 83.761719 C 50.085938 85.988281 52.128906 90.242188 56.054688 89.996094 C 58.792969 89.828125 61.429688 88.160156 63.175781 85.960938 C 65.050781 83.597656 65.742188 80.984375 66.003906 78.042969 L 66.003906 68 Z M 66 68 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(59.607846%,80.000001%,99.215686%);fill-opacity:1;" d="M 30.226562 57.835938 C 27.003906 54.46875 25.429688 49.941406 26.019531 45.722656 C 26.589844 41.652344 26.269531 37.667969 26.09375 35.527344 C 26.035156 34.8125 25.996094 34.28125 26 33.984375 C 26 33.96875 26.003906 33.957031 26.007812 33.941406 C 26.007812 33.933594 26.003906 33.925781 26.003906 33.917969 C 26.242188 27.875 28.574219 18.34375 34.988281 12.679688 C 31.863281 11.449219 26.777344 9.824219 22 10 C 14.515625 10.273438 7.273438 15.449219 8 30 C 8.273438 35.460938 14.445312 68.207031 22.878906 68 C 24.085938 67.96875 25.339844 67.195312 26.625 65.648438 C 28.65625 63.203125 30.632812 60.984375 32.039062 59.441406 C 31.410156 58.960938 30.800781 58.433594 30.226562 57.835938 Z M 74.046875 29.460938 C 74.074219 29.769531 74.050781 30.035156 74.003906 30.277344 C 74.0625 32.117188 73.867188 33.902344 73.664062 35.632812 C 73.515625 36.902344 73.363281 38.21875 73.320312 39.535156 C 73.28125 40.824219 73.460938 42.101562 73.652344 43.449219 C 74.105469 46.605469 74.570312 50.164062 72.125 54.320312 C 72.574219 54.914062 72.96875 55.464844 73.285156 55.996094 C 82.507812 41.046875 86.222656 23.273438 82.675781 18.742188 C 77.308594 11.886719 69.882812 9.902344 63.996094 10 C 62.15625 10.03125 60.480469 10.277344 59.050781 10.589844 C 69.203125 15.507812 73.726562 26.050781 74.046875 29.460938 Z M 82 60.140625 C 76.671875 61.242188 74.105469 60.65625 72.863281 59.890625 C 72.660156 60.035156 72.460938 60.15625 72.277344 60.269531 C 71.53125 60.71875 70.355469 61.4375 70.066406 65.835938 C 70.230469 65.867188 70.378906 65.882812 70.558594 65.921875 L 71.429688 66 C 74.066406 66.121094 77.527344 65.378906 79.554688 64.4375 C 83.925781 62.410156 86.304688 59.253906 82 60.140625 Z M 44.046875 64.238281 C 43.972656 63.640625 43.648438 63.160156 43.0625 62.773438 L 42.847656 62.679688 C 42.125 62.363281 41.304688 62 40 62 L 39.992188 62 C 39.738281 62.019531 39.484375 62.039062 39.230469 62.039062 C 39.128906 62.039062 39.027344 62.023438 38.921875 62.019531 C 37.972656 62.75 36.625 63.3125 33.289062 64 C 27.328125 65.519531 30.847656 67.308594 33.132812 67.589844 C 35.347656 68.140625 40.605469 68.816406 44.097656 65.96875 C 44.085938 65.074219 44.070312 64.457031 44.046875 64.238281 Z M 44.046875 64.238281 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(59.607846%,80.000001%,99.215686%);fill-opacity:1;" d="M 41.363281 37.003906 C 40.777344 37.605469 39.855469 38.132812 38.839844 37.96875 C 37.183594 37.703125 35.910156 35.703125 36.003906 34.953125 C 36.09375 34.207031 37.507812 33.816406 39.160156 34.085938 C 39.734375 34.179688 40.257812 34.339844 40.695312 34.539062 C 40.054688 33.164062 38.898438 32.371094 37.132812 32.175781 C 34.003906 31.828125 30.679688 33.464844 30.011719 34.371094 C 30.027344 34.589844 30.050781 34.871094 30.078125 35.203125 C 30.265625 37.496094 30.609375 41.773438 29.976562 46.277344 C 29.5625 49.246094 30.765625 52.617188 33.113281 55.066406 C 34.625 56.648438 36.394531 57.648438 38.136719 57.945312 C 38.359375 56.988281 38.757812 56.054688 39.164062 55.09375 C 39.390625 54.5625 39.628906 54 39.855469 53.390625 L 40.179688 52.535156 C 41.066406 50.226562 41.980469 47.835938 41.996094 43.128906 C 42.007812 41.320312 41.785156 39.253906 41.363281 37.003906 Z M 69.695312 44.015625 C 69.484375 42.554688 69.273438 41.046875 69.324219 39.40625 C 69.371094 37.925781 69.535156 36.523438 69.691406 35.171875 C 69.816406 34.105469 69.910156 33.078125 69.96875 32.070312 C 67.390625 32.285156 65.679688 33.027344 64.867188 34.285156 C 65.203125 34.171875 65.582031 34.082031 66.003906 34.027344 C 67.785156 33.796875 69.089844 34.308594 69.238281 35.300781 C 69.347656 36.027344 68.730469 36.710938 68.460938 36.972656 C 67.90625 37.511719 67.210938 37.859375 66.5 37.949219 C 66.371094 37.964844 66.242188 37.972656 66.117188 37.972656 C 65.410156 37.972656 64.734375 37.730469 64.21875 37.375 C 64.441406 41.320312 67.351562 46.597656 68.785156 49.1875 C 69.089844 49.742188 69.324219 50.183594 69.523438 50.5625 C 70.308594 48.324219 70.019531 46.285156 69.695312 44.015625 Z M 69.695312 44.015625 "/>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#b6dcfe" d="M4,31.5c-1.378,0-2.5-1.122-2.5-2.5V13c0-1.378,1.122-2.5,2.5-2.5h3.5v-2h25v2H36c1.378,0,2.5,1.122,2.5,2.5v16c0,1.378-1.122,2.5-2.5,2.5H4z"/><path fill="#4788c7" d="M32,9v1v1h1h3c1.103,0,2,0.897,2,2v16c0,1.103-0.897,2-2,2H4c-1.103,0-2-0.897-2-2V13c0-1.103,0.897-2,2-2h3h1v-1V9H32 M33,8H7v2H4c-1.657,0-3,1.343-3,3v16c0,1.657,1.343,3,3,3h32c1.657,0,3-1.343,3-3V13c0-1.657-1.343-3-3-3h-3V8L33,8z"/><path fill="#fff" d="M8.5 1.5H31.5V11.5H8.5z"/><path fill="#4788c7" d="M31,2v9H9V2H31 M32,1H8v11h24V1L32,1z"/><path fill="#dff0fe" d="M11,20.5c-1.378,0-2.5-1.122-2.5-2.5v-7.5h23V18c0,1.378-1.122,2.5-2.5,2.5H11z"/><path fill="#4788c7" d="M31,11v7c0,1.103-0.897,2-2,2H11c-1.103,0-2-0.897-2-2v-7H31 M32,10H8v8c0,1.657,1.343,3,3,3h18c1.657,0,3-1.343,3-3V10L32,10z"/><path fill="#fff" d="M8.5 25.5H31.5V38.5H8.5z"/><path fill="#4788c7" d="M31,26v12H9V26H31 M32,25H8v14h24V25L32,25z"/><path fill="#dff0fe" d="M9 26H31V29H9z"/><path fill="none" stroke="#4788c7" stroke-linecap="round" stroke-miterlimit="10" d="M13.5 29.5L26.5 29.5M13.5 33.5L26.5 33.5"/><path fill="#fff" d="M35 14A1 1 0 1 0 35 16A1 1 0 1 0 35 14Z"/><path fill="#4788c7" d="M9,28v-2h22v2h1.5c0.828,0,1.5-0.672,1.5-1.5l0,0c0-0.828-0.672-1.5-1.5-1.5h-25C6.672,25,6,25.672,6,26.5l0,0C6,27.328,6.672,28,7.5,28H9z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M28.5 1.5H31.5V38.5H28.5z"/><path fill="#4788c7" d="M31,2v36h-2V2H31 M32,1h-4v38h4V1L32,1z"/><path fill="#dff0fe" d="M23.5 1.5H26.5V38.5H23.5z"/><path fill="#4788c7" d="M26,2v36h-2V2H26 M27,1h-4v38h4V1L27,1z"/><path fill="#dff0fe" d="M18.5 1.5H21.5V38.5H18.5z"/><path fill="#4788c7" d="M21,2v36h-2V2H21 M22,1h-4v38h4V1L22,1z"/><path fill="#dff0fe" d="M13.5 1.5H16.5V38.5H13.5z"/><path fill="#4788c7" d="M16,2v36h-2V2H16 M17,1h-4v38h4V1L17,1z"/><path fill="#dff0fe" d="M8.5 1.5H11.5V38.5H8.5z"/><path fill="#4788c7" d="M11,2v36H9V2H11 M12,1H8v38h4V1L12,1z"/><path fill="#dff0fe" d="M1.5 28.5H38.5V31.5H1.5z"/><path fill="#4788c7" d="M38,29v2H2v-2H38 M39,28H1v4h38V28L39,28z"/><path fill="#dff0fe" d="M1.5 23.5H38.5V26.5H1.5z"/><path fill="#4788c7" d="M38,24v2H2v-2H38 M39,23H1v4h38V23L39,23z"/><path fill="#dff0fe" d="M1.5 18.5H38.5V21.5H1.5z"/><path fill="#4788c7" d="M38,19v2H2v-2H38 M39,18H1v4h38V18L39,18z"/><g><path fill="#dff0fe" d="M1.5 13.5H38.5V16.5H1.5z"/><path fill="#4788c7" d="M38,14v2H2v-2H38 M39,13H1v4h38V13L39,13z"/></g><g><path fill="#dff0fe" d="M1.5 8.5H38.5V11.5H1.5z"/><path fill="#4788c7" d="M38,9v2H2V9H38 M39,8H1v4h38V8L39,8z"/></g><g><path fill="#98ccfd" d="M7,34.5c-0.827,0-1.5-0.673-1.5-1.5V7c0-0.827,0.673-1.5,1.5-1.5h26c0.827,0,1.5,0.673,1.5,1.5v26 c0,0.827-0.673,1.5-1.5,1.5H7z"/><path fill="#4788c7" d="M33,6c0.551,0,1,0.449,1,1v26c0,0.551-0.449,1-1,1H7c-0.551,0-1-0.449-1-1V7c0-0.551,0.449-1,1-1 H33 M33,5H7C5.895,5,5,5.895,5,7v26c0,1.105,0.895,2,2,2h26c1.105,0,2-0.895,2-2V7C35,5.895,34.105,5,33,5L33,5z"/></g><g><path fill="#fff" d="M10.5 9A1.5 1.5 0 1 0 10.5 12A1.5 1.5 0 1 0 10.5 9Z"/></g><g><path fill="#fff" d="M29.5 9A1.5 1.5 0 1 0 29.5 12A1.5 1.5 0 1 0 29.5 9Z"/></g><g><path fill="#fff" d="M29.5 28A1.5 1.5 0 1 0 29.5 31A1.5 1.5 0 1 0 29.5 28Z"/></g><g><path fill="#fff" d="M10.5 28A1.5 1.5 0 1 0 10.5 31A1.5 1.5 0 1 0 10.5 28Z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#b6dcfe" d="M1.5,35.5v-31h10.293l3,3H38.5v28H1.5z"/><path fill="#4788c7" d="M11.586,5l2.707,2.707L14.586,8H15h23v27H2V5H11.586 M12,4H1v32h38V7H15L12,4L12,4z"/><path fill="#dff0fe" d="M1.5,35.5v-26h10.651l3-2H38.5v28H1.5z"/><path fill="#4788c7" d="M38,8v27H2V10h10h0.303l0.252-0.168L15.303,8H38 M39,7H15l-3,2H1v27h38V7L39,7z"/><rect width="13" height="2" x="20.5" y="29.5" fill="#98ccfd"/><path fill="#4788c7" d="M34,32H20v-3h14V32z M21,31h12v-1H21V31z"/><g><polygon fill="#98ccfd" points="19.428,22.189 10.236,12.996 8.822,14.411 16.623,22.212 8.822,30.014 10.236,31.428 19.428,22.236 19.405,22.212"/><path fill="#4788c7" d="M10.236,32.136l-2.121-2.122l7.802-7.802L8.115,14.41l2.121-2.121l9.899,9.899l-0.354,0.401 L10.236,32.136z M9.529,30.014l0.707,0.708l8.508-8.511l-8.508-8.508L9.529,14.41l7.802,7.802L9.529,30.014z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M1.5 6.5H38.5V33.5H1.5z"/><path fill="#4788c7" d="M38,7v26H2V7H38 M39,6H1v28h38V6L39,6z"/><path fill="#dff0fe" stroke="#4788c7" stroke-miterlimit="10" d="M1.679,12.372l15.748,8.48c1.607,0.865,3.541,0.865,5.147,0 l15.748-8.48"/><path fill="#98ccfd" d="M31 22.5A8.5 8.5 0 1 0 31 39.5A8.5 8.5 0 1 0 31 22.5Z"/><path fill="#4788c7" d="M31,23c4.411,0,8,3.589,8,8s-3.589,8-8,8s-8-3.589-8-8S26.589,23,31,23 M31,22c-4.971,0-9,4.029-9,9 s4.029,9,9,9s9-4.029,9-9S35.971,22,31,22L31,22z"/><path fill="none" stroke="#fff" stroke-miterlimit="10" stroke-width="2" d="M26.821 31.025L29.591 33.794 35.821 27.563"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#b6dcfe" d="M7,38.5c-2.481,0-4.5-2.019-4.5-4.5V5.5h13V34c0,1.858,0.926,3.504,2.341,4.5H7z"/><path fill="#4788c7" d="M15,6v28c0,1.535,0.58,2.938,1.532,4H7c-2.206,0-4-1.794-4-4V6H15 M16,5H2v29c0,2.761,2.239,5,5,5 h14c-2.761,0-5-2.239-5-5V5L16,5z"/><path fill="#fff" d="M7.5,38.5v-0.027c2.247-0.25,4-2.16,4-4.473V1.5h26V34c0,2.481-2.019,4.5-4.5,4.5H7.5z"/><path fill="#4788c7" d="M37,2v32c0,2.206-1.794,4-4,4H9.997C11.212,37.087,12,35.634,12,34V2H37 M38,1H11v33 c0,2.209-1.791,4-4,4v1h26c2.761,0,5-2.239,5-5V1L38,1z"/><path fill="#4788c7" d="M17.5 9h14C32.328 9 33 8.328 33 7.5v0C33 6.672 32.328 6 31.5 6h-14C16.672 6 16 6.672 16 7.5v0C16 8.328 16.672 9 17.5 9zM26.5 13h6c.276 0 .5-.224.5-.5v0c0-.276-.224-.5-.5-.5h-6c-.276 0-.5.224-.5.5v0C26 12.776 26.224 13 26.5 13zM26.5 16h6c.276 0 .5-.224.5-.5v0c0-.276-.224-.5-.5-.5h-6c-.276 0-.5.224-.5.5v0C26 15.776 26.224 16 26.5 16zM26.5 19h6c.276 0 .5-.224.5-.5v0c0-.276-.224-.5-.5-.5h-6c-.276 0-.5.224-.5.5v0C26 18.776 26.224 19 26.5 19zM6.5 12H11v-1H6.5C6.224 11 6 11.224 6 11.5v0C6 11.776 6.224 12 6.5 12zM6.5 15H11v-1H6.5C6.224 14 6 14.224 6 14.5v0C6 14.776 6.224 15 6.5 15zM6.5 18H11v-1H6.5C6.224 17 6 17.224 6 17.5v0C6 17.776 6.224 18 6.5 18zM6.5 21H11v-1H6.5C6.224 20 6 20.224 6 20.5v0C6 20.776 6.224 21 6.5 21zM6.5 24H11v-1H6.5C6.224 23 6 23.224 6 23.5v0C6 23.776 6.224 24 6.5 24zM6.5 27H11v-1H6.5C6.224 26 6 26.224 6 26.5v0C6 26.776 6.224 27 6.5 27zM6.5 30H11v-1H6.5C6.224 29 6 29.224 6 29.5v0C6 29.776 6.224 30 6.5 30zM6.5 33H11v-1H6.5C6.224 32 6 32.224 6 32.5l0 0C6 32.776 6.224 33 6.5 33zM16.5 13h6c.276 0 .5-.224.5-.5v0c0-.276-.224-.5-.5-.5h-6c-.276 0-.5.224-.5.5v0C16 12.776 16.224 13 16.5 13zM16.5 16h6c.276 0 .5-.224.5-.5v0c0-.276-.224-.5-.5-.5h-6c-.276 0-.5.224-.5.5v0C16 15.776 16.224 16 16.5 16zM16.5 19h6c.276 0 .5-.224.5-.5v0c0-.276-.224-.5-.5-.5h-6c-.276 0-.5.224-.5.5v0C16 18.776 16.224 19 16.5 19zM16.5 22h6c.276 0 .5-.224.5-.5v0c0-.276-.224-.5-.5-.5h-6c-.276 0-.5.224-.5.5v0C16 21.776 16.224 22 16.5 22zM16.5 25h6c.276 0 .5-.224.5-.5v0c0-.276-.224-.5-.5-.5h-6c-.276 0-.5.224-.5.5v0C16 24.776 16.224 25 16.5 25zM16.5 28h6c.276 0 .5-.224.5-.5v0c0-.276-.224-.5-.5-.5h-6c-.276 0-.5.224-.5.5v0C16 27.776 16.224 28 16.5 28zM16.5 31h6c.276 0 .5-.224.5-.5v0c0-.276-.224-.5-.5-.5h-6c-.276 0-.5.224-.5.5v0C16 30.776 16.224 31 16.5 31zM16.5 34h6c.276 0 .5-.224.5-.5l0 0c0-.276-.224-.5-.5-.5h-6c-.276 0-.5.224-.5.5l0 0C16 33.776 16.224 34 16.5 34z"/><path fill="#fff" d="M38,34c0,0-3.134,4-7,4s-7-3.134-7-7s3.134-7,7-7s7,5,7,5V34z"/><g><path fill="#dff0fe" d="M22.059 30h-1.008C21.018 30.329 21 30.662 21 31h1C22 30.662 22.022 30.329 22.059 30zM37 23.019V34c.359.322.696.668 1 1.044V23.871C37.687 23.564 37.35 23.283 37 23.019zM21.461 28h1.062c.122-.344.263-.677.424-1h-1.106C21.698 27.325 21.569 27.658 21.461 28zM25.349 38h-1.478c.357.364.746.694 1.155 1h1.864C26.341 38.718 25.824 38.384 25.349 38zM22.523 34c-.115-.326-.215-.658-.292-1h-1.029c.069.34.157.673.26 1H22.523z"/></g><g><path fill="#dff0fe" d="M31,39.5c-4.687,0-8.5-3.813-8.5-8.5s3.813-8.5,8.5-8.5c2.264,0,4.396,0.887,6.003,2.497 l0.354,0.354l2.143-2.144V29.5h-6.293l2.024-2.024l-0.353-0.354C33.835,26.076,32.458,25.5,31,25.5c-3.032,0-5.5,2.467-5.5,5.5 s2.468,5.5,5.5,5.5c2.071,0,3.958-1.167,4.895-3h3.226C38.033,37.063,34.779,39.5,31,39.5z"/><path fill="#4788c7" d="M31,23c2.131,0,4.137,0.835,5.649,2.35l0.707,0.709l0.708-0.708L39,24.414V29h-4.586l0.817-0.817 l0.706-0.706l-0.705-0.707C34.094,25.629,32.591,25,31,25c-3.308,0-6,2.692-6,6s2.692,6,6,6c2.155,0,4.127-1.158,5.191-3h2.223 c-1.199,2.998-4.091,5-7.414,5c-4.411,0-8-3.589-8-8S26.589,23,31,23 M40,22l-2.643,2.643C35.73,23.013,33.486,22,31,22 c-4.971,0-9,4.029-9,9s4.029,9,9,9c4.282,0,7.859-2.993,8.769-7h-4.191c-0.772,1.764-2.529,3-4.578,3c-2.761,0-5-2.239-5-5 s2.239-5,5-5c1.381,0,2.621,0.57,3.524,1.476L32,30h8V22L40,22z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#fff" d="M7.5,35.5v-31h17.26l7.74,7.74V35.5H7.5z"/><path fill="#4788c7" d="M33,36H7V4h17.967L33,12.033V36z M8,35h24V12.447L24.553,5H8V35z"/><rect width="25" height="11" x="7.5" y="24.5" fill="#b6dcfe"/><path fill="#4788c7" d="M33,36H7V24h26V36z M8,35h24V25H8V35z"/><path fill="#dff0fe" d="M24.5,12.5v-8h0.26l7.74,7.74v0.26H24.5z"/><path fill="#4788c7" d="M33,13h-9V4h0.967L33,12.032V13z M25,12h6.554L25,5.447V12z"/><path fill="#4788c7" d="M27.5,16h-15c-0.276,0-0.5-0.224-0.5-0.5l0,0c0-0.276,0.224-0.5,0.5-0.5h15 c0.276,0,0.5,0.224,0.5,0.5l0,0C28,15.776,27.776,16,27.5,16z M23.5,19h-11c-0.276,0-0.5-0.224-0.5-0.5l0,0 c0-0.276,0.224-0.5,0.5-0.5h11c0.276,0,0.5,0.224,0.5,0.5l0,0C24,18.776,23.776,19,23.5,19z M27.5,22h-15 c-0.276,0-0.5-0.224-0.5-0.5l0,0c0-0.276,0.224-0.5,0.5-0.5h15c0.276,0,0.5,0.224,0.5,0.5l0,0C28,21.776,27.776,22,27.5,22z M23.5,25h-11c-0.276,0-0.5-0.224-0.5-0.5l0,0c0-0.276,0.224-0.5,0.5-0.5h11c0.276,0,0.5,0.224,0.5,0.5l0,0 C24,24.776,23.776,25,23.5,25z M27.5,29h-15c-0.276,0-0.5-0.224-0.5-0.5l0,0c0-0.276,0.224-0.5,0.5-0.5h15 c0.276,0,0.5,0.224,0.5,0.5l0,0C28,28.776,27.776,29,27.5,29z"/><path fill="#4788c7" d="M3,7V3h4V2H2v5H3z M37,7h1V2h-5v1h4V7z M37,33v4h-4v1h5v-5H37z M3,33H2v5h5v-1H3V33z"/><path fill="#4788c7" d="M37.5,6L37.5,6C37.775,6,38,6.225,38,6.5v1C38,7.775,37.775,8,37.5,8l0,0C37.225,8,37,7.775,37,7.5 v-1C37,6.225,37.225,6,37.5,6z M37.5,32L37.5,32c0.275,0,0.5,0.225,0.5,0.5v1c0,0.275-0.225,0.5-0.5,0.5l0,0 c-0.275,0-0.5-0.225-0.5-0.5v-1C37,32.225,37.225,32,37.5,32z M2.5,32L2.5,32C2.775,32,3,32.225,3,32.5v1C3,33.775,2.775,34,2.5,34 l0,0C2.225,34,2,33.775,2,33.5v-1C2,32.225,2.225,32,2.5,32z M2.5,6L2.5,6C2.775,6,3,6.225,3,6.5v1C3,7.775,2.775,8,2.5,8l0,0 C2.225,8,2,7.775,2,7.5v-1C2,6.225,2.225,6,2.5,6z M6.5,2h1C7.775,2,8,2.225,8,2.5l0,0C8,2.775,7.775,3,7.5,3h-1 C6.225,3,6,2.775,6,2.5l0,0C6,2.225,6.225,2,6.5,2z M32.5,2h1C33.775,2,34,2.225,34,2.5l0,0C34,2.775,33.775,3,33.5,3h-1 C32.225,3,32,2.775,32,2.5l0,0C32,2.225,32.225,2,32.5,2z M6.5,37h1C7.775,37,8,37.225,8,37.5l0,0C8,37.775,7.775,38,7.5,38h-1 C6.225,38,6,37.775,6,37.5l0,0C6,37.225,6.225,37,6.5,37z M32.5,37h1c0.275,0,0.5,0.225,0.5,0.5l0,0c0,0.275-0.225,0.5-0.5,0.5h-1 c-0.275,0-0.5-0.225-0.5-0.5l0,0C32,37.225,32.225,37,32.5,37z M37,26H3c-0.552,0-1-0.448-1-1l0,0c0-0.552,0.448-1,1-1h34 c0.552,0,1,0.448,1,1l0,0C38,25.552,37.552,26,37,26z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#fff" d="M5.5 1.5H34.5V38.5H5.5z"/><path fill="#4788c7" d="M34,2v36H6V2H34 M35,1H5v38h30V1L35,1z"/><path fill="#b6dcfe" d="M9 5H19V15H9zM21 5H31V15H21z"/><path fill="#fff" d="M9.5 17.5H30.5V34.5H9.5z"/><path fill="#98ccfd" d="M29,19v14H11V19H29 M31,17H9v18h22V17L31,17z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#4788c7" d="M20 18A2 2 0 1 0 20 22A2 2 0 1 0 20 18Z"/><path fill="#b6dcfe" d="M20.163.008C20.108.008 20.055 0 20 0s-.108.008-.163.008H20.163zM28.484 3.054L28.484 3.054c-.242.484-.049 1.06.421 1.329C34.329 7.486 38 13.316 38 20c0 6.686-3.673 12.517-9.099 15.62-.47.269-.664.844-.422 1.328v0c.253.506.881.716 1.373.437C35.906 33.949 40 27.46 40 20c0-7.458-4.092-13.946-10.144-17.383C29.365 2.338 28.737 2.548 28.484 3.054zM11.536 36.957c.243-.485.048-1.061-.422-1.329C5.679 32.527 2 26.692 2 20c0-6.688 3.676-12.522 9.105-15.623.47-.269.664-.844.422-1.328l0 0c-.253-.506-.88-.716-1.372-.437C4.097 6.046 0 12.538 0 20c0 7.466 4.101 13.96 10.164 17.394C10.656 37.672 11.283 37.462 11.536 36.957L11.536 36.957z"/><g><path fill="#98ccfd" d="M25.793 8.428L25.793 8.428c-.23.459-.081 1.027.359 1.29 3.502 2.097 5.856 5.92 5.856 10.29 0 4.369-2.352 8.19-5.852 10.287-.439.263-.587.831-.358 1.289l0 0c.265.531.927.707 1.435.4 4.057-2.45 6.775-6.891 6.775-11.977 0-5.088-2.72-9.531-6.781-11.98C26.72 7.722 26.059 7.897 25.793 8.428zM14.223 31.589L14.223 31.589c.23-.459.081-1.027-.359-1.29-3.502-2.097-5.856-5.92-5.856-10.29 0-4.369 2.352-8.19 5.852-10.287.439-.263.587-.831.358-1.289l0 0c-.265-.531-.927-.707-1.435-.4-4.057 2.45-6.775 6.892-6.775 11.977 0 5.088 2.72 9.531 6.781 11.98C13.297 32.295 13.958 32.119 14.223 31.589z"/></g><g><path fill="#4788c7" d="M26.008 20.008c0 2.035-1.02 3.832-2.574 4.916-.409.285-.555.82-.332 1.266l0 0c.271.542.966.73 1.464.384 2.079-1.443 3.442-3.843 3.442-6.566 0-2.727-1.368-5.13-3.452-6.572-.498-.345-1.192-.158-1.463.384v0c-.224.447-.077.982.333 1.267C24.985 16.171 26.008 17.971 26.008 20.008zM14.008 20.008c0-2.035 1.02-3.832 2.575-4.916.409-.285.555-.82.332-1.266v0c-.271-.542-.966-.73-1.464-.384-2.079 1.443-3.442 3.843-3.442 6.566 0 2.727 1.368 5.129 3.452 6.572.498.345 1.192.158 1.463-.384v0c.224-.447.077-.982-.333-1.267C15.032 23.846 14.008 22.046 14.008 20.008z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M2.5 2.5H37.5V37.5H2.5z"/><path fill="#4788c7" d="M37,3v34H3V3H37 M38,2H2v36h36V2L38,2z"/><path fill="#98ccfd" d="M20.5 2.5H37.5V37.5H20.5z"/><path fill="#4788c7" d="M37,3v34H21V3H37 M38,2H20v36h18V2L38,2z"/><path fill="#fff" d="M23 11H35V15H23z" transform="rotate(180 29 13)"/><path fill="#dff0fe" d="M32 5A2 2 0 1 0 32 9 2 2 0 1 0 32 5zM26 5A2 2 0 1 0 26 9 2 2 0 1 0 26 5z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M12.267 13L0 13 0 17 11.467 17zM10.567 22L11.1 19 0 19 0 22zM10 26L10.267 24 0 24 0 26z"/><path fill="#fff" d="M7.605 32.5L12.413 7.5 39.39 7.5 34.39 32.5z"/><path fill="#4788c7" d="M38.78,8l-4.8,24H8.211l4.615-24H38.78 M40,7H12L7,33h27.8L40,7L40,7z"/><path fill="#98ccfd" d="M13.562 24.5L15.408 15.5 33.39 15.5 31.59 24.5z"/><path fill="#4788c7" d="M32.78,16l-1.6,8H14.175l1.641-8H32.78 M34,15H15l-2.051,10H32L34,15L34,15z"/><path fill="#fff" d="M16.4 21L30 21 30.6 18 17 18z"/><path fill="#4788c7" d="M19.717 21L20.317 18 19.297 18 18.697 21z"/><g><path fill="#98ccfd" d="M12.826 8L12.057 12 37.98 12 38.78 8z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#b6dcfe" d="M1,38.5c-0.276,0-0.5-0.225-0.5-0.5V15c0-0.275,0.224-0.5,0.5-0.5h38c0.276,0,0.5,0.225,0.5,0.5v23 c0,0.275-0.224,0.5-0.5,0.5H1z"/><path fill="#4788c7" d="M39,15v23H1V15H39 M39,14H1c-0.552,0-1,0.448-1,1v23c0,0.552,0.448,1,1,1h38c0.552,0,1-0.448,1-1 V15C40,14.448,39.552,14,39,14L39,14z"/><path fill="#dff0fe" d="M5.5 2.5H34.5V14.5H5.5z"/><path fill="#4788c7" d="M34,3v11H6V3H34 M35,2H5v13h30V2L35,2z"/><path fill="#4788c7" d="M23.2,6h-6.4C16.358,6,16,6.448,16,7c0,0.552,0.358,1,0.8,1h6.4C23.642,8,24,7.552,24,7 C24,6.448,23.642,6,23.2,6z"/><g><path fill="#98ccfd" d="M5.5 15.5H34.5V30.5H5.5z"/><path fill="#4788c7" d="M34,16v14H6V16H34 M35,15H5v16h30V15L35,15z"/></g><g><path fill="#dff0fe" d="M37,17v19H3V17H37 M39,15H1v23h38V15L39,15z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#98ccfd" d="M3.499,38.5c-0.534,0-1.036-0.208-1.414-0.585S1.5,37.035,1.5,36.501s0.208-1.036,0.585-1.414 l18.233-17.382l1.983,1.985L4.904,37.923C4.535,38.292,4.033,38.5,3.499,38.5z"/><path fill="#4788c7" d="M20.31,18.405l1.293,1.294L4.559,37.561C4.276,37.844,3.899,38,3.499,38 c-0.4,0-0.777-0.156-1.06-0.439c-0.584-0.584-0.584-1.535-0.017-2.103L20.31,18.405 M20.327,17.007L1.732,34.734 c-0.976,0.976-0.976,2.558,0,3.534v0C2.22,38.756,2.859,39,3.499,39c0.64,0,1.279-0.244,1.767-0.732L23,19.683L20.327,17.007 L20.327,17.007z"/><path fill="#dff0fe" d="M26,26.5c-6.893,0-12.5-5.607-12.5-12.5S19.107,1.5,26,1.5S38.5,7.107,38.5,14S32.893,26.5,26,26.5z"/><path fill="#4788c7" d="M26,2c6.617,0,12,5.383,12,12s-5.383,12-12,12s-12-5.383-12-12S19.383,2,26,2 M26,1 c-7.18,0-13,5.82-13,13c0,7.18,5.82,13,13,13s13-5.82,13-13C39,6.82,33.18,1,26,1L26,1z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#98ccfd" d="M20,38.5C9.799,38.5,1.5,30.201,1.5,20S9.799,1.5,20,1.5S38.5,9.799,38.5,20S30.201,38.5,20,38.5z"/><path fill="#4788c7" d="M20,2c9.925,0,18,8.075,18,18s-8.075,18-18,18S2,29.925,2,20S10.075,2,20,2 M20,1 C9.507,1,1,9.507,1,20s8.507,19,19,19s19-8.507,19-19S30.493,1,20,1L20,1z"/><path fill="#fff" d="M25,17H15c-1.657,0-3,1.343-3,3v7h16v-7C28,18.343,26.657,17,25,17z"/><path fill="none" stroke="#fff" stroke-miterlimit="10" stroke-width="2" d="M20,24L20,24c-2.2,0-4-1.8-4-4v-4c0-2.2,1.8-4,4-4 h0c2.2,0,4,1.8,4,4v4C24,22.2,22.2,24,20,24z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M25.73,29.878c0-2.432,1.971-4.403,4.403-4.403c0.724,0,1.397,0.191,2,0.501 C34.36,21.146,36,14.658,36,6L20,1L4,6c0,27.141,16,33,16,33s3.624-1.35,7.422-5.676C26.399,32.518,25.73,31.282,25.73,29.878z"/><path fill="#4788c7" d="M20,39.004l-0.2-0.088C18.197,38.219,4.138,31.382,4.001,6.37L3.999,6L20,1.001l0.149,0.046 L36.001,6l-0.002,0.37c-0.027,5.008-0.623,9.642-1.771,13.774c-0.074,0.266-0.345,0.423-0.615,0.348 c-0.266-0.073-0.422-0.349-0.348-0.615c1.095-3.945,1.677-8.365,1.73-13.144L20,2.048L5.004,6.733 C5.262,29.979,17.755,36.86,19.998,37.909c0.376-0.178,1.061-0.529,1.93-1.104c0.23-0.155,0.54-0.09,0.692,0.142 c0.152,0.23,0.089,0.54-0.142,0.692c-1.081,0.715-1.892,1.106-2.278,1.276L20,39.004z"/><path fill="#98ccfd" d="M28.924,38.502l-0.36-2.158l-0.307-0.085c-1.056-0.294-2.026-0.854-2.806-1.618l-0.228-0.224 l-2.047,0.767L22.1,33.321l1.69-1.393l-0.079-0.309c-0.141-0.546-0.212-1.09-0.212-1.617s0.071-1.071,0.212-1.617l0.079-0.309 l-1.69-1.393l1.076-1.863l2.047,0.767l0.228-0.224c0.779-0.765,1.75-1.324,2.806-1.618l0.307-0.085l0.36-2.158h2.152l0.36,2.158 l0.307,0.085c1.056,0.294,2.026,0.854,2.806,1.618l0.228,0.224l2.047-0.767l1.076,1.863l-1.69,1.393l0.079,0.309 c0.141,0.546,0.212,1.09,0.212,1.617s-0.071,1.071-0.212,1.617l-0.079,0.309l1.69,1.393l-1.076,1.863l-2.047-0.767l-0.228,0.224 c-0.779,0.765-1.75,1.324-2.806,1.618l-0.307,0.085l-0.36,2.158H28.924z M30,26.502c-1.93,0-3.5,1.57-3.5,3.5s1.57,3.5,3.5,3.5 s3.5-1.57,3.5-3.5S31.93,26.502,30,26.502z"/><path fill="#4788c7" d="M30.653,22.002l0.238,1.426l0.105,0.628l0.614,0.171c0.975,0.271,1.871,0.787,2.59,1.493l0.455,0.446 l0.596-0.223l1.352-0.506l0.653,1.131l-1.118,0.92l-0.491,0.404l0.158,0.616C35.934,29.015,36,29.518,36,30.002 c0,0.484-0.066,0.987-0.196,1.494l-0.158,0.616l0.491,0.404l1.118,0.92l-0.653,1.131l-1.352-0.506l-0.596-0.223l-0.455,0.446 c-0.719,0.706-1.615,1.222-2.59,1.493l-0.614,0.171l-0.105,0.628l-0.238,1.426h-1.306l-0.238-1.426l-0.105-0.628l-0.614-0.171 c-0.975-0.271-1.871-0.787-2.59-1.493l-0.455-0.446l-0.596,0.223l-1.352,0.506l-0.653-1.131l1.118-0.92l0.491-0.404l-0.158-0.616 C24.066,30.989,24,30.486,24,30.002s0.066-0.987,0.196-1.494l0.158-0.616l-0.491-0.404l-1.118-0.92l0.653-1.131l1.352,0.506 l0.596,0.223l0.455-0.446c0.719-0.705,1.615-1.222,2.59-1.493l0.614-0.171l0.105-0.628l0.238-1.426L30.653,22.002 M30,34.002 c2.206,0,4-1.794,4-4s-1.794-4-4-4s-4,1.794-4,4S27.794,34.002,30,34.002 M31.5,21.002h-3l-0.377,2.262 c-1.155,0.321-2.19,0.926-3.022,1.742l-2.145-0.804l-1.5,2.598l1.772,1.459C23.084,28.818,23,29.399,23,30.002 s0.084,1.184,0.227,1.742l-1.772,1.458l1.5,2.598l2.145-0.804c0.832,0.816,1.867,1.421,3.022,1.742L28.499,39h3l0.377-2.262 c1.155-0.321,2.19-0.926,3.022-1.742l2.145,0.804l1.5-2.598l-1.772-1.458C36.916,31.186,37,30.605,37,30.002 s-0.084-1.184-0.227-1.742l1.772-1.459l-1.5-2.598L34.9,25.007c-0.832-0.816-1.867-1.421-3.022-1.742L31.5,21.002L31.5,21.002z M30,33.002c-1.657,0-3-1.343-3-3s1.343-3,3-3c1.657,0,3,1.343,3,3C33,31.659,31.657,33.002,30,33.002L30,33.002z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#98ccfd" d="M19.999,38.458C18.291,37.715,4.636,30.984,4.501,6.367L20,1.524l15.499,4.843 C35.364,30.919,21.707,37.708,19.999,38.458z"/><path fill="#4788c7" d="M20,2.048l14.996,4.686c-0.258,23.19-12.752,30.119-15,31.177 C17.735,36.869,5.26,30.057,5.004,6.734L20,2.048 M20,1L4,6c0,27.141,16,33,16,33s16-5.932,16-33L20,1L20,1z"/><path fill="#fff" d="M17.999 20.958c.394.219 1.078.379 1.617.379.888 0 1.34-.467 1.34-1.107 0-.715-.438-1.063-1.267-1.604-1.342-.817-1.852-1.851-1.852-2.74 0-1.575 1.05-2.886 3.09-2.886.655 0 1.267.175 1.546.35l-.306 1.646c-.277-.175-.699-.334-1.24-.334-.817 0-1.21.496-1.21 1.021 0 .582.292.888 1.342 1.53 1.311.788 1.779 1.778 1.779 2.813 0 1.792-1.327 2.974-3.236 2.974-.788 0-1.546-.204-1.881-.394L17.999 20.958zM10.804 20.958c.394.219 1.078.379 1.617.379.888 0 1.34-.467 1.34-1.107 0-.715-.438-1.063-1.267-1.604-1.342-.817-1.852-1.851-1.852-2.74 0-1.575 1.05-2.886 3.09-2.886.655 0 1.267.175 1.546.35l-.306 1.646c-.277-.175-.699-.334-1.24-.334-.817 0-1.21.496-1.21 1.021 0 .582.292.888 1.342 1.53 1.311.788 1.779 1.778 1.779 2.813 0 1.792-1.327 2.974-3.236 2.974-.788 0-1.546-.204-1.881-.394L10.804 20.958zM25.697 13h1.943v8.354h2.551V23h-4.495V13H25.697z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M2 2H38V38H2z"/><path fill="#4788c7" d="M28.5 38h-7c-.275 0-.5-.225-.5-.5l0 0c0-.275.225-.5.5-.5h7c.275 0 .5.225.5.5l0 0C29 37.775 28.775 38 28.5 38zM18.5 38h-7c-.275 0-.5-.225-.5-.5l0 0c0-.275.225-.5.5-.5h7c.275 0 .5.225.5.5l0 0C19 37.775 18.775 38 18.5 38zM28.5 3h-7C21.225 3 21 2.775 21 2.5v0C21 2.225 21.225 2 21.5 2h7C28.775 2 29 2.225 29 2.5v0C29 2.775 28.775 3 28.5 3zM18.5 3h-7C11.225 3 11 2.775 11 2.5v0C11 2.225 11.225 2 11.5 2h7C18.775 2 19 2.225 19 2.5v0C19 2.775 18.775 3 18.5 3zM38 38h-6.5c-.275 0-.5-.225-.5-.5l0 0c0-.275.225-.5.5-.5H38V38z"/><path fill="#4788c7" d="M37 38v-6.5c0-.275.225-.5.5-.5l0 0c.275 0 .5.225.5.5V38H37zM38 2v6.5C38 8.775 37.775 9 37.5 9l0 0C37.225 9 37 8.775 37 8.5V2H38z"/><path fill="#4788c7" d="M38 3h-6.5C31.225 3 31 2.775 31 2.5v0C31 2.225 31.225 2 31.5 2H38V3zM2 2h6.5C8.775 2 9 2.225 9 2.5v0C9 2.775 8.775 3 8.5 3H2V2z"/><path fill="#4788c7" d="M3 2v6.5C3 8.775 2.775 9 2.5 9h0C2.225 9 2 8.775 2 8.5V2H3zM2 38v-6.5C2 31.225 2.225 31 2.5 31h0C2.775 31 3 31.225 3 31.5V38H2z"/><path fill="#4788c7" d="M2 37h6.5C8.775 37 9 37.225 9 37.5l0 0C9 37.775 8.775 38 8.5 38H2V37zM37.5 29L37.5 29c-.275 0-.5-.225-.5-.5v-7c0-.275.225-.5.5-.5l0 0c.275 0 .5.225.5.5v7C38 28.775 37.775 29 37.5 29zM37.5 19L37.5 19c-.275 0-.5-.225-.5-.5v-7c0-.275.225-.5.5-.5l0 0c.275 0 .5.225.5.5v7C38 18.775 37.775 19 37.5 19zM2.5 19L2.5 19C2.225 19 2 18.775 2 18.5v-7C2 11.225 2.225 11 2.5 11h0C2.775 11 3 11.225 3 11.5v7C3 18.775 2.775 19 2.5 19zM2.5 29L2.5 29C2.225 29 2 28.775 2 28.5v-7C2 21.225 2.225 21 2.5 21h0C2.775 21 3 21.225 3 21.5v7C3 28.775 2.775 29 2.5 29zM29.5 13h-19c-.276 0-.5-.224-.5-.5v0c0-.276.224-.5.5-.5h19c.276 0 .5.224.5.5v0C30 12.776 29.776 13 29.5 13zM23.5 17h-13c-.276 0-.5-.224-.5-.5v0c0-.276.224-.5.5-.5h13c.276 0 .5.224.5.5v0C24 16.776 23.776 17 23.5 17zM29.5 21h-19c-.276 0-.5-.224-.5-.5v0c0-.276.224-.5.5-.5h19c.276 0 .5.224.5.5v0C30 20.776 29.776 21 29.5 21zM23.5 25h-13c-.276 0-.5-.224-.5-.5v0c0-.276.224-.5.5-.5h13c.276 0 .5.224.5.5v0C24 24.776 23.776 25 23.5 25zM29.5 29h-19c-.276 0-.5-.224-.5-.5v0c0-.276.224-.5.5-.5h19c.276 0 .5.224.5.5v0C30 28.776 29.776 29 29.5 29z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M8.5 1.5H31.5V38.5H8.5z"/><path fill="#4788c7" d="M31,2v36H9V2H31 M32,1H8v38h24V1L32,1z"/><path fill="#98ccfd" d="M12.5 5.5H27.5V23.5H12.5z"/><path fill="#4788c7" d="M27,6v17H13V6H27 M28,5H12v19h16V5L28,5z"/><path fill="#4788c7" d="M19.5 3.5H20.5V19.5H19.5z" transform="rotate(90 20 11.5)"/><path fill="#4788c7" d="M19.5 9.5H20.5V25.5H19.5z" transform="rotate(90 20 17.5)"/><path fill="#fff" d="M22 14.5L22 14.5c0-.276.224-.5.5-.5h2c.276 0 .5.224.5.5v0c0 .276-.224.5-.5.5h-2C22.224 15 22 14.776 22 14.5zM22 20.5L22 20.5c0-.276.224-.5.5-.5h2c.276 0 .5.224.5.5v0c0 .276-.224.5-.5.5h-2C22.224 21 22 20.776 22 20.5zM22 8.5L22 8.5C22 8.224 22.224 8 22.5 8h2C24.776 8 25 8.224 25 8.5v0C25 8.776 24.776 9 24.5 9h-2C22.224 9 22 8.776 22 8.5z"/><g><path fill="#98ccfd" d="M20 27.5A2.5 2.5 0 1 0 20 32.5A2.5 2.5 0 1 0 20 27.5Z"/><path fill="#4788c7" d="M20,28c1.103,0,2,0.897,2,2s-0.897,2-2,2s-2-0.897-2-2S18.897,28,20,28 M20,27 c-1.657,0-3,1.343-3,3s1.343,3,3,3s3-1.343,3-3S21.657,27,20,27L20,27z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#b6dcfe" d="M21,37.5c-9.649,0-17.5-7.851-17.5-17.5S11.351,2.5,21,2.5S38.5,10.351,38.5,20 S30.649,37.5,21,37.5z M21,7.5C14.107,7.5,8.5,13.107,8.5,20S14.107,32.5,21,32.5S33.5,26.893,33.5,20S27.893,7.5,21,7.5z"/><path fill="#4788c7" d="M21,3c9.374,0,17,7.626,17,17c0,9.374-7.626,17-17,17S4,29.374,4,20C4,10.626,11.626,3,21,3 M21,33 c7.168,0,13-5.832,13-13S28.168,7,21,7S8,12.832,8,20S13.832,33,21,33 M21,2C11.059,2,3,10.059,3,20s8.059,18,18,18 s18-8.059,18-18S30.941,2,21,2L21,2z M21,32c-6.627,0-12-5.373-12-12c0-6.627,5.373-12,12-12s12,5.373,12,12 C33,26.627,27.627,32,21,32L21,32z"/><path fill="#dff0fe" d="M29 2.5A5.5 5.5 0 1 0 29 13.5A5.5 5.5 0 1 0 29 2.5Z"/><path fill="#4788c7" d="M29,3c2.757,0,5,2.243,5,5s-2.243,5-5,5s-5-2.243-5-5S26.243,3,29,3 M29,2c-3.314,0-6,2.686-6,6 s2.686,6,6,6s6-2.686,6-6S32.314,2,29,2L29,2z"/><g><path fill="#dff0fe" d="M30 26.5A5.5 5.5 0 1 0 30 37.5A5.5 5.5 0 1 0 30 26.5Z"/><path fill="#4788c7" d="M30,27c2.757,0,5,2.243,5,5s-2.243,5-5,5s-5-2.243-5-5S27.243,27,30,27 M30,26 c-3.314,0-6,2.686-6,6s2.686,6,6,6s6-2.686,6-6S33.314,26,30,26L30,26z"/></g><g><path fill="#dff0fe" d="M7 14.5A5.5 5.5 0 1 0 7 25.5A5.5 5.5 0 1 0 7 14.5Z"/><path fill="#4788c7" d="M7,15c2.757,0,5,2.243,5,5s-2.243,5-5,5s-5-2.243-5-5S4.243,15,7,15 M7,14c-3.314,0-6,2.686-6,6 s2.686,6,6,6s6-2.686,6-6S10.314,14,7,14L7,14z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M0.5,33.5v-27h2.403c0.246,0,0.453,0.176,0.493,0.418L3.66,8.5h32.68l0.264-1.582 c0.04-0.242,0.248-0.418,0.493-0.418H39.5v27H0.5z"/><path fill="#4788c7" d="M2.903,7l0.194,1.164L3.236,9h0.847h31.833h0.847l0.139-0.836L37.097,7H39v1v5.5V33H1V13.5V8V7 H2.903 M40,6h-2.903c-0.489,0-0.906,0.353-0.986,0.836L35.917,8H4.083L3.889,6.836C3.809,6.353,3.392,6,2.903,6H0v2v5.5V34h40 V13.5V8V6L40,6z"/><path fill="#b6dcfe" d="M4 12H36V30H4z"/><path fill="#98ccfd" stroke="#4788c7" stroke-linecap="round" stroke-miterlimit="10" d="M35.5 29.5L35.5 12.5M31.5 29.5L31.5 12.5M27.5 29.5L27.5 12.5M23.5 29.5L23.5 12.5M16.5 29.5L16.5 12.5M12.5 29.5L12.5 12.5M8.5 29.5L8.5 12.5M4.5 29.5L4.5 12.5"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="40px" height="40px"><path fill="#98ccfd" d="M28.045,37.5c-1.564,0-3.11-0.382-4.472-1.106l-0.153-0.082l-0.171,0.031 c-1,0.182-2.029,0.275-3.057,0.275c-9.191,0-16.67-7.372-16.67-16.432c0-1.107,0.113-2.218,0.337-3.301l0.04-0.19l-0.1-0.167 c-0.851-1.423-1.3-3.053-1.3-4.712C2.5,6.679,6.743,2.5,11.958,2.5c1.786,0,3.526,0.495,5.032,1.431l0.16,0.1l0.187-0.031 c0.945-0.16,1.906-0.241,2.855-0.241c9.193,0,16.672,7.37,16.672,16.429c0,1.195-0.131,2.381-0.389,3.526l-0.039,0.176l0.081,0.16 c0.652,1.285,0.982,2.676,0.982,4.134C37.5,33.321,33.259,37.5,28.045,37.5z"/><path fill="#4788c7" d="M11.958,3c1.693,0,3.341,0.469,4.768,1.355l0.322,0.2l0.373-0.063 c0.915-0.155,1.848-0.233,2.772-0.233c8.917,0,16.172,7.146,16.172,15.929c0,1.158-0.126,2.307-0.375,3.417l-0.079,0.351 l0.163,0.321C36.688,25.49,37,26.804,37,28.184C37,33.045,32.983,37,28.044,37c-1.483,0-2.947-0.362-4.236-1.048l-0.307-0.163 l-0.342,0.062c-0.971,0.177-1.97,0.267-2.967,0.267c-8.916,0-16.17-7.147-16.17-15.932c0-1.071,0.11-2.147,0.327-3.2l0.079-0.381 l-0.2-0.334C3.425,14.926,3,13.386,3,11.816C3,6.955,7.018,3,11.958,3 M11.958,2C6.46,2,2,6.396,2,11.816 c0,1.814,0.499,3.51,1.37,4.969c-0.227,1.101-0.348,2.238-0.348,3.402c0,9.354,7.686,16.932,17.17,16.932 c1.075,0,2.124-0.097,3.147-0.283C24.736,37.578,26.343,38,28.044,38C33.544,38,38,33.607,38,28.184 c0-1.567-0.37-3.047-1.036-4.361c0.263-1.172,0.4-2.389,0.4-3.636c0-9.348-7.688-16.929-17.172-16.929 c-1,0-1.981,0.085-2.938,0.247C15.721,2.553,13.907,2,11.958,2L11.958,2z"/><path fill="#fff" d="M27.529,26.993c-0.675,0.942-1.672,1.688-2.964,2.216C23.287,29.734,21.752,30,20.009,30 c-2.095,0-3.853-0.363-5.222-1.081c-0.981-0.522-1.79-1.23-2.401-2.102c-0.622-0.879-0.936-1.754-0.936-2.598 c0-0.526,0.205-0.984,0.608-1.358c0.401-0.37,0.913-0.556,1.523-0.556c0.501,0,0.933,0.147,1.285,0.44 c0.338,0.28,0.624,0.697,0.854,1.232c0.259,0.585,0.54,1.075,0.84,1.466c0.284,0.371,0.696,0.687,1.223,0.931 c0.529,0.248,1.241,0.372,2.119,0.372c1.206,0,2.194-0.253,2.936-0.753c0.726-0.489,1.081-1.078,1.081-1.796 c0-0.568-0.184-1.015-0.561-1.363c-0.398-0.367-0.924-0.652-1.558-0.847c-0.664-0.203-1.565-0.423-2.678-0.655 c-1.514-0.32-2.799-0.699-3.821-1.127c-1.048-0.44-1.89-1.047-2.508-1.807c-0.626-0.774-0.943-1.742-0.943-2.883 c0-1.088,0.333-2.067,0.992-2.911c0.65-0.837,1.604-1.492,2.831-1.939C16.882,10.222,18.323,10,19.951,10 c1.304,0,2.45,0.147,3.407,0.442c0.959,0.294,1.772,0.692,2.408,1.183c0.643,0.496,1.117,1.024,1.418,1.574 c0.303,0.554,0.456,1.106,0.456,1.639c0,0.514-0.2,0.982-0.598,1.389c-0.398,0.409-0.903,0.615-1.497,0.615 c-0.54,0-0.964-0.129-1.258-0.384c-0.273-0.238-0.556-0.61-0.871-1.144c-0.363-0.683-0.803-1.221-1.309-1.597 c-0.489-0.367-1.311-0.554-2.436-0.554c-1.045,0-1.895,0.206-2.526,0.615c-0.61,0.393-0.906,0.844-0.906,1.379 c0,0.327,0.096,0.601,0.291,0.837c0.21,0.248,0.501,0.468,0.871,0.65c0.384,0.189,0.778,0.341,1.174,0.449 c0.405,0.11,1.085,0.276,2.019,0.489c1.181,0.25,2.266,0.528,3.225,0.83c0.971,0.308,1.811,0.685,2.496,1.124 c0.696,0.449,1.25,1.024,1.644,1.712c0.394,0.69,0.591,1.543,0.591,2.535C28.549,24.969,28.207,26.049,27.529,26.993z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="40px" height="40px"><path fill="#dff0fe" d="M4.342,21.046c-1.208,0-2.286-0.767-2.683-1.909c-0.25-0.717-0.205-1.488,0.126-2.171 c0.33-0.683,0.907-1.196,1.624-1.446l27.305-9.496c0.303-0.105,0.616-0.159,0.934-0.159c1.207,0,2.286,0.767,2.683,1.909 c0.25,0.717,0.205,1.488-0.126,2.171c-0.33,0.683-0.907,1.196-1.624,1.446L5.275,20.888C4.973,20.993,4.659,21.046,4.342,21.046z"/><path fill="#4788c7" d="M31.647,6.366L31.647,6.366c0.995,0,1.884,0.632,2.211,1.573c0.424,1.219-0.223,2.556-1.442,2.98 L5.111,20.416c-0.25,0.087-0.508,0.131-0.769,0.131c-0.995,0-1.884-0.632-2.211-1.573c-0.424-1.219,0.223-2.556,1.442-2.98 l27.305-9.496C31.127,6.41,31.386,6.366,31.647,6.366 M31.647,5.366c-0.364,0-0.734,0.06-1.098,0.186L3.245,15.048 c-1.743,0.606-2.665,2.51-2.058,4.253c0.48,1.38,1.773,2.245,3.156,2.245c0.364,0,0.734-0.06,1.098-0.186l27.305-9.496 c1.743-0.606,2.664-2.51,2.058-4.253C34.323,6.231,33.03,5.366,31.647,5.366L31.647,5.366z"/><path fill="#b6dcfe" d="M8.353,34.134c-1.207,0-2.286-0.767-2.683-1.909c-0.25-0.717-0.205-1.488,0.126-2.171 c0.33-0.683,0.907-1.196,1.624-1.446l27.305-9.496c0.303-0.105,0.616-0.158,0.934-0.158c1.208,0,2.286,0.767,2.683,1.909 c0.25,0.717,0.205,1.488-0.126,2.171c-0.33,0.683-0.907,1.196-1.624,1.446L9.286,33.975C8.983,34.08,8.67,34.134,8.353,34.134z"/><path fill="#4788c7" d="M35.658,19.454L35.658,19.454c0.995,0,1.884,0.632,2.211,1.573c0.424,1.219-0.223,2.556-1.442,2.98 L9.122,33.503c-0.25,0.087-0.508,0.131-0.769,0.131c-0.995,0-1.884-0.632-2.211-1.573c-0.424-1.219,0.223-2.556,1.442-2.98 l27.305-9.496C35.138,19.498,35.397,19.454,35.658,19.454 M35.658,18.454c-0.364,0-0.734,0.06-1.098,0.186L7.256,28.136 c-1.743,0.606-2.664,2.51-2.058,4.253v0c0.48,1.38,1.773,2.245,3.156,2.245c0.364,0,0.734-0.06,1.098-0.186l27.305-9.496 c1.743-0.606,2.665-2.51,2.058-4.253C38.334,19.318,37.041,18.453,35.658,18.454L35.658,18.454z"/><path fill="#98ccfd" d="M31.291,34.489c-1.208,0-2.286-0.767-2.683-1.909L19.112,5.276c-0.515-1.48,0.271-3.103,1.75-3.617 C21.165,1.554,21.479,1.5,21.796,1.5c1.208,0,2.287,0.767,2.684,1.909l9.495,27.304c0.25,0.717,0.205,1.488-0.126,2.171 c-0.33,0.683-0.907,1.196-1.624,1.446C31.922,34.436,31.608,34.489,31.291,34.489z"/><path fill="#4788c7" d="M21.796,2L21.796,2c0.995,0,1.884,0.632,2.211,1.573l9.496,27.305 c0.424,1.219-0.223,2.556-1.442,2.98c-0.25,0.087-0.508,0.131-0.769,0.131c-0.995,0-1.884-0.632-2.211-1.573L19.584,5.111 c-0.205-0.591-0.169-1.226,0.104-1.789c0.272-0.563,0.748-0.986,1.339-1.192C21.276,2.044,21.535,2,21.796,2 M21.796,1 c-0.364,0-0.734,0.06-1.098,0.186c-1.743,0.606-2.665,2.51-2.058,4.253l9.496,27.305c0.48,1.38,1.773,2.245,3.156,2.245 c0.364,0,0.734-0.06,1.098-0.186c1.743-0.606,2.665-2.51,2.058-4.253L24.952,3.245C24.472,1.865,23.179,1,21.796,1L21.796,1z"/><path fill="#98ccfd" d="M25.865 21.365H31.548V27.046999999999997H25.865z" transform="rotate(-19.178 28.706 24.206)"/><path fill="#4788c7" d="M30.149,21.226l1.538,4.423l-4.423,1.538l-1.538-4.423L30.149,21.226 M30.765,19.953l-6.312,2.195 l2.195,6.312l6.312-2.195L30.765,19.953L30.765,19.953z"/><g><path fill="#98ccfd" d="M21.372 8.446H27.054000000000002V14.128H21.372z" transform="rotate(-19.178 24.213 11.287)"/><path fill="#4788c7" d="M25.656,8.306l1.538,4.423l-4.423,1.538l-1.538-4.423L25.656,8.306 M26.272,7.033L19.96,9.228 l2.195,6.312l6.312-2.195L26.272,7.033L26.272,7.033z"/></g><g><path fill="#b6dcfe" d="M18.204,38.5c-1.208,0-2.287-0.767-2.684-1.909L6.025,9.287C5.775,8.569,5.82,7.798,6.151,7.115 c0.33-0.683,0.907-1.196,1.624-1.446c0.303-0.105,0.616-0.159,0.934-0.159c1.208,0,2.286,0.767,2.683,1.909l9.496,27.305 c0.515,1.48-0.271,3.103-1.75,3.617C18.835,38.446,18.521,38.5,18.204,38.5z"/><path fill="#4788c7" d="M8.709,6.011L8.709,6.011c0.995,0,1.884,0.632,2.211,1.573l9.496,27.305 c0.424,1.219-0.223,2.556-1.442,2.98C18.724,37.956,18.465,38,18.204,38c-0.995,0-1.884-0.632-2.211-1.573L6.497,9.122 C6.292,8.531,6.329,7.896,6.601,7.333C6.873,6.77,7.349,6.347,7.94,6.142C8.189,6.055,8.448,6.011,8.709,6.011 M8.709,5.011 c-0.364,0-0.734,0.06-1.098,0.186c-1.743,0.606-2.665,2.51-2.058,4.253l9.496,27.305c0.48,1.38,1.773,2.245,3.156,2.245 c0.364,0,0.734-0.06,1.098-0.186c1.743-0.606,2.665-2.51,2.058-4.253L11.864,7.256C11.385,5.876,10.092,5.011,8.709,5.011 L8.709,5.011z"/></g><g><path fill="#b6dcfe" d="M12.945 25.865H18.627000000000002V31.546999999999997H12.945z" transform="rotate(-19.178 15.786 28.706)"/><path fill="#4788c7" d="M17.229,25.726l1.538,4.423l-4.423,1.538l-1.538-4.423L17.229,25.726 M17.845,24.453l-6.312,2.195 l2.195,6.312l6.312-2.195L17.845,24.453L17.845,24.453z"/></g><g><path fill="#b6dcfe" d="M8.452 12.946H14.135V18.628H8.452z" transform="rotate(-19.172 11.295 15.789)"/><path fill="#4788c7" d="M12.736,12.806l1.538,4.423l-4.423,1.538l-1.538-4.423L12.736,12.806 M13.352,11.533L7.04,13.728 l2.195,6.312l6.312-2.195L13.352,11.533L13.352,11.533z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#98ccfd" d="M4,38.5c-1.378,0-2.5-1.122-2.5-2.5v-8L5.494,3.411C5.65,2.317,6.592,1.5,7.687,1.5h24.626 c1.095,0,2.037,0.817,2.192,1.901l4.001,24.679L38.5,36c0,1.378-1.122,2.5-2.5,2.5H4z"/><path fill="#4788c7" d="M32.313,2c0.848,0,1.577,0.633,1.7,1.49L38,28.081V36c0,1.103-0.897,2-2,2H4c-1.103,0-2-0.897-2-2 v-7.919L5.99,3.472C6.11,2.633,6.839,2,7.687,2H32.313 M32.313,1H7.687C6.336,1,5.191,1.993,5,3.33L1,28v8c0,1.657,1.343,3,3,3h32 c1.657,0,3-1.343,3-3v-8L35,3.33C34.809,1.993,33.664,1,32.313,1L32.313,1z"/><path fill="#dff0fe" d="M7.687,2C6.839,2,6.11,2.633,5.99,3.472L2.013,28h35.974L34.013,3.49C33.89,2.633,33.161,2,32.313,2 H7.687z"/><path fill="#fff" d="M33,31c-1.105,0-2,0.895-2,2s0.895,2,2,2s2-0.895,2-2S34.105,31,33,31L33,31z"/><path fill="#4788c7" d="M5 33H27V35H5z"/><path fill="#4788c7" d="M5 31H7V35H5zM25 31H27V35H25zM9 31H11V35H9zM13 31H15V35H13zM17 31H19V35H17zM21 31H23V35H21z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#b6dcfe" d="M20 32.004L8.299 38.112 10.493 25.097 1.068 15.856 14.124 13.921 20 2.102 25.876 13.921 38.932 15.856 29.508 25.098 31.701 38.112z"/><path fill="#4788c7" d="M20,3.225l5.311,10.685l0.232,0.468l0.516,0.077l11.804,1.749l-8.52,8.354l-0.373,0.365l0.087,0.515 l1.983,11.766l-10.578-5.522L20,31.44l-0.463,0.242L8.959,37.204l1.984-11.767l0.087-0.515l-0.373-0.366l-8.521-8.353l11.803-1.749 l0.516-0.077l0.232-0.468L20,3.225 M20,0.979l-6.207,12.487L0,15.509l9.957,9.761L7.639,39.021L20,32.568l12.361,6.453 l-2.317-13.749L40,15.509l-13.793-2.044L20,0.979L20,0.979z"/><path fill="#fff" d="M28.971 24.923L29.344 24.558 37.864 16.204 26.06 14.455 25.544 14.378 25.311 13.91 20 3.225 20 31.44 20.463 31.681 31.041 37.204 29.058 25.438z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M7.783,37.517c-0.299,0-0.541-0.069-0.739-0.213c-1.167-0.847,0.25-3.821,1.501-6.445 c1.312-2.753,2.551-5.354,1.923-7.033c-0.251-0.672-1.258-1.234-3.167-2.251C4.853,20.27,1.5,18.482,1.5,16.5 c0-0.481,1.095-1,3.5-1c8.207,0,9.04-0.833,9.354-1.146c1.098-1.098,1.475-3.39,1.874-5.816C16.715,5.569,17.22,2.5,19,2.5 c2.207,0,2.847,3.175,3.467,6.245c0.491,2.436,0.955,4.736,2.241,5.661c1.359,0.977,4.311,1.111,7.298,1.111 c0.545,0,1.086-0.005,1.607-0.01C34.096,15.504,34.562,15.5,35,15.5c2.224,0,3.5,0.364,3.5,1c0,1.367-3.112,3.221-5.384,4.575 c-2.133,1.271-3.352,2.026-3.592,2.771c-0.54,1.678,0.687,4.225,1.986,6.921c1.27,2.635,2.708,5.621,1.529,6.478 c-0.199,0.145-0.438,0.215-0.729,0.215c-1.497,0-3.84-1.775-6.105-3.492C23.852,32.185,21.628,30.5,20,30.5 c-1.256,0-3.2,1.465-5.452,3.162C12.15,35.469,9.433,37.517,7.783,37.517z"/><path fill="#4788c7" d="M19,3c1.669,0,2.286,2.422,2.976,5.844c0.511,2.535,0.994,4.928,2.44,5.968 c1.391,1,4.04,1.205,7.589,1.205c0.547,0,1.089-0.005,1.612-0.009C34.098,16.004,34.563,16,35,16c2.635,0,3.001,0.5,3,0.5h0 c0,1.083-3.343,3.075-5.14,4.145c-2.302,1.371-3.516,2.13-3.812,3.048c-0.601,1.868,0.668,4.502,2.012,7.291 c1.006,2.089,2.527,5.245,1.686,5.856c-0.071,0.051-0.193,0.12-0.435,0.12c-1.328,0-3.706-1.801-5.803-3.391 C23.98,31.654,21.797,30,20,30c-1.355,0-3.069,1.24-5.753,3.263c-2.219,1.673-4.982,3.754-6.464,3.754 c-0.253,0-0.375-0.067-0.445-0.118c-0.83-0.602,0.668-3.746,1.659-5.826c1.359-2.852,2.642-5.545,1.94-7.423 c-0.315-0.843-1.326-1.412-3.4-2.517c-2.187-1.165-5.484-2.922-5.536-4.593C2.16,16.378,2.959,16,5,16 c8.414,0,9.287-0.873,9.707-1.293c1.211-1.211,1.601-3.581,2.013-6.089C17.153,5.985,17.644,3,19,3 M19,2 c-3.792,0-2.649,9.649-5,12c-0.854,0.854-5.648,1-9,1c-2.167,0-4,0.417-4,1.5c0,3.583,8.458,6.05,9,7.5 c1.201,3.215-6.036,11.686-3.25,13.708c0.294,0.213,0.642,0.309,1.033,0.309C11.132,38.017,17.62,31,20,31 c2.986,0,9.053,6.96,12.311,6.96c0.383,0,0.727-0.096,1.022-0.311C36.119,35.627,28.948,27.267,30,24c0.485-1.507,9-4.75,9-7.5 c0-1.208-1.907-1.5-4-1.5c-0.912,0-1.943,0.017-2.995,0.017c-2.806,0-5.76-0.122-7.005-1.017C22.301,12.059,23.492,2,19,2L19,2z"/><path fill="#98ccfd" d="M16.5 18A1.5 1.5 0 1 0 16.5 21 1.5 1.5 0 1 0 16.5 18zM14.5 27A1.5 1.5 0 1 0 14.5 30 1.5 1.5 0 1 0 14.5 27zM24.5 17A1.5 1.5 0 1 0 24.5 20 1.5 1.5 0 1 0 24.5 17zM25.5 25A1.5 1.5 0 1 0 25.5 28 1.5 1.5 0 1 0 25.5 25zM20 23A2 2 0 1 0 20 27 2 2 0 1 0 20 23z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#fff" d="M2.5,2.5h35v35h-35V2.5z"/><path fill="#b6dcfe" d="M2.5,34h35v3.5h-35V34z"/><path fill="#4788c7" d="M38,38H2V2h36V38z M3,37h34V3H3V37z"/><rect width="35" height="5" x="2.5" y="2.5" fill="#b6dcfe"/><path fill="#4788c7" d="M38,8H2V2h36V8z M3,7h34V3H3V7z"/><path fill="#98ccfd" d="M20.393,12.564l1.487,2.395c0.259,0.418,0.77,0.604,1.237,0.45l2.678-0.879l-0.401,2.79 c-0.07,0.487,0.202,0.958,0.658,1.14l2.617,1.048l-2.1,1.88c-0.366,0.328-0.461,0.864-0.229,1.297l1.331,2.485l-2.817,0.09 c-0.491,0.016-0.908,0.365-1.009,0.846l-0.578,2.759l-2.216-1.742c-0.386-0.304-0.93-0.304-1.317,0l-2.216,1.742l-0.578-2.759 c-0.101-0.481-0.518-0.831-1.009-0.846l-2.817-0.09l1.331-2.485c0.232-0.433,0.138-0.969-0.229-1.297l-2.1-1.88l2.617-1.048 c0.456-0.183,0.728-0.654,0.658-1.14l-0.401-2.79l2.678,0.879c0.467,0.153,0.978-0.033,1.237-0.45L20.393,12.564z"/><path fill="#4788c7" d="M17.519,29.365c-0.058,0-0.115-0.01-0.171-0.03c-0.163-0.059-0.283-0.198-0.318-0.367l-0.577-2.759 c-0.054-0.256-0.273-0.44-0.535-0.449L13.1,25.67c-0.173-0.005-0.331-0.1-0.417-0.25c-0.087-0.15-0.09-0.333-0.008-0.486 l1.331-2.485c0.123-0.23,0.073-0.514-0.121-0.688l-2.101-1.88c-0.129-0.115-0.189-0.289-0.159-0.459s0.146-0.313,0.307-0.377 l2.616-1.048c0.242-0.097,0.387-0.346,0.349-0.604l-0.4-2.791c-0.024-0.171,0.041-0.343,0.174-0.454 c0.132-0.112,0.312-0.146,0.478-0.092l2.679,0.879c0.247,0.081,0.519-0.017,0.656-0.239l1.486-2.395c0.182-0.294,0.668-0.294,0.85,0 l1.486,2.395c0.138,0.222,0.405,0.321,0.656,0.239l2.679-0.879c0.165-0.054,0.346-0.02,0.478,0.092 c0.133,0.111,0.198,0.283,0.174,0.454l-0.401,2.79c-0.037,0.259,0.106,0.507,0.35,0.604l2.616,1.048 c0.161,0.064,0.276,0.207,0.307,0.377s-0.03,0.344-0.159,0.459l-2.101,1.88c-0.194,0.174-0.244,0.458-0.121,0.688l1.331,2.485 c0.082,0.153,0.079,0.336-0.008,0.486c-0.086,0.15-0.244,0.244-0.417,0.25l-2.817,0.09c-0.262,0.009-0.481,0.193-0.535,0.449 l-0.578,2.759c-0.035,0.169-0.155,0.308-0.318,0.367c-0.163,0.059-0.345,0.03-0.479-0.077l-2.216-1.742 c-0.207-0.162-0.493-0.162-0.698,0l-2.218,1.742C17.738,29.329,17.629,29.365,17.519,29.365z M13.937,24.696l2.012,0.064 c0.725,0.023,1.334,0.534,1.482,1.243l0.412,1.971l1.584-1.244c0.569-0.449,1.364-0.448,1.934,0l1.583,1.244l0.413-1.971 c0.148-0.709,0.758-1.22,1.482-1.243l2.012-0.064l-0.95-1.774c-0.343-0.639-0.204-1.422,0.336-1.906l1.5-1.343l-1.868-0.749 c-0.673-0.269-1.071-0.958-0.969-1.675l0.287-1.993l-1.913,0.628c-0.688,0.226-1.437-0.046-1.818-0.662l-1.062-1.71l-1.062,1.71 c-0.384,0.616-1.13,0.887-1.818,0.662l-1.913-0.628l0.286,1.993c0.104,0.716-0.294,1.406-0.968,1.675l-1.868,0.749l1.5,1.343 c0.54,0.482,0.678,1.266,0.337,1.905L13.937,24.696z"/><circle cx="20.393" cy="20.857" r="3.769" fill="#dff0fe"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#4788c7" d="M37 20L30 13 30 18 16 18 16 22 30 22 30 27z"/><path fill="#98ccfd" d="M12 11.5A8.5 8.5 0 1 0 12 28.5A8.5 8.5 0 1 0 12 11.5Z"/><path fill="#4788c7" d="M12,12c4.411,0,8,3.589,8,8s-3.589,8-8,8s-8-3.589-8-8S7.589,12,12,12 M12,11c-4.971,0-9,4.029-9,9 s4.029,9,9,9s9-4.029,9-9S16.971,11,12,11L12,11z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#b6dcfe" d="M1.5 35.5L1.5 4.5 11.793 4.5 14.793 7.5 38.5 7.5 38.5 35.5z"/><path fill="#4788c7" d="M11.586,5l2.707,2.707L14.586,8H15h23v27H2V5H11.586 M12,4H1v32h38V7H15L12,4L12,4z"/><path fill="#dff0fe" d="M1.5 35.5L1.5 9.5 12.151 9.5 15.151 7.5 38.5 7.5 38.5 35.5z"/><path fill="#4788c7" d="M38,8v27H2V10h10h0.303l0.252-0.168L15.303,8H38 M39,7H15l-3,2H1v27h38V7L39,7z"/><g><path fill="#98ccfd" d="M21.321,31.5c-3.889,0-6.821-2.794-6.821-6.5c0-3.022,1.563-4.874,5.066-7.88l0.41-0.352 l-2.27-2.269H25.5v7.793l-2.579-2.58l-0.625,0.544C20.048,22.21,17.5,24.423,17.5,27c0,2.293,1.172,3.395,2.155,3.915 c0.69,0.365,1.388,0.503,1.845,0.555v0.03H21.321z"/><path fill="#4788c7" d="M25,15v6.086l-1.396-1.396l-0.66-0.66l-0.704,0.613l-0.274,0.238C19.638,21.903,17,24.195,17,27 c0,1.377,0.395,2.401,0.984,3.151C16.166,29.121,15,27.241,15,25c0-2.843,1.442-4.54,4.892-7.5l0.819-0.703l-0.763-0.763L18.914,15 H25 M26,14h-9.5l2.741,2.741C15.674,19.802,14,21.746,14,25c0,3.897,3.124,7,7.321,7H22v-1c0,0-0.005,0-0.016,0 C21.711,31,18,30.928,18,27c0-2.448,2.646-4.644,4.897-6.603L26,23.5V14L26,14z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#98ccfd" d="M20,38.5C9.799,38.5,1.5,30.201,1.5,20S9.799,1.5,20,1.5S38.5,9.799,38.5,20S30.201,38.5,20,38.5z"/><path fill="#4788c7" d="M20,2c9.925,0,18,8.075,18,18s-8.075,18-18,18S2,29.925,2,20S10.075,2,20,2 M20,1 C9.507,1,1,9.507,1,20s8.507,19,19,19s19-8.507,19-19S30.493,1,20,1L20,1z"/><path fill="#fff" d="M20,30.5c-2.64,0-5.129-0.965-7.064-2.729l2.126-2.126C16.43,26.845,18.165,27.5,20,27.5 c4.136,0,7.5-3.369,7.5-7.51v-0.5h-3.29L29,14.707l4.793,4.793H30.5V20C30.5,25.79,25.79,30.5,20,30.5z"/><path fill="#fff" d="M29,15.414L32.586,19H31h-1v1c0,5.514-4.486,10-10,10c-2.337,0-4.55-0.794-6.331-2.255l1.425-1.424 C16.491,27.41,18.2,28,20,28c4.411,0,8-3.593,8-8.01v-1h-1h-1.58l1.498-1.493L29,15.414 M29,14l-2.79,2.79L23,19.99h4 c0,3.86-3.14,7.01-7,7.01c-1.93,0-3.68-0.78-4.95-2.05l-2.83,2.83C14.21,29.77,16.96,31,20,31c6.08,0,11-4.92,11-11h4l-5.43-5.43 L29,14L29,14z"/><g><path fill="#fff" d="M6.207,20.5H9.5V20c0-5.79,4.71-10.5,10.5-10.5c2.64,0,5.129,0.965,7.064,2.728l-2.126,2.126 C23.571,13.155,21.836,12.5,20,12.5c-4.136,0-7.5,3.364-7.5,7.5v0.5h3.293L11,25.293L6.207,20.5z"/><path fill="#fff" d="M20,10c2.337,0,4.55,0.794,6.331,2.255l-1.425,1.425C23.509,12.59,21.8,12,20,12 c-4.411,0-8,3.589-8,8v1h1h1.586L11,24.586L7.414,21H9h1v-1C10,14.486,14.486,10,20,10 M20,9C13.92,9,9,13.92,9,20H5l5.43,5.43 L11,26l6-6h-4c0-3.86,3.14-7,7-7c1.93,0,3.68,0.78,4.95,2.05l2.83-2.83C25.79,10.23,23.04,9,20,9L20,9z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#98ccfd" d="M1.516,29.5c0.283-4.455,4.316-8,9.234-8h6.5c4.918,0,8.952,3.545,9.234,8H1.516z"/><path fill="#4788c7" d="M17.25,22c4.454,0,8.142,3.059,8.682,7H2.068c0.54-3.941,4.228-7,8.682-7H17.25 M17.25,21h-6.5 C5.365,21,1,25.029,1,30h26C27,25.029,22.635,21,17.25,21L17.25,21z"/><path fill="#dff0fe" d="M14,23.5c-2.362,0-3.322-1.994-3.5-2.418v-4.255h7v4.255C17.322,21.506,16.362,23.5,14,23.5z"/><path fill="#4788c7" d="M17,17.328v3.649C16.775,21.463,15.913,23,14,23c-1.917,0-2.779-1.543-3-2.023v-3.649H17 M18,16.328h-8v4.849c0,0,1.014,2.823,4,2.823s4-2.823,4-2.823V16.328L18,16.328z"/><path fill="#98ccfd" d="M19.357,14.786c-0.906,0-1.643-0.737-1.643-1.644c0-0.905,0.737-1.643,1.643-1.643 c1.518,0,1.643,0.439,1.643,0.929C21,13.415,20.172,14.786,19.357,14.786z M8.643,14.786C7.828,14.786,7,13.415,7,12.429 C7,11.939,7.125,11.5,8.643,11.5c0.906,0,1.643,0.737,1.643,1.643C10.286,14.049,9.549,14.786,8.643,14.786z"/><path fill="#4788c7" d="M19.357,12c1.143,0,1.143,0.218,1.143,0.429c0,0.82-0.709,1.857-1.143,1.857 c-0.63,0-1.143-0.513-1.143-1.143C18.214,12.513,18.727,12,19.357,12 M8.643,12c0.63,0,1.143,0.513,1.143,1.143 c0,0.63-0.513,1.143-1.143,1.143c-0.434,0-1.143-1.038-1.143-1.857C7.5,12.218,7.5,12,8.643,12 M19.357,11 c-1.183,0-2.143,0.959-2.143,2.143s0.959,2.143,2.143,2.143s2.143-1.674,2.143-2.857C21.5,11.245,20.541,11,19.357,11L19.357,11z M8.643,11C7.459,11,6.5,11.245,6.5,12.429c0,1.183,0.959,2.857,2.143,2.857s2.143-0.959,2.143-2.143S9.826,11,8.643,11L8.643,11z"/><path fill="#dff0fe" d="M14,20.5c-0.517,0-1-0.212-1.36-0.597l-0.092-0.099l-0.129-0.038 C10.111,19.074,8.5,16.909,8.5,14.5V7.526c0-1.301,1.059-2.359,2.359-2.359h6.281c1.301,0,2.359,1.059,2.359,2.359V14.5 c0,2.409-1.611,4.574-3.918,5.267l-0.129,0.038l-0.092,0.099C15,20.288,14.517,20.5,14,20.5z"/><path fill="#4788c7" d="M17.141,5.667c1.025,0,1.859,0.834,1.859,1.86V14.5c0,2.19-1.465,4.159-3.562,4.788l-0.258,0.078 l-0.184,0.197C14.731,19.845,14.377,20,14,20s-0.731-0.155-0.995-0.438l-0.184-0.197l-0.258-0.078C10.465,18.659,9,16.69,9,14.5 V7.526c0-1.025,0.834-1.86,1.859-1.86H17.141 M17.141,4.667h-6.281C9.28,4.667,8,5.947,8,7.526V14.5 c0,2.714,1.803,5.004,4.275,5.745C12.707,20.707,13.318,21,14,21s1.293-0.293,1.725-0.755C18.197,19.504,20,17.214,20,14.5V7.526 C20,5.947,18.72,4.667,17.141,4.667L17.141,4.667z"/><path fill="#98ccfd" d="M20,20.5c-1.337,0-2.588-0.888-3.216-1.419c0.921-0.766,2.716-2.704,2.716-6.171v-2.397 c0-2.742-2.294-4.104-2.392-4.16l-0.477-0.276l-0.23,0.503c-0.049,0.107-1.245,2.645-4.613,3.11C10.377,9.885,8.5,10.431,8.5,12.91 c0,3.662,1.774,5.496,2.713,6.209c-0.587,0.526-1.765,1.381-3.22,1.381c-1.743,0-2.767-0.368-3.267-0.625 c0.632-0.865,1.917-2.839,1.917-4.59c0-0.732-0.162-1.483-0.333-2.277c-0.188-0.867-0.381-1.765-0.381-2.716 c0-5.503,3.741-8.792,7.357-8.792c2.68,0,3.846,1.882,3.857,1.9l0.146,0.242h0.282c2.167,0,4.5,1.634,4.5,5.221 c0,1.155-0.197,2.384-0.389,3.572c-0.167,1.042-0.326,2.026-0.326,2.85c0,1.587,1.266,3.065,1.929,3.729 C22.721,19.542,21.489,20.5,20,20.5z"/><path fill="#4788c7" d="M13.286,2c2.357,0,3.391,1.599,3.429,1.659l0.292,0.484h0.565c1.927,0,4,1.477,4,4.721 c0,1.115-0.194,2.324-0.382,3.492c-0.171,1.063-0.332,2.067-0.332,2.93c0,1.507,0.968,2.873,1.704,3.695 C21.973,19.446,21.052,20,20,20c-0.923,0-1.822-0.5-2.444-0.949C18.584,18.034,20,16.062,20,12.91v-2.397 c0-3.027-2.533-4.531-2.641-4.593l-0.96-0.557l-0.454,1.012c-0.011,0.024-1.105,2.387-4.225,2.818C10.8,9.321,8,9.707,8,12.91 c0,3.309,1.391,5.227,2.433,6.2C9.85,19.538,8.99,20,7.993,20c-1.161,0-1.972-0.17-2.5-0.345c0.703-1.05,1.649-2.762,1.649-4.37 c0-0.786-0.167-1.562-0.345-2.383c-0.182-0.842-0.37-1.712-0.37-2.61C6.429,5.102,9.915,2,13.286,2 M13.286,1 c-4.068,0-7.857,3.671-7.857,9.292c0,1.887,0.714,3.54,0.714,4.994C6.143,17.405,4,20,4,20s1.046,1,3.993,1 C10.355,21,12,19.039,12,19.039s-3-1.508-3-6.129c0-1.936,1.274-2.508,2.857-2.726c3.704-0.512,5-3.399,5-3.399 S19,8.028,19,10.513c0,0.803,0,1.078,0,2.397c0,4.333-3,6.129-3,6.129S17.866,21,20,21c2.312,0,4-2,4-2s-2.143-1.819-2.143-3.715 c0-1.685,0.714-4.189,0.714-6.422c0-3.787-2.513-5.721-5-5.721C17.571,3.143,16.279,1,13.286,1L13.286,1z"/><g><path fill="#b6dcfe" d="M9.512,38.5c0.268-5.559,4.982-10,10.738-10h7.5c5.756,0,10.47,4.441,10.738,10H9.512z"/><path fill="#4788c7" d="M27.75,29c5.306,0,9.683,3.954,10.199,9H10.051c0.516-5.046,4.893-9,10.199-9H27.75 M27.75,28h-7.5 C14.037,28,9,32.925,9,39h30C39,32.925,33.963,28,27.75,28L27.75,28z"/></g><g><path fill="#fff" d="M24,31.5c-3.076,0-4.296-2.625-4.5-3.122v-5.469h9v5.469C28.296,28.875,27.076,31.5,24,31.5z"/><path fill="#4788c7" d="M28,23.41v4.865C27.737,28.865,26.607,31,24,31c-2.611,0-3.741-2.141-4-2.725V23.41H28 M29,22.41 H19v6.062c0,0,1.267,3.529,5,3.529s5-3.529,5-3.529V22.41L29,22.41z"/></g><g><path fill="#b6dcfe" d="M30.429,20.643c-1.143,0-2.072-0.929-2.072-2.071s0.929-2.071,2.072-2.071 c1.725,0,2.071,0.465,2.071,1.214C32.5,18.966,31.476,20.643,30.429,20.643z M17.571,20.643c-1.047,0-2.071-1.677-2.071-2.929 c0-0.749,0.347-1.214,2.071-1.214c1.143,0,2.072,0.929,2.072,2.071S18.714,20.643,17.571,20.643z"/><path fill="#4788c7" d="M30.429,17C32,17,32,17.363,32,17.714c0,1.044-0.896,2.429-1.571,2.429 c-0.867,0-1.571-0.705-1.571-1.571S29.562,17,30.429,17 M17.571,17c0.867,0,1.571,0.705,1.571,1.571s-0.705,1.571-1.571,1.571 c-0.676,0-1.571-1.385-1.571-2.429C16,17.363,16,17,17.571,17 M30.429,16c-1.42,0-2.571,1.151-2.571,2.571 s1.151,2.571,2.571,2.571S33,19.134,33,17.714S31.849,16,30.429,16L30.429,16z M17.571,16C16.151,16,15,16.294,15,17.714 s1.151,3.429,2.571,3.429s2.571-1.151,2.571-2.571S18.992,16,17.571,16L17.571,16z"/></g><g><path fill="#fff" d="M24,27.5c-0.581,0-1.134-0.224-1.56-0.631l-0.09-0.086l-0.12-0.034 c-2.785-0.786-4.73-3.356-4.73-6.249v-8.136c0-1.564,1.272-2.837,2.836-2.837h7.328c1.564,0,2.836,1.272,2.836,2.837V20.5 c0,2.893-1.945,5.463-4.73,6.249l-0.12,0.034l-0.09,0.086C25.134,27.276,24.581,27.5,24,27.5z"/><path fill="#4788c7" d="M27.664,10.028c1.288,0,2.336,1.048,2.336,2.336V20.5c0,2.67-1.796,5.042-4.367,5.768l-0.239,0.068 l-0.18,0.172C24.882,26.825,24.451,27,24,27s-0.882-0.175-1.214-0.492l-0.18-0.172l-0.239-0.068C19.796,25.542,18,23.17,18,20.5 v-8.136c0-1.288,1.048-2.336,2.336-2.336H27.664 M27.664,9.028h-7.328c-1.842,0-3.336,1.494-3.336,3.336V20.5 c0,3.205,2.156,5.9,5.095,6.731C22.591,27.705,23.26,28,24,28s1.409-0.295,1.905-0.769C28.844,26.4,31,23.705,31,20.5v-8.136 C31,10.521,29.506,9.028,27.664,9.028L27.664,9.028z"/></g><g><path fill="#b6dcfe" d="M30.5,18.5V15c0-3.484-2.217-4.425-2.312-4.463l-0.342-0.14l-0.234,0.287 C27.589,10.713,25.283,13.5,22,13.5c-0.264,0-0.53-0.009-0.791-0.017c-0.265-0.009-0.526-0.017-0.778-0.017 c-0.877,0-2.931,0-2.931,2.533v2.5h-0.214c-0.44-0.773-1.786-3.349-1.786-5.924C15.5,7.821,18.995,4.5,24,4.5 c3.078,0,4.499,2.621,4.557,2.732l0.119,0.226l0.253,0.037C30.462,7.715,32.5,8.524,32.5,13c0,2.334-1.337,4.763-1.778,5.5H30.5z"/><path fill="#4788c7" d="M24,5c2.762,0,4.062,2.367,4.114,2.463l0.237,0.454l0.507,0.073C30.321,8.199,32,8.958,32,13 c0,1.395-0.515,2.842-1,3.894V15c0-3.816-2.516-4.883-2.623-4.926l-0.687-0.279l-0.467,0.577C27.201,10.397,25.06,13,22,13 c-0.259,0-0.519-0.008-0.775-0.017c-0.27-0.009-0.536-0.017-0.794-0.017c-0.849,0-3.431,0-3.431,3.034v0.807 c-0.486-1.122-1-2.677-1-4.23C16,8.115,19.29,5,24,5 M24,4c-5.36,0-9,3.667-9,8.576C15,15.828,17,19,17,19h1c0,0,0-2.105,0-3 c0-1.791,1.085-2.034,2.431-2.034C20.932,13.966,21.469,14,22,14c3.573,0,6-3,6-3s2,0.813,2,4c0,0.984,0,4,0,4h1c0,0,2-3.037,2-6 c0-4.161-1.703-5.671-4-6C29,7,27.434,4,24,4L24,4z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M20,38.5C9.799,38.5,1.5,30.201,1.5,20S9.799,1.5,20,1.5S38.5,9.799,38.5,20S30.201,38.5,20,38.5z"/><path fill="#4788c7" d="M20,2c9.925,0,18,8.075,18,18s-8.075,18-18,18S2,29.925,2,20S10.075,2,20,2 M20,1 C9.507,1,1,9.507,1,20s8.507,19,19,19s19-8.507,19-19S30.493,1,20,1L20,1z"/><path fill="#98ccfd" d="M23.853,24.5h-7.706C15.698,24.607,7.5,26.649,7.5,32.212v1.398c3.294,3.027,7.674,4.89,12.5,4.89 s9.206-1.863,12.5-4.89v-1.398C32.5,26.652,24.302,24.607,23.853,24.5z"/><path fill="#4788c7" d="M20,39c-4.754,0-9.314-1.783-12.838-5.021L7,33.83v-1.618c0-5.97,8.662-8.11,9.031-8.198 L16.147,24l7.822,0.014C24.338,24.102,33,26.242,33,32.212v1.618l-0.162,0.148C29.314,37.217,24.754,39,20,39z M8,33.389 C11.316,36.364,15.569,38,20,38s8.684-1.636,12-4.611v-1.177c0-5.022-7.422-7.016-8.208-7.212h-7.585 C15.422,25.196,8,27.189,8,32.212V33.389z"/><g><path fill="#fff" d="M20,20.5c-3.584,0-6.5-2.916-6.5-6.5s2.916-6.5,6.5-6.5s6.5,2.916,6.5,6.5S23.584,20.5,20,20.5z"/><path fill="#4788c7" d="M20,21c-3.86,0-7-3.141-7-7s3.14-7,7-7s7,3.141,7,7S23.86,21,20,21z M20,8c-3.309,0-6,2.691-6,6 s2.691,6,6,6s6-2.691,6-6S23.309,8,20,8z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#b6dcfe" d="M6.363,37.5c-0.476,0-0.863-0.396-0.863-0.885V3.385C5.5,2.896,5.888,2.5,6.363,2.5H16.54 C16.513,2.668,16.5,2.834,16.5,3c0,1.93,1.57,3.5,3.5,3.5s3.5-1.57,3.5-3.5c0-0.166-0.013-0.332-0.04-0.5h10.177 c0.476,0,0.863,0.396,0.863,0.885v33.23c0,0.488-0.388,0.885-0.863,0.885H6.363z"/><path fill="#4788c7" d="M33.636,3C33.837,3,34,3.173,34,3.385v33.231C34,36.827,33.837,37,33.636,37H6.364 C6.163,37,6,36.827,6,36.615V3.385C6,3.173,6.163,3,6.364,3H16c0,2.206,1.794,4,4,4s4-1.794,4-4H33.636 M33.636,2h-10.82 C22.928,2.314,23,2.647,23,3c0,1.657-1.343,3-3,3s-3-1.343-3-3c0-0.353,0.072-0.686,0.184-1H6.364C5.611,2,5,2.62,5,3.385v33.231 C5,37.38,5.611,38,6.364,38h27.273C34.389,38,35,37.38,35,36.615V3.385C35,2.62,34.389,2,33.636,2L33.636,2z"/><path fill="#fff" d="M8 5H32V35H8z"/><path fill="#4788c7" d="M20,1c1.103,0,2,0.897,2,2s-0.897,2-2,2s-2-0.897-2-2S18.897,1,20,1 M20,0c-1.657,0-3,1.343-3,3 s1.343,3,3,3s3-1.343,3-3S21.657,0,20,0L20,0z"/><path fill="#98ccfd" d="M15,7.5c-0.827,0-1.5-0.673-1.5-1.5V2.5h4.036l0.038-0.106C17.525,2.588,17.5,2.791,17.5,3 c0,1.379,1.121,2.5,2.5,2.5s2.5-1.121,2.5-2.5c0-0.209-0.025-0.412-0.074-0.606L22.464,2.5H26.5V6c0,0.827-0.673,1.5-1.5,1.5H15z M20.01,0.5 M19.99,0.5 M20.007,0.5 M19.993,0.5 M19.996,0.5c0.002,0,0.006,0,0.008,0C20.002,0.5,19.998,0.5,19.996,0.5z"/><path fill="#4788c7" d="M26,3v3c0,0.551-0.449,1-1,1H15c-0.551,0-1-0.449-1-1V3h3c0,1.654,1.346,3,3,3s3-1.346,3-3H26 M20,0 c-1.304,0-2.403,0.837-2.816,2H13v4c0,1.105,0.895,2,2,2h10c1.105,0,2-0.895,2-2V2h-4.184C22.403,0.837,21.304,0,20,0L20,0z M20,5 c-1.103,0-2-0.897-2-2c0-1.103,0.897-2,2-2s2,0.897,2,2C22,4.103,21.103,5,20,5L20,5z"/><path fill="none" stroke="#4788c7" stroke-linecap="round" stroke-miterlimit="10" d="M22.5 16.5L24.375 18.375 28.5 14.5M22.5 25.5L24.375 27.375 28.5 23.5"/><g><path fill="#98ccfd" d="M19.5,17h-7c-0.275,0-0.5-0.225-0.5-0.5l0,0c0-0.275,0.225-0.5,0.5-0.5h7c0.275,0,0.5,0.225,0.5,0.5 l0,0C20,16.775,19.775,17,19.5,17z"/><path fill="#4788c7" d="M19.5,16h-7c-0.275,0-0.5,0.225-0.5,0.5s0.225,0.5,0.5,0.5h7c0.275,0,0.5-0.225,0.5-0.5 S19.775,16,19.5,16L19.5,16z"/></g><g><path fill="#98ccfd" d="M19.5,26h-7c-0.275,0-0.5-0.225-0.5-0.5l0,0c0-0.275,0.225-0.5,0.5-0.5h7c0.275,0,0.5,0.225,0.5,0.5 l0,0C20,25.775,19.775,26,19.5,26z"/><path fill="#4788c7" d="M19.5,25h-7c-0.275,0-0.5,0.225-0.5,0.5s0.225,0.5,0.5,0.5h7c0.275,0,0.5-0.225,0.5-0.5 S19.775,25,19.5,25L19.5,25z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M1.5 34.5H38.5V38.5H1.5z"/><path fill="#4788c7" d="M38,35v3H2v-3H38 M39,34H1v5h38V34L39,34z"/><path fill="#dff0fe" d="M26.5 31.5L26.5 9.5 23.022 9.5 29 1.814 34.978 9.5 31.5 9.5 31.5 31.5z"/><path fill="#4788c7" d="M29,2.629L33.955,9H32h-1v1v21h-4V10V9h-1h-1.955L29,2.629 M29,1l-7,9h4v22h6V10h4L29,1L29,1z"/><g><path fill="#dff0fe" d="M8.5 31.5L8.5 9.5 5.022 9.5 11 1.814 16.978 9.5 13.5 9.5 13.5 31.5z"/><path fill="#4788c7" d="M11,2.629L15.955,9H14h-1v1v21H9V10V9H8H6.045L11,2.629 M11,1l-7,9h4v22h6V10h4L11,1L11,1z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M10.325,33.787c0.809-1.151,0.698-2.755-0.329-3.783c-0.558-0.558-1.299-0.865-2.087-0.865 c-0.616,0-1.203,0.188-1.697,0.536L1.72,25.182L25.182,1.719l4.493,4.494c-0.809,1.151-0.699,2.756,0.329,3.783 c0.558,0.557,1.299,0.864,2.087,0.864c0.616,0,1.203-0.188,1.697-0.536l4.492,4.494L14.818,38.281L10.325,33.787z"/><path fill="#4788c7" d="M25.182,2.439l3.851,3.851c-0.691,1.307-0.487,2.967,0.611,4.066 c0.654,0.653,1.522,1.013,2.447,1.013c0.574,0,1.127-0.139,1.62-0.401l3.85,3.85L14.818,37.561l-3.851-3.851 c0.691-1.307,0.487-2.967-0.611-4.066c-0.654-0.654-1.522-1.013-2.447-1.013c-0.574,0-1.127,0.139-1.62,0.401l-3.85-3.85 L25.182,2.439 M25.182,1L1,25.182l5.182,5.182c0.477-0.477,1.102-0.715,1.727-0.715c0.625,0,1.25,0.238,1.727,0.715 c0.954,0.954,0.954,2.501,0,3.455L14.818,39L39,14.818l-5.182-5.182c-0.477,0.477-1.102,0.715-1.727,0.715 c-0.625,0-1.25-0.238-1.727-0.715c-0.954-0.954-0.954-2.501,0-3.455L25.182,1L25.182,1z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M20,38.5C9.8,38.5,1.5,30.2,1.5,20S9.8,1.5,20,1.5S38.5,9.8,38.5,20S30.2,38.5,20,38.5z"/><path fill="#fff" d="M20,35.5c-8.5,0-15.5-7-15.5-15.5S11.5,4.5,20,4.5s15.5,7,15.5,15.5S28.5,35.5,20,35.5z"/><path fill="#4788c7" d="M20,5c8.3,0,15,6.7,15,15s-6.7,15-15,15S5,28.3,5,20S11.7,5,20,5 M20,4C11.2,4,4,11.2,4,20s7.2,16,16,16 s16-7.2,16-16S28.8,4,20,4L20,4z"/><path fill="#fff" d="M6.6,6.6L6.6,6.6L20,20V10c3.3,0,6-2.7,6-6c0-0.8-0.1-1.5-0.4-2.2C23.8,1.3,21.9,1,20,1C14.8,1,10,3.1,6.6,6.6z"/><path fill="#dff0fe" d="M20,1.5c-1.4,0-2.5,1.1-2.5,2.5s1.1,2.5,2.5,2.5s2.5-1.1,2.5-2.5S21.4,1.5,20,1.5z"/><path fill="#4788c7" d="M20,2c1.1,0,2,0.9,2,2s-0.9,2-2,2s-2-0.9-2-2S18.9,2,20,2 M20,1c-1.7,0-3,1.3-3,3s1.3,3,3,3s3-1.3,3-3 S21.7,1,20,1L20,1z M21.4,18.6c0.8,0.8,0.8,2.1,0,2.9s-2.1,0.8-2.9,0s-8-10.9-8-10.9S20.6,17.8,21.4,18.6z"/><path fill="none" stroke="#4788c7" stroke-linecap="round" stroke-miterlimit="10" d="M7,6.8c-3.4,3.4-5.5,8-5.5,13.2c0,10.2,8.3,18.5,18.5,18.5S38.5,30.2,38.5,20c0-8.2-5.3-15.1-12.7-17.6"/><path fill="none" stroke="#4788c7" stroke-linecap="round" stroke-miterlimit="10" d="M25.8,5.6c5.7,2.3,9.7,7.9,9.7,14.4c0,8.6-6.9,15.5-15.5,15.5S4.5,28.6,4.5,20c0-4.3,1.7-8.2,4.5-11"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M12.008 29.045L1.5 32.32 1.5 4.796 11.992 1.526 21.992 4.955 32.5 1.68 32.5 29.204 22.008 32.474z"/><path fill="#4788c7" d="M11.985,2.052l9.69,3.322l0.31,0.106l0.312-0.097L32,2.359v26.477l-9.985,3.112l-9.69-3.322 l-0.31-0.106l-0.312,0.097L2,31.641V5.164L11.985,2.052 M33,1L22,4.429L12,1L1,4.429V33l11-3.429L22,33l11-3.429V1L33,1z"/><path fill="#fff" d="M22,31.937l-10-3.438V2.055L22,5.48V31.937z"/><path fill="#98ccfd" d="M24,38.5c-7.995,0-14.5-6.505-14.5-14.5S16.005,9.5,24,9.5S38.5,16.005,38.5,24S31.995,38.5,24,38.5 z"/><path fill="#4788c7" d="M24,10c7.72,0,14,6.28,14,14s-6.28,14-14,14s-14-6.28-14-14S16.28,10,24,10 M24,9 C15.716,9,9,15.716,9,24s6.716,15,15,15c8.284,0,15-6.716,15-15S32.284,9,24,9L24,9z"/><path fill="#fff" d="M24 12A12 12 0 1 0 24 36A12 12 0 1 0 24 12Z"/><path fill="none" stroke="#4788c7" stroke-linecap="round" stroke-miterlimit="10" d="M29.5 16L24 24 28.5 28.5"/><g><path fill="#4788c7" d="M24 22.5A1.5 1.5 0 1 0 24 25.5A1.5 1.5 0 1 0 24 22.5Z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#4788c7" d="M38.5 10h-25C13.224 10 13 9.776 13 9.5v0C13 9.224 13.224 9 13.5 9h25C38.776 9 39 9.224 39 9.5v0C39 9.776 38.776 10 38.5 10zM38.5 21h-25c-.276 0-.5-.224-.5-.5l0 0c0-.276.224-.5.5-.5h25c.276 0 .5.224.5.5l0 0C39 20.776 38.776 21 38.5 21zM38.5 32h-25c-.276 0-.5-.224-.5-.5l0 0c0-.276.224-.5.5-.5h25c.276 0 .5.224.5.5l0 0C39 31.776 38.776 32 38.5 32z"/><path fill="none" stroke="#4788c7" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M2 30L5 33 10 28M2 19L5 22 10 17M2 8L5 11 10 6"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M1.5 1.5H26.5V26.5H1.5z"/><path fill="#4788c7" d="M26,2v24H2V2H26 M27,1H1v26h26V1L27,1z"/><path fill="#98ccfd" d="M13.5 38.5L13.5 26.207 26.207 13.5 38.5 13.5 38.5 38.5z"/><path fill="#4788c7" d="M38,14v24H14V26.414L26.414,14H38 M39,13H26L13,26v13h26V13L39,13z"/><path fill="#fff" d="M22.679 28H30.179V31H22.679z"/><path fill="#fff" d="M28.383 20L24.593 20 19.429 34 22.754 34 26.364 22.671 26.492 22.671 30.104 34 33.429 34z"/><path fill="none" stroke="#4788c7" stroke-miterlimit="10" stroke-width="2" d="M7 10L21 10M14 6L14 10M19 10c0 0-2.376 10-12 10M9 13c0 0 3.451 5 9 5"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M7.5 34.5L7.5 34 3.495 5.929 3.497 5.5 36.5 5.5 36.5 6 32.505 33.929 32.502 34.5z"/><path fill="#4788c7" d="M35.99,6l-3.98,27.859L32,33.929V34H8v-0.071l-0.01-0.07L4.01,6H35.99 M37,5H3v1l4,28v1h26v-1l4-28 V5L37,5z"/><path fill="#b6dcfe" d="M3,5.5C2.725,5.5,2.5,5.276,2.5,5V2c0-0.276,0.225-0.5,0.5-0.5h34c0.275,0,0.5,0.224,0.5,0.5v3 c0,0.276-0.225,0.5-0.5,0.5H3z"/><path fill="#4788c7" d="M37,2v3H3V2H37 M37,1H3C2.448,1,2,1.448,2,2v3c0,0.552,0.448,1,1,1h34c0.552,0,1-0.448,1-1V2 C38,1.448,37.552,1,37,1L37,1z"/><g><path fill="#b6dcfe" d="M10,38.5c-1.379,0-2.5-1.122-2.5-2.5v-1.5h25V36c0,1.378-1.121,2.5-2.5,2.5H10z"/><path fill="#4788c7" d="M32,35v1c0,1.103-0.897,2-2,2H10c-1.103,0-2-0.897-2-2v-1H32 M33,34H7v2c0,1.657,1.343,3,3,3h20 c1.657,0,3-1.343,3-3V34L33,34z"/></g><g><path fill="#4788c7" d="M27.262 21.773l-1.127-1.902-.705 1.548-1.704-.121 1.127 1.902H21.62l-1.352 1.4L21.62 26h3.24c1.168 0 2.114-.498 2.595-1.364C27.932 23.775 27.856 22.721 27.262 21.773zM24.588 17.128l-2.134-3.624C21.858 12.548 20.976 12 20.034 12c-.941 0-1.822.548-2.435 1.531l-1.338 2.254 1.661-.033.745 1.463 1.323-2.227c.015-.026.031-.049.045-.07.008.012.016.025.025.038l2.114 3.592 1.918.486L24.588 17.128zM15.156 23.184l1.902-3.311-.495-1.829-1.933.434-1.895 3.298c-.592 1.008-.658 2.067-.179 2.904C13.035 25.519 13.977 26 15.14 26h3.452l-.999-1.4.999-1.4h-3.445C15.149 23.195 15.153 23.19 15.156 23.184z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><rect width="24.787" height="4.947" x="2.5" y="17.553" fill="#98ccfd"/><rect width="9.287" height="4.947" x="28" y="17.553" fill="#fff"/><rect width="15.351" height="4.947" x="2.5" y="5.527" fill="#98ccfd"/><rect width="19.5" height="4.947" x="17.5" y="5.527" fill="#fff"/><rect width="8" height="4.947" x="2.5" y="29.527" fill="#98ccfd"/><rect width="27.085" height="4.947" x="10.5" y="29.527" fill="#fff"/><rect width="35" height="5" x="2.5" y="17.5" fill="none" stroke="#4788c7" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10"/><path fill="#dff0fe" stroke="#4788c7" stroke-miterlimit="10" d="M29.5,22.625v-5.25c0-0.438-0.4-0.875-0.8-0.875h-2.4 c-0.4,0-0.8,0.438-0.8,0.875v5.25c0,0.438,0.4,0.875,0.8,0.875h2.4C29.1,23.5,29.5,23.063,29.5,22.625z"/><rect width="35" height="5" x="2.5" y="29.5" fill="none" stroke="#4788c7" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10"/><path fill="#dff0fe" stroke="#4788c7" stroke-miterlimit="10" d="M12.5,34.625v-5.25c0-0.438-0.4-0.875-0.8-0.875H9.3 c-0.4,0-0.8,0.438-0.8,0.875v5.25c0,0.438,0.4,0.875,0.8,0.875h2.4C12.1,35.5,12.5,35.063,12.5,34.625z"/><rect width="35" height="5" x="2.5" y="5.5" fill="none" stroke="#4788c7" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10"/><path fill="#dff0fe" stroke="#4788c7" stroke-miterlimit="10" d="M19.5,10.625v-5.25c0-0.438-0.4-0.875-0.8-0.875h-2.4 c-0.4,0-0.8,0.438-0.8,0.875v5.25c0,0.438,0.4,0.875,0.8,0.875h2.4C19.1,11.5,19.5,11.063,19.5,10.625z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="40px" height="40px"><path fill="#dff0fe" d="M10,37.5c-4.136,0-7.5-3.364-7.5-7.5V10c0-4.136,3.364-7.5,7.5-7.5h20c4.136,0,7.5,3.364,7.5,7.5v20 c0,4.136-3.364,7.5-7.5,7.5H10z"/><path fill="#4788c7" d="M30,3c3.86,0,7,3.14,7,7v20c0,3.86-3.14,7-7,7H10c-3.86,0-7-3.14-7-7V10c0-3.86,3.14-7,7-7H30 M30,2H10c-4.418,0-8,3.582-8,8v20c0,4.418,3.582,8,8,8h20c4.418,0,8-3.582,8-8V10C38,5.582,34.418,2,30,2L30,2z"/><polygon fill="#fff" points="24,28 12,28 12,10 30,10 30,22"/><path fill="#98ccfd" d="M10.257,9.649L9.064,12.83C9.022,12.942,9,13.061,9,13.181V28c0,0.552,0.448,1,1,1h5v2 c0,0.552,0.448,1,1,1h1.086c0.265,0,0.52-0.105,0.707-0.293L20.5,29h4.086c0.265,0,0.52-0.105,0.707-0.293l5.414-5.414 C30.895,23.105,31,22.851,31,22.586V10c0-0.552-0.448-1-1-1H11.193C10.776,9,10.403,9.259,10.257,9.649z M13,11h16v11l-3,3h-6l-3,3 v-3h-4V11z M18,15v6h2v-6H18z M23,15v6h2v-6H23z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#fff" d="M8.5 1.5H31.5V19.5H8.5z"/><path fill="#4788c7" d="M31,2v17H9V2H31 M32,1H8v19h24V1L32,1z"/><path fill="#4788c7" d="M1 19H39V20H1z"/><path fill="#dff0fe" d="M8,38.5c-1.93,0-3.5-1.57-3.5-3.5V15.5h10.039c0.358,2.202,3.095,2.999,5.461,2.999 c2.541,0,5.104-0.932,5.458-2.999H35.5V35c0,1.93-1.57,3.5-3.5,3.5H8z"/><path fill="#4788c7" d="M35,16v19c0,1.654-1.346,3-3,3H8c-1.654,0-3-1.346-3-3V16h9.146 c0.637,2.063,3.255,2.999,5.854,2.999s5.218-0.936,5.854-2.999H35 M36,15H25c0,2.219-2.829,2.999-5,2.999S15,17.25,15,15H4v20 c0,2.209,1.791,4,4,4h24c2.209,0,4-1.791,4-4V15L36,15z"/><path fill="#98ccfd" d="M8,35.5c-0.275,0-0.5-0.224-0.5-0.5v-9.5h25V35c0,0.276-0.225,0.5-0.5,0.5H8z"/><path fill="#4788c7" d="M32,26v9H8v-9H32 M33,25H7v10c0,0.552,0.448,1,1,1h24c0.552,0,1-0.448,1-1V25L33,25z"/><path fill="#98ccfd" d="M20,21.499c-4.631,0-8.441-1.401-9.5-1.83v-0.333c1.252-0.524,4-1.847,4-3.336v-0.5h0.039 c0.482,2.964,5.248,3,5.461,3s4.979-0.036,5.461-3H25.5V16c0,1.489,2.748,2.812,4,3.336v0.333 C28.441,20.098,24.631,21.499,20,21.499z"/><path fill="#4788c7" d="M25.317,17.034c0.635,1.041,2.103,1.896,3.274,2.447c-1.555,0.558-4.782,1.518-8.592,1.518 c-3.795,0-7.031-0.961-8.59-1.519c1.171-0.551,2.638-1.405,3.273-2.446C15.873,18.542,18.356,19,20,19 S24.127,18.542,25.317,17.034 M26,15h-1c0,3-5,3-5,3s-5,0-5-3h-1c0,0.006,0,1,0,1c0,1.42-4,3-4,3v1c0,0,4.376,1.999,10,1.999 S30,20,30,20v-1c0,0-4-1.58-4-3V15L26,15z"/><path fill="#fff" d="M15 33H25V34H15zM12 33H13V34H12zM9 33H10V34H9zM9 30H10V31H9zM9 27H10V28H9zM12 30H13V31H12zM12 27H13V28H12zM15 30H16V31H15zM15 27H16V28H15zM18 30H19V31H18zM18 27H19V28H18zM21 30H22V31H21zM21 27H22V28H21zM24 30H25V31H24zM24 27H25V28H24zM27 30H28V31H27zM27 27H28V28H27zM30 30H31V31H30zM27 33H28V34H27zM30 33H31V34H30zM30 27H31V28H30z"/><path fill="#4788c7" d="M2 21.996L2 21.996c-.55 0-1-.45-1-1v-3c0-.55.45-1 1-1h0c.55 0 1 .45 1 1v3C3 21.546 2.55 21.996 2 21.996zM38 21.996L38 21.996c-.55 0-1-.45-1-1v-3c0-.55.45-1 1-1l0 0c.55 0 1 .45 1 1v3C39 21.546 38.55 21.996 38 21.996z"/></svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 96 96" width="96px" height="96px">
<g id="surface37341098">
<path style="fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:10;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(27.843139%,53.333336%,78.039217%);stroke-opacity:1;stroke-miterlimit:10;" d="M 143.330076 86.000001 C 143.330076 117.534875 117.534875 143.330076 86.000001 143.330076 C 54.465127 143.330076 28.669926 117.534875 28.669926 86.000001 C 28.669926 54.465127 54.465127 28.669926 86.000001 28.669926 C 117.534875 28.669926 143.330076 54.465127 143.330076 86.000001 Z M 143.330076 86.000001 " transform="matrix(0.527442,0,0,0.527442,2.64,2.64)"/>
<path style="fill-rule:nonzero;fill:rgb(71.372551%,86.274511%,99.607843%);fill-opacity:1;stroke-width:10;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(27.843139%,53.333336%,78.039217%);stroke-opacity:1;stroke-miterlimit:10;" d="M 107.499705 86.000001 C 107.499705 97.82743 97.82743 107.499705 86.000001 107.499705 C 74.172571 107.499705 64.500297 97.82743 64.500297 86.000001 C 64.500297 74.172571 74.172571 64.500297 86.000001 64.500297 C 97.82743 64.500297 107.499705 74.172571 107.499705 86.000001 Z M 43.000593 77.038705 C 37.986711 77.038705 34.039297 80.986119 34.039297 86.000001 C 34.039297 91.013883 37.986711 94.961296 43.000593 94.961296 C 48.014475 94.961296 51.961889 91.013883 51.961889 86.000001 C 51.961889 80.986119 48.014475 77.038705 43.000593 77.038705 M 55.539001 86.000001 C 55.539001 92.806142 49.806734 98.538409 43.000593 98.538409 C 36.194452 98.538409 30.454779 92.806142 30.454779 86.000001 C 30.454779 79.193859 36.194452 73.461593 43.000593 73.461593 C 49.806734 73.461593 55.539001 79.193859 55.539001 86.000001 Z M 107.499705 112.876482 C 102.485823 112.876482 98.538409 116.81649 98.538409 121.830372 C 98.538409 126.85166 102.485823 130.791668 107.499705 130.791668 C 112.513587 130.791668 116.461 126.85166 116.461 121.830372 C 116.461 116.81649 112.513587 112.876482 107.499705 112.876482 M 120.038113 121.830372 C 120.038113 128.643919 114.305846 134.376186 107.499705 134.376186 C 100.693563 134.376186 94.961296 128.643919 94.961296 121.830372 C 94.961296 115.024231 100.693563 109.291964 107.499705 109.291964 C 114.305846 109.291964 120.038113 115.024231 120.038113 121.830372 Z M 120.038113 121.830372 " transform="matrix(0.527442,0,0,0.527442,2.64,2.64)"/>
<path style="fill-rule:nonzero;fill:rgb(71.372551%,86.274511%,99.607843%);fill-opacity:1;stroke-width:10;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(27.843139%,53.333336%,78.039217%);stroke-opacity:1;stroke-miterlimit:10;" d="M 157.668149 86.000001 C 157.668149 125.41489 125.41489 157.668149 86.000001 157.668149 C 46.585111 157.668149 14.331852 125.41489 14.331852 86.000001 C 14.331852 46.585111 46.585111 14.331852 86.000001 14.331852 C 125.41489 14.331852 157.668149 46.585111 157.668149 86.000001 Z M 109.291964 113.231971 C 117.171979 106.42583 121.830372 96.753556 121.830372 86.000001 C 121.830372 75.246446 117.171979 65.574171 109.291964 58.76803 C 113.594867 58.049645 116.461 54.465127 116.461 50.169629 C 116.461 45.148341 112.513587 41.208334 107.499705 41.208334 C 102.485823 41.208334 98.538409 45.148341 98.538409 50.169629 C 98.538409 51.243504 98.538409 51.961889 98.901304 52.672867 C 94.961296 50.880608 90.658393 50.169629 86.000001 50.169629 C 67.72192 50.169629 53.035763 63.781912 50.525119 81.341608 C 49.088349 78.830964 46.222216 77.038705 43.000593 77.038705 C 37.986711 77.038705 34.039297 80.986119 34.039297 86.000001 C 34.039297 91.013883 37.986711 94.961296 43.000593 94.961296 C 46.222216 94.961296 49.088349 93.169037 50.525119 90.658393 C 53.035763 108.218089 67.72192 121.830372 86.000001 121.830372 C 90.658393 121.830372 94.961296 121.119393 98.901304 119.327134 C 98.538409 120.038113 98.538409 121.119393 98.538409 121.830372 C 98.538409 126.85166 102.485823 130.791668 107.499705 130.791668 C 112.513587 130.791668 116.461 126.85166 116.461 121.830372 C 116.461 117.534875 113.594867 113.950356 109.291964 113.231971 Z M 109.291964 113.231971 " transform="matrix(0.527442,0,0,0.527442,2.64,2.64)"/>
<path style="fill-rule:nonzero;fill:rgb(71.372551%,86.274511%,99.607843%);fill-opacity:1;stroke-width:10;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(27.843139%,53.333336%,78.039217%);stroke-opacity:1;stroke-miterlimit:10;" d="M 107.499705 41.208334 C 102.485823 41.208334 98.538409 45.148341 98.538409 50.169629 C 98.538409 55.183511 102.485823 59.123519 107.499705 59.123519 C 112.513587 59.123519 116.461 55.183511 116.461 50.169629 C 116.461 45.148341 112.513587 41.208334 107.499705 41.208334 M 120.038113 50.169629 C 120.038113 56.975771 114.305846 62.708038 107.499705 62.708038 C 100.693563 62.708038 94.961296 56.975771 94.961296 50.169629 C 94.961296 43.356082 100.693563 37.623815 107.499705 37.623815 C 114.305846 37.623815 120.038113 43.356082 120.038113 50.169629 Z M 86.000001 86.000001 C 76.683215 71.306438 67.36643 56.975771 58.049645 42.282208 " transform="matrix(0.527442,0,0,0.527442,2.64,2.64)"/>
<path style="fill-rule:nonzero;fill:rgb(71.372551%,86.274511%,99.607843%);fill-opacity:1;stroke-width:10;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(27.843139%,53.333336%,78.039217%);stroke-opacity:1;stroke-miterlimit:10;" d="M 55.146481 44.355896 L 61.189801 40.512167 L 88.888352 84.044809 L 82.845032 87.888538 Z M 55.146481 44.355896 " transform="matrix(0.527442,0,0,0.527442,2.64,2.64)"/>
<path style="fill-rule:nonzero;fill:rgb(71.372551%,86.274511%,99.607843%);fill-opacity:1;stroke-width:10;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(27.843139%,53.333336%,78.039217%);stroke-opacity:1;stroke-miterlimit:10;" d="M 86.000001 82.415482 L 137.597809 82.415482 L 137.597809 89.584519 L 86.000001 89.584519 Z M 86.000001 82.415482 " transform="matrix(0.527442,0,0,0.527442,2.64,2.64)"/>
<path style="fill-rule:nonzero;fill:rgb(71.372551%,86.274511%,99.607843%);fill-opacity:1;stroke-width:10;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(27.843139%,53.333336%,78.039217%);stroke-opacity:1;stroke-miterlimit:10;" d="M 86.000001 86.000001 C 76.327726 100.330668 67.010941 114.668741 57.33126 128.999408 " transform="matrix(0.527442,0,0,0.527442,2.64,2.64)"/>
<path style="fill-rule:nonzero;fill:rgb(71.372551%,86.274511%,99.607843%);fill-opacity:1;stroke-width:10;stroke-linecap:butt;stroke-linejoin:round;stroke:rgb(27.843139%,53.333336%,78.039217%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.354036 126.984968 L 82.970935 84.052215 L 88.940194 88.021847 L 60.31589 130.962006 Z M 54.354036 126.984968 " transform="matrix(0.527442,0,0,0.527442,2.64,2.64)"/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 78.238281 48 C 78.238281 64.632812 64.632812 78.238281 48 78.238281 C 31.367188 78.238281 17.761719 64.632812 17.761719 48 C 17.761719 31.367188 31.367188 17.761719 48 17.761719 C 64.632812 17.761719 78.238281 31.367188 78.238281 48 Z M 78.238281 48 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(71.372551%,86.274511%,99.607843%);fill-opacity:1;" d="M 59.339844 48 C 59.339844 54.238281 54.238281 59.339844 48 59.339844 C 41.761719 59.339844 36.660156 54.238281 36.660156 48 C 36.660156 41.761719 41.761719 36.660156 48 36.660156 C 54.238281 36.660156 59.339844 41.761719 59.339844 48 Z M 25.320312 43.273438 C 27.964844 43.273438 30.046875 45.355469 30.046875 48 C 30.046875 50.644531 27.964844 52.726562 25.320312 52.726562 C 22.675781 52.726562 20.59375 50.644531 20.59375 48 C 20.59375 45.355469 22.675781 43.273438 25.320312 43.273438 M 25.320312 41.386719 C 21.730469 41.386719 18.703125 44.410156 18.703125 48 C 18.703125 51.589844 21.730469 54.613281 25.320312 54.613281 C 28.910156 54.613281 31.933594 51.589844 31.933594 48 C 31.933594 44.410156 28.910156 41.386719 25.320312 41.386719 Z M 59.339844 62.175781 C 61.984375 62.175781 64.066406 64.253906 64.066406 66.898438 C 64.066406 69.546875 61.984375 71.625 59.339844 71.625 C 56.695312 71.625 54.613281 69.546875 54.613281 66.898438 C 54.613281 64.253906 56.695312 62.175781 59.339844 62.175781 M 59.339844 60.285156 C 55.75 60.285156 52.726562 63.308594 52.726562 66.898438 C 52.726562 70.492188 55.75 73.515625 59.339844 73.515625 C 62.929688 73.515625 65.953125 70.492188 65.953125 66.898438 C 65.953125 63.308594 62.929688 60.285156 59.339844 60.285156 Z M 59.339844 60.285156 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(71.372551%,86.274511%,99.607843%);fill-opacity:1;" d="M 48 10.199219 C 27.210938 10.199219 10.199219 27.210938 10.199219 48 C 10.199219 68.789062 27.210938 85.800781 48 85.800781 C 68.789062 85.800781 85.800781 68.789062 85.800781 48 C 85.800781 27.210938 68.789062 10.199219 48 10.199219 Z M 64.066406 66.898438 C 64.066406 69.546875 61.984375 71.625 59.339844 71.625 C 56.695312 71.625 54.613281 69.546875 54.613281 66.898438 C 54.613281 66.523438 54.613281 65.953125 54.804688 65.578125 C 52.726562 66.523438 50.457031 66.898438 48 66.898438 C 38.359375 66.898438 30.613281 59.71875 29.289062 50.457031 C 28.53125 51.78125 27.019531 52.726562 25.320312 52.726562 C 22.675781 52.726562 20.59375 50.644531 20.59375 48 C 20.59375 45.355469 22.675781 43.273438 25.320312 43.273438 C 27.019531 43.273438 28.53125 44.21875 29.289062 45.542969 C 30.613281 36.28125 38.359375 29.101562 48 29.101562 C 50.457031 29.101562 52.726562 29.476562 54.804688 30.421875 C 54.613281 30.046875 54.613281 29.667969 54.613281 29.101562 C 54.613281 26.453125 56.695312 24.375 59.339844 24.375 C 61.984375 24.375 64.066406 26.453125 64.066406 29.101562 C 64.066406 31.367188 62.554688 33.257812 60.285156 33.636719 C 64.441406 37.226562 66.898438 42.328125 66.898438 48 C 66.898438 53.671875 64.441406 58.773438 60.285156 62.363281 C 62.554688 62.742188 64.066406 64.632812 64.066406 66.898438 Z M 64.066406 66.898438 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(71.372551%,86.274511%,99.607843%);fill-opacity:1;" d="M 59.339844 24.375 C 61.984375 24.375 64.066406 26.453125 64.066406 29.101562 C 64.066406 31.746094 61.984375 33.824219 59.339844 33.824219 C 56.695312 33.824219 54.613281 31.746094 54.613281 29.101562 C 54.613281 26.453125 56.695312 24.375 59.339844 24.375 M 59.339844 22.484375 C 55.75 22.484375 52.726562 25.507812 52.726562 29.101562 C 52.726562 32.691406 55.75 35.714844 59.339844 35.714844 C 62.929688 35.714844 65.953125 32.691406 65.953125 29.101562 C 65.953125 25.507812 62.929688 22.484375 59.339844 22.484375 Z M 48 48 C 43.085938 40.25 38.171875 32.691406 33.257812 24.941406 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(71.372551%,86.274511%,99.607843%);fill-opacity:1;" d="M 31.726562 26.035156 L 34.914062 24.007812 L 49.523438 46.96875 L 46.335938 48.996094 Z M 31.726562 26.035156 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(71.372551%,86.274511%,99.607843%);fill-opacity:1;" d="M 48 46.109375 L 75.214844 46.109375 L 75.214844 49.890625 L 48 49.890625 Z M 48 46.109375 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(71.372551%,86.274511%,99.607843%);fill-opacity:1;" d="M 48 48 C 42.898438 55.558594 37.984375 63.121094 32.878906 70.679688 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(71.372551%,86.274511%,99.607843%);fill-opacity:1;" d="M 31.308594 69.617188 L 46.402344 46.972656 L 49.550781 49.066406 L 34.453125 71.714844 Z M 31.308594 69.617188 "/>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M1.512,35.5c0.269-5.559,4.982-10,10.738-10h7.5c1.716,0,3.404,0.399,4.918,1.161 c-1.932,2.613-0.792,7.126-0.254,8.839H1.512z"/><path fill="#4788c7" d="M19.75,26c1.45,0,2.879,0.299,4.189,0.871c-1.421,2.515-0.731,6.169-0.192,8.129H2.051 c0.516-5.046,4.893-9,10.199-9H19.75 M19.75,25h-7.5C6.037,25,1,29.925,1,36h24.112c0,0-2.514-6.659,0.341-9.484 C23.78,25.553,21.831,25,19.75,25L19.75,25z"/><path fill="#fff" d="M16,28.5c-3.055,0-4.3-2.645-4.5-3.124v-5.467h9v5.469C20.297,25.875,19.075,28.5,16,28.5z"/><path fill="#4788c7" d="M20,20.41v4.865C19.737,25.865,18.607,28,16,28c-2.611,0-3.741-2.141-4-2.725V20.41H20 M21,19.41 H11v6.062c0,0,1.267,3.529,5,3.529s5-3.529,5-3.529V19.41L21,19.41z"/><path fill="#b6dcfe" d="M22.429,17.643c-1.143,0-2.071-0.929-2.071-2.071s0.929-2.071,2.071-2.071 c1.725,0,2.071,0.465,2.071,1.214C24.5,15.966,23.476,17.643,22.429,17.643z M9.571,17.643c-1.047,0-2.071-1.677-2.071-2.929 c0-0.749,0.347-1.214,2.071-1.214c1.143,0,2.071,0.929,2.071,2.071S10.714,17.643,9.571,17.643z"/><path fill="#4788c7" d="M22.429,14C24,14,24,14.363,24,14.714c0,1.044-0.896,2.429-1.571,2.429 c-0.867,0-1.571-0.705-1.571-1.571S21.562,14,22.429,14 M9.571,14c0.867,0,1.571,0.705,1.571,1.571s-0.705,1.571-1.571,1.571 C8.896,17.143,8,15.758,8,14.714C8,14.363,8,14,9.571,14 M22.429,13c-1.42,0-2.571,1.151-2.571,2.571s1.151,2.571,2.571,2.571 S25,16.134,25,14.714S23.849,13,22.429,13L22.429,13z M9.571,13C8.151,13,7,13.294,7,14.714s1.151,3.429,2.571,3.429 s2.571-1.151,2.571-2.571S10.992,13,9.571,13L9.571,13z"/><g><path fill="#fff" d="M16,24.5c-0.58,0-1.135-0.224-1.56-0.631l-0.09-0.086l-0.12-0.034 C11.445,22.963,9.5,20.393,9.5,17.5V9.364c0-1.564,1.272-2.837,2.836-2.837h7.328c1.563,0,2.836,1.272,2.836,2.837V17.5 c0,2.893-1.945,5.463-4.73,6.249l-0.12,0.034l-0.09,0.086C17.135,24.276,16.58,24.5,16,24.5z"/><path fill="#4788c7" d="M19.664,7.028C20.952,7.028,22,8.076,22,9.364V17.5c0,2.67-1.796,5.042-4.367,5.768l-0.239,0.068 l-0.18,0.172C16.882,23.825,16.451,24,16,24s-0.882-0.175-1.215-0.492l-0.18-0.172l-0.239-0.068C11.796,22.542,10,20.17,10,17.5 V9.364c0-1.288,1.048-2.336,2.336-2.336H19.664 M19.664,6.028h-7.328C10.494,6.028,9,7.521,9,9.364V17.5 c0,3.205,2.156,5.9,5.095,6.731C14.591,24.705,15.26,25,16,25s1.409-0.295,1.905-0.769C20.844,23.4,23,20.705,23,17.5V9.364 C23,7.521,21.506,6.028,19.664,6.028L19.664,6.028z"/></g><g><path fill="#b6dcfe" d="M22.5,15.5V12c0-3.484-2.218-4.425-2.312-4.463l-0.343-0.14l-0.234,0.287 C19.589,7.713,17.283,10.5,14,10.5c-0.264,0-0.529-0.009-0.791-0.017c-0.265-0.009-0.525-0.017-0.778-0.017 c-0.877,0-2.931,0-2.931,2.533v2.5H9.285C8.845,14.727,7.5,12.151,7.5,9.576C7.5,4.821,10.995,1.5,16,1.5 c3.095,0,4.543,2.704,4.557,2.731l0.119,0.228l0.253,0.036C22.462,4.715,24.5,5.524,24.5,10c0,2.334-1.338,4.763-1.778,5.5H22.5z"/><path fill="#4788c7" d="M16,2c2.762,0,4.062,2.367,4.113,2.463l0.237,0.454l0.507,0.073C22.321,5.199,24,5.958,24,10 c0,1.395-0.515,2.842-1,3.894V12c0-3.816-2.516-4.883-2.623-4.926l-0.687-0.279l-0.467,0.577C19.201,7.397,17.06,10,14,10 c-0.259,0-0.519-0.008-0.775-0.017c-0.27-0.009-0.537-0.017-0.794-0.017C11.582,9.966,9,9.966,9,13v0.801 c-0.486-1.124-1-2.679-1-4.225C8,5.115,11.29,2,16,2 M16,1c-5.36,0-9,3.667-9,8.576C7,12.828,9,16,9,16h1c0,0,0-2.105,0-3 c0-1.791,1.085-2.034,2.431-2.034C12.932,10.966,13.469,11,14,11c3.573,0,6-3,6-3s2,0.813,2,4c0,0.984,0,4,0,4h1c0,0,2-3.037,2-6 c0-4.161-1.703-5.671-4-6C21,4,19.434,1,16,1L16,1z"/></g><g><path fill="#98ccfd" d="M30.5,39.5c-4.963,0-9-4.037-9-9s4.037-9,9-9s9,4.037,9,9S35.463,39.5,30.5,39.5z M27.581,35.712 l0.7,0.283c0.712,0.288,1.459,0.434,2.219,0.434c3.27,0,5.929-2.659,5.929-5.929c0-0.76-0.146-1.506-0.433-2.219l-0.282-0.702 L27.581,35.712z M30.5,24.571c-3.27,0-5.929,2.659-5.929,5.929c0,0.76,0.146,1.507,0.434,2.219l0.283,0.7l8.133-8.133 l-0.702-0.282C32.006,24.717,31.26,24.571,30.5,24.571z"/><path fill="#4788c7" d="M30.5,22c4.687,0,8.5,3.813,8.5,8.5S35.187,39,30.5,39c-4.687,0-8.5-3.813-8.5-8.5 S25.813,22,30.5,22 M25.107,34.307l1.068-1.068l7.064-7.064l1.068-1.068l-1.401-0.566c-0.771-0.312-1.581-0.47-2.407-0.47 c-3.545,0-6.429,2.884-6.429,6.429c0,0.826,0.158,1.635,0.47,2.406L25.107,34.307 M30.5,36.929c3.545,0,6.429-2.884,6.429-6.429 c0-0.826-0.158-1.636-0.47-2.407l-0.566-1.4l-1.068,1.068l-7.064,7.064l-1.068,1.068l1.4,0.566 C28.865,36.77,29.674,36.929,30.5,36.929 M30.5,21c-5.247,0-9.5,4.253-9.5,9.5c0,5.247,4.253,9.5,9.5,9.5s9.5-4.253,9.5-9.5 C40,25.253,35.747,21,30.5,21L30.5,21z M25.468,32.532c-0.254-0.628-0.397-1.313-0.397-2.032c0-2.998,2.43-5.429,5.429-5.429 c0.719,0,1.404,0.143,2.032,0.397L25.468,32.532L25.468,32.532z M30.5,35.929c-0.719,0-1.404-0.143-2.032-0.397l7.063-7.063 c0.254,0.628,0.397,1.313,0.397,2.032C35.929,33.498,33.498,35.929,30.5,35.929L30.5,35.929z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#4788c7" d="M31,9v22H9V9H31 M32,8H8v24h24V8L32,8z"/><path fill="#98ccfd" d="M2.5 2.5H14.5V14.5H2.5z"/><path fill="#4788c7" d="M14,3v11H3V3H14 M15,2H2v13h13V2L15,2z"/><path fill="#dff0fe" d="M25.5 2.5H37.5V14.5H25.5z"/><path fill="#4788c7" d="M37,3v11H26V3H37 M38,2H25v13h13V2L38,2z"/><g><path fill="#dff0fe" d="M2.5 25.5H14.5V37.5H2.5z"/><path fill="#4788c7" d="M14,26v11H3V26H14 M15,25H2v13h13V25L15,25z"/></g><g><path fill="#dff0fe" d="M25.5 25.5H37.5V37.5H25.5z"/><path fill="#4788c7" d="M37,26v11H26V26H37 M38,25H25v13h13V25L38,25z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#98ccfd" d="M20 16.499A3.5 3.5 0 1 0 20 23.499A3.5 3.5 0 1 0 20 16.499Z"/><path fill="#4788c7" d="M20,17c1.654,0,3,1.345,3,2.998C23,21.653,21.654,23,20,23s-3-1.347-3-3.002 C17,18.345,18.346,17,20,17 M20,16c-2.2,0-4,1.799-4,3.998S17.8,24,20,24s4-1.803,4-4.002S22.2,16,20,16L20,16z"/><path fill="#dff0fe" d="M36 18.5A1.5 1.5 0 1 0 36 21.5A1.5 1.5 0 1 0 36 18.5Z"/><path fill="#4788c7" d="M36,19c0.551,0,1,0.449,1,1s-0.449,1-1,1s-1-0.449-1-1S35.449,19,36,19 M36,18 c-1.105,0-2,0.897-2,2c0,1.107,0.895,2,2,2c1.105,0,2-0.893,2-2C38,18.897,37.105,18,36,18L36,18z"/><path fill="#dff0fe" d="M4 18.5A1.5 1.5 0 1 0 4 21.5A1.5 1.5 0 1 0 4 18.5Z"/><path fill="#4788c7" d="M4,19c0.551,0,1,0.449,1,1s-0.449,1-1,1s-1-0.449-1-1S3.449,19,4,19 M4,18c-1.105,0-2,0.897-2,2 c0,1.107,0.895,2,2,2s2-0.893,2-2C6,18.897,5.105,18,4,18L4,18z"/><path fill="#98ccfd" d="M20 9.5A1.5 1.5 0 1 0 20 12.5A1.5 1.5 0 1 0 20 9.5Z"/><path fill="#4788c7" d="M20,10c0.551,0,1,0.449,1,1s-0.449,1-1,1s-1-0.449-1-1S19.449,10,20,10 M20,9c-1.105,0-2,0.895-2,2 s0.895,2,2,2s2-0.895,2-2S21.105,9,20,9L20,9z"/><g><path fill="#98ccfd" d="M29 18.5A1.5 1.5 0 1 0 29 21.5A1.5 1.5 0 1 0 29 18.5Z"/><path fill="#4788c7" d="M29,19c0.551,0,1,0.449,1,1s-0.449,1-1,1s-1-0.449-1-1S28.449,19,29,19 M29,18c-1.105,0-2,0.897-2,2 c0,1.107,0.895,2,2,2c1.105,0,2-0.893,2-2C31,18.897,30.105,18,29,18L29,18z"/></g><g><path fill="#98ccfd" d="M11 18.5A1.5 1.5 0 1 0 11 21.5A1.5 1.5 0 1 0 11 18.5Z"/><path fill="#4788c7" d="M11,19c0.551,0,1,0.449,1,1s-0.449,1-1,1s-1-0.449-1-1S10.449,19,11,19 M11,18c-1.105,0-2,0.897-2,2 c0,1.107,0.895,2,2,2s2-0.893,2-2C13,18.897,12.105,18,11,18L11,18z"/></g><g><path fill="#98ccfd" d="M20 27.5A1.5 1.5 0 1 0 20 30.5A1.5 1.5 0 1 0 20 27.5Z"/><path fill="#4788c7" d="M20,28c0.551,0,1,0.449,1,1s-0.449,1-1,1s-1-0.449-1-1S19.449,28,20,28 M20,27c-1.105,0-2,0.895-2,2 s0.895,2,2,2s2-0.895,2-2S21.105,27,20,27L20,27z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#b6dcfe" d="M1.5 35.5L1.5 4.5 11.793 4.5 14.793 7.5 38.5 7.5 38.5 35.5z"/><path fill="#4788c7" d="M11.586,5l2.707,2.707L14.586,8H15h23v27H2V5H11.586 M12,4H1v32h38V7H15L12,4L12,4z"/><path fill="#dff0fe" d="M1.5 35.5L1.5 9.5 12.151 9.5 15.151 7.5 38.5 7.5 38.5 35.5z"/><path fill="#4788c7" d="M38,8v27H2V10h10h0.303l0.252-0.168L15.303,8H38 M39,7H15l-3,2H1v27h38V7L39,7z"/><path fill="#dff0fe" d="M13 33H27V36H13z"/><path fill="#4788c7" d="M19,25v13c0,0.552,0.448,1,1,1h0c0.552,0,1-0.448,1-1V25h6l-7-7l-7,7H19z"/><path fill="#dff0fe" d="M24 7H39V22H24z"/><path fill="#4788c7" d="M35,7c0,2.209,1.791,4,4,4V7H35z"/><path fill="none" stroke="#4788c7" stroke-linecap="round" stroke-miterlimit="10" d="M38.5 14.5c-3.922 0-7-3.078-7-7M38.5 18.5c-6.058 0-11-4.942-11-11"/><path fill="#4788c7" d="M22.5 8h2C24.775 8 25 7.775 25 7.5v0C25 7.225 24.775 7 24.5 7h-2C22.225 7 22 7.225 22 7.5v0C22 7.775 22.225 8 22.5 8zM38.5 24L38.5 24c.275 0 .5-.225.5-.5v-2c0-.275-.225-.5-.5-.5l0 0c-.275 0-.5.225-.5.5v2C38 23.775 38.225 24 38.5 24zM32.5 36h-9c-.275 0-.5-.225-.5-.5l0 0c0-.275.225-.5.5-.5h9c.275 0 .5.225.5.5l0 0C33 35.775 32.775 36 32.5 36zM16.5 36h-9C7.225 36 7 35.775 7 35.5l0 0C7 35.225 7.225 35 7.5 35h9c.275 0 .5.225.5.5l0 0C17 35.775 16.775 36 16.5 36z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M6.5,28.5c-3.309,0-6-2.691-6-6s2.691-6,6-6c0.497,0,1.011,0.068,1.529,0.204l0.494,0.13 l0.119-0.497c0.423-1.771,1.775-3.17,3.53-3.652l0.332-0.092l0.034-0.341C12.919,8.402,16.127,5.5,20,5.5 c2.859,0,5.43,1.596,6.709,4.165l0.204,0.408l0.425-0.165C28.037,9.638,28.765,9.5,29.5,9.5c3.309,0,6,2.691,6,6 c0,0.271-0.024,0.556-0.075,0.896l-0.058,0.391l0.366,0.147c2.288,0.919,3.767,3.104,3.767,5.565c0,3.309-2.691,6-6,6H6.5z"/><path fill="#4788c7" d="M20,6c2.668,0,5.068,1.49,6.262,3.888l0.406,0.816l0.85-0.329C28.161,10.126,28.828,10,29.5,10 c3.033,0,5.5,2.467,5.5,5.5c0,0.247-0.022,0.508-0.069,0.822l-0.117,0.782l0.734,0.295C37.645,18.241,39,20.244,39,22.5 c0,3.033-2.467,5.5-5.5,5.5h-27C3.467,28,1,25.533,1,22.5S3.467,17,6.5,17c0.455,0,0.927,0.063,1.401,0.188l0.99,0.26l0.237-0.995 c0.38-1.593,1.598-2.852,3.177-3.287l0.662-0.182l0.068-0.683C13.391,8.709,16.385,6,20,6 M20,5c-4.149,0-7.559,3.159-7.96,7.202 c-1.922,0.529-3.42,2.071-3.885,4.019C7.626,16.082,7.073,16,6.5,16C2.91,16,0,18.91,0,22.5S2.91,29,6.5,29c3.43,0,23.41,0,27,0 s6.5-2.91,6.5-6.5c0-2.734-1.69-5.069-4.08-6.03c0.048-0.317,0.08-0.64,0.08-0.97c0-3.59-2.91-6.5-6.5-6.5 c-0.827,0-1.615,0.161-2.343,0.442C25.847,6.812,23.138,5,20,5L20,5z"/><path fill="#dff0fe" d="M16 27H24V29H16z"/><path fill="#4788c7" d="M19,21v13c0,0.552,0.448,1,1,1h0c0.552,0,1-0.448,1-1V21h5l-6-6l-6,6H19z"/><path fill="#4788c7" d="M25.5 28h-2c-.275 0-.5.225-.5.5l0 0c0 .275.225.5.5.5h2c.275 0 .5-.225.5-.5l0 0C26 28.225 25.775 28 25.5 28zM16.5 28h-2c-.275 0-.5.225-.5.5l0 0c0 .275.225.5.5.5h2c.275 0 .5-.225.5-.5l0 0C17 28.225 16.775 28 16.5 28z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#4788c7" d="M25,10c-1.105,0-2,0.895-2,2c0,1.105,0.895,2,2,2s2-1.562,2-2.667S26.105,10,25,10z M15,10 c-1.105,0-2,0.229-2,1.333S13.895,14,15,14s2-0.895,2-2C17,10.895,16.105,10,15,10z"/><path fill="#dff0fe" d="M20,18.5c-0.4,0-0.78-0.182-1.044-0.498l-0.105-0.126l-0.16-0.04 c-2.467-0.604-4.19-2.798-4.19-5.336V7.243c0-1.301,1.059-2.359,2.359-2.359h6.281c1.301,0,2.359,1.059,2.359,2.359V12.5 c0,2.538-1.723,4.732-4.19,5.336l-0.16,0.04l-0.105,0.126C20.78,18.318,20.4,18.5,20,18.5z"/><path fill="#4788c7" d="M23.141,5.384c1.025,0,1.859,0.834,1.859,1.86V12.5c0,2.307-1.567,4.302-3.81,4.85l-0.32,0.078 l-0.211,0.253C20.561,17.801,20.343,18,20,18s-0.561-0.199-0.66-0.318l-0.211-0.253l-0.32-0.078C16.567,16.802,15,14.807,15,12.5 V7.243c0-1.025,0.834-1.86,1.859-1.86H23.141 M23.141,4.384h-6.281C15.28,4.384,14,5.664,14,7.243V12.5 c0,2.821,1.949,5.18,4.572,5.822C18.914,18.733,19.423,19,20,19s1.086-0.267,1.428-0.678C24.051,17.68,26,15.321,26,12.5V7.243 C26,5.664,24.72,4.384,23.141,4.384L23.141,4.384z"/><path fill="#b6dcfe" d="M25.5,12.5V11c0-2.703-2.189-4.146-2.283-4.206l-0.332-0.213l-0.285,0.272 c-0.013,0.012-1.511,1.378-4.663,1.378c-1.711,0-3.437,1.025-3.437,3.315V12.5h-0.119C14.133,11.562,13.5,8.98,13.5,7 c0-2.733,2.12-5.5,6.173-5.5c2.17,0,2.834,1.612,2.861,1.681l0.125,0.316L23,3.5c1.467,0,3.5,1.24,3.5,3.568 c0,1.809-0.637,4.467-0.885,5.432H25.5z"/><path fill="#4788c7" d="M19.673 2c1.779 0 2.339 1.229 2.393 1.356L22.311 4H23c1.046 0 3 .9 3 3.068 0 .703-.101 1.544-.237 2.36-.61-1.959-2.192-3.001-2.274-3.054l-.656-.409-.569.519c-.056.051-1.402 1.248-4.326 1.248-1.71 0-3.04.854-3.62 2.204C14.142 8.981 14 7.921 14 7 14 4.515 15.949 2 19.673 2M19.673 1C15.455 1 13 3.872 13 7c0 2.555 1 6 1 6h1c0 0 0-.75 0-1.453 0-1.931 1.399-2.816 2.937-2.816 3.423 0 5.009-1.517 5.009-1.517S25 8.539 25 11c0 .773 0 2 0 2h1c0 0 1-3.603 1-5.932C27 4.414 24.685 3 23 3 23 3 22.238 1 19.673 1L19.673 1zM1 26H39V27H1z"/><path fill="#dff0fe" d="M8,38.5c-1.93,0-3.5-1.57-3.5-3.5v-7.5h31V35c0,1.93-1.57,3.5-3.5,3.5H8z"/><path fill="#4788c7" d="M35,28v7c0,1.654-1.346,3-3,3H8c-1.654,0-3-1.346-3-3v-7H35 M36,27H4v8c0,2.209,1.791,4,4,4h24 c2.209,0,4-1.791,4-4V27L36,27z"/><path fill="#98ccfd" d="M4.5 22.5H35.5V28.5H4.5z"/><path fill="#4788c7" d="M35,23v5H5v-5H35 M36,22H4v7h32V22L36,22z"/><g><path fill="#fff" d="M8.5 17.5H31.5V25.5H8.5z"/><path fill="#4788c7" d="M31,18v7H9v-7H31 M32,17H8v9h24V17L32,17z"/></g><path fill="#4788c7" d="M2 29L2 29c-.55 0-1-.45-1-1v-3c0-.55.45-1 1-1h0c.55 0 1 .45 1 1v3C3 28.55 2.55 29 2 29zM38 29L38 29c-.55 0-1-.45-1-1v-3c0-.55.45-1 1-1l0 0c.55 0 1 .45 1 1v3C39 28.55 38.55 29 38 29z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M2,28.5c-0.276,0-0.5-0.225-0.5-0.5V12c0-0.275,0.224-0.5,0.5-0.5h36c0.276,0,0.5,0.225,0.5,0.5v16 c0,0.275-0.224,0.5-0.5,0.5H2z"/><path fill="#4788c7" d="M38,12v16H2V12H38 M38,11H2c-0.55,0-1,0.45-1,1v16c0,0.55,0.45,1,1,1h36c0.55,0,1-0.45,1-1V12 C39,11.45,38.55,11,38,11L38,11z"/><path fill="#4788c7" d="M20 17A3 3 0 1 0 20 23 3 3 0 1 0 20 17zM10 17A3 3 0 1 0 10 23 3 3 0 1 0 10 17zM30 17A3 3 0 1 0 30 23 3 3 0 1 0 30 17z"/><path fill="#98ccfd" d="M31 22.5A8.5 8.5 0 1 0 31 39.5A8.5 8.5 0 1 0 31 22.5Z"/><path fill="#4788c7" d="M31,23c4.411,0,8,3.589,8,8s-3.589,8-8,8s-8-3.589-8-8S26.589,23,31,23 M31,22 c-4.971,0-9,4.029-9,9s4.029,9,9,9s9-4.029,9-9S35.971,22,31,22L31,22z"/><path fill="none" stroke="#fff" stroke-miterlimit="10" stroke-width="2" d="M26.821 31.025L29.591 33.794 35.821 27.563"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#dff0fe" d="M5.5,37.5V4c0-1.379,1.122-2.5,2.5-2.5h24c1.378,0,2.5,1.121,2.5,2.5v33.5H5.5z"/><path fill="#4788c7" d="M32,2c1.103,0,2,0.897,2,2v33H6V4c0-1.103,0.897-2,2-2H32 M32,1H8C6.343,1,5,2.343,5,4v34h30V4 C35,2.343,33.657,1,32,1L32,1z"/><path fill="#fff" d="M20,32.5c-5.238,0-9.5-4.262-9.5-9.5s4.262-9.5,9.5-9.5s9.5,4.262,9.5,9.5S25.238,32.5,20,32.5z"/><path fill="#4788c7" d="M20,14c4.963,0,9,4.037,9,9s-4.037,9-9,9s-9-4.037-9-9S15.037,14,20,14 M20,13 c-5.523,0-10,4.477-10,10s4.477,10,10,10s10-4.477,10-10S25.523,13,20,13L20,13z"/><path fill="#98ccfd" d="M28.958,22.17c-1.069-0.423-2.904-1.027-4.672-1.027c-2.715,0-7.41,2.857-10,2.857 c-1.444,0-2.56-0.442-3.277-0.835C11.097,28.058,15.085,32,20,32c4.971,0,9-4.029,9-9C29,22.72,28.983,22.443,28.958,22.17z"/><path fill="none" stroke="#4788c7" stroke-miterlimit="10" d="M5.75 8.5L34.25 8.5"/><path fill="#4788c7" d="M9 4A1 1 0 1 0 9 6 1 1 0 1 0 9 4zM13 4A1 1 0 1 0 13 6 1 1 0 1 0 13 4zM31 4A1 1 0 1 0 31 6 1 1 0 1 0 31 4zM31 37h3c.552 0 1 .448 1 1l0 0c0 .552-.448 1-1 1h-3c-.552 0-1-.448-1-1l0 0C30 37.448 30.448 37 31 37zM6 37h3c.552 0 1 .448 1 1l0 0c0 .552-.448 1-1 1H6c-.552 0-1-.448-1-1l0 0C5 37.448 5.448 37 6 37z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="80px" height="80px"><path fill="#98ccfd" d="M16.5 26.5H23.5V33.5H16.5z"/><path fill="#4788c7" d="M23,27v6h-6v-6H23 M24,26h-8v8h8V26L24,26z"/><path fill="#fff" d="M0.5 6.5H39.5V29.5H0.5z"/><path fill="#4788c7" d="M39,7v22H1V7H39 M40,6H0v24h40V6L40,6z"/><path fill="#98ccfd" d="M10.5,35.5V35c0-1.379,1.122-2.5,2.5-2.5h14c1.378,0,2.5,1.121,2.5,2.5v0.5H10.5z"/><path fill="#4788c7" d="M27,33c1.103,0,2,0.897,2,2H11c0-1.103,0.897-2,2-2H27 M27,32H13c-1.657,0-3,1.343-3,3v1h20v-1 C30,33.343,28.657,32,27,32L27,32z"/><path fill="none" stroke="#4788c7" stroke-miterlimit="10" d="M32.939 13.377L7.061 22.787"/><path fill="#4788c7" d="M32.623 15.599L35 12.447 31.079 11.993zM7.377 20.401L5 23.553 8.921 24.007z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="40px" height="40px"><path fill="#dff0fe" d="M15.5,20.5h-14v12.148l14,1.921V20.5z M15.5,4.589l-14,1.965V18.5h14V4.589z M17.5,4.241V18.5h20 v-17L17.5,4.241z M17.5,20.5v14.276l20,2.811V20.5H17.5z"/><path fill="#4788c7" d="M37.5,38.086c-0.023,0-0.046-0.001-0.069-0.005l-20-2.811C17.184,35.236,17,35.025,17,34.776V20.5 c0-0.276,0.224-0.5,0.5-0.5h20c0.276,0,0.5,0.224,0.5,0.5v17.086c0,0.145-0.063,0.282-0.172,0.377 C37.736,38.043,37.62,38.086,37.5,38.086z M18,34.341l19,2.67V21H18V34.341z M15.5,35.069c-0.022,0-0.045-0.001-0.068-0.005 l-14-1.921C1.185,33.109,1,32.897,1,32.647V20.5C1,20.224,1.224,20,1.5,20h14c0.276,0,0.5,0.224,0.5,0.5v14.069 c0,0.145-0.063,0.282-0.171,0.377C15.737,35.025,15.62,35.069,15.5,35.069z M2,32.211l13,1.784V21H2V32.211z M37.5,19h-20 c-0.276,0-0.5-0.224-0.5-0.5V4.241c0-0.25,0.185-0.461,0.432-0.496l20-2.741c0.141-0.018,0.287,0.024,0.396,0.119 C37.938,1.218,38,1.355,38,1.5v17C38,18.776,37.776,19,37.5,19z M18,18h19V2.073L18,4.677V18z M15.5,19h-14 C1.224,19,1,18.776,1,18.5V6.554c0-0.25,0.184-0.46,0.431-0.495l14-1.965c0.143-0.023,0.288,0.023,0.397,0.118 C15.938,4.307,16,4.444,16,4.589V18.5C16,18.776,15.776,19,15.5,19z M2,18h13V5.164L2,6.989V18z"/></svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 128 128" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<path d="M63.692,64.781c0,0 20.812,0.75 30.375,9c9.562,8.25 16.125,24 13.312,37.688c-5.625,-1.313 -29.625,-5.438 -39.375,-17.438c-9.75,-12 -9.375,-20.437 -8.25,-25.5c1.125,-5.062 3.938,-3.75 3.938,-3.75" style="fill:#1c9cf3;fill-rule:nonzero;"/>
<path d="M60.044,68.582c-0.475,2.139 -0.988,5.498 0.046,9.953c1.125,4.848 3.801,10.068 8.198,15.31c10.06,11.993 38.391,16.857 38.734,16.932c1.078,-6.234 0.351,-12.729 -2.174,-19.516c-2.494,-6.705 -6.5,-12.669 -11.279,-16.793c-9.415,-8.122 -30.26,-8.963 -30.469,-8.971l-0.215,-0.007l-0.155,-0.081c-0.002,0 -0.177,-0.068 -0.418,-0.068c-0.998,0 -1.803,1.151 -2.268,3.241Z" style="fill:url(#_Radial1);fill-rule:nonzero;"/>
<path d="M58.254,64.781c0,0 2.625,5.438 -3.562,13.688c-6.188,8.25 -19.125,21.562 -51.375,18.75c1.125,-7.688 6.75,-15.563 12.937,-21.188c6.188,-5.625 20.063,-11.437 29.25,-11.625c9.188,-0.187 12.75,0.375 12.75,0.375" style="fill:#04bbf3;fill-rule:nonzero;"/>
<path d="M45.667,65.135c-4.286,0.086 -10.037,1.469 -15.783,3.791c-5.597,2.263 -10.53,5.128 -13.534,7.859c-6.762,6.148 -11.116,13.417 -12.413,19.94c2.596,0.201 7.447,0.302 7.447,0.302c11.549,0 21.195,-2.117 29.11,-6.626c7.017,-3.996 11.231,-8.995 13.79,-12.407c4.909,-6.545 4.149,-11.122 3.717,-12.555c-1.08,-0.116 -3.81,-0.344 -8.669,-0.344c-1.165,0 -2.398,0.013 -3.665,0.04Z" style="fill:url(#_Linear2);fill-rule:nonzero;"/>
<path d="M123.879,45.656c0,0 -3.75,10.875 -22.125,16.125c-18.375,5.25 -38.062,1.875 -38.062,1.875c0,0 4.687,-12.375 18.187,-18.187c13.5,-5.813 37.313,-0.563 42,0.187" style="fill:#02bef3;fill-rule:nonzero;"/>
<path d="M81.544,46.68c-10.988,4.731 -16.174,13.887 -17.695,17.055c2.266,0.309 7.463,0.901 13.983,0.901c8.656,0 16.566,-1.005 23.51,-2.989c14.825,-4.235 20.235,-12.672 21.72,-15.505c-0.243,-0.043 -17.126,-3.378 -26.758,-3.378c-6.904,0 -10.593,2.121 -14.76,3.916Z" style="fill:url(#_Radial3);fill-rule:nonzero;"/>
<path d="M57.921,65.406c0,0 -26.74,-1.259 -42.436,-12.71c-15.695,-11.451 -15.333,-15.226 -15.333,-15.226c0,0 17.598,-0.054 26.286,3.078c8.688,3.133 22.335,11.948 31.483,24.858" style="fill:#02bef3;fill-rule:nonzero;"/>
<path d="M16.409,52.486c6.069,4.428 13.396,7.559 22.006,9.665c0.002,0.001 0.002,0.001 0.004,0.001c9.149,1.098 16.735,2.791 18.559,2.946c-4.016,-5.462 -9.015,-10.404 -14.381,-14.517c-5.193,-3.99 -10.674,-7.143 -15.228,-8.943c-0.845,-0.336 -1.74,-0.638 -2.662,-0.915c-8.018,-2.397 -21.465,-2.553 -23.533,-2.583c0.509,0.942 2.299,4.909 15.235,14.346Z" style="fill:url(#_Radial4);fill-rule:nonzero;"/>
<path d="M58.113,67.998c2.377,0.304 3.66,5.62 2.862,11.865c-0.798,6.244 -3.376,11.067 -5.754,10.763c-2.377,-0.303 -3.66,-5.62 -2.862,-11.864c0.798,-6.245 3.376,-11.068 5.754,-10.764Z" style="fill:url(#_Radial5);"/>
<g>
<path d="M61.629,64.651c-7.957,1.497 3.291,37.119 15.337,42.529c23.156,10.401 35.993,-9.611 35.993,-16.859c0,-7.249 -31.885,-29.326 -51.33,-25.67Z" style="fill:url(#_Radial6);fill-rule:nonzero;"/>
<path d="M50.386,74.833c-2.895,5.261 20.365,23.165 30.768,21.166c10.402,-2 24.271,-12.529 23.192,-18.252c-1.079,-5.724 -19.995,-21.583 -35.132,-15.913c-9.928,3.719 -15.933,7.738 -18.828,12.999Z" style="fill:url(#_Radial7);fill-rule:nonzero;"/>
<path d="M60.31,77.16c-2.178,5.597 13.079,21.534 23.128,18.182c10.048,-3.352 22.409,-15.617 20.586,-21.148c-1.824,-5.532 -22.664,-18.761 -36.922,-11.146c-9.351,4.994 -4.615,8.515 -6.792,14.112Z" style="fill:url(#_Radial8);fill-rule:nonzero;"/>
<path d="M58.727,74.603c-1.855,4.721 11.081,18.141 19.616,15.304c8.535,-2.837 19.043,-13.192 17.501,-17.853c-1.542,-4.662 -19.221,-15.793 -31.334,-9.357c-7.946,4.221 -3.928,7.185 -5.783,11.906Z" style="fill:url(#_Radial9);fill-rule:nonzero;"/>
</g>
<g>
<path d="M61.553,74.101c-1.577,4.793 -19.173,24.596 -31.313,27.374c-12.14,2.779 -24.092,-9.922 -25.211,-15.785c-1.119,-5.862 17.202,-22.572 35.975,-24.02c12.313,-0.95 23.195,4.394 20.549,12.431" style="fill:url(#_Radial10);fill-rule:nonzero;"/>
<path d="M61.211,71.442c-1.214,5.581 -17.369,27.784 -29.357,30.15c-11.989,2.368 -24.988,-13.673 -26.567,-20.736c-1.579,-7.063 15.545,-25.529 34.304,-25.799c12.305,-0.176 23.657,7.026 21.62,16.385" style="fill:url(#_Radial11);fill-rule:nonzero;"/>
<path d="M52.51,74.882c-1.717,3.102 -15.803,13.833 -23.882,13.516c-8.079,-0.316 -13.708,-11.577 -13.531,-15.946c0.177,-4.369 14.254,-12.769 26.319,-10.259c7.913,1.647 13.974,7.488 11.094,12.689" style="fill:url(#_Radial12);fill-rule:nonzero;"/>
</g>
<path d="M34.746,69.666c-3.518,0.435 -20.481,-4.645 -24.977,-11.365c-4.497,-6.719 1.299,-17.895 4.937,-20.322c3.637,-2.426 18.71,4.018 23.777,15.251c3.322,7.368 2.164,15.705 -3.737,16.436" style="fill:url(#_Radial13);fill-rule:nonzero;"/>
<g>
<path d="M96.436,40.499c15.231,-2.015 28.385,2.308 29.356,9.649c0.971,7.34 -10.605,14.936 -25.836,16.951c-15.231,2.015 -28.385,-2.308 -29.356,-9.648c-0.971,-7.341 10.606,-14.937 25.836,-16.952Z" style="fill:url(#_Radial14);"/>
<path d="M99.526,41.492c13.736,1.417 24.292,8.341 23.559,15.452c-0.734,7.111 -12.482,11.734 -26.218,10.316c-13.737,-1.417 -24.293,-8.341 -23.559,-15.452c0.733,-7.111 12.481,-11.734 26.218,-10.316Z" style="fill:url(#_Radial15);"/>
<path d="M89.733,43.795c11.582,-1.429 21.602,2.408 22.361,8.563c0.76,6.154 -8.027,12.311 -19.609,13.74c-11.581,1.429 -21.601,-2.407 -22.36,-8.562c-0.76,-6.154 8.027,-12.311 19.608,-13.741Z" style="fill:url(#_Radial16);"/>
</g>
<path d="M59.353,65.162c0.022,0.369 0.978,7.846 -5.49,10.654c-5.003,2.171 -11.154,3.242 -24.792,-2.947c-13.638,-6.189 -18.377,-15.18 -18.377,-15.18c0,0 7.628,2.802 12.367,3.153c4.739,0.351 16.99,2.102 20.11,2.685c3.121,0.585 8.669,0.117 10.749,-0.349c2.081,-0.468 5.202,-1.752 5.433,1.984" style="fill:#b3c3ce;fill-rule:nonzero;"/>
<path d="M29.071,72.494c13.639,6.188 19.79,5.117 24.792,2.948c6.468,-2.809 5.512,-10.287 5.49,-10.655c-0.232,-3.736 -3.352,-2.452 -5.432,-1.984c-2.081,0.467 -7.49,0.137 -11.979,-0.178c-5.344,-0.375 -13.969,-1.5 -18.88,-2.158c-4.71,-0.631 -12.368,-3.153 -12.368,-3.153c0,0 4.74,8.991 18.377,15.18Z" style="fill:url(#_Linear17);fill-rule:nonzero;"/>
<path d="M55.262,58.355c0,0 -4.342,-3.433 -7.875,-7.169c-3.534,-3.735 -14.943,-14.538 -17.77,-17.466c-2.826,-2.928 -10.5,-12.924 -11.51,-17.164c-2.322,5.149 -3.836,14.539 -1.009,23.626c2.826,9.087 9.39,15.648 18.072,19.284c8.683,3.634 16.255,3.432 18.375,3.432c2.121,0 5.049,-1.413 1.717,-4.543" style="fill:#f5f6f2;fill-rule:nonzero;"/>
<path d="M17.473,40.182c2.827,9.086 9.39,15.649 18.073,19.283c8.682,3.635 16.254,3.687 18.375,3.687c1.197,0 4.989,-0.152 5.177,-0.715c0.403,-1.21 -1.926,-2.107 -3.375,-3.468c-3.848,-3.042 -3.776,-3.358 -7.961,-7.782c-3.534,-3.736 -14.943,-14.539 -17.769,-17.467c-2.827,-2.928 -10.502,-12.923 -11.511,-17.165c-2.322,5.15 -3.837,14.54 -1.009,23.627Z" style="fill:url(#_Linear18);fill-rule:nonzero;"/>
<path d="M103.337,21.668c-3.75,3.375 -10.395,7.863 -16.77,11.988c-6.375,4.125 -10.5,11.063 -15.375,18.375c-4.875,7.313 -9.75,10.875 -9.75,10.875c0,0 7.687,1.125 15,1.125c11.256,0 24,-9.375 28.687,-14.437c4.688,-5.063 7.838,-13.311 7.875,-21.75c0.043,-9.861 -4.519,-11.792 -4.519,-11.792c0,0 -1.398,2.24 -5.148,5.615Z" style="fill:url(#_Linear19);fill-rule:nonzero;"/>
<path d="M103.865,20.907c-3.751,3.375 -11.298,8.624 -17.673,12.749c-6.375,4.125 -10.5,11.063 -15.375,18.375c-3.751,5.625 -8.444,8.724 -10.41,10.329c-0.59,0.482 -0.934,1.765 -0.934,1.765c6.769,0.99 8.351,-0.094 16.594,-0.094c11.255,0 24,-9.375 28.687,-14.437c4.688,-5.063 7.688,-13.313 7.875,-21.75c0.188,-8.438 -4.125,-11.813 -4.125,-11.813c0,0 -0.89,1.501 -4.639,4.876Z" style="fill:url(#_Linear20);fill-rule:nonzero;"/>
<g>
<path d="M42.638,45.578c8.133,5.258 12.662,12.735 10.107,16.686c-2.555,3.952 -11.232,2.89 -19.365,-2.368c-8.132,-5.259 -12.661,-12.736 -10.106,-16.687c2.555,-3.951 11.232,-2.89 19.364,2.369Z" style="fill:url(#_Radial21);"/>
<path d="M41.855,45.022c7.726,5.84 12.065,13.139 9.684,16.29c-2.382,3.151 -10.588,0.968 -18.314,-4.871c-7.726,-5.839 -12.065,-13.139 -9.684,-16.29c2.382,-3.151 10.588,-0.968 18.314,4.871Z" style="fill:url(#_Radial22);"/>
</g>
<g>
<path d="M76.747,50.134c8.038,-4.494 15.957,-5.649 17.674,-2.578c1.717,3.071 -3.415,9.213 -11.452,13.706c-8.038,4.494 -15.958,5.649 -17.674,2.578c-1.717,-3.071 3.414,-9.213 11.452,-13.706Z" style="fill:url(#_Radial23);"/>
<path d="M79.138,46.315c7.951,-4.445 15.94,-5.31 17.83,-1.93c1.889,3.38 -3.032,9.733 -10.983,14.178c-7.951,4.445 -15.94,5.31 -17.83,1.93c-1.889,-3.38 3.032,-9.733 10.983,-14.178Z" style="fill:url(#_Radial24);"/>
<path d="M78.132,49.395c7.5,-5.169 15.482,-6.621 17.812,-3.24c2.33,3.381 -1.867,10.323 -9.367,15.492c-7.5,5.17 -15.481,6.622 -17.812,3.241c-2.33,-3.381 1.867,-10.323 9.367,-15.493Z" style="fill:url(#_Radial25);"/>
<path d="M87.314,42.046c2.878,-6.448 7.508,-10.659 10.332,-9.399c2.825,1.261 2.781,7.519 -0.098,13.967c-2.878,6.448 -7.508,10.659 -10.332,9.399c-2.824,-1.261 -2.78,-7.52 0.098,-13.967Z" style="fill:url(#_Radial26);"/>
</g>
<path d="M24.702,32.262c-0.805,5.902 0.586,11.977 3.363,15.977c2.778,4.001 10.763,11.808 18.631,12.917c5.111,0.72 10.596,0.69 10.596,0.69c0,0 -3.058,-2.97 -5.745,-8.561c-2.687,-5.591 -4.888,-10.846 -8.937,-14.358c-4.05,-3.511 -8.254,-7.303 -10.543,-10.031c-2.288,-2.729 -3.044,-4.431 -3.044,-4.431c0,0 -3.38,0.899 -4.321,7.797Z" style="fill:url(#_Linear27);fill-rule:nonzero;"/>
<path d="M24.965,32.299c-0.7,5.916 0.585,11.978 3.363,15.978c2.778,3.999 10.762,11.808 18.63,12.915c5.762,0.813 6.31,1.128 11.139,1.102c0,0 -3.6,-3.381 -6.288,-8.972c-2.688,-5.591 -4.887,-10.847 -8.937,-14.358c-4.05,-3.51 -8.808,-7.923 -11.097,-10.651c-2.289,-2.728 -2.764,-3.865 -2.764,-3.865c0,0 -3.347,1.934 -4.046,7.851Z" style="fill:url(#_Linear28);fill-rule:nonzero;"/>
<g>
<path d="M55.714,66.066c1.06,3.068 -2.837,7.203 -8.698,9.227c-5.86,2.024 -11.478,1.176 -12.538,-1.892c-1.059,-3.069 2.838,-7.203 8.698,-9.227c5.86,-2.024 11.478,-1.176 12.538,1.892Z" style="fill:url(#_Radial29);"/>
<path d="M53.204,68.127c0.12,2.902 -4.178,5.44 -9.591,5.663c-5.413,0.223 -9.905,-1.952 -10.024,-4.854c-0.12,-2.903 4.178,-5.44 9.591,-5.664c5.413,-0.223 9.905,1.953 10.024,4.855Z" style="fill:url(#_Radial30);"/>
<path d="M58.03,66.776c0.851,2.014 -2.078,5.179 -6.538,7.064c-4.459,1.885 -8.771,1.78 -9.622,-0.233c-0.851,-2.014 2.078,-5.179 6.538,-7.064c4.46,-1.885 8.771,-1.78 9.622,0.233Z" style="fill:url(#_Radial31);"/>
</g>
<path d="M31.673,65.694c2.166,3.131 5.442,5.398 8.477,6.086c3.035,0.689 10.168,0.927 14.358,-1.942c2.722,-1.865 5.295,-4.244 5.295,-4.244c0,0 -2.723,-0.082 -6.401,-1.561c-3.679,-1.478 -6.984,-3.008 -10.407,-2.918c-3.425,0.09 -7.043,0.115 -9.299,-0.185c-2.257,-0.299 -3.348,-0.777 -3.348,-0.777c0,0 -1.205,1.882 1.325,5.541Z" style="fill:url(#_Linear32);fill-rule:nonzero;"/>
<path d="M31.813,65.599c2.221,3.091 5.441,5.396 8.476,6.086c3.036,0.688 10.17,0.928 14.358,-1.942c3.068,-2.103 3.462,-2.19 5.729,-4.285c0,0 -3.155,-0.042 -6.835,-1.52c-3.679,-1.478 -6.982,-3.009 -10.407,-2.918c-3.424,0.091 -7.572,0.061 -9.828,-0.239c-2.256,-0.3 -2.97,-0.631 -2.97,-0.631c0,0 -0.745,2.356 1.477,5.449Z" style="fill:url(#_Linear33);fill-rule:nonzero;"/>
<path d="M98.926,64.619c-3.373,1.42 -18.374,0.622 -23.876,0c-5.503,-0.621 -11.189,-0.526 -12.25,-0.621c-3.796,-0.342 -3.106,0.887 -3.373,4.703c-0.621,10.563 3.373,12.694 6.302,13.138c2.93,0.443 5.593,-0.976 5.593,-0.976c0,0 29.024,-13.137 31.687,-14.558c0.496,-2.725 0.376,-3.586 -0.232,-3.586c-0.7,0 -2.047,1.14 -3.851,1.9Z" style="fill:url(#_Radial34);fill-rule:nonzero;"/>
<g>
<path d="M71.826,68.086c4.948,3.511 7.617,8.26 5.957,10.598c-1.659,2.338 -7.023,1.386 -11.971,-2.126c-4.947,-3.511 -7.616,-8.261 -5.957,-10.599c1.66,-2.338 7.024,-1.385 11.971,2.127Z" style="fill:url(#_Radial35);"/>
<path d="M70.546,68.086c3.798,2.696 5.535,6.783 3.875,9.121c-1.659,2.338 -6.09,2.047 -9.889,-0.649c-3.798,-2.696 -5.534,-6.783 -3.875,-9.121c1.66,-2.338 6.091,-2.047 9.889,0.649Z" style="fill:url(#_Radial36);"/>
<path d="M74.322,68.379c3.799,2.696 5.535,6.783 3.876,9.121c-1.66,2.338 -6.091,2.047 -9.889,-0.649c-3.799,-2.695 -5.535,-6.783 -3.875,-9.121c1.659,-2.338 6.09,-2.047 9.888,0.649Z" style="fill:url(#_Radial37);"/>
</g>
<path d="M61.502,69.307c2.637,4.341 9.236,7.059 12.286,7.682c3.05,0.622 6.968,-0.097 10.231,-2.06c3.811,-2.292 3.487,-4.503 3.487,-4.503c0,0 -1.191,-0.014 -3.37,-0.669c-2.18,-0.656 -5.468,-2.167 -8.551,-3.659c-3.083,-1.492 -6.724,-1.457 -10.686,-1.624c-3.961,-0.167 -6.476,-1.212 -6.476,-1.212c0,0 1.366,3.228 3.079,6.045Z" style="fill:url(#_Linear38);fill-rule:nonzero;"/>
<path d="M61.415,69.164c2.635,4.34 9.235,7.059 12.285,7.68c3.05,0.622 6.933,-0.154 10.23,-2.058c3.298,-1.903 3.588,-4.357 3.588,-4.357c0,0 -0.786,0.008 -2.965,-0.647c-2.18,-0.656 -5.972,-2.337 -9.056,-3.829c-3.083,-1.491 -6.724,-1.457 -10.686,-1.623c-3.961,-0.168 -6.854,-1.429 -6.854,-1.429c1.203,2.843 1.527,3.085 3.458,6.263Z" style="fill:url(#_Linear39);fill-rule:nonzero;"/>
<path d="M102.035,66.75c0,0 1.219,-0.938 1.125,-2.813c-0.093,-1.874 0.375,-4.687 -9.562,-10.781c-3.281,5.907 -14.625,21.657 -19.594,25.219c-4.969,3.563 -5.765,3.442 -5.765,3.442c0,0 2.871,-0.343 5.39,-2.223c2.722,-2.032 28.406,-12.844 28.406,-12.844" style="fill:#cbd3dd;fill-rule:nonzero;"/>
<path d="M74.379,78.563c-3.085,2.212 -4.026,2.655 -4.716,2.945c0.257,-0.077 2.189,-0.583 4.341,-1.726c3,-1.594 28.406,-12.844 28.406,-12.844c0,-0.001 1.219,-0.938 1.125,-2.813c-0.093,-1.875 0.375,-4.687 -9.562,-10.781c-3.281,5.906 -14.625,21.657 -19.594,25.219Z" style="fill:url(#_Linear40);fill-rule:nonzero;"/>
<path d="M58.915,67.448c-0.618,-0.001 -6.022,9.818 -3.491,21.069c0,-0.001 3.615,-4.339 4.058,-15.247c0.183,-4.5 -0.133,-5.823 -0.567,-5.823Z" style="fill:url(#_Linear41);fill-rule:nonzero;"/>
<path d="M44.829,36.179c1.272,-1.24 5.597,-0.248 6.615,1.116c0.995,1.333 6.118,6.458 5.875,14.213c0.788,0.033 1.832,0.17 3.031,0.17c1.035,0 1.994,-0.102 2.781,-0.152c-0.252,-7.765 4.878,-12.897 5.873,-14.231c1.017,-1.364 5.343,-2.356 6.615,-1.116c1.273,1.24 -2.036,1.116 -3.562,0.744c-4.941,1.094 -8.097,12.039 -8.77,14.594c1.153,-0.063 1.897,0.018 1.897,0.781c0,1.156 -1.619,3.021 -3.872,3.221c0.092,0.464 0.627,3.053 0.024,5.777c-0.245,1.107 -2.519,2.36 -2.519,2.36c-2.415,-7.912 -0.023,-8.682 0.01,-8.748c-1.978,-0.296 -3.058,-1.549 -3.058,-2.61c0,-0.676 0.518,-0.817 1.388,-0.796c-0.681,-2.582 -3.835,-13.487 -8.765,-14.579c-1.527,0.372 -4.835,0.496 -3.563,-0.744" style="fill:#00c6f9;fill-rule:nonzero;"/>
<path d="M69.004,37.669c-0.995,1.335 -6.125,6.466 -5.873,14.232c-0.787,0.05 -1.746,0.152 -2.781,0.152c-1.199,0 -2.243,-0.137 -3.031,-0.17c0.243,-7.755 -4.88,-12.88 -5.874,-14.214c-1.018,-1.364 -5.344,-2.355 -6.616,-1.115c-1.272,1.24 2.036,1.115 3.563,0.743c4.93,1.093 8.084,11.998 8.765,14.58c-0.87,-0.02 -1.387,0.12 -1.387,0.796c0,1.061 0.786,2.39 2.763,2.684c-0.033,0.066 -1.658,1.242 0.284,8.674c0,0 3.102,-0.292 2.628,-6.64c-0.054,-0.732 -0.13,-1.318 -0.223,-1.782c2.252,-0.201 3.962,-1.781 3.962,-2.936c0,-0.763 -0.744,-0.844 -1.897,-0.781c0.674,-2.555 3.829,-13.5 8.77,-14.595c1.527,0.372 4.835,0.497 3.562,-0.743c-0.408,-0.398 -1.13,-0.566 -1.956,-0.566c-1.75,0 -3.968,0.755 -4.659,1.681Z" style="fill:url(#_Radial42);fill-rule:nonzero;"/>
<path d="M48.011,24.197c-0.937,1.89 2.368,2.171 3.493,1.605c3.635,1.665 5.958,18.288 6.46,22.223c-0.641,-0.031 -1.022,0.183 -1.022,1.213c0,1.617 0.873,3.929 2.329,4.38c-0.024,0.1 -0.037,0.16 -0.037,0.16c0,0 -2.48,4.628 -0.417,14.753c0,0 2.307,-5.062 2.307,-12.099c0,-1.119 -0.096,-2.01 -0.165,-2.719c1.66,-0.305 2.92,-2.713 2.92,-4.475c0,-1.161 -0.547,-1.285 -1.397,-1.189c0.387,-4.644 1.969,-20.385 6.463,-22.247c1.125,0.566 4.286,0.354 3.348,-1.536c-0.937,-1.89 -4.255,-0.383 -5.571,1.387c-1.445,1.942 -4.932,10.629 -4.747,22.466c-0.579,0.076 -0.896,0.174 -1.658,0.174c-0.883,0 -1.653,-0.208 -2.234,-0.259c0.179,-11.822 -3.677,-19.606 -4.329,-21.666c-0.616,-1.949 -2.533,-3.101 -4.027,-3.101c-0.755,0 -1.401,0.295 -1.716,0.93Z" style="fill:url(#_Linear43);fill-rule:nonzero;"/>
<path d="M48.011,24.565c-0.937,1.874 2.368,2.154 3.493,1.591c3.635,1.652 5.958,18.142 6.46,22.047c-0.641,-0.031 -1.022,0.181 -1.022,1.203c0,1.604 0.873,3.897 2.329,4.343c-0.024,0.1 -0.037,0.159 -0.037,0.159c0,0 -4.295,14.835 -1.471,24.549c0,0 3.709,-12.317 3.361,-21.915c-0.04,-1.109 -0.096,-1.994 -0.165,-2.697c1.66,-0.303 2.92,-2.691 2.92,-4.439c0,-1.153 -0.547,-1.276 -1.397,-1.181c0.387,-4.607 1.969,-20.222 6.463,-22.069c1.125,0.563 4.286,0.352 3.348,-1.523c-0.937,-1.875 -4.255,-0.38 -5.571,1.375c-1.445,1.927 -4.932,10.545 -4.747,22.287c-0.579,0.075 -0.896,0.174 -1.658,0.174c-0.883,0 -1.653,-0.207 -2.234,-0.258c0.179,-11.728 -3.677,-19.448 -4.329,-21.492c-0.616,-1.934 -2.533,-3.077 -4.027,-3.077c-0.754,0.001 -1.401,0.293 -1.716,0.923Z" style="fill:url(#_Linear44);fill-rule:nonzero;"/>
<path d="M64.284,58.419c0,0 3.743,-2.96 6.791,-6.181c3.047,-3.222 12.885,-12.537 15.323,-15.063c2.438,-2.524 9.055,-11.144 9.926,-14.801c2.003,4.441 3.308,12.538 0.87,20.373c-2.437,7.836 -8.097,13.496 -15.584,16.63c-7.488,3.134 -14.018,2.96 -15.845,2.96c-1.829,0 -4.354,-1.219 -1.481,-3.918" style="fill:#f5f6f2;fill-rule:nonzero;"/>
<path d="M86.075,37.175c-2.439,2.525 -12.276,11.84 -15.323,15.062c-3.609,3.816 -3.547,4.088 -6.865,6.711c-1.25,1.174 -3.205,2.508 -2.946,3.073c0.259,0.564 3.467,0.316 4.5,0.316c1.828,0 8.358,0.174 15.846,-2.96c7.487,-3.135 13.146,-8.794 15.584,-16.629c2.439,-7.836 1.132,-15.933 -0.871,-20.374c-0.87,3.658 -7.487,12.277 -9.925,14.801Z" style="fill:url(#_Linear45);fill-rule:nonzero;"/>
<defs>
<radialGradient id="_Radial1" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-66.1387,0,-0,66.1387,60.5806,63.95)"><stop offset="0" style="stop-color:#3d4ead;stop-opacity:1"/><stop offset="1" style="stop-color:#00c0f3;stop-opacity:1"/></radialGradient>
<linearGradient id="_Linear2" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-54.7355,0,0,-32.1015,58.3206,81.1455)"><stop offset="0" style="stop-color:#3f51b4;stop-opacity:1"/><stop offset="1" style="stop-color:#00c0f3;stop-opacity:1"/></linearGradient>
<radialGradient id="_Radial3" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-66.1374,0,-0,66.1374,60.5808,63.95)"><stop offset="0" style="stop-color:#3d4ead;stop-opacity:1"/><stop offset="1" style="stop-color:#00c0f3;stop-opacity:1"/></radialGradient>
<radialGradient id="_Radial4" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-52.6361,-107.604,-12.8428,112.241,48.7863,138.585)"><stop offset="0" style="stop-color:#0072e9;stop-opacity:1"/><stop offset="1" style="stop-color:#00fdfe;stop-opacity:1"/></radialGradient>
<radialGradient id="_Radial5" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(4.0052,0.526563,-1.46889,11.3112,56.6669,79.3122)"><stop offset="0" style="stop-color:#153e68;stop-opacity:0.34"/><stop offset="1" style="stop-color:#153e68;stop-opacity:0.01"/></radialGradient>
<radialGradient id="_Radial6" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-10.3568,10.999,26.0381,24.5177,74.5359,78.3911)"><stop offset="0" style="stop-color:#00336f;stop-opacity:1"/><stop offset="1" style="stop-color:#00336f;stop-opacity:0"/></radialGradient>
<radialGradient id="_Radial7" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-6.51962,11.4057,24.5674,14.4231,72.7521,72.772)"><stop offset="0" style="stop-color:#00336f;stop-opacity:0.5"/><stop offset="1" style="stop-color:#00336f;stop-opacity:0"/></radialGradient>
<radialGradient id="_Radial8" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-4.96046,12.1651,26.2531,11.0614,72.05,73.4244)"><stop offset="0" style="stop-color:#00336f;stop-opacity:0.5"/><stop offset="1" style="stop-color:#00336f;stop-opacity:0"/></radialGradient>
<radialGradient id="_Radial9" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-4.22491,10.2622,22.277,9.29717,68.699,71.4404)"><stop offset="0" style="stop-color:#00336f;stop-opacity:1"/><stop offset="1" style="stop-color:#00336f;stop-opacity:0"/></radialGradient>
<radialGradient id="_Radial10" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-9.78901,-10.0451,-28.1355,22.8978,42.6909,72.541)"><stop offset="0" style="stop-color:#002d68;stop-opacity:1"/><stop offset="1" style="stop-color:#002d68;stop-opacity:0"/></radialGradient>
<radialGradient id="_Radial11" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-10.6184,-12.7117,-26.5102,25.0697,42.1289,68.125)"><stop offset="0" style="stop-color:#002d68;stop-opacity:1"/><stop offset="1" style="stop-color:#002d68;stop-opacity:0"/></radialGradient>
<radialGradient id="_Radial12" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-4.66402,-8.96904,-21.2029,10.9396,40.8426,70.2218)"><stop offset="0" style="stop-color:#002d68;stop-opacity:1"/><stop offset="1" style="stop-color:#002d68;stop-opacity:0"/></radialGradient>
<radialGradient id="_Radial13" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(4.51007,-9.04744,-21.3185,-10.7126,31.6527,57.4886)"><stop offset="0" style="stop-color:#002d68;stop-opacity:1"/><stop offset="1" style="stop-color:#002d68;stop-opacity:0"/></radialGradient>
<radialGradient id="_Radial14" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(55.5618,-7.25333,2.08197,15.9483,70.5908,57.3802)"><stop offset="0" style="stop-color:#00326d;stop-opacity:1"/><stop offset="1" style="stop-color:#003b79;stop-opacity:0"/></radialGradient>
<radialGradient id="_Radial15" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(50.0892,5.26339,-1.61895,15.4438,73.3147,51.7397)"><stop offset="0" style="stop-color:#00326d;stop-opacity:1"/><stop offset="1" style="stop-color:#003b79;stop-opacity:0"/></radialGradient>
<radialGradient id="_Radial16" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(42.2509,-5.13094,1.62846,13.3715,70.1175,57.4772)"><stop offset="0" style="stop-color:#00326d;stop-opacity:1"/><stop offset="1" style="stop-color:#003b79;stop-opacity:0"/></radialGradient>
<linearGradient id="_Linear17" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-48.7206,0,-0,48.7206,59.4148,67.2287)"><stop offset="0" style="stop-color:#f5f7fa;stop-opacity:1"/><stop offset="0.53" style="stop-color:#f1f4f2;stop-opacity:1"/><stop offset="1" style="stop-color:#bad7e9;stop-opacity:1"/></linearGradient>
<linearGradient id="_Linear18" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-43.2077,0,-0,43.2077,59.144,39.7308)"><stop offset="0" style="stop-color:#fafafa;stop-opacity:1"/><stop offset="0.26" style="stop-color:#f1f6f8;stop-opacity:1"/><stop offset="0.73" style="stop-color:#dce5eb;stop-opacity:1"/><stop offset="1" style="stop-color:#bbcfda;stop-opacity:1"/></linearGradient>
<linearGradient id="_Linear19" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0,-47.9791,-47.9791,-0,87.2229,64.0313)"><stop offset="0" style="stop-color:#fdfdff;stop-opacity:1"/><stop offset="0.26" style="stop-color:#f1f2f2;stop-opacity:1"/><stop offset="0.73" style="stop-color:#bfd2e0;stop-opacity:1"/><stop offset="1" style="stop-color:#afc0cc;stop-opacity:1"/></linearGradient>
<linearGradient id="_Linear20" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0,-48.0543,-48.0543,-0,86.4289,64.0856)"><stop offset="0" style="stop-color:#f1f6f6;stop-opacity:1"/><stop offset="0.41" style="stop-color:#fdfdfd;stop-opacity:1"/><stop offset="0.55" style="stop-color:#f5f8fa;stop-opacity:1"/><stop offset="0.89" style="stop-color:#d6e1e7;stop-opacity:1"/><stop offset="0.98" style="stop-color:#c3d3dd;stop-opacity:1"/><stop offset="1" style="stop-color:#c3d3dd;stop-opacity:1"/></linearGradient>
<radialGradient id="_Radial21" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(14.7354,9.52776,-4.62893,7.15901,38.0093,52.7366)"><stop offset="0" style="stop-color:#153e68;stop-opacity:1"/><stop offset="1" style="stop-color:#153e68;stop-opacity:0"/></radialGradient>
<radialGradient id="_Radial22" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(13.9988,10.5803,-4.31511,5.70934,37.54,50.7316)"><stop offset="0" style="stop-color:#153e68;stop-opacity:1"/><stop offset="1" style="stop-color:#153e68;stop-opacity:0"/></radialGradient>
<radialGradient id="_Radial23" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(14.5634,-8.14176,3.11074,5.56427,79.858,55.6982)"><stop offset="0" style="stop-color:#153e68;stop-opacity:1"/><stop offset="1" style="stop-color:#153e68;stop-opacity:0"/></radialGradient>
<radialGradient id="_Radial24" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(14.4062,-8.05386,3.42371,6.12408,82.5616,52.4391)"><stop offset="0" style="stop-color:#153e68;stop-opacity:1"/><stop offset="1" style="stop-color:#153e68;stop-opacity:0"/></radialGradient>
<radialGradient id="_Radial25" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(13.5894,-9.36638,4.22241,6.1262,82.3546,55.5213)"><stop offset="0" style="stop-color:#153e68;stop-opacity:1"/><stop offset="1" style="stop-color:#1a426b;stop-opacity:0"/></radialGradient>
<radialGradient id="_Radial26" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(5.21516,-11.6826,5.1171,2.2843,92.4313,44.33)"><stop offset="0" style="stop-color:#153e68;stop-opacity:1"/><stop offset="1" style="stop-color:#1b436c;stop-opacity:0"/></radialGradient>
<linearGradient id="_Linear27" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(4.72457,-33.536,33.536,4.72457,39.1596,60.0944)"><stop offset="0" style="stop-color:#fdfdff;stop-opacity:1"/><stop offset="0.26" style="stop-color:#f1f2f2;stop-opacity:1"/><stop offset="0.73" style="stop-color:#bfd2e0;stop-opacity:1"/><stop offset="1" style="stop-color:#afc0cc;stop-opacity:1"/></linearGradient>
<linearGradient id="_Linear28" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-33.3203,-0.000343575,0.000343575,-33.3203,58.0971,43.372)"><stop offset="0" style="stop-color:#fafafa;stop-opacity:1"/><stop offset="0.26" style="stop-color:#f1f6f8;stop-opacity:1"/><stop offset="0.73" style="stop-color:#dce5eb;stop-opacity:1"/><stop offset="1" style="stop-color:#bbcfda;stop-opacity:1"/></linearGradient>
<radialGradient id="_Radial29" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.92018,5.55941,-10.6179,3.66735,45.0962,69.7332)"><stop offset="0" style="stop-color:#153e68;stop-opacity:1"/><stop offset="1" style="stop-color:#153e68;stop-opacity:0"/></radialGradient>
<radialGradient id="_Radial30" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.21678,5.25887,-9.80783,0.404296,43.3965,68.5313)"><stop offset="0" style="stop-color:#153e68;stop-opacity:1"/><stop offset="1" style="stop-color:#153e68;stop-opacity:0"/></radialGradient>
<radialGradient id="_Radial31" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.54211,3.64848,-8.0801,3.41524,49.9501,70.1915)"><stop offset="0" style="stop-color:#153e68;stop-opacity:1"/><stop offset="1" style="stop-color:#153e68;stop-opacity:0"/></radialGradient>
<linearGradient id="_Linear32" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-12.2342,-17.8556,17.8556,-12.2342,50.4952,72.5871)"><stop offset="0" style="stop-color:#fdfdff;stop-opacity:1"/><stop offset="0.26" style="stop-color:#f1f2f2;stop-opacity:1"/><stop offset="0.73" style="stop-color:#bfd2e0;stop-opacity:1"/><stop offset="1" style="stop-color:#afc0cc;stop-opacity:1"/></linearGradient>
<linearGradient id="_Linear33" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-15.7162,14.3692,-14.3692,-15.7162,52.2159,56.533)"><stop offset="0" style="stop-color:#fafafa;stop-opacity:1"/><stop offset="0.26" style="stop-color:#f1f6f8;stop-opacity:1"/><stop offset="0.73" style="stop-color:#dce5eb;stop-opacity:1"/><stop offset="1" style="stop-color:#bbcfda;stop-opacity:1"/></linearGradient>
<radialGradient id="_Radial34" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-16.9591,0,-0,16.9591,81.3402,72.3216)"><stop offset="0" style="stop-color:#f9f9fa;stop-opacity:1"/><stop offset="1" style="stop-color:#f5f7f7;stop-opacity:1"/></radialGradient>
<radialGradient id="_Radial35" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(8.96408,6.36252,-3.00685,4.23632,68.8193,72.3219)"><stop offset="0" style="stop-color:#153e68;stop-opacity:1"/><stop offset="1" style="stop-color:#153e68;stop-opacity:0"/></radialGradient>
<radialGradient id="_Radial36" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(6.8821,4.88477,-3.00685,4.23632,67.5393,72.3219)"><stop offset="0" style="stop-color:#153e68;stop-opacity:1"/><stop offset="1" style="stop-color:#153e68;stop-opacity:0"/></radialGradient>
<radialGradient id="_Radial37" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(6.8821,4.88477,-3.00685,4.23632,71.3156,72.6152)"><stop offset="0" style="stop-color:#153e68;stop-opacity:1"/><stop offset="1" style="stop-color:#153e68;stop-opacity:0"/></radialGradient>
<linearGradient id="_Linear38" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(18.4986,-11.2373,-11.2373,-18.4986,64.0277,73.4655)"><stop offset="0" style="stop-color:#fdfdff;stop-opacity:1"/><stop offset="0.26" style="stop-color:#f1f2f2;stop-opacity:1"/><stop offset="0.73" style="stop-color:#bfd2e0;stop-opacity:1"/><stop offset="1" style="stop-color:#afc0cc;stop-opacity:1"/></linearGradient>
<linearGradient id="_Linear39" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(8.40915,19.5646,19.5646,-8.40915,69.0669,58.1262)"><stop offset="0" style="stop-color:#fafafa;stop-opacity:1"/><stop offset="0.26" style="stop-color:#f1f6f8;stop-opacity:1"/><stop offset="0.73" style="stop-color:#dce5eb;stop-opacity:1"/><stop offset="1" style="stop-color:#bbcfda;stop-opacity:1"/></linearGradient>
<linearGradient id="_Linear40" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(6.46873,14.3437,14.3437,-6.46873,80.3566,59.6296)"><stop offset="0" style="stop-color:#aebcd0;stop-opacity:1"/><stop offset="0.22" style="stop-color:#859bb9;stop-opacity:1"/><stop offset="0.53" style="stop-color:#a1b1c9;stop-opacity:1"/><stop offset="1" style="stop-color:#97a9c3;stop-opacity:1"/></linearGradient>
<linearGradient id="_Linear41" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0,-21.0692,-21.0692,0,57.0961,88.5161)"><stop offset="0" style="stop-color:#c0cbda;stop-opacity:1"/><stop offset="0.02" style="stop-color:#c0cbda;stop-opacity:1"/><stop offset="0.11" style="stop-color:#d4dbe5;stop-opacity:1"/><stop offset="0.45" style="stop-color:#f5f6f9;stop-opacity:1"/><stop offset="0.59" style="stop-color:#fdfdfd;stop-opacity:1"/><stop offset="1" style="stop-color:#fcfdfd;stop-opacity:1"/></linearGradient>
<radialGradient id="_Radial42" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-18.2184,0,-0,12.4951,60.2241,50.0098)"><stop offset="0" style="stop-color:#3f51b5;stop-opacity:1"/><stop offset="1" style="stop-color:#04bbf3;stop-opacity:1"/></radialGradient>
<linearGradient id="_Linear43" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0,-45.2637,-45.2637,-0,60.1552,68.5313)"><stop offset="0" style="stop-color:#afc0cc;stop-opacity:1"/><stop offset="0.24" style="stop-color:#afc0cc;stop-opacity:1"/><stop offset="0.74" style="stop-color:#f1f2f2;stop-opacity:1"/><stop offset="1" style="stop-color:#fdfdff;stop-opacity:1"/></linearGradient>
<linearGradient id="_Linear44" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0,-46.5257,-46.5257,-0,60.1552,70.1682)"><stop offset="0" style="stop-color:#fafafa;stop-opacity:1"/><stop offset="0.26" style="stop-color:#f1f6f8;stop-opacity:1"/><stop offset="0.73" style="stop-color:#dce5eb;stop-opacity:1"/><stop offset="1" style="stop-color:#bbcfda;stop-opacity:1"/></linearGradient>
<linearGradient id="_Linear45" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0,-39.9686,39.9686,-0,79.5662,62.3429)"><stop offset="0" style="stop-color:#f1f6f6;stop-opacity:1"/><stop offset="0.41" style="stop-color:#fdfdfd;stop-opacity:1"/><stop offset="0.55" style="stop-color:#f5f8fa;stop-opacity:1"/><stop offset="0.89" style="stop-color:#d6e1e7;stop-opacity:1"/><stop offset="0.98" style="stop-color:#c3d3dd;stop-opacity:1"/><stop offset="1" style="stop-color:#c3d3dd;stop-opacity:1"/></linearGradient>
</defs>
</svg>
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
/* eslint-env node */
/*
* This file runs in a Node context (it's NOT transpiled by Babel), so use only
* the ES6 features that are supported by your Node version. https://node.green/
*/
// Configuration for your app
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js
const { configure } = require('quasar/wrappers')
const path = require('path')
module.exports = configure(function (/* ctx */) {
return {
eslint: {
fix: true,
// include = [],
// exclude = [],
// rawOptions = {},
warnings: true,
errors: true
},
// https://v2.quasar.dev/quasar-cli/prefetch-feature
preFetch: true,
// app boot file (/src/boot)
// --> boot files are part of "main.js"
// https://v2.quasar.dev/quasar-cli/boot-files
boot: [
'apollo',
'i18n'
],
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#css
css: [
'app.scss'
],
// https://github.com/quasarframework/quasar/tree/dev/extras
extras: [
// 'ionicons-v4',
// 'mdi-v5',
'fontawesome-v6',
// 'eva-icons',
// 'themify',
'line-awesome',
'roboto-font-latin-ext' // this or either 'roboto-font', NEVER both!
// 'roboto-font', // optional, you are not bound to it
// 'material-icons' // optional, you are not bound to it
],
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#build
build: {
target: {
browser: ['es2019', 'edge88', 'firefox78', 'chrome87', 'safari13.1'],
node: 'node16'
},
vueRouterMode: 'history', // available values: 'hash', 'history'
// vueRouterBase,
// vueDevtools,
vueOptionsAPI: true,
rebuildCache: true, // rebuilds Vite/linter/etc cache on startup
// publicPath: '/',
// analyze: true,
// env: {},
// rawDefine: {}
// ignorePublicFolder: true,
// minify: false,
// polyfillModulePreload: true,
// distDir
// extendViteConf (viteConf) {},
// viteVuePluginOptions: {},
vitePlugins: [
['@intlify/vite-plugin-vue-i18n', {
// if you want to use Vue I18n Legacy API, you need to set `compositionOnly: false`
// compositionOnly: false,
// you need to set i18n resource including paths !
include: path.resolve(__dirname, './src/i18n/locales/**')
}]
]
},
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#devServer
devServer: {
// https: true
open: false, // opens browser window automatically
proxy: {
'/_graphql': 'http://localhost:3000/graphql'
}
},
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#framework
framework: {
config: {
brand: {
header: '#000',
sidebar: '#1976D2'
},
loading: {
delay: 500,
spinner: 'QSpinnerGrid',
spinnerSize: 32,
spinnerColor: 'white'
},
loadingBar: {
color: 'primary',
size: '1px',
position: 'top'
},
notify: {
position: 'top',
progress: true,
color: 'green',
icon: 'las la-check',
actions: [
{
icon: 'las la-times',
color: 'white',
size: 'sm',
round: true,
handler: () => {}
}
]
}
},
iconSet: 'fontawesome-v6', // Quasar icon set
lang: 'en-US', // Quasar language pack
// For special cases outside of where the auto-import strategy can have an impact
// (like functional components as one of the examples),
// you can manually specify Quasar components/directives to be available everywhere:
//
// components: [],
// directives: [],
// Quasar plugins
plugins: [
'Dialog',
'Loading',
'LoadingBar',
'Meta',
'Notify'
]
},
// animations: 'all', // --- includes all animations
// https://v2.quasar.dev/options/animations
animations: [],
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#property-sourcefiles
sourceFiles: {
// rootComponent: 'src/App.vue',
// router: 'src/router/index',
store: 'src/stores/index'
// registerServiceWorker: 'src-pwa/register-service-worker',
// serviceWorker: 'src-pwa/custom-service-worker',
// pwaManifestFile: 'src-pwa/manifest.json',
// electronMain: 'src-electron/electron-main',
// electronPreload: 'src-electron/electron-preload'
},
// https://v2.quasar.dev/quasar-cli/developing-ssr/configuring-ssr
ssr: {
// ssrPwaHtmlFilename: 'offline.html', // do NOT use index.html as name!
// will mess up SSR
// extendSSRWebserverConf (esbuildConf) {},
// extendPackageJson (json) {},
pwa: false,
// manualStoreHydration: true,
// manualPostHydrationTrigger: true,
prodPort: 3000, // The default port that the production server should use
// (gets superseded if process.env.PORT is specified at runtime)
middlewares: [
'render' // keep this as last one
]
},
// https://v2.quasar.dev/quasar-cli/developing-pwa/configuring-pwa
pwa: {
workboxMode: 'generateSW', // or 'injectManifest'
injectPwaMetaTags: true,
swFilename: 'sw.js',
manifestFilename: 'manifest.json',
useCredentialsForManifestTag: false
// extendGenerateSWOptions (cfg) {}
// extendInjectManifestOptions (cfg) {},
// extendManifestJson (json) {}
// extendPWACustomSWConf (esbuildConf) {}
},
// Full list of options: https://v2.quasar.dev/quasar-cli/developing-electron-apps/configuring-electron
electron: {
// extendElectronMainConf (esbuildConf)
// extendElectronPreloadConf (esbuildConf)
inspectPort: 5858,
bundler: 'packager', // 'packager' or 'builder'
packager: {
// https://github.com/electron-userland/electron-packager/blob/master/docs/api.md#options
// OS X / Mac App Store
// appBundleId: '',
// appCategoryType: '',
// osxSign: '',
// protocol: 'myapp://path',
// Windows only
// win32metadata: { ... }
},
builder: {
// https://www.electron.build/configuration/configuration
appId: 'ux'
}
}
}
})
<template>
<router-view />
</template>
<script>
import { defineComponent, nextTick, onMounted } from 'vue'
export default defineComponent({
name: 'App',
setup () {
onMounted(() => {
nextTick(() => {
document.querySelector('.init-loading').remove()
})
})
}
})
</script>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 356 360">
<path
d="M43.4 303.4c0 3.8-2.3 6.3-7.1 6.3h-15v-22h14.4c4.3 0 6.2 2.2 6.2 5.2 0 2.6-1.5 4.4-3.4 5 2.8.4 4.9 2.5 4.9 5.5zm-8-13H24.1v6.9H35c2.1 0 4-1.3 4-3.8 0-2.2-1.3-3.1-3.7-3.1zm5.1 12.6c0-2.3-1.8-3.7-4-3.7H24.2v7.7h11.7c3.4 0 4.6-1.8 4.6-4zm36.3 4v2.7H56v-22h20.6v2.7H58.9v6.8h14.6v2.3H58.9v7.5h17.9zm23-5.8v8.5H97v-8.5l-11-13.4h3.4l8.9 11 8.8-11h3.4l-10.8 13.4zm19.1-1.8V298c0-7.9 5.2-10.7 12.7-10.7 7.5 0 13 2.8 13 10.7v1.4c0 7.9-5.5 10.8-13 10.8s-12.7-3-12.7-10.8zm22.7 0V298c0-5.7-3.9-8-10-8-6 0-9.8 2.3-9.8 8v1.4c0 5.8 3.8 8.1 9.8 8.1 6 0 10-2.3 10-8.1zm37.2-11.6v21.9h-2.9l-15.8-17.9v17.9h-2.8v-22h3l15.6 18v-18h2.9zm37.9 10.2v1.3c0 7.8-5.2 10.4-12.4 10.4H193v-22h11.2c7.2 0 12.4 2.8 12.4 10.3zm-3 0c0-5.3-3.3-7.6-9.4-7.6h-8.4V307h8.4c6 0 9.5-2 9.5-7.7V298zm50.8-7.6h-9.7v19.3h-3v-19.3h-9.7v-2.6h22.4v2.6zm34.4-2.6v21.9h-3v-10.1h-16.8v10h-2.8v-21.8h2.8v9.2H296v-9.2h2.9zm34.9 19.2v2.7h-20.7v-22h20.6v2.7H316v6.8h14.5v2.3H316v7.5h17.8zM24 340.2v7.3h13.9v2.4h-14v9.6H21v-22h20v2.7H24zm41.5 11.4h-9.8v7.9H53v-22h13.3c5.1 0 8 1.9 8 6.8 0 3.7-2 6.3-5.6 7l6 8.2h-3.3l-5.8-8zm-9.8-2.6H66c3.1 0 5.3-1.5 5.3-4.7 0-3.3-2.2-4.1-5.3-4.1H55.7v8.8zm47.9 6.2H89l-2 4.3h-3.2l10.7-22.2H98l10.7 22.2h-3.2l-2-4.3zm-1-2.3l-6.3-13-6 13h12.2zm46.3-15.3v21.9H146v-17.2L135.7 358h-2.1l-10.2-15.6v17h-2.8v-21.8h3l11 16.9 11.3-17h3zm35 19.3v2.6h-20.7v-22h20.6v2.7H166v6.8h14.5v2.3H166v7.6h17.8zm47-19.3l-8.3 22h-3l-7.1-18.6-7 18.6h-3l-8.2-22h3.3L204 356l6.8-18.5h3.4L221 356l6.6-18.5h3.3zm10 11.6v-1.4c0-7.8 5.2-10.7 12.7-10.7 7.6 0 13 2.9 13 10.7v1.4c0 7.9-5.4 10.8-13 10.8-7.5 0-12.7-3-12.7-10.8zm22.8 0v-1.4c0-5.7-4-8-10-8s-9.9 2.3-9.9 8v1.4c0 5.8 3.8 8.2 9.8 8.2 6.1 0 10-2.4 10-8.2zm28.3 2.4h-9.8v7.9h-2.8v-22h13.2c5.2 0 8 1.9 8 6.8 0 3.7-2 6.3-5.6 7l6 8.2h-3.3l-5.8-8zm-9.8-2.6h10.2c3 0 5.2-1.5 5.2-4.7 0-3.3-2.1-4.1-5.2-4.1h-10.2v8.8zm40.3-1.5l-6.8 5.6v6.4h-2.9v-22h2.9v12.3l15.2-12.2h3.7l-9.9 8.1 10.3 13.8h-3.6l-8.9-12z" />
<path fill="#050A14"
d="M188.4 71.7a10.4 10.4 0 01-20.8 0 10.4 10.4 0 1120.8 0zM224.2 45c-2.2-3.9-5-7.5-8.2-10.7l-12 7c-3.7-3.2-8-5.7-12.6-7.3a49.4 49.4 0 00-9.7 13.9 59 59 0 0140.1 14l7.6-4.4a57 57 0 00-5.2-12.5zM178 125.1c4.5 0 9-.6 13.4-1.7v-14a40 40 0 0012.5-7.2 47.7 47.7 0 00-7.1-15.3 59 59 0 01-32.2 27.7v8.7c4.4 1.2 8.9 1.8 13.4 1.8zM131.8 45c-2.3 4-4 8.1-5.2 12.5l12 7a40 40 0 000 14.4c5.7 1.5 11.3 2 16.9 1.5a59 59 0 01-8-41.7l-7.5-4.3c-3.2 3.2-6 6.7-8.2 10.6z" />
<path fill="#00B4FF"
d="M224.2 98.4c2.3-3.9 4-8 5.2-12.4l-12-7a40 40 0 000-14.5c-5.7-1.5-11.3-2-16.9-1.5a59 59 0 018 41.7l7.5 4.4c3.2-3.2 6-6.8 8.2-10.7zm-92.4 0c2.2 4 5 7.5 8.2 10.7l12-7a40 40 0 0012.6 7.3c4-4.1 7.3-8.8 9.7-13.8a59 59 0 01-40-14l-7.7 4.4c1.2 4.3 3 8.5 5.2 12.4zm46.2-80c-4.5 0-9 .5-13.4 1.7V34a40 40 0 00-12.5 7.2c1.5 5.7 4 10.8 7.1 15.4a59 59 0 0132.2-27.7V20a53.3 53.3 0 00-13.4-1.8z" />
<path fill="#00B4FF"
d="M178 9.2a62.6 62.6 0 11-.1 125.2A62.6 62.6 0 01178 9.2m0-9.2a71.7 71.7 0 100 143.5A71.7 71.7 0 00178 0z" />
<path fill="#050A14"
d="M96.6 212v4.3c-9.2-.8-15.4-5.8-15.4-17.8V180h4.6v18.4c0 8.6 4 12.6 10.8 13.5zm16-31.9v18.4c0 8.9-4.3 12.8-10.9 13.5v4.4c9.2-.7 15.5-5.6 15.5-18v-18.3h-4.7zM62.2 199v-2.2c0-12.7-8.8-17.4-21-17.4-12.1 0-20.7 4.7-20.7 17.4v2.2c0 12.8 8.6 17.6 20.7 17.6 1.5 0 3-.1 4.4-.3l11.8 6.2 2-3.3-8.2-4-6.4-3.1a32 32 0 01-3.6.2c-9.8 0-16-3.9-16-13.3v-2.2c0-9.3 6.2-13.1 16-13.1 9.9 0 16.3 3.8 16.3 13.1v2.2c0 5.3-2.1 8.7-5.6 10.8l4.8 2.4c3.4-2.8 5.5-7 5.5-13.2zM168 215.6h5.1L156 179.7h-4.8l17 36zM143 205l7.4-15.7-2.4-5-15.1 31.4h5.1l3.3-7h18.3l-1.8-3.7H143zm133.7 10.7h5.2l-17.3-35.9h-4.8l17 36zm-25-10.7l7.4-15.7-2.4-5-15.1 31.4h5.1l3.3-7h18.3l-1.7-3.7h-14.8zm73.8-2.5c6-1.2 9-5.4 9-11.4 0-8-4.5-10.9-12.9-10.9h-21.4v35.5h4.6v-31.3h16.5c5 0 8.5 1.4 8.5 6.7 0 5.2-3.5 7.7-8.5 7.7h-11.4v4.1h10.7l9.3 12.8h5.5l-9.9-13.2zm-117.4 9.9c-9.7 0-14.7-2.5-18.6-6.3l-2.2 3.8c5.1 5 11 6.7 21 6.7 1.6 0 3.1-.1 4.6-.3l-1.9-4h-3zm18.4-7c0-6.4-4.7-8.6-13.8-9.4l-10.1-1c-6.7-.7-9.3-2.2-9.3-5.6 0-2.5 1.4-4 4.6-5l-1.8-3.8c-4.7 1.4-7.5 4.2-7.5 8.9 0 5.2 3.4 8.7 13 9.6l11.3 1.2c6.4.6 8.9 2 8.9 5.4 0 2.7-2.1 4.7-6 5.8l1.8 3.9c5.3-1.6 8.9-4.7 8.9-10zm-20.3-21.9c7.9 0 13.3 1.8 18.1 5.7l1.8-3.9a30 30 0 00-19.6-5.9c-2 0-4 .1-5.7.3l1.9 4 3.5-.2z" />
<path fill="#00B4FF"
d="M.5 251.9c29.6-.5 59.2-.8 88.8-1l88.7-.3 88.7.3 44.4.4 44.4.6-44.4.6-44.4.4-88.7.3-88.7-.3a7981 7981 0 01-88.8-1z" />
<path fill="none" d="M-565.2 324H-252v15.8h-313.2z" />
</svg>
\ No newline at end of file
import { boot } from 'quasar/wrappers'
import { createApolloProvider } from '@vue/apollo-option'
import { ApolloClient, InMemoryCache } from '@apollo/client/core'
import { setContext } from '@apollo/client/link/context'
import { createUploadLink } from 'apollo-upload-client'
export default boot(({ app }) => {
// Authentication Link
const authLink = setContext(async (req, { headers }) => {
const token = 'test' // await window.auth0Client.getTokenSilently()
return {
headers: {
...headers,
Authorization: token ? `Bearer ${token}` : ''
}
}
})
// Upload / HTTP Link
const uploadLink = createUploadLink({
uri () {
return '/_graphql'
}
})
// Cache
const cache = new InMemoryCache()
if (typeof window !== 'undefined') {
const state = window.__APOLLO_STATE__
if (state) {
cache.restore(state.defaultClient)
}
}
// Client
const client = new ApolloClient({
cache,
link: authLink.concat(uploadLink),
credentials: 'omit',
ssrForceFetchDelay: 100
})
// Init Vue Apollo
const apolloProvider = createApolloProvider({
defaultClient: client
})
if (import.meta.env.SSR) {
global.APOLLO_CLIENT = client
} else {
window.APOLLO_CLIENT = client
}
app.use(apolloProvider)
})
import { boot } from 'quasar/wrappers'
import { createI18n } from 'vue-i18n'
import messages from 'src/i18n'
export default boot(({ app }) => {
const i18n = createI18n({
legacy: false,
locale: 'en-US',
allowComposition: true,
messages
})
// Set i18n instance on app
app.use(i18n)
})
<template lang='pug'>
q-btn.q-ml-md(flat, round, dense, color='grey')
q-icon(v-if='!user.picture', name='las la-user-circle')
q-avatar(v-else)
img(:src='user.picture')
q-menu(auto-close)
q-card(flat, style='width: 300px;', :dark='false')
q-card-section(align='center')
.text-subtitle1.text-grey-7 {{user.name}}
.text-caption.text-grey-8 {{user.email}}
q-separator(:dark='false')
q-card-actions(align='center')
q-btn(
flat
label='Profile'
icon='las la-user-alt'
color='primary'
to='/p'
no-caps
)
q-btn(flat
label='Logout'
icon='las la-sign-out-alt'
color='red'
href='/logout'
no-caps
)
q-tooltip Account
</template>
<script>
export default {
name: 'AccountMenu',
data () {
return {
user: {
name: 'John Doe',
email: 'test@example.com',
picture: null
}
}
}
}
</script>
<template lang="pug">
div(style='max-width: 760px;')
Player(controls)
Youtube(video-id='DyTCOwB0DVw', :autoplay='0')
//- DefaultUi(noControls)
//- DefaultControls(
//- hideOnMouseLeave
//- :activeDuration='2000'
//- )
</template>
<script>
import '@vime/core/themes/default.css'
import { Player, Video, DefaultUi, DefaultControls, Youtube } from '@vime/vue-next'
export default {
components: {
Player,
Video,
DefaultUi,
DefaultControls,
Youtube
}
}
</script>
<template lang='pug'>
q-item-section(avatar)
q-avatar.blueprint-icon(
:color='avatarBgColor'
:text-color='avatarTextColor'
font-size='14px'
rounded
:style='hueRotate !== 0 ? `filter: hue-rotate(` + hueRotate + `deg)` : ``'
)
q-badge(
v-if='indicatorDot'
rounded
:color='indicatorDot'
floating
)
q-tooltip(v-if='indicatorText') {{indicatorText}}
q-icon(
v-if='!textMode'
:name='`img:/_assets/icons/ultraviolet-` + icon + `.svg`'
size='sm'
)
span.text-uppercase(v-else) {{text}}
</template>
<script>
export default {
name: 'BlueprintIcon',
props: {
icon: {
type: String,
default: ''
},
dark: {
type: Boolean,
default: false
},
indicator: {
type: String,
default: null
},
indicatorText: {
type: String,
default: null
},
hueRotate: {
type: Number,
default: 0
},
text: {
type: String,
default: null
}
},
data () {
return {
imgPath: null
}
},
computed: {
textMode () { return this.text !== null },
avatarBgColor () { return this.$q.dark.isActive || this.dark ? 'dark-4' : 'blue-1' },
avatarTextColor () { return this.$q.dark.isActive || this.dark ? 'white' : 'blue-7' },
indicatorDot () {
if (this.indicator === null) { return null }
return (this.indicator === '') ? 'pink' : this.indicator
}
}
}
</script>
<template lang="pug">
.channel-container
.channel-sidebar
q-card.rounded-borders.bg-dark
q-list(
padding
dark
)
q-item(
v-for='ch of channels'
:key='ch.id'
active-class='bg-primary text-white'
:active='selectedChannel === ch.id'
@click='selectedChannel = ch.id'
clickable
)
q-item-section(side)
q-icon(name='las la-grip-lines')
q-item-section
q-item-label
span #&nbsp;
strong {{ch.name}}
q-item-label(caption) {{ch.description}}
//- q-item-section(side)
//- q-badge(color='accent', label='0')
q-btn.q-mt-sm.full-width(
color='primary'
icon='las la-plus'
:label='$t(`Add Channel`)'
no-caps
)
.channel-main
</template>
<script>
export default {
data () {
return {
selectedChannel: 'xyz',
channels: [
{
id: 'xyz',
name: 'general',
description: 'General discussions super long stuff'
},
{
id: 'yas',
name: 'random',
description: 'Unrelated / fun stuff'
},
{
id: 'asd',
name: 'devs',
description: 'Developer only'
}
]
}
}
}
</script>
<style lang="scss">
.channel {
&-container {
display: flex;
height: 100%;
}
&-sidebar {
width: 300px;
flex: 0 0 300px;
padding: 16px;
}
&-main {
background-color: #FFF;
flex: 1;
}
}
</style>
<template lang="pug">
.quill-container
</template>
<script>
export default {
data () {
return {
}
}
}
</script>
<template lang="pug">
.wysiwyg-container
.wysiwyg-toolbar(v-if='editor')
template(v-for='menuItem of menuBar')
q-separator.q-mx-xs(
v-if='menuItem.type === `divider`'
vertical
)
q-btn(
v-else-if='menuItem.type === `dropdown`'
:key='menuItem.key'
flat
:icon='menuItem.icon'
padding='xs'
:class='{ "is-active": menuItem.isActive && menuItem.isActive() }'
:color='menuItem.isActive && menuItem.isActive() ? `primary` : `grey-10`'
:aria-label='menuItem.title'
split
:disabled='menuItem.disabled && menuItem.disabled()'
)
q-menu
q-list(
dense
padding
)
template(v-for='child of menuItem.children')
q-separator.q-my-sm(v-if='child.type === `divider`')
q-item(
v-else
:key='menuItem.key + `-` + child.key'
clickable
@click='child.action'
:active='child.isActive && child.isActive()'
active-class='text-primary'
:disabled='child.disabled && child.disabled()'
)
q-item-section(side)
q-icon(
:name='child.icon'
:color='child.color'
)
q-item-section
q-item-label {{child.title}}
q-btn-group(
v-else-if='menuItem.type === `btngroup`'
:key='menuItem.key'
flat
)
q-btn(
v-for='child of menuItem.children'
:key='menuItem.key + `-` + child.key'
flat
:icon='child.icon'
padding='xs'
:class='{ "is-active": child.isActive && child.isActive() }'
:color='child.isActive && child.isActive() ? `primary` : `grey-10`'
@click='child.action'
:aria-label='child.title'
:disabled='menuItem.disabled && menuItem.disabled()'
)
q-btn(
v-else
flat
:icon='menuItem.icon'
padding='xs'
:class='{ "is-active": menuItem.isActive && menuItem.isActive() }'
:color='menuItem.isActive && menuItem.isActive() ? `primary` : `grey-10`'
@click='menuItem.action'
:aria-label='menuItem.title'
:disabled='menuItem.disabled && menuItem.disabled()'
)
q-space
q-btn(
size='sm'
unelevated
color='red'
label='Test'
@click='snapshot'
)
q-scroll-area(
:thumb-style='thumbStyle'
:bar-style='barStyle'
style='height: 100%;'
)
editor-content(:editor='editor')
</template>
<script>
import { Editor, EditorContent } from '@tiptap/vue-3'
import StarterKit from '@tiptap/starter-kit'
// import Collaboration from '@tiptap/extension-collaboration'
import CodeBlockLowlight from '@tiptap/extension-code-block-lowlight'
import { Color } from '@tiptap/extension-color'
import FontFamily from '@tiptap/extension-font-family'
import Highlight from '@tiptap/extension-highlight'
import Image from '@tiptap/extension-image'
import Mention from '@tiptap/extension-mention'
import Placeholder from '@tiptap/extension-placeholder'
import Table from '@tiptap/extension-table'
import TableRow from '@tiptap/extension-table-row'
import TableCell from '@tiptap/extension-table-cell'
import TableHeader from '@tiptap/extension-table-header'
import TaskList from '@tiptap/extension-task-list'
import TaskItem from '@tiptap/extension-task-item'
import TextAlign from '@tiptap/extension-text-align'
import TextStyle from '@tiptap/extension-text-style'
import Typography from '@tiptap/extension-typography'
// import * as Y from 'yjs'
// import { IndexeddbPersistence } from 'y-indexeddb'
// import { WebsocketProvider } from 'y-websocket'
export default {
components: {
EditorContent
},
data () {
return {
editor: null,
ydoc: null,
thumbStyle: {
right: '2px',
borderRadius: '5px',
backgroundColor: '#000',
width: '5px',
opacity: 0.15
},
barStyle: {
backgroundColor: '#FAFAFA',
width: '9px',
opacity: 1
},
menuBar: [
{
key: 'bold',
icon: 'mdi-format-bold',
title: 'Bold',
action: () => this.editor.chain().focus().toggleBold().run(),
isActive: () => this.editor.isActive('bold')
},
{
key: 'italic',
icon: 'mdi-format-italic',
title: 'Italic',
action: () => this.editor.chain().focus().toggleItalic().run(),
isActive: () => this.editor.isActive('italic')
},
{
key: 'strikethrough',
icon: 'mdi-format-strikethrough',
title: 'Strike',
action: () => this.editor.chain().focus().toggleStrike().run(),
isActive: () => this.editor.isActive('strike')
},
{
key: 'code',
icon: 'mdi-code-tags',
title: 'Code',
action: () => this.editor.chain().focus().toggleCode().run(),
isActive: () => this.editor.isActive('code')
},
{
key: 'fontfamily',
icon: 'mdi-format-font',
title: 'Font Family',
type: 'dropdown',
isActive: () => this.editor.isActive('fontFamily'),
children: [
{
key: 'fontunset',
icon: 'mdi-format-font',
title: 'Sans-Serif',
action: () => this.editor.chain().focus().unsetFontFamily().run()
},
{
key: 'monospace',
icon: 'mdi-format-font',
title: 'Monospace',
action: () => this.editor.chain().focus().setFontFamily('monospace').run()
}
]
},
{
key: 'color',
icon: 'mdi-palette',
title: 'Text Color',
type: 'dropdown',
isActive: () => this.editor.isActive('color'),
children: [
{
key: 'blue',
icon: 'mdi-palette',
title: 'Blue',
color: 'blue',
action: () => this.editor.chain().focus().toggleHighlight().run()
},
{
key: 'brown',
icon: 'mdi-palette',
title: 'Brown',
color: 'brown',
action: () => this.editor.chain().focus().toggleHighlight().run()
},
{
key: 'green',
icon: 'mdi-palette',
title: 'Green',
color: 'green',
action: () => this.editor.chain().focus().toggleHighlight().run()
},
{
key: 'orange',
icon: 'mdi-palette',
title: 'Orange',
color: 'orange',
action: () => this.editor.chain().focus().toggleHighlight().run()
},
{
key: 'pink',
icon: 'mdi-palette',
title: 'Pink',
color: 'pink',
action: () => this.editor.chain().focus().toggleHighlight().run()
},
{
key: 'purple',
icon: 'mdi-palette',
title: 'Purple',
color: 'purple',
action: () => this.editor.chain().focus().toggleHighlight().run()
},
{
key: 'red',
icon: 'mdi-palette',
title: 'Red',
color: 'red',
action: () => this.editor.chain().focus().toggleHighlight().run()
},
{
key: 'teal',
icon: 'mdi-palette',
title: 'Teal',
color: 'teal',
action: () => this.editor.chain().focus().toggleHighlight().run()
},
{
key: 'yellow',
icon: 'mdi-palette',
title: 'Yellow',
color: 'yellow',
action: () => this.editor.chain().focus().toggleHighlight().run()
},
{
type: 'divider'
},
{
key: 'remove',
icon: 'mdi-water-off',
title: 'Default',
color: 'grey',
action: () => this.editor.chain().focus().unsetHighlight().run()
}
]
},
{
key: 'highlight',
icon: 'mdi-marker',
title: 'Highlight',
type: 'dropdown',
isActive: () => this.editor.isActive('highlight'),
children: [
{
key: 'yellow',
icon: 'mdi-marker',
title: 'Yellow',
color: 'yellow',
action: () => this.editor.chain().focus().toggleHighlight().run()
},
{
key: 'blue',
icon: 'mdi-marker',
title: 'Blue',
color: 'blue',
action: () => this.editor.chain().focus().toggleHighlight().run()
},
{
key: 'pink',
icon: 'mdi-marker',
title: 'Pink',
color: 'pink',
action: () => this.editor.chain().focus().toggleHighlight().run()
},
{
key: 'green',
icon: 'mdi-marker',
title: 'Green',
color: 'green',
action: () => this.editor.chain().focus().toggleHighlight().run()
},
{
key: 'orange',
icon: 'mdi-marker',
title: 'Orange',
color: 'orange',
action: () => this.editor.chain().focus().toggleHighlight().run()
},
{
type: 'divider'
},
{
key: 'remove',
icon: 'mdi-marker-cancel',
title: 'Remove',
color: 'grey',
action: () => this.editor.chain().focus().unsetHighlight().run()
}
]
},
{
type: 'divider'
},
{
key: 'header',
icon: 'mdi-format-header-pound',
title: 'Header',
type: 'dropdown',
isActive: () => this.editor.isActive('heading'),
children: [
{
key: 'h1',
icon: 'mdi-format-header-1',
title: 'Header 1',
action: () => this.editor.chain().focus().toggleHeading({ level: 1 }).run(),
isActive: () => this.editor.isActive('heading', { level: 1 })
},
{
key: 'h2',
icon: 'mdi-format-header-2',
title: 'Header 2',
action: () => this.editor.chain().focus().toggleHeading({ level: 2 }).run(),
isActive: () => this.editor.isActive('heading', { level: 2 })
},
{
key: 'h3',
icon: 'mdi-format-header-3',
title: 'Header 3',
action: () => this.editor.chain().focus().toggleHeading({ level: 3 }).run(),
isActive: () => this.editor.isActive('heading', { level: 3 })
},
{
key: 'h4',
icon: 'mdi-format-header-4',
title: 'Header 4',
action: () => this.editor.chain().focus().toggleHeading({ level: 4 }).run(),
isActive: () => this.editor.isActive('heading', { level: 4 })
},
{
key: 'h5',
icon: 'mdi-format-header-5',
title: 'Header 5',
action: () => this.editor.chain().focus().toggleHeading({ level: 5 }).run(),
isActive: () => this.editor.isActive('heading', { level: 5 })
},
{
key: 'h6',
icon: 'mdi-format-header-6',
title: 'Header 6',
action: () => this.editor.chain().focus().toggleHeading({ level: 6 }).run(),
isActive: () => this.editor.isActive('heading', { level: 6 })
}
]
},
{
key: 'paragraph',
icon: 'mdi-format-paragraph',
title: 'Paragraph',
action: () => this.editor.chain().focus().setParagraph().run(),
isActive: () => this.editor.isActive('paragraph')
},
{
type: 'divider'
},
{
key: 'align',
type: 'btngroup',
children: [
{
key: 'left',
icon: 'mdi-format-align-left',
title: 'Left Align',
action: () => this.editor.chain().focus().setTextAlign('left').run(),
isActive: () => this.editor.isActive({ textAlign: 'left' })
},
{
key: 'center',
icon: 'mdi-format-align-center',
title: 'Center Align',
action: () => this.editor.chain().focus().setTextAlign('center').run(),
isActive: () => this.editor.isActive({ textAlign: 'center' })
},
{
key: 'right',
icon: 'mdi-format-align-right',
title: 'Right Align',
action: () => this.editor.chain().focus().setTextAlign('right').run(),
isActive: () => this.editor.isActive({ textAlign: 'right' })
},
{
key: 'justify',
icon: 'mdi-format-align-justify',
title: 'Justify Align',
action: () => this.editor.chain().focus().setTextAlign('justify').run(),
isActive: () => this.editor.isActive({ textAlign: 'justify' })
}
]
},
{
type: 'divider'
},
{
key: 'bulletlist',
icon: 'mdi-format-list-bulleted',
title: 'Bullet List',
action: () => this.editor.chain().focus().toggleBulletList().run(),
isActive: () => this.editor.isActive('bulletList')
},
{
key: 'orderedlist',
icon: 'mdi-format-list-numbered',
title: 'Ordered List',
action: () => this.editor.chain().focus().toggleOrderedList().run(),
isActive: () => this.editor.isActive('orderedList')
},
{
key: 'tasklist',
icon: 'mdi-format-list-checkbox',
title: 'Task List',
action: () => this.editor.chain().focus().toggleTaskList().run(),
isActive: () => this.editor.isActive('taskList')
},
{
type: 'divider'
},
{
key: 'codeblock',
icon: 'mdi-code-json',
title: 'Code Block',
action: () => this.editor.chain().focus().toggleCodeBlock().run(),
isActive: () => this.editor.isActive('codeBlock')
},
{
key: 'blockquote',
icon: 'mdi-format-quote-close',
title: 'Blockquote',
action: () => this.editor.chain().focus().toggleBlockquote().run(),
isActive: () => this.editor.isActive('blockquote')
},
{
key: 'rule',
icon: 'mdi-minus',
title: 'Horizontal Rule',
action: () => this.editor.chain().focus().setHorizontalRule().run()
},
{
key: 'link',
icon: 'mdi-link-plus',
title: 'Link',
action: () => {
// TODO: insert link
}
},
{
key: 'image',
icon: 'mdi-image-plus',
title: 'Image',
action: () => {
// TODO: insert image
}
},
{
key: 'table',
icon: 'mdi-table-large',
title: 'Table',
type: 'dropdown',
isActive: () => this.editor.isActive('table'),
children: [
{
key: 'insert',
icon: 'mdi-table-large-plus',
title: 'Insert Table',
action: () => this.editor.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run()
},
{
type: 'divider'
},
{
key: 'addcolumnbefore',
icon: 'mdi-table-column-plus-before',
title: 'Add Column Before',
action: () => this.editor.chain().focus().addColumnBefore().run(),
disabled: () => !this.editor.can().addColumnBefore()
},
{
key: 'addcolumnafter',
icon: 'mdi-table-column-plus-after',
title: 'Add Column After',
action: () => this.editor.chain().focus().addColumnAfter().run(),
disabled: () => !this.editor.can().addColumnAfter()
},
{
key: 'deletecolumn',
icon: 'mdi-table-column-remove',
title: 'Remove Column',
action: () => this.editor.chain().focus().deleteColumn().run(),
disabled: () => !this.editor.can().deleteColumn()
},
{
type: 'divider'
},
{
key: 'addrowbefore',
icon: 'mdi-table-row-plus-before',
title: 'Add Row Before',
action: () => this.editor.chain().focus().addRowBefore().run(),
disabled: () => !this.editor.can().addRowBefore()
},
{
key: 'addrowafter',
icon: 'mdi-table-row-plus-after',
title: 'Add Row After',
action: () => this.editor.chain().focus().addRowAfter().run(),
disabled: () => !this.editor.can().addRowAfter()
},
{
key: 'deleterow',
icon: 'mdi-table-row-remove',
title: 'Remove Row',
action: () => this.editor.chain().focus().deleteRow().run(),
disabled: () => !this.editor.can().deleteRow()
},
{
type: 'divider'
},
{
key: 'merge',
icon: 'mdi-table-merge-cells',
title: 'Merge Cells',
action: () => this.editor.chain().focus().mergeCells().run(),
disabled: () => !this.editor.can().mergeCells()
},
{
key: 'split',
icon: 'mdi-table-split-cell',
title: 'Split Cell',
action: () => this.editor.chain().focus().splitCell().run(),
disabled: () => !this.editor.can().splitCell()
},
{
type: 'divider'
},
{
key: 'toggleHeaderColumn',
icon: 'mdi-table-column',
title: 'Toggle Header Column',
action: () => this.editor.chain().focus().toggleHeaderColumn().run(),
disabled: () => !this.editor.can().toggleHeaderColumn()
},
{
key: 'toggleHeaderRow',
icon: 'mdi-table-row',
title: 'Toggle Header Row',
action: () => this.editor.chain().focus().toggleHeaderRow().run(),
disabled: () => !this.editor.can().toggleHeaderRow()
},
{
key: 'toggleHeaderCell',
icon: 'mdi-crop-square',
title: 'Toggle Header Cell',
action: () => this.editor.chain().focus().toggleHeaderCell().run(),
disabled: () => !this.editor.can().toggleHeaderCell()
},
{
type: 'divider'
},
{
key: 'fix',
icon: 'mdi-table-heart',
title: 'Fix Table',
action: () => this.editor.chain().focus().fixTables().run(),
disabled: () => !this.editor.can().fixTables()
},
{
key: 'remove',
icon: 'mdi-table-large-remove',
title: 'Delete Table',
action: () => this.editor.chain().focus().deleteTable().run(),
disabled: () => !this.editor.can().deleteTable()
}
]
},
{
type: 'divider'
},
{
key: 'pagebreak',
icon: 'mdi-format-page-break',
title: 'Hard Break',
action: () => this.editor.chain().focus().setHardBreak().run()
},
{
key: 'clearformat',
icon: 'mdi-format-clear',
title: 'Clear Format',
action: () => this.editor.chain()
.focus()
.clearNodes()
.unsetAllMarks()
.run()
},
{
type: 'divider'
},
{
key: 'undo',
icon: 'mdi-undo-variant',
title: 'Undo',
action: () => this.editor.chain().focus().undo().run(),
disabled: () => !this.editor.can().undo()
},
{
key: 'redo',
icon: 'mdi-redo-variant',
title: 'Redo',
action: () => this.editor.chain().focus().redo().run(),
disabled: () => !this.editor.can().redo()
}
]
}
},
mounted () {
if (!import.meta.env.SSR) {
this.init()
}
},
beforeUnmount () {
this.editor.destroy()
},
methods: {
init () {
console.info('BOOP')
// this.ydoc = new Y.Doc()
/* eslint-disable no-unused-vars */
// const dbProvider = new IndexeddbPersistence('example-document', this.ydoc)
// const wsProvider = new WebsocketProvider('ws://127.0.0.1:1234', 'example-document', this.ydoc)
/* eslint-enable no-unused-vars */
this.editor = new Editor({
content: this.$store.get('page/render'),
extensions: [
StarterKit.configure({
codeBlock: false,
history: {
depth: 500
}
}),
CodeBlockLowlight,
Color,
// Collaboration.configure({
// document: this.ydoc
// }),
FontFamily,
Highlight.configure({
multicolor: true
}),
Image,
Mention.configure({
// TODO: suggestions
}),
Placeholder.configure({
placeholder: 'Enter some content here...'
}),
Table.configure({
resizable: true
}),
TableRow,
TableHeader,
TableCell,
TaskList,
TaskItem,
TextAlign,
TextStyle,
Typography
],
onUpdate: () => {
this.$store.set('page/render', this.editor.getHTML())
}
})
},
insertTable () {
// this.ql.getModule('table').insertTable(3, 3)
},
snapshot () {
// console.info(Y.encodeStateVector(this.ydoc))
}
}
}
</script>
<style lang="scss">
.wysiwyg-container {
height: calc(100% - 41px);
.wysiwyg-toolbar {
border: none;
border-bottom: 1px solid $grey-4;
display: flex;
align-items: center;
padding: 4px;
background: linear-gradient(to top, $grey-1 0%, #FFF 100%);
}
.ProseMirror {
padding: 16px;
min-height: 75vh;
&-focused {
border: none;
outline: none;
}
> * + * {
margin-top: 0.75em;
}
ul,
ol {
padding: 0 1rem;
}
h1,
h2,
h3,
h4,
h5,
h6 {
line-height: 1.1;
}
code {
background-color: rgba(#616161, 0.1);
color: #616161;
}
pre {
background: #0D0D0D;
color: #FFF;
font-family: 'JetBrainsMono', monospace;
padding: 0.75rem 1rem;
border-radius: 0.5rem;
code {
color: inherit;
padding: 0;
background: none;
font-size: 0.8rem;
}
}
img {
max-width: 100%;
height: auto;
}
blockquote {
padding-left: 1rem;
border-left: 2px solid rgba(#0D0D0D, 0.1);
}
hr {
border: none;
border-top: 2px solid rgba(#0D0D0D, 0.1);
margin: 2rem 0;
}
table {
border-collapse: collapse;
table-layout: fixed;
width: 100%;
margin: 0;
overflow: hidden;
td,
th {
min-width: 1em;
border: 2px solid #ced4da;
padding: 3px 5px;
vertical-align: top;
box-sizing: border-box;
position: relative;
> * {
margin-bottom: 0;
}
}
th {
font-weight: bold;
text-align: left;
background-color: #f1f3f5;
}
.selectedCell:after {
z-index: 2;
position: absolute;
content: "";
left: 0; right: 0; top: 0; bottom: 0;
background: rgba(200, 200, 255, 0.4);
pointer-events: none;
}
.column-resize-handle {
position: absolute;
right: -2px;
top: 0;
bottom: -2px;
width: 4px;
background-color: #adf;
pointer-events: none;
}
}
.tableWrapper {
overflow-x: auto;
}
.resize-cursor {
cursor: ew-resize;
cursor: col-resize;
}
ul[data-type="taskList"] {
list-style: none;
padding: 0;
li {
display: flex;
align-items: center;
> label {
flex: 0 0 auto;
margin-right: 0.5rem;
}
}
}
p.is-editor-empty:first-child::before {
content: attr(data-placeholder);
float: left;
color: #ced4da;
pointer-events: none;
height: 0;
}
}
}
</style>
<template lang="pug">
q-dialog(ref='dialog', @hide='onDialogHide', persistent)
q-card(style='min-width: 350px; max-width: 550px;')
q-card-section.card-header
q-icon(name='img:/_assets/icons/ultraviolet-github.svg', left, size='sm')
span {{$t(`admin.storage.githubSetupInstallApp`)}}
q-card-section
.text-body2 {{$t(`admin.storage.githubSetupInstallAppInfo`)}}
.text-body2.q-mt-md: strong.text-deep-orange {{$t('admin.storage.githubSetupInstallAppSelect')}}
.text-body2.q-mt-md {{$t(`admin.storage.githubSetupInstallAppReturn`)}}
q-card-actions.card-actions
q-space
q-btn(
unelevated
:label='$t(`admin.storage.githubSetupContinue`)'
color='positive'
padding='xs md'
@click='confirm'
)
</template>
<script>
export default {
emits: ['ok', 'hide'],
data () {
return {
}
},
methods: {
show () {
this.$refs.dialog.show()
},
hide () {
this.$refs.dialog.hide()
},
onDialogHide () {
this.$emit('hide')
},
confirm () {
this.$emit('ok')
this.hide()
}
}
}
</script>
<template lang="pug">
q-dialog(ref='dialog', @hide='onDialogHide')
q-card(style='min-width: 450px;')
q-card-section.card-header
q-icon(name='img:/_assets/icons/fluent-plus-plus.svg', left, size='sm')
span {{$t(`admin.groups.create`)}}
q-form.q-py-sm(ref='createGroupForm', @submit='create')
q-item
blueprint-icon(icon='team')
q-item-section
q-input(
outlined
v-model='groupName'
dense
:rules=`[
val => val.length > 0 || $t('admin.groups.nameMissing'),
val => /^[^<>"]+$/.test(val) || $t('admin.groups.nameInvalidChars')
]`
hide-bottom-space
:label='$t(`common.field.name`)'
:aria-label='$t(`common.field.name`)'
lazy-rules='ondemand'
autofocus
)
q-card-actions.card-actions
q-space
q-btn.acrylic-btn(
flat
:label='$t(`common.actions.cancel`)'
color='grey'
padding='xs md'
@click='hide'
)
q-btn(
unelevated
:label='$t(`common.actions.create`)'
color='primary'
padding='xs md'
@click='create'
:loading='isLoading'
)
</template>
<script>
import gql from 'graphql-tag'
export default {
emits: ['ok', 'hide'],
data () {
return {
groupName: '',
isLoading: false
}
},
methods: {
show () {
this.$refs.dialog.show()
},
hide () {
this.$refs.dialog.hide()
},
onDialogHide () {
this.$emit('hide')
},
async create () {
this.isLoading = true
try {
const isFormValid = await this.$refs.createGroupForm.validate(true)
if (!isFormValid) {
throw new Error(this.$t('admin.groups.createInvalidData'))
}
const resp = await this.$apollo.mutate({
mutation: gql`
mutation createGroup (
$name: String!
) {
createGroup(
name: $name
) {
status {
succeeded
message
}
}
}
`,
variables: {
name: this.groupName
}
})
if (resp?.data?.createGroup?.status?.succeeded) {
this.$q.notify({
type: 'positive',
message: this.$t('admin.groups.createSuccess')
})
this.$emit('ok')
this.hide()
} else {
throw new Error(resp?.data?.createGroup?.status?.message || 'An unexpected error occured.')
}
} catch (err) {
this.$q.notify({
type: 'negative',
message: err.message
})
}
this.isLoading = false
}
}
}
</script>
<template lang="pug">
q-dialog(ref='dialog', @hide='onDialogHide')
q-card(style='min-width: 350px; max-width: 450px;')
q-card-section.card-header
q-icon(name='img:/_assets/icons/fluent-delete-bin.svg', left, size='sm')
span {{$t(`admin.groups.delete`)}}
q-card-section
.text-body2
i18n-t(keypath='admin.groups.deleteConfirm')
template(#groupName)
strong {{group.name}}
.text-body2.q-mt-md
strong.text-negative {{$t(`admin.groups.deleteConfirmWarn`)}}
q-card-actions.card-actions
q-space
q-btn.acrylic-btn(
flat
:label='$t(`common.actions.cancel`)'
color='grey'
padding='xs md'
@click='hide'
)
q-btn(
unelevated
:label='$t(`common.actions.delete`)'
color='negative'
padding='xs md'
@click='confirm'
)
</template>
<script>
import gql from 'graphql-tag'
export default {
props: {
group: {
type: Object,
required: true
}
},
emits: ['ok', 'hide'],
data () {
return {
}
},
methods: {
show () {
this.$refs.dialog.show()
},
hide () {
this.$refs.dialog.hide()
},
onDialogHide () {
this.$emit('hide')
},
async confirm () {
try {
const resp = await this.$apollo.mutate({
mutation: gql`
mutation deleteGroup ($id: UUID!) {
deleteGroup(id: $id) {
status {
succeeded
message
}
}
}
`,
variables: {
id: this.group.id
}
})
if (resp?.data?.deleteGroup?.status?.succeeded) {
this.$q.notify({
type: 'positive',
message: this.$t('admin.groups.deleteSuccess')
})
this.$emit('ok')
this.hide()
} else {
throw new Error(resp?.data?.deleteGroup?.status?.message || 'An unexpected error occured.')
}
} catch (err) {
this.$q.notify({
type: 'negative',
message: err.message
})
}
}
}
}
</script>
<template lang="pug">
q-layout(view='hHh lpR fFf', container)
q-header.card-header.q-px-md.q-py-sm
q-icon(name='img:/_assets/icons/fluent-people.svg', left, size='md')
div
span {{$t(`admin.groups.edit`)}}
.text-caption {{group.name}}
q-space
q-btn-group(push)
q-btn(
push
color='grey-6'
text-color='white'
:aria-label='$t(`common.actions.refresh`)'
icon='las la-redo-alt'
@click='refresh'
)
q-tooltip(anchor='center left', self='center right') {{$t(`common.actions.refresh`)}}
q-btn(
push
color='white'
text-color='grey-7'
:label='$t(`common.actions.close`)'
icon='las la-times'
@click='close'
)
q-btn(
push
color='positive'
text-color='white'
:label='$t(`common.actions.save`)'
icon='las la-check'
)
q-drawer.bg-dark-6(:model-value='true', :width='250', dark)
q-list(padding, v-show='!isLoading')
q-item(
v-for='sc of sections'
:key='`section-` + sc.key'
clickable
:to='{ params: { section: sc.key } }'
active-class='bg-primary text-white'
:disabled='sc.disabled'
)
q-item-section(side)
q-icon(:name='sc.icon', color='white')
q-item-section {{sc.text}}
q-item-section(side, v-if='sc.usersTotal')
q-badge(color='dark-3', :label='usersTotal')
q-item-section(side, v-if='sc.rulesTotal && group.rules')
q-badge(color='dark-3', :label='group.rules.length')
q-page-container
q-page(v-if='isLoading')
//- -----------------------------------------------------------------------
//- OVERVIEW
//- -----------------------------------------------------------------------
q-page(v-else-if='$route.params.section === `overview`')
.q-pa-md
.row.q-col-gutter-md
.col-12.col-lg-8
q-card.shadow-1.q-pb-sm
q-card-section
.text-subtitle1 {{$t('admin.groups.general')}}
q-item
blueprint-icon(icon='team')
q-item-section
q-item-label {{$t(`admin.groups.name`)}}
q-item-label(caption) {{$t(`admin.groups.nameHint`)}}
q-item-section
q-input(
outlined
v-model='group.name'
dense
:rules=`[
val => /^[^<>"]+$/.test(val) || $t('admin.groups.nameInvalidChars')
]`
hide-bottom-space
:aria-label='$t(`admin.groups.name`)'
)
q-card.shadow-1.q-pb-sm.q-mt-md
q-card-section
.text-subtitle1 {{$t('admin.groups.authBehaviors')}}
q-item
blueprint-icon(icon='double-right')
q-item-section
q-item-label {{$t(`admin.groups.redirectOnLogin`)}}
q-item-label(caption) {{$t(`admin.groups.redirectOnLoginHint`)}}
q-item-section
q-input(
outlined
v-model='group.redirectOnLogin'
dense
:aria-label='$t(`admin.groups.redirectOnLogin`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='chevron-right')
q-item-section
q-item-label {{$t(`admin.groups.redirectOnFirstLogin`)}}
q-item-label(caption) {{$t(`admin.groups.redirectOnFirstLoginHint`)}}
q-item-section
q-input(
outlined
v-model='group.redirectOnFirstLogin'
dense
:aria-label='$t(`admin.groups.redirectOnLogin`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='exit')
q-item-section
q-item-label {{$t(`admin.groups.redirectOnLogout`)}}
q-item-label(caption) {{$t(`admin.groups.redirectOnLogoutHint`)}}
q-item-section
q-input(
outlined
v-model='group.redirectOnLogout'
dense
:aria-label='$t(`admin.groups.redirectOnLogout`)'
)
.col-12.col-lg-4
q-card.shadow-1.q-pb-sm
q-card-section
.text-subtitle1 {{$t('admin.groups.info')}}
q-item
blueprint-icon(icon='team', :hue-rotate='-45')
q-item-section
q-item-label {{$t(`common.field.id`)}}
q-item-label: strong {{groupId}}
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='calendar-plus', :hue-rotate='-45')
q-item-section
q-item-label {{$t(`common.field.createdOn`)}}
q-item-label: strong {{humanizeDate(group.createdAt)}}
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='summertime', :hue-rotate='-45')
q-item-section
q-item-label {{$t(`common.field.lastUpdated`)}}
q-item-label: strong {{humanizeDate(group.updatedAt)}}
//- -----------------------------------------------------------------------
//- RULES
//- -----------------------------------------------------------------------
q-page(v-else-if='$route.params.section === `rules`')
q-toolbar.q-pl-md(
:class='$q.dark.isActive ? `bg-dark-3` : `bg-white`'
)
.text-subtitle1 {{$t('admin.groups.rules')}}
q-space
q-btn.acrylic-btn.q-mr-sm(
icon='las la-question-circle'
flat
color='grey'
type='a'
href='https://docs.js.wiki/admin/groups#rules'
target='_blank'
)
q-btn.acrylic-btn.q-mr-sm(
flat
color='indigo'
icon='las la-file-export'
@click='exportRules'
)
q-tooltip {{$t('admin.groups.exportRules')}}
q-btn.acrylic-btn.q-mr-sm(
flat
color='indigo'
icon='las la-file-import'
@click='importRules'
)
q-tooltip {{$t('admin.groups.importRules')}}
q-btn(
unelevated
color='primary'
icon='las la-plus'
label='New Rule'
@click='newRule'
)
q-separator
.q-pa-md
q-banner(
v-if='!group.rules || group.rules.length < 1'
rounded
:class='$q.dark.isActive ? `bg-negative text-white` : `bg-grey-4 text-grey-9`'
) {{$t('admin.groups.rulesNone')}}
q-card.shadow-1.q-pb-sm(v-else)
q-card-section
.admin-groups-rule(
v-for='(rule, idx) of group.rules'
:key='rule.id'
)
.admin-groups-rule-icon(:class='getRuleModeColor(rule.mode)')
q-icon.cursor-pointer(
:name='getRuleModeIcon(rule.mode)'
color='white'
@click='rule.mode = getNextRuleMode(rule.mode)'
)
.admin-groups-rule-name
.admin-groups-rule-name-text: strong(:class='getRuleModeColor(rule.mode)') {{getRuleModeName(rule.mode)}}
q-separator.q-ml-sm.q-mr-xs(vertical)
input(
type='text'
v-model='rule.name'
placeholder='Rule Name'
)
q-card.admin-groups-rule-card.q-mt-md(flat)
q-card-section.admin-groups-rule-card-permissions(:class='getRuleModeClass(rule.mode)')
q-select.q-mt-xs(
standout
v-model='rule.roles'
emit-value
map-options
dense
:aria-label='$t(`admin.groups.ruleSites`)'
:options='rules'
placeholder='Select permissions...'
option-value='permission'
option-label='title'
options-dense
multiple
use-chips
stack-label
)
template(v-slot:option='{ itemProps, itemEvents, opt, selected, toggleOption }')
q-item(v-bind='itemProps', v-on='itemEvents')
q-item-section(side)
q-toggle(
:value='selected'
@input='toggleOption(opt)'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='opt.label'
)
//- q-item-section(side, style='flex-basis: 150px;')
//- q-chip.text-caption(
//- square
//- color='teal'
//- text-color='white'
//- dense
//- ) {{opt.permission}}
q-item-section
q-item-label {{opt.title}}
q-item-label(caption) {{opt.hint}}
q-btn.acrylic-btn.q-ml-md(
flat
icon='las la-trash'
color='negative'
padding='sm sm'
size='md',
@click='deleteRule(rule.id)'
)
q-card-section(horizontal)
q-card-section.admin-groups-rule-card-filters
.text-caption Applies to...
q-select.q-mt-xs(
standout
v-model='rule.sites'
emit-value
map-options
dense
:aria-label='$t(`admin.groups.ruleSites`)'
:options='sites'
option-value='id'
option-label='title'
multiple
behavior='dialog'
:display-value='$tc(`admin.groups.selectedSites`, rule.sites.length, { count: rule.sites.length })'
)
template(v-slot:option='{ itemProps, itemEvents, opt, selected, toggleOption }')
q-item(v-bind='itemProps', v-on='itemEvents')
q-item-section
q-item-label {{opt.title}}
q-item-section(side)
q-toggle(
:value='selected'
@input='toggleOption(opt)'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='opt.label'
)
q-select.q-mt-sm(
standout
v-model='rule.locales'
emit-value
map-options
dense
:aria-label='$t(`admin.groups.ruleLocales`)'
:options='locales'
option-value='code'
option-label='name'
multiple
behavior='dialog'
:display-value='$tc(`admin.groups.selectedLocales`, rule.locales.length, { count: rule.locales.length, locale: rule.locales.length === 1 ? rule.locales[0].toUpperCase() : `` })'
)
template(v-slot:option='{ itemProps, opt, selected, toggleOption }')
q-item(v-bind='itemProps')
q-item-section
q-item-label {{opt.name}}
q-item-section(side)
q-toggle(
:model-value='selected'
@update:model-value='toggleOption(opt)'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='opt.name'
)
q-card-section.admin-groups-rule-card-pattern
.text-caption Pattern
q-select.q-mt-xs(
standout
v-model='rule.match'
emit-value
map-options
dense
:aria-label='$t(`admin.groups.ruleMatch`)'
:options=`[
{ label: $t('admin.groups.ruleMatchStart'), value: 'START' },
{ label: $t('admin.groups.ruleMatchEnd'), value: 'END' },
{ label: $t('admin.groups.ruleMatchRegex'), value: 'REGEX' },
{ label: $t('admin.groups.ruleMatchTag'), value: 'TAG' },
{ label: $t('admin.groups.ruleMatchTagAll'), value: 'TAGALL' },
{ label: $t('admin.groups.ruleMatchExact'), value: 'EXACT' }
]`
)
q-input.q-mt-sm(
standout
v-model='rule.path'
dense
:prefix='[`START`, `REGEX`, `EXACT`].includes(rule.match) ? `/` : null'
:suffix='rule.match === `REGEX` ? `/` : null'
:aria-label='$t(`admin.groups.rulePath`)'
)
//- -----------------------------------------------------------------------
//- PERMISSIONS
//- -----------------------------------------------------------------------
q-page(v-else-if='$route.params.section === `permissions`')
.q-pa-md
.row.q-col-gutter-md
.col-12.col-lg-6
q-card.shadow-1.q-pb-sm
.flex.justify-between
q-card-section
.text-subtitle1 {{$t(`admin.groups.permissions`)}}
q-card-section
q-btn.acrylic-btn(
icon='las la-question-circle'
flat
color='grey'
type='a'
href='https://docs.js.wiki/admin/groups#permissions'
target='_blank'
)
template(v-for='(perm, idx) of permissions', :key='perm.permission')
q-item(tag='label', v-ripple)
q-item-section.items-center(style='flex: 0 0 40px;')
q-icon(
name='las la-comments'
color='primary'
size='sm'
)
q-item-section
q-item-label {{perm.permission}}
q-item-label(caption) {{perm.hint}}
q-item-section(avatar)
q-toggle(
v-model='group.permissions'
:val='perm.permission'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.general.allowComments`)'
)
q-separator.q-my-sm(inset, v-if='idx < permissions.length - 1')
//- -----------------------------------------------------------------------
//- USERS
//- -----------------------------------------------------------------------
q-page(v-else-if='$route.params.section === `users`')
q-toolbar(
:class='$q.dark.isActive ? `bg-dark-3` : `bg-white`'
)
.text-subtitle1 {{$t('admin.groups.users')}}
q-space
q-btn.acrylic-btn.q-mr-sm(
icon='las la-question-circle'
flat
color='grey'
type='a'
href='https://docs.js.wiki/admin/groups#users'
target='_blank'
)
q-input.denser.fill-outline.q-mr-sm(
outlined
v-model='usersFilter'
:placeholder='$t(`admin.groups.filterUsers`)'
dense
)
template(#prepend)
q-icon(name='las la-search')
q-btn.q-mr-sm.acrylic-btn(
icon='las la-redo-alt'
flat
color='secondary'
@click='refreshUsers'
)
q-btn.q-mr-xs(
unelevated
icon='las la-user-plus'
:label='$t(`admin.groups.assignUser`)'
color='primary'
@click='assignUser'
)
q-separator
.q-pa-md
q-card.shadow-1
q-table(
:rows='users'
:columns='usersHeaders'
row-key='id'
flat
hide-header
hide-bottom
:rows-per-page-options='[0]'
:loading='isLoadingUsers'
)
template(v-slot:body-cell-id='props')
q-td(:props='props')
q-icon(name='las la-user', color='primary', size='sm')
template(v-slot:body-cell-name='props')
q-td(:props='props')
.flex.items-center
strong {{props.value}}
q-icon.q-ml-sm(
v-if='props.row.isSystem'
name='las la-lock'
color='pink'
)
q-icon.q-ml-sm(
v-if='!props.row.isActive'
name='las la-ban'
color='pink'
)
template(v-slot:body-cell-email='props')
q-td(:props='props')
em {{ props.value }}
template(v-slot:body-cell-date='props')
q-td(:props='props')
i18n-t.text-caption(keypath='admin.users.createdAt', tag='div')
template(#date)
strong {{ humanizeDate(props.value) }}
i18n-t.text-caption(
v-if='props.row.lastLoginAt'
keypath='admin.users.lastLoginAt'
tag='div'
)
template(#date)
strong {{ humanizeDate(props.row.lastLoginAt) }}
template(v-slot:body-cell-edit='props')
q-td(:props='props')
q-btn.acrylic-btn.q-mr-sm(
v-if='!props.row.isSystem'
flat
:to='`/_admin/users/` + props.row.id'
icon='las la-pen'
color='indigo'
:label='$t(`common.actions.edit`)'
no-caps
)
q-btn.acrylic-btn(
v-if='!props.row.isSystem'
flat
icon='las la-user-minus'
color='accent'
@click='unassignUser(props.row)'
)
.flex.flex-center.q-mt-md(v-if='usersTotalPages > 1')
q-pagination(
v-model='usersPage'
:max='usersTotalPages'
:max-pages='9'
boundary-numbers
direction-links
)
</template>
<script>
import gql from 'graphql-tag'
import { get } from 'vuex-pathify'
import { DateTime } from 'luxon'
import cloneDeep from 'lodash/cloneDeep'
import some from 'lodash/some'
import { v4 as uuid } from 'uuid'
import { exportFile } from 'quasar'
import { fileOpen } from 'browser-fs-access'
export default {
data () {
return {
sections: [
{ key: 'overview', text: this.$t('admin.groups.overview'), icon: 'las la-users' },
{ key: 'rules', text: this.$t('admin.groups.rules'), icon: 'las la-file-invoice', rulesTotal: true },
{ key: 'permissions', text: this.$t('admin.groups.permissions'), icon: 'las la-list-alt' },
{ key: 'users', text: this.$t('admin.groups.users'), icon: 'las la-user', usersTotal: true }
],
group: {
rules: []
},
isLoading: false,
// RULES
rules: [
{
permission: 'read:pages',
title: 'Read Pages',
hint: 'Can view and search pages.',
warning: false,
restrictedForSystem: false,
disabled: false
},
{
permission: 'write:pages',
title: 'Write Pages',
hint: 'Can create and edit pages.',
warning: false,
restrictedForSystem: true,
disabled: false
},
{
permission: 'review:pages',
title: 'Review Pages',
hint: 'Can review and approve edits submitted by users.',
warning: false,
restrictedForSystem: true,
disabled: false
},
{
permission: 'manage:pages',
title: 'Manage Pages',
hint: 'Can move existing pages to other locations the user has write access to.',
warning: false,
restrictedForSystem: true,
disabled: false
},
{
permission: 'delete:pages',
title: 'Delete Pages',
hint: 'Can delete existing pages.',
warning: false,
restrictedForSystem: true,
disabled: false
},
{
permission: 'write:styles',
title: 'Use CSS',
hint: 'Can insert CSS styles in pages.',
warning: false,
restrictedForSystem: true,
disabled: false
},
{
permission: 'write:scripts',
title: 'Use JavaScript',
hint: 'Can insert JavaScript in pages.',
warning: false,
restrictedForSystem: true,
disabled: false
},
{
permission: 'read:source',
title: 'View Pages Source',
hint: 'Can view pages source.',
warning: false,
restrictedForSystem: false,
disabled: false
},
{
permission: 'read:history',
title: 'View Page History',
hint: 'Can view previous versions of pages.',
warning: false,
restrictedForSystem: false,
disabled: false
},
{
permission: 'read:assets',
title: 'View Assets',
hint: 'Can view / use assets (such as images and files) in pages.',
warning: false,
restrictedForSystem: false,
disabled: false
},
{
permission: 'write:assets',
title: 'Upload Assets',
hint: 'Can upload new assets (such as images and files).',
warning: false,
restrictedForSystem: true,
disabled: false
},
{
permission: 'manage:assets',
title: 'Manage Assets',
hint: 'Can edit and delete existing assets (such as images and files).',
warning: false,
restrictedForSystem: true,
disabled: false
},
{
permission: 'read:comments',
title: 'Read Comments',
hint: 'Can view page comments.',
warning: false,
restrictedForSystem: false,
disabled: false
},
{
permission: 'write:comments',
title: 'Write Comments',
hint: 'Can post new comments on pages.',
warning: false,
restrictedForSystem: false,
disabled: false
},
{
permission: 'manage:comments',
title: 'Manage Comments',
hint: 'Can edit and delete existing page comments.',
warning: false,
restrictedForSystem: true,
disabled: false
}
],
// PERMISSIONS
permissions: [
{
permission: 'write:users',
hint: 'Can create or authorize new users, but not modify existing ones',
warning: false,
restrictedForSystem: true,
disabled: false
},
{
permission: 'manage:users',
hint: 'Can manage all users (but not users with administrative permissions)',
warning: false,
restrictedForSystem: true,
disabled: false
},
{
permission: 'write:groups',
hint: 'Can manage groups and assign CONTENT permissions / page rules',
warning: false,
restrictedForSystem: true,
disabled: false
},
{
permission: 'manage:groups',
hint: 'Can manage groups and assign ANY permissions (but not manage:system) / page rules',
warning: true,
restrictedForSystem: true,
disabled: false
},
{
permission: 'manage:navigation',
hint: 'Can manage the site navigation',
warning: false,
restrictedForSystem: true,
disabled: false
},
{
permission: 'manage:theme',
hint: 'Can manage and modify themes',
warning: false,
restrictedForSystem: true,
disabled: false
},
{
permission: 'manage:api',
hint: 'Can generate and revoke API keys',
warning: true,
restrictedForSystem: true,
disabled: false
},
{
permission: 'manage:system',
hint: 'Can manage and access everything. Root administrator.',
warning: true,
restrictedForSystem: true,
disabled: true
}
],
// USERS
users: [],
isLoadingUsers: false,
usersFilter: '',
usersPage: 1,
usersPageSize: 15,
usersTotal: 0,
usersHeaders: [
{
align: 'center',
field: 'id',
name: 'id',
sortable: false,
style: 'width: 20px'
},
{
label: this.$t('common.field.name'),
align: 'left',
field: 'name',
name: 'name',
sortable: true
},
{
label: this.$t('admin.users.email'),
align: 'left',
field: 'email',
name: 'email',
sortable: false
},
{
align: 'left',
field: 'createdAt',
name: 'date',
sortable: false
},
{
label: '',
align: 'right',
field: 'edit',
name: 'edit',
sortable: false,
style: 'width: 250px'
}
]
}
},
computed: {
groupId: get('admin/overlayOpts@id', false),
sites: get('admin/sites', false),
locales: get('admin/locales', false),
usersTotalPages () {
if (this.usersTotal < 1) { return 0 }
return Math.ceil(this.usersTotal / this.usersPageSize)
}
},
watch: {
$route: 'checkRoute',
usersPage () {
this.refreshUsers()
},
usersFilter () {
this.refreshUsers()
}
},
mounted () {
this.checkRoute()
this.fetchGroup()
},
methods: {
close () {
this.$store.set('admin/overlay', '')
},
checkRoute () {
if (!this.$route.params.section) {
this.$router.replace({ params: { section: 'overview' } })
} else if (this.$route.params.section === 'users') {
this.refreshUsers()
}
},
humanizeDate (val) {
if (!val) { return '---' }
return DateTime.fromISO(val).toLocaleString(DateTime.DATETIME_FULL)
},
getRuleModeColor: (mode) => ({
DENY: 'text-negative',
ALLOW: 'text-positive',
FORCEALLOW: 'text-blue'
})[mode],
getRuleModeClass (mode) {
return 'is-' + mode.toLowerCase()
},
getRuleModeIcon: (mode) => ({
DENY: 'las la-ban',
ALLOW: 'las la-check',
FORCEALLOW: 'las la-check-double'
})[mode] || 'las la-frog',
getNextRuleMode: (mode) => ({
DENY: 'FORCEALLOW',
ALLOW: 'DENY',
FORCEALLOW: 'ALLOW'
})[mode] || 'ALLOW',
getRuleModeName (mode) {
switch (mode) {
case 'ALLOW': return this.$t('admin.groups.ruleAllow')
case 'DENY': return this.$t('admin.groups.ruleDeny')
case 'FORCEALLOW': return this.$t('admin.groups.ruleForceAllow')
default: return '???'
}
},
refresh () {
this.fetchGroup()
},
async fetchGroup () {
this.isLoading = true
try {
const resp = await this.$apollo.query({
query: gql`
query adminFetchGroup (
$id: UUID!
) {
groupById(
id: $id
) {
id
name
redirectOnLogin
redirectOnFirstLogin
redirectOnLogout
isSystem
permissions
rules {
id
name
path
roles
match
mode
locales
sites
}
userCount
createdAt
updatedAt
}
}
`,
variables: {
id: this.groupId
},
fetchPolicy: 'network-only'
})
if (resp?.data?.groupById) {
this.group = cloneDeep(resp.data.groupById)
this.usersTotal = this.group.userCount ?? 0
} else {
throw new Error('An unexpected error occured while fetching group details.')
}
} catch (err) {
this.$q.notify({
type: 'negative',
message: err.message
})
}
this.isLoading = false
},
newRule () {
this.group.rules.push({
id: uuid(),
name: this.$t('admin.groups.ruleUntitled'),
mode: 'ALLOW',
match: 'START',
roles: [],
path: '',
locales: [],
sites: []
})
},
deleteRule (id) {
this.group.rules = this.group.rules.filter(r => r.id !== id)
},
exportRules () {
if (this.group.rules.length < 1) {
return this.$q.notify({
type: 'negative',
message: this.$t('admin.groups.exportRulesNoneError')
})
}
exportFile('rules.json', JSON.stringify(this.group.rules, null, 2), { mimeType: 'application/json;charset=UTF-8' })
},
async importRules () {
try {
const blob = await fileOpen({
mimeTypes: ['application/json'],
extensions: ['.json'],
startIn: 'downloads',
excludeAcceptAllOption: true
})
const rulesRaw = await blob.text()
const rules = JSON.parse(rulesRaw)
if (!Array.isArray(rules) || rules.length < 1) {
throw new Error('Invalid Rules Format')
}
this.$q.dialog({
title: this.$t('admin.groups.importModeTitle'),
message: this.$t('admin.groups.importModeText'),
options: {
model: 'replace',
type: 'radio',
items: [
{ label: this.$t('admin.groups.importModeReplace'), value: 'replace' },
{ label: this.$t('admin.groups.importModeAdd'), value: 'add' }
]
},
persistent: true
}).onOk(choice => {
if (choice === 'replace') {
this.group.rules = []
}
this.group.rules = [
...this.group.rules,
...rules.map(r => ({
id: uuid(),
name: r.name || this.$t('admin.groups.ruleUntitled'),
mode: ['ALLOW', 'DENY', 'FORCEALLOW'].includes(r.mode) ? r.mode : 'DENY',
match: ['START', 'END', 'REGEX', 'TAG', 'TAGALL', 'EXACT'].includes(r.match) ? r.match : 'START',
roles: r.roles || [],
path: r.path || '',
locales: r.locales.filter(l => some(this.locales, ['code', l])),
sites: r.sites.filter(s => some(this.sites, ['id', s]))
}))
]
this.$q.notify({
type: 'positive',
message: this.$t('admin.groups.importSuccess')
})
})
} catch (err) {
this.$q.notify({
type: 'negative',
message: this.$t('admin.groups.importFailed') + ` [${err.message}]`
})
}
},
async refreshUsers () {
this.isLoadingUsers = true
try {
const resp = await this.$apollo.query({
query: gql`
query adminFetchGroupUsers (
$filter: String
$page: Int
$pageSize: Int
$groupId: UUID!
) {
groupById (
id: $groupId
) {
id
userCount
users (
filter: $filter
page: $page
pageSize: $pageSize
) {
id
name
email
isSystem
isActive
createdAt
lastLoginAt
}
}
}
`,
variables: {
filter: this.usersFilter,
page: this.usersPage,
pageSize: this.usersPageSize,
groupId: this.groupId
},
fetchPolicy: 'network-only'
})
if (resp?.data?.groupById?.users) {
this.usersTotal = resp.data.groupById.userCount ?? 0
this.users = cloneDeep(resp.data.groupById.users)
} else {
throw new Error('An unexpected error occured while fetching group users.')
}
} catch (err) {
this.$q.notify({
type: 'negative',
message: err.message
})
}
this.isLoadingUsers = false
},
assignUser () {
},
unassignUser () {
}
}
}
</script>
<style lang="scss">
.admin-groups-rule {
position: relative;
padding: 10px 0 24px 40px;
&-icon {
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 31px;
&::before {
position: absolute;
content: "";
border-radius: 100%;
width: 31px;
height: 31px;
background-color: currentColor;
top: 4px;
}
&::after {
position: absolute;
content: "";
width: 3px;
top: 41px;
bottom: 0;
left: 14px;
opacity: .4;
background-color: currentColor;
display: block;
}
.q-icon {
position: absolute;
top: 0;
left: 0;
right: 0;
font-size: 16px;
height: 38px;
line-height: 38px;
width: 100%;
align-items: center;
justify-content: center;
display: flex;
}
}
&-name {
line-height: 12px;
display: flex;
flex-wrap: nowrap;
padding-top: 4px;
&-text {
flex: 0 0;
white-space: nowrap;
}
input {
font-weight: 700;
color: $grey-6;
letter-spacing: 1px;
font-size: 12px;
line-height: 12px;
border: none;
padding: 0 0 0 5px;
outline: none;
flex: 1;
background-color: transparent;
&::placeholder {
color: $grey-5;
}
@at-root .body--dark & {
color: rgba(255,255,255,.7);
&::placeholder {
color: rgba(255,255,255,.4);
}
}
}
}
&-card {
background-color: $grey-2 !important;
@at-root .body--dark & {
background-color: $dark-6 !important;
}
&-permissions {
background-color: rgba($positive, .1);
border-bottom: 1px solid rgba($positive, .3);
display: flex;
align-items: center;
.q-select {
flex-basis: 100%;
}
&.is-allow {
background-color: rgba($positive, .1);
border-bottom: 1px solid rgba($positive, .3);
}
&.is-deny {
background-color: rgba($negative, .1);
border-bottom: 1px solid rgba($negative, .3);
}
&.is-forceallow {
background-color: rgba($blue, .1);
border-bottom: 1px solid rgba($blue, .3);
}
}
&-filters {
background-color: $grey-3;
flex-basis: 300px;
.text-caption:first-child {
color: $grey-7;
}
@at-root .body--dark & {
background-color: $dark-5;
}
}
&-pattern {
flex-grow: 1;
}
}
}
</style>
<template lang="pug">
q-header.bg-header.text-white.site-header(
height-hint='64'
)
.row.no-wrap
q-toolbar(
style='height: 64px;'
dark
)
q-btn(
dense
flat
to='/'
)
q-avatar(
size='34px'
square
)
img(src='/_assets/logo-wikijs.svg')
q-toolbar-title.text-h6.font-poppins {{siteTitle}}
q-toolbar.gt-sm(
style='height: 64px;'
dark
)
q-input(
dark
v-model='search'
standout='bg-white text-dark'
dense
rounded
ref='searchField'
style='width: 100%;'
label='Search...'
)
template(v-slot:prepend)
q-icon(name='las la-search')
template(v-slot:append)
q-icon.cursor-pointer(
name='las la-times'
@click='search=``'
v-if='search.length > 0'
:color='$q.dark.isActive ? `blue` : `grey-4`'
)
q-btn.q-ml-md(
flat
round
dense
icon='las la-tags'
color='grey'
to='/t'
)
q-toolbar(
style='height: 64px;'
dark
)
q-space
transition(name='syncing')
q-spinner-rings.q-mr-sm(
v-show='isSyncing'
color='orange'
size='34px'
)
q-btn.q-ml-md(
flat
round
dense
icon='las la-plus-circle'
color='blue-4'
aria-label='Create New Page'
)
q-tooltip Create New Page
new-menu
q-btn.q-ml-md(
flat
round
dense
icon='las la-tools'
color='secondary'
to='/_admin'
aria-label='Administration'
)
q-tooltip Administration
account-menu
</template>
<script>
import { get } from 'vuex-pathify'
import AccountMenu from './AccountMenu.vue'
import NewMenu from './PageNewMenu.vue'
export default {
components: {
AccountMenu,
NewMenu
},
data () {
return {
search: ''
}
},
computed: {
isSyncing: get('isLoading', false),
siteTitle: get('site/title', false)
}
}
</script>
<style lang="scss">
.syncing-enter-active {
animation: syncing-anim .1s;
}
.syncing-leave-active {
animation: syncing-anim 1s reverse;
}
@keyframes syncing-anim {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
</style>
<template lang="pug">
q-card.icon-picker(flat, style='width: 400px;')
q-tabs.text-primary(
v-model='currentTab'
no-caps
inline-label
)
q-tab(
name='icon'
icon='las la-icons'
label='Icon'
)
q-tab(
name='img'
icon='las la-image'
label='Image'
)
q-separator
q-tab-panels(
v-model='currentTab'
)
q-tab-panel(name='icon')
q-select(
:options='iconPacks'
v-model='selPack'
emit-value
map-options
outlined
dense
transition-show='jump-down'
transition-hide='jump-up'
)
template(v-slot:option='scope')
q-item(
v-bind='scope.itemProps'
v-on='scope.itemEvents'
:class='scope.selected ? `bg-primary text-white` : ``'
)
q-item-section(side)
q-icon(
name='las la-box'
:color='scope.selected ? `white` : `grey`'
)
q-item-section
q-item-label {{scope.opt.name}}
q-item-label(caption): strong(:class='scope.selected ? `text-white` : `text-primary`') {{scope.opt.subset}}
q-item-section(side, v-if='scope.opt.subset')
q-chip(
color='primary'
text-color='white'
rounded
size='sm'
) {{scope.opt.subset.toUpperCase()}}
q-input.q-mt-md(
v-model='selIcon'
outlined
label='Icon Name'
dense
)
.row.q-gutter-md.q-mt-none
.col-auto
q-avatar(
size='64px'
color='primary'
rounded
)
q-icon(
:name='iconName'
color='white'
size='64px'
)
.col
.text-caption Learn how to #[a(href='https://docs.requarks.io') use icons].
.text-caption.q-mt-sm View #[a(:href='iconPackRefWebsite', target='_blank') Icon Pack reference] for all possible options.
q-tab-panel(name='img')
.row.q-gutter-sm
q-btn.col(
label='Browse...'
color='secondary'
icon='las la-file-image'
unelevated
no-caps
)
q-btn.col(
label='Upload...'
color='secondary'
icon='las la-upload'
unelevated
no-caps
)
.q-mt-md.text-center
q-avatar(
size='64px'
rounded
)
q-img(
transition='jump-down'
:ratio='1'
:src='imgPath'
)
q-separator
q-card-actions
q-space
q-btn(
icon='las la-times'
label='Discard'
outline
color='grey-7'
v-close-popup
)
q-btn(
icon='las la-check'
label='Apply'
unelevated
color='secondary'
@click='apply'
v-close-popup
)
</template>
<script>
import find from 'lodash/find'
export default {
props: {
value: {
type: String,
required: true
}
},
data () {
return {
currentTab: 'icon',
selPack: 'las',
selIcon: '',
imgPath: 'https://placeimg.com/64/64/nature',
iconPacks: [
{ value: 'las', label: 'Line Awesome (solid)', name: 'Line Awesome', subset: 'solid', prefix: 'las la-', reference: 'https://icons8.com/line-awesome' },
{ value: 'lab', label: 'Line Awesome (brands)', name: 'Line Awesome', subset: 'brands', prefix: 'lab la-', reference: 'https://icons8.com/line-awesome' },
{ value: 'mdi', label: 'Material Design Icons', name: 'Material Design Icons', prefix: 'mdi-', reference: 'https://materialdesignicons.com' },
{ value: 'fas', label: 'Font Awesome (solid)', name: 'Font Awesome', subset: 'solid', prefix: 'fas fa-', reference: 'https://fontawesome.com/icons' },
{ value: 'far', label: 'Font Awesome (regular)', name: 'Font Awesome', subset: 'regular', prefix: 'far fa-', reference: 'https://fontawesome.com/icons' },
{ value: 'fal', label: 'Font Awesome (light)', name: 'Font Awesome', subset: 'light', prefix: 'fal fa-', reference: 'https://fontawesome.com/icons' },
{ value: 'fad', label: 'Font Awesome (duotone)', name: 'Font Awesome', subset: 'duotone', prefix: 'fad fa-', reference: 'https://fontawesome.com/icons' },
{ value: 'fab', label: 'Font Awesome (brands)', name: 'Font Awesome', subset: 'brands', prefix: 'fab fa-', reference: 'https://fontawesome.com/icons' }
]
}
},
computed: {
iconName () {
return find(this.iconPacks, ['value', this.selPack]).prefix + this.selIcon
},
iconPackRefWebsite () {
return find(this.iconPacks, ['value', this.selPack]).reference
}
},
mounted () {
if (this.value?.startsWith('img:')) {
this.currentTab = 'img'
this.imgPath = this.value.substring(4)
} else {
this.currentTab = 'icon'
for (const pack of this.iconPacks) {
if (this.value?.startsWith(pack.prefix)) {
this.selPack = pack.value
this.selIcon = this.value.substring(pack.prefix.length)
break
}
}
}
},
methods: {
apply () {
if (this.currentTab === 'img') {
this.$emit('input', `img:${this.imgPath}`)
} else {
this.$emit('input', this.iconName)
}
}
}
}
</script>
<style lang="scss">
.icon-picker {
a {
@at-root .body--light & {
color: $blue-7;
}
@at-root .body--dark & {
color: $blue-3;
}
}
.q-tab-panels {
@at-root .body--light & {
background-color: $grey-1;
}
@at-root .body--dark & {
background-color: $dark-4;
}
}
.q-input .q-field__control, .q-select .q-field__control {
@at-root .body--light & {
background-color: #FFF;
}
@at-root .body--dark & {
background-color: $dark-5;
}
}
}
</style>
<template lang="pug">
q-dialog(ref='dialog', @hide='onDialogHide')
q-card(style='min-width: 850px;')
q-card-section.card-header
q-icon(name='img:/_assets/icons/fluent-down.svg', left, size='sm')
span {{$t(`admin.locale.downloadTitle`)}}
q-card-section.q-pa-none
q-table.no-border-radius(
:data='locales'
:columns='headers'
row-name='code'
flat
hide-bottom
:rows-per-page-options='[0]'
:loading='loading > 0'
)
template(v-slot:body-cell-code='props')
q-td(:props='props')
q-chip(
square
color='teal'
text-color='white'
dense
): span.text-caption {{props.value}}
template(v-slot:body-cell-name='props')
q-td(:props='props')
strong {{props.value}}
template(v-slot:body-cell-isRTL='props')
q-td(:props='props')
q-icon(
v-if='props.value'
name='las la-check'
color='brown'
size='xs'
)
template(v-slot:body-cell-availability='props')
q-td(:props='props')
q-circular-progress(
size='md'
show-value
:value='props.value'
:thickness='0.1'
:color='props.value <= 33 ? `negative` : (props.value <= 66) ? `warning` : `positive`'
) {{ props.value }}%
template(v-slot:body-cell-isInstalled='props')
q-td(:props='props')
q-spinner(
v-if='props.row.isDownloading'
color='primary'
size='20px'
:thickness='2'
)
q-btn(
v-else-if='props.value && props.row.installDate < props.row.updatedAt'
flat
round
dense
@click='download(props.row)'
icon='las la-redo-alt'
color='accent'
)
q-btn(
v-else-if='props.value'
flat
round
dense
@click='download(props.row)'
icon='las la-check-circle'
color='positive'
)
q-btn(
v-else
flat
round
dense
@click='download(props.row)'
icon='las la-cloud-download-alt'
color='primary'
)
q-card-actions.card-actions
q-space
q-btn.acrylic-btn(
flat
:label='$t(`common.actions.close`)'
color='grey'
padding='xs md'
@click='hide'
)
q-inner-loading(:showing='loading')
q-spinner(color='accent', size='lg')
</template>
<script>
// import gql from 'graphql-tag'
// import cloneDeep from 'lodash/cloneDeep'
export default {
emits: ['ok', 'hide'],
data () {
return {
locales: [],
loading: 0
}
},
computed: {
headers () {
return [
{
label: this.$t('admin.locale.code'),
align: 'left',
field: 'code',
name: 'code',
sortable: true,
style: 'width: 90px'
},
{
label: this.$t('admin.locale.name'),
align: 'left',
field: 'name',
name: 'name',
sortable: true
},
{
label: this.$t('admin.locale.nativeName'),
align: 'left',
field: 'nativeName',
name: 'nativeName',
sortable: true
},
{
label: this.$t('admin.locale.rtl'),
align: 'center',
field: 'isRTL',
name: 'isRTL',
sortable: false,
style: 'width: 10px'
},
{
label: this.$t('admin.locale.availability'),
align: 'center',
field: 'availability',
name: 'availability',
sortable: false,
style: 'width: 120px'
},
{
label: this.$t('admin.locale.download'),
align: 'center',
field: 'isInstalled',
name: 'isInstalled',
sortable: false,
style: 'width: 100px'
}
]
}
},
methods: {
show () {
this.$refs.dialog.show()
},
hide () {
this.$refs.dialog.hide()
},
onDialogHide () {
this.$emit('hide')
}
}
}
</script>
<template lang="pug">
.row
.col-auto.bg-grey-1(style='width: 250px;')
q-tree(
:nodes='tree'
default-expand-all
node-key='label'
@lazy-load='onLazyLoad'
)
.col Doude
</template>
<script>
export default {
data () {
return {
tree: [
{
label: 'Item 1',
icon: 'las la-folder',
children: [
{ label: 'Item 1.1' },
{
label: 'Item 1.2',
icon: 'las la-folder',
children: [
{ label: 'Item 1.2.1' },
{ label: 'Item 1.2.2' }
]
}
]
}
]
}
},
methods: {
async onLazyLoad ({ node, key, done, fail }) {
done([])
}
}
}
</script>
<template lang="pug">
q-card.page-data-dialog(style='width: 750px;')
q-toolbar.bg-primary.text-white.flex
.text-subtitle2 {{$t('editor.pageData.title')}}
q-space
q-btn(
icon='las la-times'
dense
flat
v-close-popup
)
q-card-section.page-data-dialog-selector
//- .text-overline.text-white {{$t('editor.pageData.template')}}
.flex.q-gutter-sm
q-select(
dark
v-model='templateId'
:label='$t(`editor.pageData.template`)'
:aria-label='$t(`editor.pageData.template`)'
:options='templates'
option-value='id'
map-options
emit-value
standout
dense
style='flex: 1 0 auto;'
)
q-btn.acrylic-btn(
dark
icon='las la-pen'
:label='$t(`common.actions.manage`)'
unelevated
no-caps
color='deep-orange-9'
@click='editTemplates'
)
q-tabs.alt-card(
v-model='mode'
inline-label
no-caps
)
q-tab(
name='visual'
label='Visual'
)
q-tab(
name='code'
label='YAML'
)
q-scroll-area(
:thumb-style='thumbStyle'
:bar-style='barStyle'
style='height: calc(100% - 50px - 75px - 48px);'
)
q-card-section(v-if='mode === `visual`')
.q-gutter-sm
q-input(
label='Attribute Text'
dense
outlined
)
template(v-slot:before)
q-icon(name='las la-font', color='primary')
q-input(
label='Attribute Number'
dense
outlined
type='number'
)
template(v-slot:before)
q-icon(name='las la-infinity', color='primary')
.q-py-xs
q-checkbox(
label='Attribute Boolean'
color='primary'
dense
size='lg'
)
q-no-ssr(v-else, :placeholder='$t(`common.loading`)')
codemirror.admin-theme-cm(
ref='cmData'
v-model='content'
:options='{ mode: `text/yaml` }'
)
q-dialog(
v-model='showDataTemplateDialog'
)
page-data-template-dialog
</template>
<script>
import { get } from 'vuex-pathify'
import PageDataTemplateDialog from './PageDataTemplateDialog.vue'
export default {
components: {
PageDataTemplateDialog
},
data () {
return {
showDataTemplateDialog: false,
templateId: '',
content: '',
mode: 'visual'
}
},
computed: {
thumbStyle: get('site/thumbStyle', false),
barStyle: get('site/barStyle', false),
templates () {
return [
{
id: '',
label: 'None',
data: []
},
...this.$store.get('site/pageDataTemplates'),
{
id: 'basic',
label: 'Basic',
data: []
}
]
}
},
methods: {
editTemplates () {
this.showDataTemplateDialog = !this.showDataTemplateDialog
}
}
}
</script>
<style lang="scss">
.page-data-dialog {
&-selector {
@at-root .body--light & {
background-color: $dark-3;
box-shadow: inset 0px 1px 0 0 rgba(0,0,0,.75), inset 0px -1px 0 0 rgba(0,0,0,.75), 0 -1px 0 0 rgba(255,255,255,.1);
border-bottom: 1px solid #FFF;
}
@at-root .body--dark & {
background-color: $dark-4;
box-shadow: inset 0px 1px 0 0 rgba(0,0,0, 0.75), inset 0px -1px 0 0 rgba(0,0,0,.75), 0 -1px 0 0 rgba(255,255,255,.1);
border-bottom: 1px solid lighten($dark-3, 10%);
}
}
}
</style>
<template lang="pug">
q-card.page-datatmpl-dialog(style='width: 1100px; max-width: 1100px;')
q-toolbar.bg-primary.text-white
.text-subtitle2 {{$t('editor.pageData.manageTemplates')}}
q-space
q-btn(
icon='las la-times'
dense
flat
v-close-popup
)
q-card-section.page-datatmpl-selector
.flex.q-gutter-md
q-select.col(
v-model='selectedTemplateId'
:options='templates'
standout
:label='$t(`editor.pageData.template`)'
dense
dark
option-value='id'
map-options
emit-value
)
q-btn(
icon='las la-plus'
:label='$t(`common.actions.new`)'
unelevated
color='primary'
no-caps
@click='create'
)
.row(v-if='tmpl')
.col-auto.page-datatmpl-sd
.q-pa-md
q-btn.acrylic-btn.full-width(
:label='$t(`common.actions.howItWorks`)'
icon='las la-question-circle'
flat
color='pink'
no-caps
)
q-item-label(header, style='margin-top: 2px;') {{$t('editor.pageData.templateFullRowTypes')}}
.q-px-md
draggable(
class='q-list rounded-borders'
:list='inventoryMisc'
:group='{name: `shared`, pull: `clone`, put: false}'
:clone='cloneFieldType'
:sort='false'
:animation='150'
@start='dragStarted = true'
@end='dragStarted = false'
item-key='id'
)
template(#item='{element}')
q-item(clickable)
q-item-section(side)
q-icon(:name='element.icon', color='primary')
q-item-section
q-item-label {{element.label}}
q-item-label(header) {{$t('editor.pageData.templateKeyValueTypes')}}
.q-px-md.q-pb-md
draggable(
class='q-list rounded-borders'
:list='inventoryKV'
:group='{name: `shared`, pull: `clone`, put: false}'
:clone='cloneFieldType'
:sort='false'
:animation='150'
@start='dragStarted = true'
@end='dragStarted = false'
item-key='id'
)
template(#item='{element}')
q-item(clickable)
q-item-section(side)
q-icon(:name='element.icon', color='primary')
q-item-section
q-item-label {{element.label}}
.col.page-datatmpl-content
q-scroll-area(
ref='scrollArea'
:thumb-style='thumbStyle'
:bar-style='barStyle'
style='height: 100%;'
)
.col.page-datatmpl-meta.q-px-md.q-py-md.flex.q-gutter-md
q-input.col(
ref='tmplTitleIpt'
:label='$t(`editor.pageData.templateTitle`)'
outlined
dense
v-model='tmpl.label'
)
q-btn.acrylic-btn(
icon='las la-check'
:label='$t(`common.actions.commit`)'
no-caps
flat
color='positive'
@click='commit'
)
q-btn.acrylic-btn(
icon='las la-trash'
:aria-label='$t(`common.actions.delete`)'
flat
color='negative'
@click='remove'
)
q-item-label(header) {{$t('editor.pageData.templateStructure')}}
.q-px-md.q-pb-md
div(:class='(dragStarted || tmpl.data.length < 1 ? `page-datatmpl-box` : ``)')
.text-caption.text-primary.q-pa-md(v-if='tmpl.data.length < 1 && !dragStarted'): em {{$t('editor.pageData.dragDropHint')}}
draggable(
class='q-list rounded-borders'
:list='tmpl.data'
group='shared'
:animation='150'
handle='.handle'
@end='dragStarted = false'
item-key='id'
)
template(#item='{element}')
q-item
q-item-section(side)
q-icon.handle(name='las la-bars')
q-item-section(side)
q-icon(:name='element.icon', color='primary')
q-item-section
q-input(
:label='$t(`editor.pageData.label`)'
v-model='element.label'
outlined
dense
)
q-item-section(v-if='element.type !== `header`')
q-input(
:label='$t(`editor.pageData.uniqueKey`)'
v-model='element.key'
outlined
dense
)
q-item-section(side)
q-btn.acrylic-btn(
color='negative'
:aria-label='$t(`common.actions.delete`)'
padding='xs'
icon='las la-times'
flat
@click='removeItem(item)'
)
.page-datatmpl-scrollend(ref='scrollAreaEnd')
.q-pa-md.text-center(v-else-if='templates.length > 0')
em.text-grey-6 {{$t('editor.pageData.selectTemplateAbove')}}
.q-pa-md.text-center(v-else)
em.text-grey-6 {{$t('editor.pageData.noTemplate')}}
</template>
<script>
import { get, sync } from 'vuex-pathify'
import { v4 as uuid } from 'uuid'
import cloneDeep from 'lodash/cloneDeep'
import sortBy from 'lodash/sortBy'
import draggable from 'vuedraggable'
export default {
props: {
editId: {
type: String,
default: null
}
},
components: {
draggable
},
data () {
return {
selectedTemplateId: null,
dragStarted: false,
tmpl: null
}
},
computed: {
templates: sync('site/pageDataTemplates', false),
thumbStyle: get('site/thumbStyle', false),
barStyle: get('site/barStyle', false),
inventoryMisc () {
return [
{
key: 'header',
label: this.$t('editor.pageData.fieldTypeHeader'),
icon: 'las la-heading'
},
{
key: 'image',
label: this.$t('editor.pageData.fieldTypeImage'),
icon: 'las la-image'
}
]
},
inventoryKV () {
return [
{
key: 'text',
label: this.$t('editor.pageData.fieldTypeText'),
icon: 'las la-font'
},
{
key: 'number',
label: this.$t('editor.pageData.fieldTypeNumber'),
icon: 'las la-infinity'
},
{
key: 'boolean',
label: this.$t('editor.pageData.fieldTypeBoolean'),
icon: 'las la-check-square'
},
{
key: 'link',
label: this.$t('editor.pageData.fieldTypeLink'),
icon: 'las la-link'
}
]
}
},
watch: {
dragStarted (newValue) {
if (newValue) {
this.$nextTick(() => {
this.$refs.scrollAreaEnd.scrollIntoView({
behavior: 'smooth'
})
})
}
},
selectedTemplateId (newValue) {
this.tmpl = cloneDeep(this.templates.find(t => t.id === this.selectedTemplateId))
}
},
mounted () {
if (this.templates.length > 0) {
this.tmpl = this.templates[0]
this.selectedTemplateId = this.tmpl.id
} else {
this.create()
}
},
methods: {
cloneFieldType (tp) {
return {
id: uuid(),
type: tp.key,
label: '',
...(tp.key !== 'header' ? { key: '' } : {}),
icon: tp.icon
}
},
removeItem (item) {
this.tmpl.data = this.tmpl.data.filter(i => i.id !== item.id)
},
create () {
this.tmpl = {
id: uuid(),
label: this.$t('editor.pageData.templateUntitled'),
data: []
}
this.$nextTick(() => {
this.$refs.tmplTitleIpt.focus()
this.$nextTick(() => {
document.execCommand('selectall')
})
})
},
commit () {
try {
if (this.tmpl.label.length < 1) {
throw new Error(this.$t('editor.pageData.invalidTemplateName'))
} else if (this.tmpl.data.length < 1) {
throw new Error(this.$t('editor.pageData.emptyTemplateStructure'))
} else if (this.tmpl.data.some(f => f.label.length < 1)) {
throw new Error(this.$t('editor.pageData.invalidTemplateLabels'))
} else if (this.tmpl.data.some(f => f.type !== 'header' && f.key.length < 1)) {
throw new Error(this.$t('editor.pageData.invalidTemplateKeys'))
}
const keys = this.tmpl.data.filter(f => f.type !== 'header').map(f => f.key)
if ((new Set(keys)).size !== keys.length) {
throw new Error(this.$t('editor.pageData.duplicateTemplateKeys'))
}
if (this.templates.some(t => t.id === this.tmpl.id)) {
this.templates = sortBy([...this.templates.filter(t => t.id !== this.tmpl.id), cloneDeep(this.tmpl)], 'label')
} else {
this.templates = sortBy([...this.templates, cloneDeep(this.tmpl)], 'label')
}
this.selectedTemplateId = this.tmpl.id
} catch (err) {
this.$q.notify({
type: 'negative',
message: err.message
})
}
},
remove () {
this.$q.dialog({
title: this.$t('editor.pageData.templateDeleteConfirmTitle'),
message: this.$t('editor.pageData.templateDeleteConfirmText'),
cancel: true,
persistent: true,
color: 'negative'
}).onOk(() => {
this.templates = this.templates.filter(t => t.id !== this.selectedTemplateId)
this.selectedTemplateId = null
this.tmpl = null
})
}
}
}
</script>
<style lang="scss">
.page-datatmpl {
&-selector {
@at-root .body--light & {
background-color: $dark-3;
box-shadow: inset 0px 1px 0 0 rgba(0,0,0,.75), inset 0px -1px 0 0 rgba(0,0,0,.75), 0 -1px 0 0 rgba(255,255,255,.1);
border-bottom: 1px solid #FFF;
}
@at-root .body--dark & {
background-color: $dark-4;
box-shadow: inset 0px 1px 0 0 rgba(0,0,0, 0.75), inset 0px -1px 0 0 rgba(0,0,0,.75), 0 -1px 0 0 rgba(255,255,255,.1);
border-bottom: 1px solid lighten($dark-3, 10%);
}
}
&-sd {
flex-basis: 250px;
min-height: 500px;
padding-top: 2px;
@at-root .body--light & {
background-color: $grey-3;
border-right: 1px solid $grey-4;
}
@at-root .body--dark & {
background-color: lighten($dark-3, 2%);
border-right: 1px solid $dark-5;
}
.q-list {
@at-root .body--light & {
background-color: $grey-4;
}
@at-root .body--dark & {
background-color: $dark-5;
}
}
.q-item {
border-bottom: 1px solid;
cursor: grab;
@at-root .body--light & {
border-bottom-color: rgba(0,0,0,.05);
}
@at-root .body--dark & {
border-bottom-color: rgba(255, 255, 255, .05);
}
&:last-child {
border-bottom: none;
}
}
}
&-content {
.q-list {
min-height: 200px;
padding-bottom: 50px;
}
.handle {
cursor: ns-resize;
}
}
&-box {
background-color: rgba($blue, .05);
border: 2px dashed $primary;
border-radius: 5px;
}
&-meta {
border-bottom: 1px solid;
@at-root .body--light & {
background-color: $grey-2;
box-shadow: inset 0 -1px 0 0 #FFF;
border-bottom-color: rgba(0,0,0,.05);
.q-input {
background-color: #FFF;
}
}
@at-root .body--dark & {
background-color: lighten($dark-3, 2%);
box-shadow: inset 0 -1px 0 0 $dark-6;
border-bottom-color: rgba(255,255,255,.1);
.q-input {
background-color: $dark-5;
}
}
}
&-scrollend {
content: ' ';
width: 1px;
height: 1px;
}
}
</style>
<template lang="pug">
q-menu(
auto-close
anchor='bottom right'
self='top right'
)
q-list(padding)
q-item(clickable, @click='create(`wysiwyg`)')
blueprint-icon(icon='google-presentation')
q-item-section.q-pr-sm New Page
q-item(clickable, @click='create(`markdown`)')
blueprint-icon(icon='markdown')
q-item-section.q-pr-sm New Markdown Page
q-item(clickable, @click='create(`channel`)')
blueprint-icon(icon='chat')
q-item-section.q-pr-sm New Discussion Space
q-item(clickable, @click='create(`blog`)')
blueprint-icon(icon='typewriter-with-paper')
q-item-section.q-pr-sm New Blog Page
q-item(clickable, @click='create(`api`)')
blueprint-icon(icon='api')
q-item-section.q-pr-sm New API Documentation
q-item(clickable, @click='create(`redirect`)')
blueprint-icon(icon='advance')
q-item-section.q-pr-sm New Redirection
q-separator.q-my-sm(inset)
q-item(clickable, to='/f')
blueprint-icon(icon='add-image')
q-item-section.q-pr-sm Upload Media Asset
</template>
<script>
export default {
data () {
return { }
},
methods: {
create (editor) {
this.$store.dispatch('page/pageCreate', { editor })
}
}
}
</script>
<template lang="pug">
q-card.page-properties-dialog
.floating-sidepanel-quickaccess.animated.fadeIn(v-if='showQuickAccess', style='right: 486px;')
template(v-for='(qa, idx) of quickaccess', :key='`qa-` + qa.key')
q-btn(
:icon='qa.icon'
flat
padding='sm xs'
size='sm'
@click='jumpToSection(qa.key)'
)
q-tooltip(anchor='center left' self='center right') {{qa.label}}
q-separator(dark, v-if='idx < quickaccess.length - 1')
q-toolbar.bg-primary.text-white.flex
.text-subtitle2 {{$t('editor.props.pageProperties')}}
q-space
q-btn(
icon='las la-times'
dense
flat
v-close-popup
)
q-scroll-area(
ref='scrollArea'
:thumb-style='thumbStyle'
:bar-style='barStyle'
style='height: calc(100% - 50px);'
)
q-card-section(ref='card-info')
.text-overline.items-center.flex #[q-icon.q-mr-sm(name='las la-info-circle', size='xs')] {{$t('editor.props.info')}}
q-form.q-gutter-sm
q-input(
v-model='title'
:label='$t(`editor.props.title`)'
outlined
dense
)
q-input(
v-model='description'
:label='$t(`editor.props.shortDescription`)'
outlined
dense
)
q-card-section.alt-card(ref='card-publishstate')
.text-overline.q-pb-xs.items-center.flex #[q-icon.q-mr-sm(name='las la-power-off', size='xs')] {{$t('editor.props.publishState')}}
q-form.q-gutter-md
div
q-btn-toggle(
v-model='isPublished'
push
glossy
no-caps
toggle-color='primary'
:options=`[
{ label: $t('editor.props.draft'), value: false },
{ label: $t('editor.props.published'), value: true },
{ label: $t('editor.props.dateRange'), value: null }
]`
)
.text-caption(v-if='isPublished'): em {{$t('editor.props.publishedHint')}}
.text-caption(v-else-if='isPublished === false'): em {{$t('editor.props.draftHint')}}
template(v-else-if='isPublished === null')
.text-caption: em {{$t('editor.props.dateRangeHint')}}
q-date(
v-model='publishingRange'
range
flat
bordered
landscape
minimal
)
q-card-section(ref='card-relations')
.text-overline.items-center.flex #[q-icon.q-mr-sm(name='las la-sun', size='xs')] {{$t('editor.props.relations')}}
q-list.rounded-borders.q-mb-sm.bg-white(
v-if='relations.length > 0'
separator
bordered
)
q-item(v-for='rel of relations', :key='`rel-id-` + rel.id')
q-item-section(side)
q-icon(:name='rel.icon')
q-item-section
q-item-label: strong {{rel.label}}
q-item-label(caption) {{rel.caption}}
q-item-section(side)
q-chip.q-px-sm(
dense
square
color='primary'
text-color='white'
)
.text-caption {{rel.position}}
q-item-section(side)
q-btn(
icon='las la-pen'
dense
flat
padding='none'
@click='editRelation(rel)'
)
q-item-section(side)
q-btn(
icon='las la-times'
dense
flat
padding='none'
@click='removeRelation(rel)'
)
q-btn.full-width(
:label='$t(`editor.props.relationAdd`)'
icon='las la-plus'
no-caps
unelevated
color='secondary'
@click='newRelation'
)
q-tooltip {{$t('editor.props.relationAddHint')}}
q-card-section.alt-card(ref='card-scripts')
.text-overline.items-center.flex #[q-icon.q-mr-sm(name='las la-code', size='xs')] {{$t('editor.props.scripts')}}
q-btn.full-width(
:label='$t(`editor.props.jsLoad`)'
icon='lab la-js-square'
no-caps
unelevated
color='secondary'
@click='editScripts(`jsLoad`)'
)
q-tooltip {{$t('editor.props.jsLoadHint')}}
q-btn.full-width.q-mt-sm(
:label='$t(`editor.props.jsUnload`)'
icon='lab la-js-square'
no-caps
unelevated
color='secondary'
@click='editScripts(`jsUnload`)'
)
q-tooltip {{$t('editor.props.jsUnloadHint')}}
q-btn.full-width.q-mt-sm(
:label='$t(`editor.props.styles`)'
icon='lab la-css3-alt'
no-caps
unelevated
color='secondary'
@click='editScripts(`styles`)'
)
q-tooltip {{$t('editor.props.stylesHint')}}
q-card-section.q-pb-lg(ref='card-sidebar')
.text-overline.items-center.flex #[q-icon.q-mr-sm(name='las la-ruler-vertical', size='xs')] {{$t('editor.props.sidebar')}}
q-form.q-gutter-md.q-pt-sm
div
q-toggle(
v-model='showSidebar'
dense
:label='$t(`editor.props.showSidebar`)'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
)
div
q-toggle(
v-if='showSidebar'
v-model='showToc'
dense
:label='$t(`editor.props.showToc`)'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
)
div(
v-if='showSidebar && showToc'
style='padding-left: 40px;'
)
.text-caption {{$t('editor.props.tocMinMaxDepth')}} #[strong (H{{tocDepth.min}} &rarr; H{{tocDepth.max}})]
q-range(
v-model='tocDepth'
:min='1'
:max='6'
color='primary'
:left-label-value='`H` + tocDepth.min'
:right-label-value='`H` + tocDepth.max'
snap
label
markers
)
div
q-toggle(
v-if='showSidebar'
v-model='showTags'
dense
:label='$t(`editor.props.showTags`)'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
)
q-card-section.alt-card.q-pb-lg(ref='card-social')
.text-overline.items-center.flex #[q-icon.q-mr-sm(name='las la-comments', size='xs')] {{$t('editor.props.social')}}
q-form.q-gutter-md.q-pt-sm
div
q-toggle(
v-model='allowComments'
dense
:label='$t(`editor.props.allowComments`)'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
)
div
q-toggle(
v-model='allowContributions'
dense
:label='$t(`editor.props.allowContributions`)'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
)
div
q-toggle(
v-model='allowRatings'
dense
:label='$t(`editor.props.allowRatings`)'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
)
q-card-section.q-pb-lg(ref='card-tags')
.text-overline.items-center.flex #[q-icon.q-mr-sm(name='las la-tags', size='xs')] {{$t('editor.props.tags')}}
page-tags(edit)
q-card-section.alt-card.q-pb-lg(ref='card-visibility')
.text-overline.items-center.flex #[q-icon.q-mr-sm(name='las la-eye', size='xs')] {{$t('editor.props.visibility')}}
q-form.q-gutter-md.q-pt-sm
div
q-toggle(
v-model='showInTree'
dense
:label='$t(`editor.props.showInTree`)'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
)
div
q-toggle(
v-model='requirePassword'
dense
:label='$t(`editor.props.requirePassword`)'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
)
div(
v-if='requirePassword'
style='padding-left: 40px;'
)
q-input(
ref='iptPagePassword'
v-model='password'
:label='$t(`editor.props.password`)'
:hint='$t(`editor.props.passwordHint`)'
outlined
dense
)
q-dialog(
v-model='showRelationDialog'
)
page-relation-dialog(:edit-id='editRelationId')
q-dialog(
v-model='showScriptsDialog'
)
page-scripts-dialog(:mode='pageScriptsMode')
</template>
<script>
import { get, sync } from 'vuex-pathify'
import PageRelationDialog from './PageRelationDialog.vue'
import PageScriptsDialog from './PageScriptsDialog.vue'
import PageTags from './PageTags.vue'
export default {
components: {
PageRelationDialog,
PageScriptsDialog,
PageTags
},
data () {
return {
showRelationDialog: false,
showScriptsDialog: false,
publishingRange: {},
requirePassword: false,
password: '',
editRelationId: null,
pageScriptsMode: 'jsLoad',
showQuickAccess: true
}
},
computed: {
title: sync('page/title', false),
description: sync('page/description', false),
showInTree: sync('page/showInTree', false),
isPublished: sync('page/isPublished', false),
relations: sync('page/relations', false),
showSidebar: sync('page/showSidebar', false),
showToc: sync('page/showToc', false),
showTags: sync('page/showTags', false),
tocDepth: sync('page/tocDepth', false),
allowComments: sync('page/allowComments', false),
allowContributions: sync('page/allowContributions', false),
allowRatings: sync('page/allowRatings', false),
thumbStyle: get('site/thumbStyle', false),
barStyle: get('site/barStyle', false),
quickaccess () {
return [
{ key: 'info', icon: 'las la-info-circle', label: this.$t('editor.props.info') },
{ key: 'publishstate', icon: 'las la-power-off', label: this.$t('editor.props.publishState') },
{ key: 'relations', icon: 'las la-sun', label: this.$t('editor.props.relations') },
{ key: 'scripts', icon: 'las la-code', label: this.$t('editor.props.scripts') },
{ key: 'sidebar', icon: 'las la-ruler-vertical', label: this.$t('editor.props.sidebar') },
{ key: 'social', icon: 'las la-comments', label: this.$t('editor.props.social') },
{ key: 'tags', icon: 'las la-tags', label: this.$t('editor.props.tags') },
{ key: 'visibility', icon: 'las la-eye', label: this.$t('editor.props.visibility') }
]
}
},
watch: {
requirePassword (newValue) {
if (newValue) {
this.$nextTick(() => {
this.$refs.iptPagePassword.focus()
this.$refs.iptPagePassword.$el.scrollIntoView({
behavior: 'smooth'
})
})
}
}
},
mounted () {
setTimeout(() => {
this.showQuickAccess = true
}, 300)
},
methods: {
editScripts (mode) {
this.pageScriptsMode = mode
this.showScriptsDialog = true
},
newRelation () {
this.editRelationId = null
this.showRelationDialog = true
},
editRelation (rel) {
this.editRelationId = rel.id
this.showRelationDialog = true
},
removeRelation (rel) {
this.relations = this.$store.get('page/relations').filter(r => r.id !== rel.id)
},
jumpToSection (id) {
this.$refs[`card-${id}`].$el.scrollIntoView({
behavior: 'smooth'
})
// this.$refs.scrollArea.setScrollPosition(offset, 600)
}
}
}
</script>
<template lang="pug">
q-card.page-relation-dialog(style='width: 500px;')
q-toolbar.bg-primary.text-white
.text-subtitle2(v-if='isEditMode') {{$t('editor.pageRel.titleEdit')}}
.text-subtitle2(v-else) {{$t('editor.pageRel.title')}}
q-card-section
.text-overline {{$t('editor.pageRel.position')}}
q-form.q-gutter-md.q-pt-md
div
q-btn-toggle(
v-model='pos'
push
glossy
no-caps
toggle-color='primary'
:options=`[
{ label: $t('editor.pageRel.left'), value: 'left' },
{ label: $t('editor.pageRel.center'), value: 'center' },
{ label: $t('editor.pageRel.right'), value: 'right' }
]`
)
.text-overline {{$t('editor.pageRel.button')}}
q-input(
ref='iptRelLabel'
outlined
dense
:label='$t(`editor.pageRel.label`)'
v-model='label'
)
template(v-if='pos !== `center`')
q-input(
outlined
dense
:label='$t(`editor.pageRel.caption`)'
v-model='caption'
)
q-btn.rounded-borders(
:label='$t(`editor.pageRel.selectIcon`)'
color='primary'
outline
)
q-menu(content-class='shadow-7')
icon-picker-dialog(v-model='icon')
.text-overline {{$t('editor.pageRel.target')}}
q-btn.rounded-borders(
:label='$t(`editor.pageRel.selectPage`)'
color='primary'
outline
)
.text-overline {{$t('editor.pageRel.preview')}}
q-btn(
v-if='pos === `left`'
padding='sm md'
outline
:icon='icon'
no-caps
color='primary'
)
.column.text-left.q-pl-md
.text-body2: strong {{label}}
.text-caption {{caption}}
q-btn.full-width(
v-else-if='pos === `center`'
:label='label'
color='primary'
flat
no-caps
:icon='icon'
)
q-btn(
v-else-if='pos === `right`'
padding='sm md'
outline
:icon-right='icon'
no-caps
color='primary'
)
.column.text-left.q-pr-md
.text-body2: strong {{label}}
.text-caption {{caption}}
q-card-actions.card-actions
q-space
q-btn.acrylic-btn(
icon='las la-times'
:label='$t(`common.actions.discard`)'
color='grey-7'
padding='xs md'
v-close-popup
flat
)
q-btn(
v-if='isEditMode'
:disabled='!canSubmit'
icon='las la-check'
:label='$t(`common.actions.save`)'
unelevated
color='primary'
padding='xs md'
@click='persist'
v-close-popup
)
q-btn(
v-else
:disabled='!canSubmit'
icon='las la-plus'
:label='$t(`common.actions.create`)'
unelevated
color='primary'
padding='xs md'
@click='create'
v-close-popup
)
</template>
<script>
import { v4 as uuid } from 'uuid'
import find from 'lodash/find'
import cloneDeep from 'lodash/cloneDeep'
import IconPickerDialog from './IconPickerDialog.vue'
export default {
components: {
IconPickerDialog
},
props: {
editId: {
type: String,
default: null
}
},
data () {
return {
pos: 'left',
label: '',
caption: '',
icon: 'las la-arrow-left',
target: ''
}
},
computed: {
canSubmit () {
return this.label.length > 0
},
isEditMode () {
return Boolean(this.editId)
}
},
watch: {
pos (newValue) {
switch (newValue) {
case 'left': {
this.icon = 'las la-arrow-left'
break
}
case 'center': {
this.icon = 'las la-book'
break
}
case 'right': {
this.icon = 'las la-arrow-right'
break
}
}
}
},
mounted () {
if (this.editId) {
const rel = find(this.$store.get('page/relations'), ['id', this.editId])
if (rel) {
this.pos = rel.position
this.label = rel.label
this.caption = rel.caption || ''
this.icon = rel.icon
this.target = rel.target
}
}
this.$nextTick(() => {
this.$refs.iptRelLabel.focus()
})
},
methods: {
create () {
this.$store.set('page/relations', [
...this.$store.get('page/relations'),
{
id: uuid(),
position: this.pos,
label: this.label,
...(this.pos !== 'center' ? { caption: this.caption } : {}),
icon: this.icon,
target: this.target
}
])
},
persist () {
const rels = cloneDeep(this.$store.get('page/relations'))
for (const rel of rels) {
if (rel.id === this.editId) {
rel.position = this.pos
rel.label = this.label
rel.caption = this.caption
rel.icon = this.icon
rel.target = this.target
}
}
this.$store.set('page/relations', rels)
}
}
}
</script>
<template lang="pug">
q-card.page-save-dialog(style='width: 860px; max-width: 90vw;')
q-toolbar.bg-primary.text-white
.text-subtitle2 {{$t('editor.pageSave.title')}}
page-browser
q-card-section
q-input(
v-model='reason'
label='Reason for change'
dense
outlined
)
q-card-actions.card-actions
q-space
q-btn.acrylic-btn(
icon='las la-times'
:label='$t(`common.actions.cancel`)'
color='grey-7'
padding='xs md'
v-close-popup
flat
)
q-btn(
icon='las la-check'
:label='$t(`common.actions.save`)'
unelevated
color='primary'
padding='xs md'
@click=''
v-close-popup
)
</template>
<script>
import PageBrowser from './PageBrowser.vue'
export default {
components: {
PageBrowser
},
data () {
return {
reason: ''
}
},
computed: {
},
mounted () {
},
methods: {
}
}
</script>
<style lang="scss">
</style>
<template lang="pug">
q-card.page-scripts-dialog(style='width: 860px; max-width: 90vw;')
q-toolbar.bg-primary.text-white
.text-subtitle2 {{$t('editor.pageScripts.title')}} - {{$t('editor.props.' + mode)}}
q-space
q-chip(
square
style='background-color: rgba(0,0,0,.1)'
text-color='white'
)
.text-caption {{this.languageLabel}}
div(style='min-height: 450px;')
q-no-ssr(:placeholder='$t(`common.loading`)')
util-code-editor(
v-if='showEditor'
ref='editor'
v-model='content'
:language='language'
:min-height='450'
)
q-card-actions.card-actions
q-space
q-btn.acrylic-btn(
icon='las la-times'
:label='$t(`common.actions.discard`)'
color='grey-7'
padding='xs md'
v-close-popup
flat
)
q-btn(
icon='las la-check'
:label='$t(`common.actions.save`)'
unelevated
color='primary'
padding='xs md'
@click='persist'
v-close-popup
)
</template>
<script>
import UtilCodeEditor from './UtilCodeEditor.vue'
export default {
components: {
UtilCodeEditor
},
props: {
mode: {
type: String,
default: 'css'
}
},
data () {
return {
content: '',
showEditor: false
}
},
computed: {
language () {
switch (this.mode) {
case 'jsLoad':
case 'jsUnload':
return 'javascript'
case 'styles':
return 'css'
default:
return 'plaintext'
}
},
languageLabel () {
switch (this.language) {
case 'javascript':
return 'Javascript'
case 'css':
return 'CSS'
default:
return 'Plain Text'
}
},
contentStoreKey () {
return 'script' + this.mode.charAt(0).toUpperCase() + this.mode.slice(1)
}
},
mounted () {
this.content = this.$store.get(`page/${this.contentStoreKey}`)
this.$nextTick(() => {
setTimeout(() => {
this.showEditor = true
}, 250)
})
},
methods: {
persist () {
this.$store.set(`page/${this.contentStoreKey}`, this.content)
}
}
}
</script>
<style lang="scss">
</style>
<template lang="pug">
.q-gutter-xs
template(v-if='tags && tags.length > 0')
q-chip(
square
color='secondary'
text-color='white'
dense
clickable
:removable='edit'
@remove='removeTag(tag)'
v-for='tag of tags'
:key='`tag-` + tag'
)
q-icon.q-mr-xs(name='las la-tag', size='14px')
span.text-caption {{tag}}
q-chip(
v-if='!edit && tags.length > 1'
square
color='secondary'
text-color='white'
dense
clickable
)
q-icon(name='las la-tags', size='14px')
q-input.q-mt-md(
v-if='edit'
outlined
v-model='newTag'
dense
placeholder='Add new tag...'
)
</template>
<script>
import { sync } from 'vuex-pathify'
export default {
props: {
edit: {
type: Boolean,
default: false
}
},
data () {
return {
newTag: ''
}
},
computed: {
tags: sync('page/tags', false)
},
methods: {
removeTag (tag) {
this.tags = this.tags.filter(t => t !== tag)
}
}
}
</script>
<template lang="pug">
q-dialog(ref='dialog', @hide='onDialogHide')
q-card(style='min-width: 350px; max-width: 450px;')
q-card-section.card-header
q-icon(name='img:/_assets/icons/fluent-shutdown.svg', left, size='sm')
span {{value ? $t(`admin.sites.activate`) : $t(`admin.sites.deactivate`)}}
q-card-section
.text-body2
i18n-t(:keypath='value ? `admin.sites.activateConfirm` : `admin.sites.deactivateConfirm`')
template(v-slot:siteTitle)
strong {{site.title}}
q-card-actions.card-actions
q-space
q-btn.acrylic-btn(
flat
:label='$t(`common.actions.cancel`)'
color='grey'
padding='xs md'
@click='hide'
)
q-btn(
unelevated
:label='value ? $t(`common.actions.activate`) : $t(`common.actions.deactivate`)'
:color='value ? `positive` : `negative`'
padding='xs md'
@click='confirm'
)
</template>
<script>
import gql from 'graphql-tag'
import cloneDeep from 'lodash/cloneDeep'
export default {
props: {
site: {
type: Object
},
value: {
type: Boolean,
default: false
}
},
emits: ['ok', 'hide'],
data () {
return {
}
},
methods: {
show () {
this.$refs.dialog.show()
},
hide () {
this.$refs.dialog.hide()
},
onDialogHide () {
this.$emit('hide')
},
async confirm () {
try {
const siteId = this.site.id
const resp = await this.$apollo.mutate({
mutation: gql`
mutation updateSite (
$id: UUID!
$newState: Boolean
) {
updateSite(
id: $id
patch: {
isEnabled: $newState
}
) {
status {
succeeded
message
}
}
}
`,
variables: {
id: siteId,
newState: this.value
}
})
if (resp?.data?.updateSite?.status?.succeeded) {
this.$q.notify({
type: 'positive',
message: this.$t('admin.sites.updateSuccess')
})
this.$store.set('admin/sites', this.$store.get('admin/sites').map(s => {
if (s.id === siteId) {
const ns = cloneDeep(s)
ns.isEnabled = this.value
return ns
} else {
return s
}
}))
this.$emit('ok')
this.hide()
} else {
throw new Error(resp?.data?.updateSite?.status?.message || 'An unexpected error occured.')
}
} catch (err) {
this.$q.notify({
type: 'negative',
message: err.message
})
}
}
}
}
</script>
<template lang="pug">
q-dialog(ref='dialog', @hide='onDialogHide')
q-card(style='min-width: 450px;')
q-card-section.card-header
q-icon(name='img:/_assets/icons/fluent-plus-plus.svg', left, size='sm')
span {{$t(`admin.sites.new`)}}
q-form.q-py-sm(ref='createSiteForm')
q-item
blueprint-icon(icon='home')
q-item-section
q-input(
outlined
v-model='siteName'
dense
:rules=`[
val => val.length > 0 || $t('admin.sites.nameMissing'),
val => /^[^<>"]+$/.test(val) || $t('admin.sites.nameInvalidChars')
]`
hide-bottom-space
:label='$t(`common.field.name`)'
:aria-label='$t(`common.field.name`)'
lazy-rules='ondemand'
autofocus
)
q-item
blueprint-icon.self-start(icon='dns')
q-item-section
q-input(
outlined
v-model='siteHostname'
dense
:rules=`[
val => val.length > 0 || $t('admin.sites.hostnameMissing'),
val => /^(\\*)|([a-z0-9\-.:]+)$/.test(val) || $t('admin.sites.hostnameInvalidChars')
]`
:hint='$t(`admin.sites.hostnameHint`)'
hide-bottom-space
:label='$t(`admin.sites.hostname`)'
:aria-label='$t(`admin.sites.hostname`)'
lazy-rules='ondemand'
)
q-card-actions.card-actions
q-space
q-btn.acrylic-btn(
flat
:label='$t(`common.actions.cancel`)'
color='grey'
padding='xs md'
@click='hide'
)
q-btn(
unelevated
:label='$t(`common.actions.create`)'
color='primary'
padding='xs md'
@click='create'
:loading='isLoading'
)
</template>
<script>
import gql from 'graphql-tag'
export default {
emits: ['ok', 'hide'],
data () {
return {
siteName: '',
siteHostname: 'wiki.example.com',
isLoading: false
}
},
methods: {
show () {
this.$refs.dialog.show()
},
hide () {
this.$refs.dialog.hide()
},
onDialogHide () {
this.$emit('hide')
},
async create () {
this.isLoading = true
try {
const isFormValid = await this.$refs.createSiteForm.validate(true)
if (!isFormValid) {
throw new Error(this.$t('admin.sites.createInvalidData'))
}
const resp = await this.$apollo.mutate({
mutation: gql`
mutation createSite (
$hostname: String!
$title: String!
) {
createSite(
hostname: $hostname
title: $title
) {
status {
succeeded
message
}
}
}
`,
variables: {
hostname: this.siteHostname,
title: this.siteName
}
})
if (resp?.data?.createSite?.status?.succeeded) {
this.$q.notify({
type: 'positive',
message: this.$t('admin.sites.createSuccess')
})
await this.$store.dispatch('admin/fetchSites')
this.$emit('ok')
this.hide()
} else {
throw new Error(resp?.data?.createSite?.status?.message || 'An unexpected error occured.')
}
} catch (err) {
this.$q.notify({
type: 'negative',
message: err.message
})
}
this.isLoading = false
}
}
}
</script>
<template lang="pug">
q-dialog(ref='dialog', @hide='onDialogHide')
q-card(style='min-width: 350px; max-width: 450px;')
q-card-section.card-header
q-icon(name='img:/_assets/icons/fluent-delete-bin.svg', left, size='sm')
span {{$t(`admin.sites.delete`)}}
q-card-section
.text-body2
i18n-t(keypath='admin.sites.deleteConfirm')
template(v-slot:siteTitle)
strong {{site.title}}
.text-body2.q-mt-md
strong.text-negative {{$t(`admin.sites.deleteConfirmWarn`)}}
q-card-actions.card-actions
q-space
q-btn.acrylic-btn(
flat
:label='$t(`common.actions.cancel`)'
color='grey'
padding='xs md'
@click='hide'
)
q-btn(
unelevated
:label='$t(`common.actions.delete`)'
color='negative'
padding='xs md'
@click='confirm'
)
</template>
<script>
import gql from 'graphql-tag'
export default {
props: {
site: {
type: Object
}
},
emits: ['ok', 'hide'],
data () {
return {
}
},
methods: {
show () {
this.$refs.dialog.show()
},
hide () {
this.$refs.dialog.hide()
},
onDialogHide () {
this.$emit('hide')
},
async confirm () {
try {
const siteId = this.site.id
const resp = await this.$apollo.mutate({
mutation: gql`
mutation deleteSite ($id: UUID!) {
deleteSite(id: $id) {
status {
succeeded
message
}
}
}
`,
variables: {
id: siteId
}
})
if (resp?.data?.deleteSite?.status?.succeeded) {
this.$q.notify({
type: 'positive',
message: this.$t('admin.sites.deleteSuccess')
})
this.$store.set('admin/sites', this.$store.get('admin/sites').filter(s => s.id !== siteId))
this.$emit('ok')
this.hide()
} else {
throw new Error(resp?.data?.deleteSite?.status?.message || 'An unexpected error occured.')
}
} catch (err) {
this.$q.notify({
type: 'negative',
message: err.message
})
}
}
}
}
</script>
<template lang="pug">
q-menu(
auto-close
anchor='bottom middle'
self='top middle'
@show='menuShown'
@before-hide='menuHidden'
)
q-list(dense, padding)
q-item(clickable, @click='', ref='copyUrlButton')
q-item-section.items-center(avatar)
q-icon(color='grey', name='las la-clipboard', size='sm')
q-item-section.q-pr-md Copy URL
q-item(clickable, tag='a', :href='`mailto:?subject=` + encodeURIComponent(title) + `&body=` + encodeURIComponent(urlFormatted) + `%0D%0A%0D%0A` + encodeURIComponent(description)', target='_blank')
q-item-section.items-center(avatar)
q-icon(color='grey', name='las la-envelope', size='sm')
q-item-section.q-pr-md Email
q-item(clickable, @click='openSocialPop(`https://www.facebook.com/sharer/sharer.php?u=` + encodeURIComponent(urlFormatted) + `&title=` + encodeURIComponent(title) + `&description=` + encodeURIComponent(description))')
q-item-section.items-center(avatar)
q-icon(color='grey', name='lab la-facebook', size='sm')
q-item-section.q-pr-md Facebook
q-item(clickable, @click='openSocialPop(`https://www.linkedin.com/shareArticle?mini=true&url=` + encodeURIComponent(urlFormatted) + `&title=` + encodeURIComponent(title) + `&summary=` + encodeURIComponent(description))')
q-item-section.items-center(avatar)
q-icon(color='grey', name='lab la-linkedin', size='sm')
q-item-section.q-pr-md LinkedIn
q-item(clickable, @click='openSocialPop(`https://www.reddit.com/submit?url=` + encodeURIComponent(urlFormatted) + `&title=` + encodeURIComponent(title))')
q-item-section.items-center(avatar)
q-icon(color='grey', name='lab la-reddit', size='sm')
q-item-section.q-pr-md Reddit
q-item(clickable, @click='openSocialPop(`https://t.me/share/url?url=` + encodeURIComponent(urlFormatted) + `&text=` + encodeURIComponent(title))')
q-item-section.items-center(avatar)
q-icon(color='grey', name='lab la-telegram', size='sm')
q-item-section.q-pr-md Telegram
q-item(clickable, @click='openSocialPop(`https://twitter.com/intent/tweet?url=` + encodeURIComponent(urlFormatted) + `&text=` + encodeURIComponent(title))')
q-item-section.items-center(avatar)
q-icon(color='grey', name='lab la-twitter', size='sm')
q-item-section.q-pr-md Twitter
q-item(clickable, :href='`viber://forward?text=` + encodeURIComponent(urlFormatted) + ` ` + encodeURIComponent(description)')
q-item-section.items-center(avatar)
q-icon(color='grey', name='lab la-viber', size='sm')
q-item-section.q-pr-md Viber
q-item(clickable, @click='openSocialPop(`http://service.weibo.com/share/share.php?url=` + encodeURIComponent(urlFormatted) + `&title=` + encodeURIComponent(title))')
q-item-section.items-center(avatar)
q-icon(color='grey', name='lab la-weibo', size='sm')
q-item-section.q-pr-md Weibo
q-item(clickable, @click='openSocialPop(`https://api.whatsapp.com/send?text=` + encodeURIComponent(title) + `%0D%0A` + encodeURIComponent(urlFormatted))')
q-item-section.items-center(avatar)
q-icon(color='grey', name='lab la-whatsapp', size='sm')
q-item-section.q-pr-md Whatsapp
</template>
<script>
import ClipboardJS from 'clipboard'
export default {
props: {
url: {
type: String,
default: null
},
title: {
type: String,
default: 'Untitled Page'
},
description: {
type: String,
default: ''
}
},
data () {
return {
width: 626,
height: 436,
left: 0,
top: 0,
clip: null
}
},
computed: {
urlFormatted () {
if (!import.meta.env.SSR) {
return this.url ? this.url : window.location.href
} else {
return ''
}
}
},
methods: {
openSocialPop (url) {
const popupWindow = window.open(
url,
'sharer',
`status=no,height=${this.height},width=${this.width},resizable=yes,left=${this.left},top=${this.top},screenX=${this.left},screenY=${this.top},toolbar=no,menubar=no,scrollbars=no,location=no,directories=no`
)
popupWindow.focus()
},
menuShown (ev) {
this.clip = new ClipboardJS(this.$refs.copyUrlButton.$el, {
text: () => { return this.urlFormatted }
})
this.clip.on('success', () => {
this.$q.notify({
message: 'URL copied successfully',
icon: 'las la-clipboard'
})
})
this.clip.on('error', () => {
this.$q.notify({
type: 'negative',
message: 'Failed to copy to clipboard'
})
})
},
menuHidden (ev) {
this.clip.destroy()
}
},
mounted () {
/**
* Center the popup on dual screens
* http://stackoverflow.com/questions/4068373/center-a-popup-window-on-screen/32261263
*/
const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left
const dualScreenTop = window.screenTop !== undefined ? window.screenTop : screen.top
const width = window.innerWidth ? window.innerWidth : (document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width)
const height = window.innerHeight ? window.innerHeight : (document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height)
this.left = ((width / 2) - (this.width / 2)) + dualScreenLeft
this.top = ((height / 2) - (this.height / 2)) + dualScreenTop
}
}
</script>
<template lang="pug">
q-dialog(ref='dialog', @hide='onDialogHide')
q-card(style='min-width: 650px;')
q-card-section.card-header
q-icon(name='img:/_assets/icons/fluent-password-reset.svg', left, size='sm')
span {{$t(`admin.users.changePassword`)}}
q-form.q-py-sm(ref='changeUserPwdForm', @submit='save')
q-item
blueprint-icon(icon='password')
q-item-section
q-input(
outlined
v-model='userPassword'
dense
:rules=`[
val => val.length > 0 || $t('admin.users.passwordMissing'),
val => val.length >= 8 || $t('admin.users.passwordTooShort')
]`
hide-bottom-space
:label='$t(`admin.users.password`)'
:aria-label='$t(`admin.users.password`)'
lazy-rules='ondemand'
autofocus
)
template(#append)
.flex.items-center
q-badge(
:color='passwordStrength.color'
:label='passwordStrength.label'
)
q-separator.q-mx-sm(vertical)
q-btn(
flat
dense
padding='none xs'
color='brown'
@click='randomizePassword'
)
q-icon(name='las la-dice-d6')
.q-pl-xs.text-caption: strong Generate
q-item(tag='label', v-ripple)
blueprint-icon(icon='password-reset')
q-item-section
q-item-label {{$t(`admin.users.mustChangePwd`)}}
q-item-label(caption) {{$t(`admin.users.mustChangePwdHint`)}}
q-item-section(avatar)
q-toggle(
v-model='userMustChangePassword'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.users.mustChangePwd`)'
)
q-card-actions.card-actions
q-space
q-btn.acrylic-btn(
flat
:label='$t(`common.actions.cancel`)'
color='grey'
padding='xs md'
@click='hide'
)
q-btn(
unelevated
:label='$t(`common.actions.update`)'
color='primary'
padding='xs md'
@click='save'
:loading='isLoading'
)
</template>
<script>
import gql from 'graphql-tag'
import sampleSize from 'lodash/sampleSize'
import zxcvbn from 'zxcvbn'
export default {
props: {
userId: {
type: String,
required: true
}
},
emits: ['ok', 'hide'],
data () {
return {
userPassword: '',
userMustChangePassword: false,
isLoading: false
}
},
computed: {
passwordStrength () {
if (this.userPassword.length < 8) {
return {
color: 'negative',
label: this.$t('admin.users.pwdStrengthWeak')
}
} else {
switch (zxcvbn(this.userPassword).score) {
case 1:
return {
color: 'deep-orange-7',
label: this.$t('admin.users.pwdStrengthPoor')
}
case 2:
return {
color: 'purple-7',
label: this.$t('admin.users.pwdStrengthMedium')
}
case 3:
return {
color: 'blue-7',
label: this.$t('admin.users.pwdStrengthGood')
}
case 4:
return {
color: 'green-7',
label: this.$t('admin.users.pwdStrengthStrong')
}
default:
return {
color: 'negative',
label: this.$t('admin.users.pwdStrengthWeak')
}
}
}
}
},
methods: {
show () {
this.$refs.dialog.show()
},
hide () {
this.$refs.dialog.hide()
},
onDialogHide () {
this.$emit('hide')
},
randomizePassword () {
const pwdChars = 'abcdefghkmnpqrstuvwxyzABCDEFHJKLMNPQRSTUVWXYZ23456789_*=?#!()+'
this.userPassword = sampleSize(pwdChars, 16).join('')
},
async save () {
this.isLoading = true
try {
const isFormValid = await this.$refs.changeUserPwdForm.validate(true)
if (!isFormValid) {
throw new Error(this.$t('admin.users.createInvalidData'))
}
const resp = await this.$apollo.mutate({
mutation: gql`
mutation adminUpdateUserPwd (
$id: UUID!
$patch: UserUpdateInput!
) {
updateUser (
id: $id
patch: $patch
) {
status {
succeeded
message
}
}
}
`,
variables: {
id: this.userId,
patch: {
newPassword: this.userPassword,
mustChangePassword: this.userMustChangePassword
}
}
})
if (resp?.data?.updateUser?.status?.succeeded) {
this.$q.notify({
type: 'positive',
message: this.$t('admin.users.createSuccess')
})
this.$emit('ok', {
mustChangePassword: this.userMustChangePassword
})
this.hide()
} else {
throw new Error(resp?.data?.updateUser?.status?.message || 'An unexpected error occured.')
}
} catch (err) {
this.$q.notify({
type: 'negative',
message: err.message
})
}
this.isLoading = false
}
}
}
</script>
<template lang="pug">
q-dialog(ref='dialog', @hide='onDialogHide')
q-card(style='min-width: 650px;')
q-card-section.card-header
q-icon(name='img:/_assets/icons/fluent-plus-plus.svg', left, size='sm')
span {{$t(`admin.users.create`)}}
q-form.q-py-sm(ref='createUserForm', @submit='create')
q-item
blueprint-icon(icon='person')
q-item-section
q-input(
outlined
v-model='userName'
dense
:rules=`[
val => val.length > 0 || $t('admin.users.nameMissing'),
val => /^[^<>"]+$/.test(val) || $t('admin.users.nameInvalidChars')
]`
hide-bottom-space
:label='$t(`common.field.name`)'
:aria-label='$t(`common.field.name`)'
lazy-rules='ondemand'
autofocus
ref='iptName'
)
q-item
blueprint-icon(icon='email')
q-item-section
q-input(
outlined
v-model='userEmail'
dense
type='email'
:rules=`[
val => val.length > 0 || $t('admin.users.emailMissing'),
val => /^.+\@.+\..+$/.test(val) || $t('admin.users.emailInvalid')
]`
hide-bottom-space
:label='$t(`admin.users.email`)'
:aria-label='$t(`admin.users.email`)'
lazy-rules='ondemand'
autofocus
)
q-item
blueprint-icon(icon='password')
q-item-section
q-input(
outlined
v-model='userPassword'
dense
:rules=`[
val => val.length > 0 || $t('admin.users.passwordMissing'),
val => val.length >= 8 || $t('admin.users.passwordTooShort')
]`
hide-bottom-space
:label='$t(`admin.users.password`)'
:aria-label='$t(`admin.users.password`)'
lazy-rules='ondemand'
autofocus
)
template(#append)
.flex.items-center
q-badge(
:color='passwordStrength.color'
:label='passwordStrength.label'
)
q-separator.q-mx-sm(vertical)
q-btn(
flat
dense
padding='none xs'
color='brown'
@click='randomizePassword'
)
q-icon(name='las la-dice-d6')
.q-pl-xs.text-caption: strong Generate
q-item
blueprint-icon(icon='team')
q-item-section
q-select(
outlined
:options='groups'
v-model='userGroups'
multiple
map-options
emit-value
option-value='id'
option-label='name'
options-dense
dense
:rules=`[
val => val.length > 0 || $t('admin.users.groupsMissing')
]`
hide-bottom-space
:label='$t(`admin.users.groups`)'
:aria-label='$t(`admin.users.groups`)'
lazy-rules='ondemand'
:loading='loadingGroups'
)
template(v-slot:selected)
.text-caption(v-if='userGroups.length > 1')
i18n-t(keypath='admin.users.groupsSelected')
template(#count)
strong {{ userGroups.length }}
.text-caption(v-else-if='userGroups.length === 1')
i18n-t(keypath='admin.users.groupSelected')
template(#group)
strong {{ selectedGroupName }}
span(v-else)
template(v-slot:option='{ itemProps, itemEvents, opt, selected, toggleOption }')
q-item(
v-bind='itemProps'
v-on='itemEvents'
)
q-item-section(side)
q-checkbox(
size='sm'
:model-value='selected'
@update:model-value='toggleOption(opt)'
)
q-item-section
q-item-label {{opt.name}}
q-item(tag='label', v-ripple)
blueprint-icon(icon='password-reset')
q-item-section
q-item-label {{$t(`admin.users.mustChangePwd`)}}
q-item-label(caption) {{$t(`admin.users.mustChangePwdHint`)}}
q-item-section(avatar)
q-toggle(
v-model='userMustChangePassword'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.users.mustChangePwd`)'
)
q-item(tag='label', v-ripple)
blueprint-icon(icon='email-open')
q-item-section
q-item-label {{$t(`admin.users.sendWelcomeEmail`)}}
q-item-label(caption) {{$t(`admin.users.sendWelcomeEmailHint`)}}
q-item-section(avatar)
q-toggle(
v-model='userSendWelcomeEmail'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.users.sendWelcomeEmail`)'
)
q-card-actions.card-actions
q-checkbox(
v-model='keepOpened'
color='primary'
:label='$t(`admin.users.createKeepOpened`)'
size='sm'
)
q-space
q-btn.acrylic-btn(
flat
:label='$t(`common.actions.cancel`)'
color='grey'
padding='xs md'
@click='hide'
)
q-btn(
unelevated
:label='$t(`common.actions.create`)'
color='primary'
padding='xs md'
@click='create'
:loading='loading > 0'
)
</template>
<script>
import gql from 'graphql-tag'
import sampleSize from 'lodash/sampleSize'
import zxcvbn from 'zxcvbn'
import cloneDeep from 'lodash/cloneDeep'
export default {
emits: ['ok', 'hide'],
data () {
return {
userName: '',
userEmail: '',
userPassword: '',
userGroups: [],
userMustChangePassword: false,
userSendWelcomeEmail: false,
keepOpened: false,
groups: [],
loadingGroups: false,
loading: false
}
},
computed: {
passwordStrength () {
if (this.userPassword.length < 8) {
return {
color: 'negative',
label: this.$t('admin.users.pwdStrengthWeak')
}
} else {
switch (zxcvbn(this.userPassword).score) {
case 1:
return {
color: 'deep-orange-7',
label: this.$t('admin.users.pwdStrengthPoor')
}
case 2:
return {
color: 'purple-7',
label: this.$t('admin.users.pwdStrengthMedium')
}
case 3:
return {
color: 'blue-7',
label: this.$t('admin.users.pwdStrengthGood')
}
case 4:
return {
color: 'green-7',
label: this.$t('admin.users.pwdStrengthStrong')
}
default:
return {
color: 'negative',
label: this.$t('admin.users.pwdStrengthWeak')
}
}
}
},
selectedGroupName () {
return this.groups.filter(g => g.id === this.userGroups[0])[0]?.name
}
},
methods: {
async show () {
this.$refs.dialog.show()
this.loading++
this.loadingGroups = true
const resp = await this.$apollo.query({
query: gql`
query getGroupsForCreateUser {
groups {
id
name
}
}
`,
fetchPolicy: 'network-only'
})
this.groups = cloneDeep(resp?.data?.groups?.filter(g => g.id !== '10000000-0000-4000-0000-000000000001') ?? [])
this.loadingGroups = false
this.loading--
},
hide () {
this.$refs.dialog.hide()
},
onDialogHide () {
this.$emit('hide')
},
randomizePassword () {
const pwdChars = 'abcdefghkmnpqrstuvwxyzABCDEFHJKLMNPQRSTUVWXYZ23456789_*=?#!()+'
this.userPassword = sampleSize(pwdChars, 16).join('')
},
async create () {
this.loading++
try {
const isFormValid = await this.$refs.createUserForm.validate(true)
if (!isFormValid) {
throw new Error(this.$t('admin.users.createInvalidData'))
}
const resp = await this.$apollo.mutate({
mutation: gql`
mutation createUser (
$name: String!
$email: String!
$password: String!
$groups: [UUID]!
$mustChangePassword: Boolean!
$sendWelcomeEmail: Boolean!
) {
createUser (
name: $name
email: $email
password: $password
groups: $groups
mustChangePassword: $mustChangePassword
sendWelcomeEmail: $sendWelcomeEmail
) {
status {
succeeded
message
}
}
}
`,
variables: {
name: this.userName,
email: this.userEmail,
password: this.userPassword,
groups: this.userGroups,
mustChangePassword: this.userMustChangePassword,
sendWelcomeEmail: this.userSendWelcomeEmail
}
})
if (resp?.data?.createUser?.status?.succeeded) {
this.$q.notify({
type: 'positive',
message: this.$t('admin.users.createSuccess')
})
if (this.keepOpened) {
this.userName = ''
this.userEmail = ''
this.userPassword = ''
this.$refs.iptName.focus()
} else {
this.$emit('ok')
this.hide()
}
} else {
throw new Error(resp?.data?.createUser?.status?.message || 'An unexpected error occured.')
}
} catch (err) {
this.$q.notify({
type: 'negative',
message: err.message
})
}
this.loading--
}
}
}
</script>
<template lang="pug">
q-layout(view='hHh lpR fFf', container)
q-header.card-header.q-px-md.q-py-sm
q-icon(name='img:/_assets/icons/fluent-account.svg', left, size='md')
div
span {{$t(`admin.users.edit`)}}
.text-caption {{user.name}}
q-space
q-btn-group(push)
q-btn(
push
color='grey-6'
text-color='white'
:aria-label='$t(`common.actions.refresh`)'
icon='las la-redo-alt'
@click='load'
:loading='loading > 0'
)
q-tooltip(anchor='center left', self='center right') {{$t(`common.actions.refresh`)}}
q-btn(
push
color='white'
text-color='grey-7'
:label='$t(`common.actions.close`)'
:aria-label='$t(`common.actions.close`)'
icon='las la-times'
@click='close'
)
q-btn(
push
color='positive'
text-color='white'
:label='$t(`common.actions.save`)'
:aria-label='$t(`common.actions.save`)'
icon='las la-check'
@click='save()'
:disabled='loading > 0'
)
q-drawer.bg-dark-6(:model-value='true', :width='250', dark)
q-list(padding, v-if='loading < 1')
q-item(
v-for='sc of sections'
:key='`section-` + sc.key'
clickable
:to='{ params: { section: sc.key } }'
active-class='bg-primary text-white'
:disabled='sc.disabled'
)
q-item-section(side)
q-icon(:name='sc.icon', color='white')
q-item-section {{sc.text}}
q-page-container
q-page(v-if='loading > 0')
.flex.q-pa-lg.items-center
q-spinner-tail(color='primary', size='32px', :thickness='2')
.text-caption.text-primary.q-pl-md: strong {{$t('admin.users.loading')}}
q-page(v-else-if='$route.params.section === `overview`')
.q-pa-md
.row.q-col-gutter-md
.col-12.col-lg-8
q-card.shadow-1.q-pb-sm
q-card-section
.text-subtitle1 {{$t('admin.users.profile')}}
q-item
blueprint-icon(icon='contact')
q-item-section
q-item-label {{$t(`admin.users.name`)}}
q-item-label(caption) {{$t(`admin.users.nameHint`)}}
q-item-section
q-input(
outlined
v-model='user.name'
dense
:rules=`[
val => invalidCharsRegex.test(val) || $t('admin.users.nameInvalidChars')
]`
hide-bottom-space
:aria-label='$t(`admin.users.name`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='envelope')
q-item-section
q-item-label {{$t(`admin.users.email`)}}
q-item-label(caption) {{$t(`admin.users.emailHint`)}}
q-item-section
q-input(
outlined
v-model='user.email'
dense
:aria-label='$t(`admin.users.email`)'
)
template(v-if='user.meta')
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='address')
q-item-section
q-item-label {{$t(`admin.users.location`)}}
q-item-label(caption) {{$t(`admin.users.locationHint`)}}
q-item-section
q-input(
outlined
v-model='user.meta.location'
dense
:aria-label='$t(`admin.users.location`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='new-job')
q-item-section
q-item-label {{$t(`admin.users.jobTitle`)}}
q-item-label(caption) {{$t(`admin.users.jobTitleHint`)}}
q-item-section
q-input(
outlined
v-model='user.meta.jobTitle'
dense
:aria-label='$t(`admin.users.jobTitle`)'
)
q-card.shadow-1.q-pb-sm.q-mt-md(v-if='user.meta')
q-card-section
.text-subtitle1 {{$t('admin.users.preferences')}}
q-item
blueprint-icon(icon='timezone')
q-item-section
q-item-label {{$t(`admin.users.timezone`)}}
q-item-label(caption) {{$t(`admin.users.timezoneHint`)}}
q-item-section
q-select(
outlined
v-model='user.prefs.timezone'
:options='timezones'
option-value='value'
option-label='text'
emit-value
map-options
dense
options-dense
:aria-label='$t(`admin.users.timezone`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='calendar')
q-item-section
q-item-label {{$t(`admin.users.dateFormat`)}}
q-item-label(caption) {{$t(`admin.users.dateFormatHint`)}}
q-item-section
q-select(
outlined
v-model='user.prefs.dateFormat'
emit-value
map-options
dense
:aria-label='$t(`admin.users.dateFormat`)'
:options=`[
{ label: $t('profile.localeDefault'), value: '' },
{ label: 'DD/MM/YYYY', value: 'DD/MM/YYYY' },
{ label: 'DD.MM.YYYY', value: 'DD.MM.YYYY' },
{ label: 'MM/DD/YYYY', value: 'MM/DD/YYYY' },
{ label: 'YYYY-MM-DD', value: 'YYYY-MM-DD' },
{ label: 'YYYY/MM/DD', value: 'YYYY/MM/DD' }
]`
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='clock')
q-item-section
q-item-label {{$t(`admin.users.timeFormat`)}}
q-item-label(caption) {{$t(`admin.users.timeFormatHint`)}}
q-item-section.col-auto
q-btn-toggle(
v-model='user.prefs.timeFormat'
push
glossy
no-caps
toggle-color='primary'
:options=`[
{ label: $t('profile.timeFormat12h'), value: '12h' },
{ label: $t('profile.timeFormat24h'), value: '24h' }
]`
)
q-separator.q-my-sm(inset)
q-item(tag='label', v-ripple)
blueprint-icon(icon='light-on')
q-item-section
q-item-label {{$t(`admin.users.darkMode`)}}
q-item-label(caption) {{$t(`admin.users.darkModeHint`)}}
q-item-section(avatar)
q-toggle(
v-model='user.prefs.darkMode'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.users.darkMode`)'
)
.col-12.col-lg-4
q-card.shadow-1.q-pb-sm
q-card-section
.text-subtitle1 {{$t('admin.users.info')}}
q-item
blueprint-icon(icon='person', :hue-rotate='-45')
q-item-section
q-item-label {{$t(`common.field.id`)}}
q-item-label: strong {{userId}}
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='calendar-plus', :hue-rotate='-45')
q-item-section
q-item-label {{$t(`common.field.createdOn`)}}
q-item-label: strong {{humanizeDate(user.createdAt)}}
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='summertime', :hue-rotate='-45')
q-item-section
q-item-label {{$t(`common.field.lastUpdated`)}}
q-item-label: strong {{humanizeDate(user.updatedAt)}}
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='enter', :hue-rotate='-45')
q-item-section
q-item-label {{$t(`admin.users.lastLoginAt`)}}
q-item-label: strong {{humanizeDate(user.lastLoginAt)}}
q-card.shadow-1.q-pb-sm.q-mt-md(v-if='user.meta')
q-card-section
.text-subtitle1 {{$t('admin.users.notes')}}
q-input.q-mt-sm(
outlined
v-model='user.meta.notes'
type='textarea'
:aria-label='$t(`admin.users.notes`)'
input-style='min-height: 243px'
:hint='$t(`admin.users.noteHint`)'
)
q-page(v-else-if='$route.params.section === `activity`')
span ---
q-page(v-else-if='$route.params.section === `auth`')
.q-pa-md
.row.q-col-gutter-md
.col-12.col-lg-7
q-card.shadow-1.q-pb-sm
q-card-section
.text-subtitle1 {{$t('admin.users.passAuth')}}
q-item
blueprint-icon(icon='password', :hue-rotate='45')
q-item-section
q-item-label {{$t(`admin.users.changePassword`)}}
q-item-label(caption) {{$t(`admin.users.changePasswordHint`)}}
q-item-label(caption): strong(:class='localAuth.password ? `text-positive` : `text-negative`') {{localAuth.password ? $t(`admin.users.pwdSet`) : $t(`admin.users.pwdNotSet`)}}
q-item-section(side)
q-btn.acrylic-btn(
flat
icon='las la-arrow-circle-right'
color='primary'
@click='changePassword'
:label='$t(`common.actions.proceed`)'
)
q-separator.q-my-sm(inset)
q-item(tag='label', v-ripple)
blueprint-icon(icon='password-reset')
q-item-section
q-item-label {{$t(`admin.users.mustChangePwd`)}}
q-item-label(caption) {{$t(`admin.users.mustChangePwdHint`)}}
q-item-section(avatar)
q-toggle(
v-model='localAuth.mustChangePwd'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.users.mustChangePwd`)'
)
q-separator.q-my-sm(inset)
q-item(tag='label', v-ripple)
blueprint-icon(icon='key')
q-item-section
q-item-label {{$t(`admin.users.pwdAuthRestrict`)}}
q-item-label(caption) {{$t(`admin.users.pwdAuthRestrictHint`)}}
q-item-section(avatar)
q-toggle(
v-model='localAuth.restrictLogin'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.users.pwdAuthRestrict`)'
)
q-card.shadow-1.q-pb-sm.q-mt-md
q-card-section
.text-subtitle1 {{$t('admin.users.tfa')}}
q-item(tag='label', v-ripple)
blueprint-icon(icon='key')
q-item-section
q-item-label {{$t(`admin.users.tfaRequired`)}}
q-item-label(caption) {{$t(`admin.users.tfaRequiredHint`)}}
q-item-section(avatar)
q-toggle(
v-model='localAuth.tfaRequired'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.users.tfaRequired`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='password', :hue-rotate='45')
q-item-section
q-item-label {{$t(`admin.users.tfaInvalidate`)}}
q-item-label(caption) {{$t(`admin.users.tfaInvalidateHint`)}}
q-item-label(caption): strong(:class='localAuth.tfaSecret ? `text-positive` : `text-negative`') {{localAuth.tfaSecret ? $t(`admin.users.tfaSet`) : $t(`admin.users.tfaNotSet`)}}
q-item-section(side)
q-btn.acrylic-btn(
flat
icon='las la-arrow-circle-right'
color='primary'
@click='invalidateTFA'
:label='$t(`common.actions.proceed`)'
)
.col-12.col-lg-5
q-card.shadow-1.q-pb-sm
q-card-section
.text-subtitle1 {{$t('admin.users.linkedProviders')}}
q-banner.q-mt-md(
v-if='linkedAuthProviders.length < 1'
rounded
:class='$q.dark.isActive ? `bg-negative text-white` : `bg-grey-2 text-grey-7`'
) {{$t('admin.users.noLinkedProviders')}}
template(
v-for='(prv, idx) in linkedAuthProviders'
:key='prv._id'
)
q-separator.q-my-sm(inset, v-if='idx > 0')
q-item
blueprint-icon(icon='google', :hue-rotate='-45')
q-item-section
q-item-label {{prv._moduleName}}
q-item-label(caption) {{prv.key}}
q-page(v-else-if='$route.params.section === `groups`')
.q-pa-md
.row.q-col-gutter-md
.col-12.col-lg-8
q-card.shadow-1.q-pb-sm
q-card-section
.text-subtitle1 {{$t('admin.users.groups')}}
template(
v-for='(grp, idx) of user.groups'
:key='grp.id'
)
q-separator.q-my-sm(inset, v-if='idx > 0')
q-item
blueprint-icon(icon='team', :hue-rotate='-45')
q-item-section
q-item-label {{grp.name}}
q-item-section(side)
q-btn.acrylic-btn(
flat
icon='las la-times'
color='accent'
@click='unassignGroup(grp.id)'
:aria-label='$t(`admin.users.unassignGroup`)'
)
q-tooltip(anchor='center left' self='center right') {{$t('admin.users.unassignGroup')}}
q-card.shadow-1.q-py-sm.q-mt-md
q-item
blueprint-icon(icon='join')
q-item-section
q-select(
outlined
:options='groups'
v-model='groupToAdd'
map-options
emit-value
option-value='id'
option-label='name'
options-dense
dense
hide-bottom-space
:label='$t(`admin.users.groups`)'
:aria-label='$t(`admin.users.groups`)'
:loading='loading > 0'
)
q-item-section(side)
q-btn(
unelevated
icon='las la-plus'
:label='$t(`admin.users.assignGroup`)'
color='primary'
@click='assignGroup'
)
q-page(v-else-if='$route.params.section === `metadata`')
.q-pa-md
.row.q-col-gutter-md
.col-12.col-lg-8
q-card.shadow-1.q-pb-sm
q-card-section.flex.items-center
.text-subtitle1 {{$t('admin.users.metadata')}}
q-space
q-badge(
v-if='metadataInvalidJSON'
color='negative'
)
q-icon.q-mr-xs(name='las la-exclamation-triangle', size='20px')
span {{$t('admin.users.invalidJSON')}}
q-badge.q-py-xs(
v-else
label='JSON'
color='positive'
)
q-item
q-item-section
q-no-ssr(:placeholder='$t(`common.loading`)')
util-code-editor.admin-theme-cm(
v-model='metadata'
language='json'
:min-height='500'
)
q-page(v-else-if='$route.params.section === `operations`')
.q-pa-md
.row.q-col-gutter-md
.col-12.col-lg-8
q-card.shadow-1.q-pb-sm
q-card-section
.text-subtitle1 {{$t('admin.users.operations')}}
q-item
blueprint-icon(icon='email-open', :hue-rotate='45')
q-item-section
q-item-label {{$t(`admin.users.sendWelcomeEmail`)}}
q-item-label(caption) {{$t(`admin.users.sendWelcomeEmailAltHint`)}}
q-item-section(side)
q-btn.acrylic-btn(
flat
icon='las la-arrow-circle-right'
color='primary'
@click='sendWelcomeEmail'
:label='$t(`common.actions.proceed`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='apply', :hue-rotate='45')
q-item-section
q-item-label {{user.isVerified ? $t(`admin.users.unverify`) : $t(`admin.users.verify`)}}
q-item-label(caption) {{user.isVerified ? $t(`admin.users.unverifyHint`) : $t(`admin.users.verifyHint`)}}
q-item-label(caption): strong(:class='user.isVerified ? `text-positive` : `text-negative`') {{user.isVerified ? $t(`admin.users.verified`) : $t(`admin.users.unverified`)}}
q-item-section(side)
q-btn.acrylic-btn(
flat
icon='las la-arrow-circle-right'
color='primary'
@click='toggleVerified'
:label='$t(`common.actions.proceed`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='unfriend', :hue-rotate='45')
q-item-section
q-item-label {{user.isActive ? $t(`admin.users.ban`) : $t(`admin.users.unban`)}}
q-item-label(caption) {{user.isActive ? $t(`admin.users.banHint`) : $t(`admin.users.unbanHint`)}}
q-item-label(caption): strong(:class='user.isActive ? `text-positive` : `text-negative`') {{user.isActive ? $t(`admin.users.active`) : $t(`admin.users.banned`)}}
q-item-section(side)
q-btn.acrylic-btn(
flat
icon='las la-arrow-circle-right'
color='primary'
@click='toggleBan'
:label='$t(`common.actions.proceed`)'
)
q-card.shadow-1.q-py-sm.q-mt-md
q-item
blueprint-icon(icon='denied', :hue-rotate='140')
q-item-section
q-item-label {{$t(`admin.users.delete`)}}
q-item-label(caption) {{$t(`admin.users.deleteHint`)}}
q-item-section(side)
q-btn.acrylic-btn(
flat
icon='las la-arrow-circle-right'
color='negative'
@click='deleteUser'
:label='$t(`common.actions.proceed`)'
)
</template>
<script>
import gql from 'graphql-tag'
import cloneDeep from 'lodash/cloneDeep'
import some from 'lodash/some'
import find from 'lodash/find'
import findKey from 'lodash/findKey'
import _get from 'lodash/get'
import map from 'lodash/map'
import { get } from 'vuex-pathify'
import { DateTime } from 'luxon'
import UtilCodeEditor from './UtilCodeEditor.vue'
import UserChangePwdDialog from './UserChangePwdDialog.vue'
export default {
components: {
UtilCodeEditor
},
data () {
return {
invalidCharsRegex: /^[^<>"]+$/,
sections: [
{ key: 'overview', text: this.$t('admin.users.overview'), icon: 'las la-user' },
{ key: 'activity', text: this.$t('admin.users.activity'), icon: 'las la-chart-area' },
{ key: 'auth', text: this.$t('admin.users.auth'), icon: 'las la-key' },
{ key: 'groups', text: this.$t('admin.users.groups'), icon: 'las la-users' },
{ key: 'metadata', text: this.$t('admin.users.metadata'), icon: 'las la-clipboard-list' },
{ key: 'operations', text: this.$t('admin.users.operations'), icon: 'las la-tools' }
],
user: {
meta: {},
prefs: {},
groups: []
},
groups: [],
groupToAdd: null,
loading: 0,
metadataInvalidJSON: false
}
},
computed: {
timezones: get('data/timezones', false),
userId: get('admin/overlayOpts@id', false),
metadata: {
get () { return JSON.stringify(this.user.meta ?? {}, null, 2) },
set (val) {
try {
this.user.meta = JSON.parse(val)
this.metadataInvalidJSON = false
} catch (err) {
this.metadataInvalidJSON = true
}
}
},
localAuthId () {
return findKey(this.user.auth, ['module', 'local'])
},
localAuth: {
get () {
return this.localAuthId ? _get(this.user.auth, this.localAuthId, {}) : {}
},
set (val) {
if (this.localAuthId) {
this.user.auth[this.localAuthId] = val
}
}
},
linkedAuthProviders () {
if (!this.user?.auth) { return [] }
return map(this.user.auth, (obj, key) => {
return {
...obj,
_id: key
}
}).filter(prv => prv.module !== 'local')
}
},
watch: {
$route: 'checkRoute'
},
mounted () {
this.checkRoute()
this.load()
},
methods: {
async load () {
this.loading++
this.$q.loading.show()
try {
const resp = await this.$apollo.query({
query: gql`
query adminFetchUser (
$id: UUID!
) {
groups {
id
name
}
userById(
id: $id
) {
id
email
name
isSystem
isVerified
isActive
auth
meta
prefs
lastLoginAt
createdAt
updatedAt
groups {
id
name
}
}
}
`,
variables: {
id: this.userId
},
fetchPolicy: 'network-only'
})
this.groups = resp?.data?.groups?.filter(g => g.id !== '10000000-0000-4000-0000-000000000001') ?? []
if (resp?.data?.userById) {
this.user = cloneDeep(resp.data.userById)
} else {
throw new Error('An unexpected error occured while fetching user details.')
}
} catch (err) {
this.$q.notify({
type: 'negative',
message: err.message
})
}
this.$q.loading.hide()
this.loading--
},
close () {
this.$store.set('admin/overlay', '')
},
checkRoute () {
if (!this.$route.params.section) {
this.$router.replace({ params: { section: 'overview' } })
}
if (this.$route.params.section === 'metadata') {
this.metadataInvalidJSON = false
}
},
humanizeDate (val) {
if (!val) { return '---' }
return DateTime.fromISO(val).toLocaleString(DateTime.DATETIME_FULL)
},
assignGroup () {
if (!this.groupToAdd) {
this.$q.notify({
type: 'negative',
message: this.$t('admin.users.noGroupSelected')
})
} else if (some(this.user.groups, gr => gr.id === this.groupToAdd)) {
this.$q.notify({
type: 'warning',
message: this.$t('admin.users.groupAlreadyAssigned')
})
} else {
const newGroup = find(this.groups, ['id', this.groupToAdd])
this.user.groups = [...this.user.groups, newGroup]
}
},
unassignGroup (id) {
if (this.user.groups.length <= 1) {
this.$q.notify({
type: 'negative',
message: this.$t('admin.users.minimumGroupRequired')
})
} else {
this.user.groups = this.user.groups.filter(gr => gr.id === id)
}
},
async save (patch, { silent, keepOpen } = { silent: false, keepOpen: false }) {
this.$q.loading.show()
if (!patch) {
patch = {
name: this.user.name,
email: this.user.email,
isVerified: this.user.isVerified,
isActive: this.user.isActive,
meta: this.user.meta,
prefs: this.user.prefs,
groups: this.user.groups.map(gr => gr.id)
}
}
try {
const resp = await this.$apollo.mutate({
mutation: gql`
mutation adminSaveUser (
$id: UUID!
$patch: UserUpdateInput!
) {
updateUser (
id: $id
patch: $patch
) {
status {
succeeded
message
}
}
}
`,
variables: {
id: this.userId,
patch
}
})
if (resp?.data?.updateUser?.status?.succeeded) {
if (!silent) {
this.$q.notify({
type: 'positive',
message: this.$t('admin.users.saveSuccess')
})
}
if (!keepOpen) {
this.close()
}
} else {
throw new Error(resp?.data?.updateUser?.status?.message || 'An unexpected error occured.')
}
} catch (err) {
this.$q.notify({
type: 'negative',
message: err.message
})
}
this.$q.loading.hide()
},
changePassword () {
this.$q.dialog({
component: UserChangePwdDialog,
componentProps: {
userId: this.userId
}
}).onOk(({ mustChangePassword }) => {
this.localAuth = {
...this.localAuth,
mustChangePwd: mustChangePassword
}
})
},
invalidateTFA () {
this.$q.dialog({
title: this.$t('admin.users.tfaInvalidate'),
message: this.$t('admin.users.tfaInvalidateConfirm'),
cancel: true,
persistent: true,
ok: {
label: this.$t('common.actions.confirm')
}
}).onOk(() => {
this.localAuth.tfaSecret = ''
this.$q.notify({
type: 'positive',
message: this.$t('admin.users.tfaInvalidateSuccess')
})
})
},
async sendWelcomeEmail () {
},
toggleVerified () {
this.user.isVerified = !this.user.isVerified
this.save({
isVerified: this.user.isVerified
}, { silent: true, keepOpen: true })
},
toggleBan () {
this.user.isActive = !this.user.isActive
this.save({
isActive: this.user.isActive
}, { silent: true, keepOpen: true })
},
async deleteUser () {
}
}
}
</script>
<template lang="pug">
.util-code-editor(
ref='editor'
)
</template>
<script>
/* eslint no-unused-vars: "off" */
// import { keymap, EditorView } from '@codemirror/view'
// import { EditorState } from '@codemirror/state'
// import { history, historyKeymap } from '@codemirror/history'
// import { defaultKeymap, indentWithTab } from '@codemirror/commands'
// import { lineNumbers } from '@codemirror/gutter'
// import { defaultHighlightStyle } from '@codemirror/highlight'
export default {
props: {
modelValue: {
type: String,
default: ''
},
language: {
type: String,
default: 'plaintext'
},
minHeight: {
type: Number,
default: 150
}
},
emits: ['update:modelValue'],
data () {
return {
editor: null
}
},
watch: {
modelValue (newVal) {
// Ignore loopback changes while editing
if (!this.editor.hasFocus) {
this.editor.dispatch({
changes: { from: 0, to: this.editor.state.length, insert: newVal }
})
}
}
},
async mounted () {
let langModule = null
switch (this.language) {
case 'css': {
langModule = (await import('@codemirror/lang-css')).css
break
}
case 'html': {
langModule = (await import('@codemirror/lang-html')).html
break
}
case 'javascript': {
langModule = (await import('@codemirror/lang-javascript')).javascript
break
}
case 'json': {
langModule = (await import('@codemirror/lang-json')).json
break
}
case 'markdown': {
langModule = (await import('@codemirror/lang-markdown')).markdown
break
}
}
// this.editor = new EditorView({
// state: EditorState.create({
// doc: this.modelValue,
// extensions: [
// // history()
// // keymap.of([...defaultKeymap, ...historyKeymap, indentWithTab])
// lineNumbers()
// // EditorView.theme({
// // '.cm-content, .cm-gutter': { minHeight: `${this.minHeight}px` }
// // }),
// // ...langModule && [langModule()],
// // defaultHighlightStyle,
// // EditorView.updateListener.of(v => {
// // if (v.docChanged) {
// // this.$emit('update:modelValue', v.state.doc.toString())
// // }
// // })
// ]
// }),
// parent: this.$refs.editor
// })
},
beforeUnmount () {
if (this.editor) {
this.editor.destroy()
}
}
}
</script>
<style lang="scss">
.util-code-editor {
min-height: 100px;
border: 1px solid #CCC;
border-radius: 5px;
overflow: hidden;
> .CodeMirror {
height: 150px;
}
}
</style>
<template lang="pug">
q-dialog(ref='dialog', @hide='onDialogHide')
q-card(style='min-width: 350px; max-width: 450px;')
q-card-section.card-header
q-icon(name='img:/_assets/icons/fluent-delete-bin.svg', left, size='sm')
span {{$t(`admin.webhooks.delete`)}}
q-card-section
.text-body2
i18n-t(keypath='admin.webhooks.deleteConfirm')
template(v-slot:name)
strong {{hook.name}}
.text-body2.q-mt-md
strong.text-negative {{$t(`admin.webhooks.deleteConfirmWarn`)}}
q-card-actions.card-actions
q-space
q-btn.acrylic-btn(
flat
:label='$t(`common.actions.cancel`)'
color='grey'
padding='xs md'
@click='hide'
)
q-btn(
unelevated
:label='$t(`common.actions.delete`)'
color='negative'
padding='xs md'
@click='confirm'
)
</template>
<script>
import gql from 'graphql-tag'
export default {
props: {
hook: {
type: Object
}
},
emits: ['ok', 'hide'],
data () {
return {
}
},
methods: {
show () {
this.$refs.dialog.show()
},
hide () {
this.$refs.dialog.hide()
},
onDialogHide () {
this.$emit('hide')
},
async confirm () {
try {
const resp = await this.$apollo.mutate({
mutation: gql`
mutation deleteHook ($id: UUID!) {
deleteHook(id: $id) {
status {
succeeded
message
}
}
}
`,
variables: {
id: this.hook.id
}
})
if (resp?.data?.deleteHook?.status?.succeeded) {
this.$q.notify({
type: 'positive',
message: this.$t('admin.webhooks.deleteSuccess')
})
this.$emit('ok')
this.hide()
} else {
throw new Error(resp?.data?.deleteHook?.status?.message || 'An unexpected error occured.')
}
} catch (err) {
this.$q.notify({
type: 'negative',
message: err.message
})
}
}
}
}
</script>
<template lang="pug">
q-dialog(ref='dialog', @hide='onDialogHide')
q-card(style='min-width: 850px;')
q-card-section.card-header
template(v-if='hookId')
q-icon(name='img:/_assets/icons/fluent-pencil-drawing.svg', left, size='sm')
span {{$t(`admin.webhooks.edit`)}}
template(v-else)
q-icon(name='img:/_assets/icons/fluent-plus-plus.svg', left, size='sm')
span {{$t(`admin.webhooks.new`)}}
//- STATE INFO BAR
q-card-section.flex.items-center.bg-indigo.text-white(v-if='hookId && hook.state === `pending`')
q-spinner-clock.q-mr-sm(
color='white'
size='xs'
)
.text-caption {{$t('admin.webhooks.statePendingHint')}}
q-card-section.flex.items-center.bg-positive.text-white(v-if='hookId && hook.state === `success`')
q-spinner-infinity.q-mr-sm(
color='white'
size='xs'
)
.text-caption {{$t('admin.webhooks.stateSuccessHint')}}
q-card-section.bg-negative.text-white(v-if='hookId && hook.state === `error`')
.flex.items-center
q-icon.q-mr-sm(
color='white'
size='xs'
name='las la-exclamation-triangle'
)
.text-caption {{$t('admin.webhooks.stateErrorExplain')}}
.text-caption.q-pl-lg.q-ml-xs.text-red-2 {{hook.lastErrorMessage}}
//- FORM
q-form.q-py-sm(ref='editWebhookForm')
q-item
blueprint-icon(icon='info-popup')
q-item-section
q-input(
outlined
v-model='hook.name'
dense
:rules=`[
val => val.length > 0 || $t('admin.webhooks.nameMissing'),
val => /^[^<>"]+$/.test(val) || $t('admin.webhooks.nameInvalidChars')
]`
hide-bottom-space
:label='$t(`common.field.name`)'
:aria-label='$t(`common.field.name`)'
lazy-rules='ondemand'
autofocus
)
q-item
blueprint-icon(icon='lightning-bolt')
q-item-section
q-select(
outlined
:options='events'
v-model='hook.events'
multiple
map-options
emit-value
option-value='key'
option-label='name'
options-dense
dense
:rules=`[
val => val.length > 0 || $t('admin.webhooks.eventsMissing')
]`
hide-bottom-space
:label='$t(`admin.webhooks.events`)'
:aria-label='$t(`admin.webhooks.events`)'
lazy-rules='ondemand'
)
template(v-slot:selected)
.text-caption(v-if='hook.events.length > 0') {{$tc(`admin.webhooks.eventsSelected`, hook.events.length, { count: hook.events.length })}}
span(v-else)
template(v-slot:option='{ itemProps, itemEvents, opt, selected, toggleOption }')
q-item(
v-bind='itemProps'
v-on='itemEvents'
)
q-item-section(side)
q-checkbox(
:model-value='selected'
@update:model-value='toggleOption(opt)'
size='sm'
)
q-item-section(side)
q-chip.q-mx-none(
size='sm'
color='positive'
text-color='white'
square
) {{opt.type}}
q-item-section
q-item-label {{opt.name}}
q-item
blueprint-icon.self-start(icon='unknown-status')
q-item-section
q-item-label {{$t(`admin.webhooks.url`)}}
q-item-label(caption) {{$t(`admin.webhooks.urlHint`)}}
q-input.q-mt-sm(
outlined
v-model='hook.url'
dense
:rules=`[
val => (val.length > 0 && val.startsWith('http')) || $t('admin.webhooks.urlMissing'),
val => /^[^<>"]+$/.test(val) || $t('admin.webhooks.urlInvalidChars')
]`
hide-bottom-space
placeholder='https://'
:aria-label='$t(`admin.webhooks.url`)'
lazy-rules='ondemand'
)
template(v-slot:prepend)
q-chip.q-mx-none(
color='positive'
text-color='white'
square
size='sm'
) POST
q-item(tag='label', v-ripple)
blueprint-icon(icon='rescan-document')
q-item-section
q-item-label {{$t(`admin.webhooks.includeMetadata`)}}
q-item-label(caption) {{$t(`admin.webhooks.includeMetadataHint`)}}
q-item-section(avatar)
q-toggle(
v-model='hook.includeMetadata'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.webhooks.includeMetadata`)'
)
q-item(tag='label', v-ripple)
blueprint-icon(icon='select-all')
q-item-section
q-item-label {{$t(`admin.webhooks.includeContent`)}}
q-item-label(caption) {{$t(`admin.webhooks.includeContentHint`)}}
q-item-section(avatar)
q-toggle(
v-model='hook.includeContent'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.webhooks.includeContent`)'
)
q-item(tag='label', v-ripple)
blueprint-icon(icon='security-ssl')
q-item-section
q-item-label {{$t(`admin.webhooks.acceptUntrusted`)}}
q-item-label(caption) {{$t(`admin.webhooks.acceptUntrustedHint`)}}
q-item-section(avatar)
q-toggle(
v-model='hook.acceptUntrusted'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.webhooks.acceptUntrusted`)'
)
q-item
blueprint-icon.self-start(icon='fingerprint-scan')
q-item-section
q-item-label {{$t(`admin.webhooks.authHeader`)}}
q-item-label(caption) {{$t(`admin.webhooks.authHeaderHint`)}}
q-input.q-mt-sm(
outlined
v-model='hook.authHeader'
dense
:aria-label='$t(`admin.webhooks.authHeader`)'
)
q-card-actions.card-actions
q-space
q-btn.acrylic-btn(
flat
:label='$t(`common.actions.cancel`)'
color='grey'
padding='xs md'
@click='hide'
)
q-btn(
v-if='hookId'
unelevated
:label='$t(`common.actions.save`)'
color='primary'
padding='xs md'
@click='save'
:loading='loading'
)
q-btn(
v-else
unelevated
:label='$t(`common.actions.create`)'
color='primary'
padding='xs md'
@click='create'
:loading='loading'
)
q-inner-loading(:showing='loading')
q-spinner(color='accent', size='lg')
</template>
<script>
import gql from 'graphql-tag'
import cloneDeep from 'lodash/cloneDeep'
import { QSpinnerClock, QSpinnerInfinity } from 'quasar'
export default {
components: {
QSpinnerClock,
QSpinnerInfinity
},
props: {
hookId: {
type: String,
default: null
}
},
emits: ['ok', 'hide'],
data () {
return {
hook: {
name: '',
events: [],
url: '',
acceptUntrusted: false,
authHeader: '',
includeMetadata: true,
includeContent: false,
state: 'pending',
lastErrorMessage: ''
},
loading: false
}
},
computed: {
events () {
return [
{ key: 'page:create', name: this.$t('admin.webhooks.eventCreatePage'), type: this.$t('admin.webhooks.typePage') },
{ key: 'page:edit', name: this.$t('admin.webhooks.eventEditPage'), type: this.$t('admin.webhooks.typePage') },
{ key: 'page:rename', name: this.$t('admin.webhooks.eventRenamePage'), type: this.$t('admin.webhooks.typePage') },
{ key: 'page:delete', name: this.$t('admin.webhooks.eventDeletePage'), type: this.$t('admin.webhooks.typePage') },
{ key: 'asset:upload', name: this.$t('admin.webhooks.eventUploadAsset'), type: this.$t('admin.webhooks.typeAsset') },
{ key: 'asset:edit', name: this.$t('admin.webhooks.eventEditAsset'), type: this.$t('admin.webhooks.typeAsset') },
{ key: 'asset:rename', name: this.$t('admin.webhooks.eventRenameAsset'), type: this.$t('admin.webhooks.typeAsset') },
{ key: 'asset:delete', name: this.$t('admin.webhooks.eventDeleteAsset'), type: this.$t('admin.webhooks.typeAsset') },
{ key: 'comment:new', name: this.$t('admin.webhooks.eventNewComment'), type: this.$t('admin.webhooks.typeComment') },
{ key: 'comment:edit', name: this.$t('admin.webhooks.eventEditComment'), type: this.$t('admin.webhooks.typeComment') },
{ key: 'comment:delete', name: this.$t('admin.webhooks.eventDeleteComment'), type: this.$t('admin.webhooks.typeComment') },
{ key: 'user:join', name: this.$t('admin.webhooks.eventUserJoin'), type: this.$t('admin.webhooks.typeUser') },
{ key: 'user:login', name: this.$t('admin.webhooks.eventUserLogin'), type: this.$t('admin.webhooks.typeUser') },
{ key: 'user:logout', name: this.$t('admin.webhooks.eventUserLogout'), type: this.$t('admin.webhooks.typeUser') }
]
}
},
methods: {
show () {
this.$refs.dialog.show()
if (this.hookId) {
this.fetchHook(this.hookId)
}
},
hide () {
this.$refs.dialog.hide()
},
onDialogHide () {
this.$emit('hide')
},
async fetchHook (id) {
this.loading = true
try {
const resp = await this.$apollo.query({
query: gql`
query getHook (
$id: UUID!
) {
hookById (
id: $id
) {
name
events
url
includeMetadata
includeContent
acceptUntrusted
authHeader
state
lastErrorMessage
}
}
`,
fetchPolicy: 'no-cache',
variables: { id }
})
if (resp?.data?.hookById) {
this.hook = cloneDeep(resp.data.hookById)
} else {
throw new Error('Failed to fetch webhook configuration.')
}
} catch (err) {
this.$q.notify({
type: 'negative',
message: err.message
})
this.hide()
}
this.loading = false
},
async create () {
this.loading = true
try {
const isFormValid = await this.$refs.editWebhookForm.validate(true)
if (!isFormValid) {
throw new Error(this.$t('admin.webhooks.createInvalidData'))
}
const resp = await this.$apollo.mutate({
mutation: gql`
mutation createHook (
$name: String!
$events: [String]!
$url: String!
$includeMetadata: Boolean!
$includeContent: Boolean!
$acceptUntrusted: Boolean!
$authHeader: String
) {
createHook (
name: $name
events: $events
url: $url
includeMetadata: $includeMetadata
includeContent: $includeContent
acceptUntrusted: $acceptUntrusted
authHeader: $authHeader
) {
status {
succeeded
message
}
}
}
`,
variables: this.hook
})
if (resp?.data?.createHook?.status?.succeeded) {
this.$q.notify({
type: 'positive',
message: this.$t('admin.webhooks.createSuccess')
})
this.$emit('ok')
this.hide()
} else {
throw new Error(resp?.data?.createHook?.status?.message || 'An unexpected error occured.')
}
} catch (err) {
this.$q.notify({
type: 'negative',
message: err.message
})
}
this.loading = false
},
async save () {
this.loading = true
try {
const isFormValid = await this.$refs.editWebhookForm.validate(true)
if (!isFormValid) {
throw new Error(this.$t('admin.webhooks.createInvalidData'))
}
const resp = await this.$apollo.mutate({
mutation: gql`
mutation saveHook (
$id: UUID!
$patch: HookUpdateInput!
) {
updateHook (
id: $id
patch: $patch
) {
status {
succeeded
message
}
}
}
`,
variables: {
id: this.hookId,
patch: {
name: this.hook.name,
events: this.hook.events,
url: this.hook.url,
acceptUntrusted: this.hook.acceptUntrusted,
authHeader: this.hook.authHeader,
includeMetadata: this.hook.includeMetadata,
includeContent: this.hook.includeContent
}
}
})
if (resp?.data?.updateHook?.status?.succeeded) {
this.$q.notify({
type: 'positive',
message: this.$t('admin.webhooks.updateSuccess')
})
this.$emit('ok')
this.hide()
} else {
throw new Error(resp?.data?.updateHook?.status?.message || 'An unexpected error occured.')
}
} catch (err) {
this.$q.notify({
type: 'negative',
message: err.message
})
}
this.loading = false
}
}
}
</script>
// ------------------------------------------------------------------
// ANIMATION
// ------------------------------------------------------------------
:root {
--animate-duration: .6s;
--animate-delay: 1s;
--animate-repeat: 1;
}
.animated {
animation-duration: var(--animate-duration);
animation-fill-mode: both;
&.infinite {
animation-iteration-count: infinite;
}
}
@for $i from 1 to 12 {
.wait-p#{$i}s {
animation-delay: $i * .1s !important;
}
}
// -> Fade Transition
.fade-enter-active,
.fade-leave-active {
transition-duration: 0.3s;
transition-property: opacity;
transition-timing-function: ease;
}
.fade-enter,
.fade-leave-active {
opacity: 0
}
// -> fadeIn
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.fadeIn {
animation-name: fadeIn;
}
// -> fadeInDown
@keyframes fadeInDown {
from {
opacity: 0;
transform: translate3d(0, -10px, 0);
}
to {
opacity: 1;
transform: translate3d(0, 0, 0);
}
}
.fadeInDown {
animation-name: fadeInDown;
}
// -> fadeInLeft
@keyframes fadeInLeft {
from {
opacity: 0;
transform: translate3d(-10px, 0, 0);
}
to {
opacity: 1;
transform: translate3d(0, 0, 0);
}
}
.fadeInLeft {
animation-name: fadeInLeft;
}
// -> fadeInRight
@keyframes fadeInRight {
from {
opacity: 0;
transform: translate3d(10px, 0, 0);
}
to {
opacity: 1;
transform: translate3d(0, 0, 0);
}
}
.fadeInRight {
animation-name: fadeInRight;
}
// -> fadeInUp
@keyframes fadeInUp {
from {
opacity: 0;
transform: translate3d(0, 10px, 0);
}
to {
opacity: 1;
transform: translate3d(0, 0, 0);
}
}
.fadeInUp {
animation-name: fadeInUp;
}
// -> Print + Reduce Motion
@media print, (prefers-reduced-motion: reduce) {
.animated {
animation-duration: 1ms !important;
transition-duration: 1ms !important;
animation-iteration-count: 1 !important;
}
.animated[class*='Out'] {
opacity: 0;
}
}
// app global css in SCSS form
// ------------------------------------------------------------------
// SCROLLBAR
// ------------------------------------------------------------------
html {
--scrollbarBG: #CCC;
--thumbBG: #999;
}
body::-webkit-scrollbar {
width: 7px;
}
body {
scrollbar-width: thin;
scrollbar-color: var(--thumbBG) var(--scrollbarBG);
}
body::-webkit-scrollbar-track {
background: var(--scrollbarBG);
}
body::-webkit-scrollbar-thumb {
background-color: var(--thumbBG);
border-radius: 6px;
border: 1px solid var(--scrollbarBG);
}
// ------------------------------------------------------------------
// FONTS
// ------------------------------------------------------------------
@font-face {
font-family: 'Poppins';
src: url(./fonts/poppins-medium.woff2);
}
.font-poppins {
font-family: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}
@font-face {
font-family: 'Roboto Mono';
src: url(./fonts/roboto-mono.woff2);
}
.font-robotomono {
font-family: 'Roboto Mono', Consolas, "Liberation Mono", Courier, monospace;
}
// ------------------------------------------------------------------
// THEME COLORS
// ------------------------------------------------------------------
:root {
--q-header: #000;
--q-sidebar: #1976D2;
}
.header, .bg-header {
background: #000;
background: var(--q-header);
}
.sidebar, .bg-sidebar {
background: #1976D2;
background: var(--q-sidebar);
}
.bg-dark-6 { background-color: #070a0d; }
.bg-dark-5 { background-color: #0d1117; }
.bg-dark-4 { background-color: #161b22; }
.bg-dark-3 { background-color: #1e232a; }
// ------------------------------------------------------------------
// FORMS
// ------------------------------------------------------------------
.v-textarea.is-monospaced textarea {
font-family: 'Roboto Mono', 'Courier New', Courier, monospace;
font-size: 13px;
font-weight: 600;
line-height: 1.4;
}
.q-field.denser .q-field__control {
height: 36px;
.q-field__prepend {
height: 36px;
}
}
.q-field.fill-outline .q-field__control {
background-color: #FFF;
@at-root .body--light & {
background-color: #FFF;
}
@at-root .body--dark & {
background-color: $dark;
}
}
// ------------------------------------------------------------------
// BUTTONS
// ------------------------------------------------------------------
body.desktop .acrylic-btn {
.q-focus-helper {
background-color: currentColor;
opacity: .1;
}
&:hover .q-focus-helper {
opacity: .3;
}
}
// ------------------------------------------------------------------
// ICONS
// ------------------------------------------------------------------
.blueprint-icon {
&-alt {
filter: hue-rotate(100);
}
}
// ------------------------------------------------------------------
// IMPORTS
// ------------------------------------------------------------------
@import './animation.scss';
// @import '~codemirror/lib/codemirror.css';
// @import '~codemirror/theme/elegant.css';
// @import '~codemirror/theme/material-ocean.css';
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
// Quasar SCSS (& Sass) Variables
// --------------------------------------------------
// To customize the look and feel of this app, you can override
// the Sass/SCSS variables found in Quasar's source Sass/SCSS files.
// Check documentation for full list of Quasar variables
// Your own variables (that are declared here) and Quasar's own
// ones will be available out of the box in your .vue/.scss/.sass files
// It's highly recommended to change the default colors
// to match your app's branding.
// Tip: Use the "Theme Builder" on Quasar's documentation website.
$primary : #1976D2;
$secondary : #02C39A;
$accent : #f03a47;
$dark : #0d1117;
$positive : #02C39A;
$negative : #f03a47;
$info : #3e6990;
$warning : #f99d4d;
$header : #000;
$sidebar: $primary;
$dark-6: #070a0d;
$dark-5: #0d1117;
$dark-4: #161b22;
$dark-3: #1e232a;
import en from './locales/en.json'
export default {
'en-US': en
}
{
"admin.adminArea": "Administration Area",
"admin.analytics.providerConfiguration": "Provider Configuration",
"admin.analytics.providerNoConfiguration": "This provider has no configuration options you can modify.",
"admin.analytics.providers": "Providers",
"admin.analytics.refreshSuccess": "List of providers refreshed successfully.",
"admin.analytics.saveSuccess": "Analytics configuration saved successfully",
"admin.analytics.subtitle": "Add analytics and tracking tools to your wiki",
"admin.analytics.title": "Analytics",
"admin.api.disableButton": "Disable API",
"admin.api.disabled": "API Disabled",
"admin.api.enableButton": "Enable API",
"admin.api.enabled": "API Enabled",
"admin.api.expiration180d": "180 days",
"admin.api.expiration1y": "1 year",
"admin.api.expiration30d": "30 days",
"admin.api.expiration3y": "3 years",
"admin.api.expiration90d": "90 days",
"admin.api.headerCreated": "Created",
"admin.api.headerExpiration": "Expiration",
"admin.api.headerKeyEnding": "Key Ending",
"admin.api.headerLastUpdated": "Last Updated",
"admin.api.headerName": "Name",
"admin.api.headerRevoke": "Revoke",
"admin.api.newKeyButton": "New API Key",
"admin.api.newKeyCopyWarn": "Copy the key shown below as {bold}",
"admin.api.newKeyCopyWarnBold": "it will NOT be shown again",
"admin.api.newKeyExpiration": "Expiration",
"admin.api.newKeyExpirationHint": "You can still revoke a key anytime regardless of the expiration.",
"admin.api.newKeyFullAccess": "Full Access",
"admin.api.newKeyGroup": "Group",
"admin.api.newKeyGroupError": "You must select a group.",
"admin.api.newKeyGroupHint": "The API key will have the same permissions as the selected group.",
"admin.api.newKeyGroupPermissions": "or use group permissions...",
"admin.api.newKeyGuestGroupError": "The guests group cannot be used for API keys.",
"admin.api.newKeyName": "Name",
"admin.api.newKeyNameError": "Name is missing or invalid.",
"admin.api.newKeyNameHint": "Purpose of this key",
"admin.api.newKeyPermissionScopes": "Permission Scopes",
"admin.api.newKeySuccess": "API key created successfully.",
"admin.api.newKeyTitle": "New API Key",
"admin.api.noKeyInfo": "No API keys have been generated yet.",
"admin.api.refreshSuccess": "List of API keys has been refreshed.",
"admin.api.revoke": "Revoke",
"admin.api.revokeConfirm": "Revoke API Key?",
"admin.api.revokeConfirmText": "Are you sure you want to revoke key {name}? This action cannot be undone!",
"admin.api.revokeSuccess": "The key has been revoked successfully.",
"admin.api.subtitle": "Manage keys to access the API",
"admin.api.title": "API Access",
"admin.api.toggleStateDisabledSuccess": "API has been disabled successfully.",
"admin.api.toggleStateEnabledSuccess": "API has been enabled successfully.",
"admin.approval.title": "Approvals",
"admin.audit.title": "Audit Log",
"admin.auth.activeStrategies": "Active Strategies",
"admin.auth.addStrategy": "Add Strategy",
"admin.auth.allowedWebOrigins": "Allowed Web Origins",
"admin.auth.autoEnrollGroups": "Assign to group",
"admin.auth.autoEnrollGroupsHint": "Automatically assign new users to these groups.",
"admin.auth.callbackUrl": "Callback URL / Redirect URI",
"admin.auth.configReference": "Configuration Reference",
"admin.auth.configReferenceSubtitle": "Some strategies may require some configuration values to be set on your provider. These are provided for reference only and may not be needed by the current strategy.",
"admin.auth.displayName": "Display Name",
"admin.auth.displayNameHint": "The title shown to the end user for this authentication strategy.",
"admin.auth.domainsWhitelist": "Limit to specific email domains",
"admin.auth.domainsWhitelistHint": "A list of domains authorized to register. The user email address domain must match one of these to gain access.",
"admin.auth.force2fa": "Force all users to use Two-Factor Authentication (2FA)",
"admin.auth.force2faHint": "Users will be required to setup 2FA the first time they login and cannot be disabled by the user.",
"admin.auth.globalAdvSettings": "Global Advanced Settings",
"admin.auth.loginUrl": "Login URL",
"admin.auth.logoutUrl": "Logout URL",
"admin.auth.refreshSuccess": "List of strategies has been refreshed.",
"admin.auth.registration": "Registration",
"admin.auth.saveSuccess": "Authentication configuration saved successfully.",
"admin.auth.security": "Security",
"admin.auth.selfRegistration": "Allow self-registration",
"admin.auth.selfRegistrationHint": "Allow any user successfully authorized by the strategy to access the wiki.",
"admin.auth.siteUrlNotSetup": "You must set a valid {siteUrl} first! Click on {general} in the left sidebar.",
"admin.auth.strategies": "Strategies",
"admin.auth.strategyConfiguration": "Strategy Configuration",
"admin.auth.strategyIsEnabled": "Active",
"admin.auth.strategyIsEnabledHint": "Are users able to login using this strategy?",
"admin.auth.strategyNoConfiguration": "This strategy has no configuration options you can modify.",
"admin.auth.strategyState": "This strategy is {state} {locked}",
"admin.auth.strategyStateActive": "active",
"admin.auth.strategyStateInactive": "not active",
"admin.auth.strategyStateLocked": "and cannot be disabled.",
"admin.auth.subtitle": "Configure the authentication settings of your wiki",
"admin.auth.title": "Authentication",
"admin.comments.provider": "Provider",
"admin.comments.providerConfig": "Provider Configuration",
"admin.comments.providerNoConfig": "This provider has no configuration options you can modify.",
"admin.comments.subtitle": "Add discussions to your wiki pages",
"admin.comments.title": "Comments",
"admin.contribute.title": "Donate",
"admin.dashboard.contributeHelp": "We need your help!",
"admin.dashboard.contributeLearnMore": "Learn More",
"admin.dashboard.contributeSubtitle": "Wiki.js is a free and open source project. There are several ways you can contribute to the project.",
"admin.dashboard.groups": "Groups",
"admin.dashboard.lastLogins": "Last Logins",
"admin.dashboard.mostPopularPages": "Most Popular Pages",
"admin.dashboard.pages": "Pages",
"admin.dashboard.recentPages": "Recent Pages",
"admin.dashboard.subtitle": "Wiki.js",
"admin.dashboard.title": "Dashboard",
"admin.dashboard.users": "Users",
"admin.dashboard.versionLatest": "You are running the latest version.",
"admin.dashboard.versionNew": "A new version is available: {version}",
"admin.dev.flags.title": "Flags",
"admin.dev.graphiql.title": "GraphiQL",
"admin.dev.title": "Developer Tools",
"admin.dev.voyager.title": "Voyager",
"admin.editors.apiDescription": "Document your REST / GraphQL APIs.",
"admin.editors.apiName": "API Docs Editor",
"admin.editors.blogDescription": "Write a series of posts over time.",
"admin.editors.blogName": "Blog Editor",
"admin.editors.channelDescription": "Create discussion channels to collaborate in real-time with your team.",
"admin.editors.channelName": "Discussion Channels",
"admin.editors.configuration": "Configuration",
"admin.editors.markdownDescription": "Use the Markdown syntax to write content. Includes real-time preview and code completion features.",
"admin.editors.markdownName": "Markdown Editor",
"admin.editors.redirectDescription": "Create redirections to other pages / external links.",
"admin.editors.redirectName": "Redirection",
"admin.editors.subtitle": "Manage editors and their configuration",
"admin.editors.title": "Editors",
"admin.editors.wysiwygDescription": "A visual WYSIWYG editor. The recommended editor for non-technical users.",
"admin.editors.wysiwygName": "Visual Editor",
"admin.extensions.incompatible": "not compatible",
"admin.extensions.install": "Install",
"admin.extensions.installFailed": "Failed to install extension.",
"admin.extensions.installSuccess": "Extension installed successfully.",
"admin.extensions.installed": "Installed",
"admin.extensions.installing": "Installing extension...",
"admin.extensions.installingHint": "This may take a while depending on your server.",
"admin.extensions.instructions": "Instructions",
"admin.extensions.instructionsHint": "Must be installed manually",
"admin.extensions.reinstall": "Reinstall",
"admin.extensions.requiresSharp": "Requires Sharp extension",
"admin.extensions.subtitle": "Install extensions for extra functionality",
"admin.extensions.title": "Extensions",
"admin.flags.hidedonatebtn.hint": "You have already donated to this project (thank you!) and want to hide the button from the administration area.",
"admin.flags.hidedonatebtn.label": "Hide Donate Button",
"admin.flags.ldapdebug.hint": "Log detailed debug info on LDAP/AD login attempts.",
"admin.flags.ldapdebug.label": "LDAP Debug",
"admin.flags.sqllog.hint": "Log all queries made to the database to console.",
"admin.flags.sqllog.label": "SQL Query Logging",
"admin.flags.subtitle": "Low-level system flags for debugging or experimental purposes",
"admin.flags.title": "Flags",
"admin.flags.warn.hint": "Doing so may result in data loss or broken installation!",
"admin.flags.warn.label": "Do NOT enable these flags unless you know what you're doing!",
"admin.general.allowComments": "Allow Comments",
"admin.general.allowCommentsHint": "Can users leave comments on pages? Can be restricted using Page Rules.",
"admin.general.allowContributions": "Allow Contributions",
"admin.general.allowContributionsHint": "Can users with read access permissions propose changes for pages? Can be restricted using Page Rules.",
"admin.general.allowProfile": "Allow Profile Editing",
"admin.general.allowProfileHint": "Can users edit their own profile? If profile data is managed by an external identity provider, you should turn this off.",
"admin.general.allowRatings": "Allow Ratings",
"admin.general.allowRatingsHint": "Can users leave ratings on pages? Can be restricted using Page Rules.",
"admin.general.allowSearch": "Allow Search",
"admin.general.allowSearchHint": "Can users search for content they have read access to?",
"admin.general.companyName": "Company / Organization Name",
"admin.general.companyNameHint": "Name to use when displaying copyright notice in the footer. Leave empty to hide.",
"admin.general.contentLicense": "Content License",
"admin.general.contentLicenseHint": "License shown in the footer of all content pages.",
"admin.general.defaultDateFormat": "Default Date Format",
"admin.general.defaultDateFormatHint": "The default date format for new users.",
"admin.general.defaultTimeFormat": "Default Time Format",
"admin.general.defaultTimeFormat12h": "12 hour",
"admin.general.defaultTimeFormat24h": "24 hour",
"admin.general.defaultTimeFormatHint": "The default time format for new users.",
"admin.general.defaultTimezone": "Default Timezone",
"admin.general.defaultTimezoneHint": "The default timezone for new users.",
"admin.general.defaults": "Site Defaults",
"admin.general.displaySiteTitle": "Display Site Title",
"admin.general.displaySiteTitleHint": "Should the site title be displayed next to the logo? If your logo isn't square and contain your brand name, turn this option off.",
"admin.general.favicon": "Favicon",
"admin.general.faviconHint": "Favicon image file, in SVG, PNG, ICO or GIF format. Must be a square image.",
"admin.general.faviconUploadSuccess": "Site Favicon uploaded successfully.",
"admin.general.features": "Features",
"admin.general.footerCopyright": "Footer / Copyright",
"admin.general.general": "General",
"admin.general.logo": "Logo",
"admin.general.logoUpl": "Site Logo",
"admin.general.logoUplHint": "Logo image file, in SVG, PNG, JPG or GIF format.",
"admin.general.logoUploadSuccess": "Site logo uploaded successfully.",
"admin.general.ratingsOff": "Off",
"admin.general.ratingsStars": "Stars",
"admin.general.ratingsThumbs": "Thumbs",
"admin.general.saveSuccess": "Site configuration saved successfully.",
"admin.general.searchAllowFollow": "Allow Search Engines to Follow Links",
"admin.general.searchAllowFollowHint": "This sets the meta-robots property to follow or nofollow.",
"admin.general.searchAllowIndexing": "Allow Indexing by Search Engines",
"admin.general.searchAllowIndexingHint": "This sets the meta-robots property to index or noindex.",
"admin.general.senderEmailHint": "Email address of the sender.",
"admin.general.senderNameHint": "Name of the sender.",
"admin.general.siteBranding": "Site Branding",
"admin.general.siteDescription": "Site Description",
"admin.general.siteDescriptionHint": "Default description when none is provided for a page.",
"admin.general.siteHostname": "Site Hostname",
"admin.general.siteHostnameHint": "Hostname this site should respond to. Set * for catch-all / fallback domain.",
"admin.general.siteHostnameInvalid": "Invalid Hostname",
"admin.general.siteInfo": "Site Info",
"admin.general.siteTitle": "Site Title",
"admin.general.siteTitleHint": "Displayed in the top bar and appended to all pages meta title.",
"admin.general.siteTitleInvalidChars": "Site Title contains invalid characters.",
"admin.general.subtitle": "Main settings of your wiki",
"admin.general.title": "General",
"admin.general.uploadClear": "Clear",
"admin.general.uploadLogo": "Upload Logo",
"admin.general.uploadSizeHint": "An image of {size} pixels is recommended for best results.",
"admin.general.uploadTypesHint": "{typeList} or {lastType} files only",
"admin.groups.assignUser": "Assign User",
"admin.groups.authBehaviors": "Authentication Behaviors",
"admin.groups.create": "New Group",
"admin.groups.createSuccess": "Group created successfully.",
"admin.groups.delete": "Delete Group",
"admin.groups.deleteConfirm": "Are you sure you want delete group {groupName}? Any user currently assigned to this group will be unassigned from it.",
"admin.groups.deleteConfirmWarn": "This action cannot be undone!",
"admin.groups.deleteSuccess": "Group was deleted successfully.",
"admin.groups.edit": "Edit Group",
"admin.groups.exportRules": "Export Rules",
"admin.groups.exportRulesNoneError": "This group has no rule to export!",
"admin.groups.filterUsers": "Filter...",
"admin.groups.general": "General",
"admin.groups.importFailed": "Something went wrong while importing this file. Making sure it is a valid rules JSON file.",
"admin.groups.importModeAdd": "Add to Existing",
"admin.groups.importModeReplace": "Replace All",
"admin.groups.importModeText": "Do you want to replace all existing rules with these ones or add these rules to the existing ones?",
"admin.groups.importModeTitle": "Add or replace?",
"admin.groups.importRules": "Import Rules",
"admin.groups.importSuccess": "Rules imported successfully!",
"admin.groups.info": "Group Info",
"admin.groups.name": "Group Name",
"admin.groups.nameHint": "Name of the group",
"admin.groups.overview": "Overview",
"admin.groups.permissions": "Permissions",
"admin.groups.redirectOnFirstLogin": "First-time Login Redirect",
"admin.groups.redirectOnFirstLoginHint": "Optionally redirect the user to a specific page when he/she login for the first time. Leave empty to use the site-defined value.",
"admin.groups.redirectOnLogin": "Redirect on Login",
"admin.groups.redirectOnLoginHint": "The path / URL where the user will be redirected upon successful login. Leave empty to use the site-defined value.",
"admin.groups.redirectOnLogout": "Redirect on Logout",
"admin.groups.redirectOnLogoutHint": "The path / URL where the user will be redirected upon logout. Leave empty to use the site-defined value.",
"admin.groups.refreshSuccess": "Groups refreshed successfully.",
"admin.groups.ruleAllow": "Allow",
"admin.groups.ruleDeny": "Deny",
"admin.groups.ruleForceAllow": "Force Allow",
"admin.groups.ruleLocales": "Locale(s)",
"admin.groups.ruleMatchEnd": "Path Ends With...",
"admin.groups.ruleMatchExact": "Path Is Exactly...",
"admin.groups.ruleMatchRegex": "Path Matches Regex...",
"admin.groups.ruleMatchStart": "Path Starts With...",
"admin.groups.ruleMatchTag": "Has Any Tag...",
"admin.groups.ruleMatchTagAll": "Has All Tags...",
"admin.groups.ruleSites": "Site(s)",
"admin.groups.ruleUntitled": "Untitled Rule",
"admin.groups.rules": "Rules",
"admin.groups.rulesNone": "This group doesn't have any rules yet.",
"admin.groups.selectedLocales": "Any Locale | {locale} locale only | {count} locales selected",
"admin.groups.selectedSites": "Any Site | 1 site selected | {count} sites selected",
"admin.groups.subtitle": "Manage user groups and permissions",
"admin.groups.title": "Groups",
"admin.groups.userCount": "User Count",
"admin.groups.users": "Users",
"admin.groups.usersCount": "0 user | 1 user | {count} users",
"admin.locale.activeNamespaces": "Active Namespaces",
"admin.locale.autoUpdate.hint": "Automatically download updates to this locale as they become available.",
"admin.locale.autoUpdate.hintWithNS": "Automatically download updates to all namespaced locales enabled below.",
"admin.locale.autoUpdate.label": "Update Automatically",
"admin.locale.availability": "Availability",
"admin.locale.base.hint": "All UI text elements will be displayed in selected language.",
"admin.locale.base.label": "Site Locale",
"admin.locale.base.labelWithNS": "Base Locale",
"admin.locale.code": "Code",
"admin.locale.download": "Download",
"admin.locale.downloadNew": "Install New Locale",
"admin.locale.downloadTitle": "Download Locale",
"admin.locale.name": "Name",
"admin.locale.namespaces.hint": "Enables multiple language versions of the same page.",
"admin.locale.namespaces.label": "Multilingual Namespaces",
"admin.locale.namespacing": "Multilingual Namespacing",
"admin.locale.namespacingPrefixWarning.subtitle": "Paths without a locale code will be automatically redirected to the base locale defined above.",
"admin.locale.namespacingPrefixWarning.title": "The locale code will be prefixed to all paths. (e.g. /{langCode}/page-name)",
"admin.locale.nativeName": "Native Name",
"admin.locale.rtl": "RTL",
"admin.locale.settings": "Locale Settings",
"admin.locale.sideload": "Sideload Locale Package",
"admin.locale.sideloadHelp": "If you are not connected to the internet or cannot download locale files using the method above, you can instead sideload packages manually by uploading them below.",
"admin.locale.subtitle": "Set localization options for your wiki",
"admin.locale.title": "Locale",
"admin.logging.title": "Logging",
"admin.login.background": "Background Image",
"admin.login.backgroundHint": "Specify an image to use as the login background. PNG and JPG are supported, 1920x1080 recommended. Leave empty for default.",
"admin.login.bypassScreen": "Bypass Login Screen",
"admin.login.bypassScreenHint": "Should the user be redirected automatically to the first authentication provider. Has no effect if the first provider is a username/password provider type.",
"admin.login.bypassUnauthorized": "Bypass Unauthorized Screen",
"admin.login.bypassUnauthorizedHint": "Always redirect the user to the login screen instead of showing an unauthorized error page when the user is not logged in.",
"admin.login.experience": "User Experience",
"admin.login.loginRedirect": "Login Redirect",
"admin.login.loginRedirectHint": "Optionally redirect the user to a specific page when he/she logins (except if first time login which is defined below). This can be overridden at the group level.",
"admin.login.logoutRedirect": "Logout Redirect",
"admin.login.logoutRedirectHint": "Optionally redirect the user to a specific page when he/she logouts. This can be overridden at the group level.",
"admin.login.providers": "Login Providers",
"admin.login.providersVisbleWarning": "Note that you can always temporarily show all hidden providers by adding ?all to the url. This is useful to login as local admin while hiding it from normal users.",
"admin.login.subtitle": "Configure the login user experience of your wiki site",
"admin.login.title": "Login",
"admin.login.welcomeRedirect": "First-time Login Redirect",
"admin.login.welcomeRedirectHint": "Optionally redirect the user to a specific page when he/she login for the first time. This can be overridden at the group level.",
"admin.mail.configuration": "Configuration",
"admin.mail.dkim": "DKIM (optional)",
"admin.mail.dkimDomainName": "Domain Name",
"admin.mail.dkimDomainNameHint": "Domain name used for DKIM validation.",
"admin.mail.dkimHint": "DKIM (DomainKeys Identified Mail) provides a layer of security on all emails sent from Wiki.js by providing the means for recipients to validate the domain name and ensure the message authenticity.",
"admin.mail.dkimKeySelector": "Key Selector",
"admin.mail.dkimKeySelectorHint": "Determines which key to use for DKIM in your DNS records.",
"admin.mail.dkimPrivateKey": "Private Key",
"admin.mail.dkimPrivateKeyHint": "Private key for the selector in PEM format",
"admin.mail.dkimUse": "Use DKIM",
"admin.mail.dkimUseHint": "Should DKIM be used when sending emails.",
"admin.mail.saveSuccess": "Configuration saved successfully.",
"admin.mail.sendTestSuccess": "A test email was sent successfully.",
"admin.mail.sender": "Sender",
"admin.mail.senderEmail": "Sender Email",
"admin.mail.senderName": "Sender Name",
"admin.mail.smtp": "SMTP Settings",
"admin.mail.smtpHost": "Host",
"admin.mail.smtpHostHint": "Hostname or IP address of the SMTP server.",
"admin.mail.smtpPort": "Port",
"admin.mail.smtpPortHint": "Usually 465 (recommended), 587 or 25.",
"admin.mail.smtpPwd": "Password",
"admin.mail.smtpPwdHint": "Password used for authenticating to the SMTP server.",
"admin.mail.smtpTLS": "Secure (TLS)",
"admin.mail.smtpTLSHint": "Should be enabled when using port 465, otherwise turned off (587 or 25).",
"admin.mail.smtpUser": "Username",
"admin.mail.smtpUserHint": "Username used for authenticating to the SMTP server.",
"admin.mail.smtpVerifySSL": "Verify SSL Certificate",
"admin.mail.smtpVerifySSLHint": "Some hosts requires SSL certificate checking to be disabled. Leave enabled for proper security.",
"admin.mail.subtitle": "Configure mail settings",
"admin.mail.templateResetPwd": "Password Reset Email",
"admin.mail.templateWelcome": "Welcome Email",
"admin.mail.templates": "Mail Templates",
"admin.mail.test": "Send a test email",
"admin.mail.testHint": "Send a test email to ensure your SMTP configuration is working.",
"admin.mail.testRecipient": "Recipient Email Address",
"admin.mail.testRecipientHint": "Email address that should receive the test email.",
"admin.mail.testSend": "Send Email",
"admin.mail.title": "Mail",
"admin.nav.modules": "Modules",
"admin.nav.site": "Site",
"admin.nav.system": "System",
"admin.nav.users": "Users",
"admin.navigation.copyFromLocale": "Copy from locale...",
"admin.navigation.copyFromLocaleInfoText": "Select the locale from which items will be copied from. Items will be appended to the current list of items in the active locale.",
"admin.navigation.delete": "Delete {kind}",
"admin.navigation.divider": "Divider",
"admin.navigation.edit": "Edit {kind}",
"admin.navigation.emptyList": "Navigation is empty",
"admin.navigation.header": "Header",
"admin.navigation.icon": "Icon",
"admin.navigation.label": "Label",
"admin.navigation.link": "Link",
"admin.navigation.mode": "Navigation Mode",
"admin.navigation.modeCustom.description": "Static Navigation Menu + Site Tree Button",
"admin.navigation.modeCustom.title": "Custom Navigation",
"admin.navigation.modeNone.description": "Disable Site Navigation",
"admin.navigation.modeNone.title": "None",
"admin.navigation.modeSiteTree.description": "Classic Tree-based Navigation",
"admin.navigation.modeSiteTree.title": "Site Tree",
"admin.navigation.modeStatic.description": "Static Navigation Menu Only",
"admin.navigation.modeStatic.title": "Static Navigation",
"admin.navigation.navType.external": "External Link",
"admin.navigation.navType.externalblank": "External Link (New Window)",
"admin.navigation.navType.home": "Home",
"admin.navigation.navType.page": "Page",
"admin.navigation.navType.searchQuery": "Search Query",
"admin.navigation.noItemsText": "Click the Add button to add your first navigation item.",
"admin.navigation.noSelectionText": "Select a navigation item on the left.",
"admin.navigation.saveSuccess": "Navigation saved successfully.",
"admin.navigation.selectPageButton": "Select Page...",
"admin.navigation.sourceLocale": "Source Locale",
"admin.navigation.sourceLocaleHint": "The locale from which navigation items will be copied from.",
"admin.navigation.subtitle": "Manage the site navigation",
"admin.navigation.target": "Target",
"admin.navigation.targetType": "Target Type",
"admin.navigation.title": "Navigation",
"admin.navigation.untitled": "Untitled {kind}",
"admin.navigation.visibilityMode.all": "Visible to everyone",
"admin.navigation.visibilityMode.restricted": "Visible to select groups...",
"admin.pages.title": "Pages",
"admin.rendering.subtitle": "Configure the page rendering pipeline",
"admin.rendering.title": "Rendering",
"admin.search.configSaveSuccess": "Search engine configuration saved successfully.",
"admin.search.engineConfig": "Engine Configuration",
"admin.search.engineNoConfig": "This engine has no configuration options you can modify.",
"admin.search.indexRebuildSuccess": "Index rebuilt successfully.",
"admin.search.listRefreshSuccess": "List of search engines has been refreshed.",
"admin.search.rebuildIndex": "Rebuild Index",
"admin.search.searchEngine": "Search Engine",
"admin.search.subtitle": "Configure the search capabilities of your wiki",
"admin.search.title": "Search Engine",
"admin.security.cors": "CORS (Cross-Origin Resource Sharing)",
"admin.security.corsHostnames": "Hostnames Whitelist",
"admin.security.corsHostnamesHint": "Enter one hostname per line",
"admin.security.corsMode": "CORS Mode",
"admin.security.corsModeHint": "How the GraphQL server should handle preflight requests?",
"admin.security.corsRegex": "Regex Pattern",
"admin.security.corsRegexHint": "Pattern against which the request hostname is matched.",
"admin.security.disallowFloc": "Disallow Google FLoC",
"admin.security.disallowFlocHint": "Broadcast that this website should be opted-out of Google Federed Learning of Cohorts (FLoC). Recommended for privacy.",
"admin.security.disallowIframe": "Disallow iFrame Embedding",
"admin.security.disallowIframeHint": "Prevents other websites from embedding your wiki in an iframe. This provides clickjacking protection.",
"admin.security.disallowOpenRedirect": "Block Open Redirect",
"admin.security.disallowOpenRedirectHint": "Prevents user controlled URLs from directing to websites outside of your wiki. This provides Open Redirect protection.",
"admin.security.enforce2fa": "Enforce 2FA",
"admin.security.enforce2faHint": "Force all users to use Two-Factor Authentication when using an authentication provider with a user / password form.",
"admin.security.enforceHsts": "Enforce HSTS",
"admin.security.enforceHstsHint": "This ensures the connection cannot be established through an insecure HTTP connection.",
"admin.security.enforceSameOriginReferrerPolicy": "Enforce Same-Origin Referrer Policy",
"admin.security.enforceSameOriginReferrerPolicyHint": "Whether the referrer information should be included to requests to external endpoints.",
"admin.security.forceAssetDownload": "Force Asset Download for Unsafe Extensions",
"admin.security.forceAssetDownloadHint": "Should non-image files be forced as downloads when accessed directly. This prevents potential XSS attacks.",
"admin.security.hsts": "HSTS (HTTP Strict Transport Security)",
"admin.security.hstsDuration": "HSTS Max Age",
"admin.security.hstsDurationHint": "Defines the duration for which the server should only deliver content through HTTPS. It's a good idea to start with small values and make sure that nothing breaks on your wiki before moving to longer values.",
"admin.security.jwt": "JWT Configuration",
"admin.security.jwtAudience": "JWT Audience",
"admin.security.jwtAudienceHint": "Audience URN used in JWT issued upon login. Usually your domain name. (e.g. urn:your.domain.com)",
"admin.security.loginScreen": "Login Screen",
"admin.security.maxUploadBatch": "Max Files per Upload",
"admin.security.maxUploadBatchHint": "How many files can be uploaded in a single batch?",
"admin.security.maxUploadBatchSuffix": "files",
"admin.security.maxUploadSize": "Max Upload Size",
"admin.security.maxUploadSizeHint": "The maximum size for a single file. Final value in base 2.",
"admin.security.maxUploadSizeSuffix": "bytes",
"admin.security.saveSuccess": "Security configuration updated successfully.",
"admin.security.scanSVG": "Scan and Sanitize SVG Uploads",
"admin.security.scanSVGHint": "Should SVG uploads be scanned for vulnerabilities and stripped of any potentially unsafe content.",
"admin.security.subtitle": "Configure security settings",
"admin.security.title": "Security",
"admin.security.tokenEndpointAuthMethod": "Token Endpoint Authentication Method",
"admin.security.tokenExpiration": "Token Expiration",
"admin.security.tokenExpirationHint": "The expiration period of a token until it must be renewed. (default: 30m)",
"admin.security.tokenRenewalPeriod": "Token Renewal Period",
"admin.security.tokenRenewalPeriodHint": "The maximum period a token can be renewed when expired. (default: 14d)",
"admin.security.trustProxy": "Trust X-Forwarded-* Proxy Headers",
"admin.security.trustProxyHint": "Should be enabled when using a reverse-proxy like nginx, apache, CloudFlare, etc in front of Wiki.js. Turn off otherwise.",
"admin.security.uploads": "Uploads",
"admin.security.uploadsInfo": "These settings only affect Wiki.js. If you're using a reverse-proxy (e.g. nginx, Apache, Cloudflare), you must also change its settings to match.",
"admin.security.warn": "Make sure to understand the implications before turning on / off a security feature.",
"admin.sites.activate": "Activate Site",
"admin.sites.activateConfirm": "Are you sure you want activate site {siteTitle}? The site will become accessible to users with read access.",
"admin.sites.createSuccess": "Site created successfully.",
"admin.sites.deactivate": "Deactivate Site",
"admin.sites.deactivateConfirm": "Are you sure you want deactivate site {siteTitle}? The site will no longer be accessible to users.",
"admin.sites.delete": "Delete Site",
"admin.sites.deleteConfirm": "Are you sure you want delete site {siteTitle}? This will permanently delete all site content (including pages, history, comments and assets) and configuration!",
"admin.sites.deleteConfirmWarn": "This action cannot be undone!",
"admin.sites.deleteSuccess": "Site was deleted successfully.",
"admin.sites.edit": "Edit Site",
"admin.sites.hostname": "Hostname",
"admin.sites.hostnameHint": "Must be a fully-qualified domain name (e.g. wiki.example.com) or * for a catch-all site. Note that there can only be 1 catch-all site.",
"admin.sites.isActive": "Active",
"admin.sites.new": "New Site",
"admin.sites.refreshSuccess": "List of sites refreshed successfully.",
"admin.sites.subtitle": "Manage your wiki sites",
"admin.sites.title": "Sites",
"admin.ssl.currentState": "Current State",
"admin.ssl.domain": "Domain",
"admin.ssl.domainHint": "Enter the fully qualified domain pointing to your wiki. (e.g. wiki.example.com)",
"admin.ssl.expiration": "Certificate Expiration",
"admin.ssl.httpPort": "HTTP Port",
"admin.ssl.httpPortHint": "Non-SSL port the server will listen to for HTTP requests. Usually 80 or 3000.",
"admin.ssl.httpPortRedirect": "Redirect HTTP requests to HTTPS",
"admin.ssl.httpPortRedirectHint": "Will automatically redirect any requests on the HTTP port to HTTPS.",
"admin.ssl.httpPortRedirectSaveSuccess": "HTTP Redirection changed successfully.",
"admin.ssl.httpPortRedirectTurnOff": "Turn Off",
"admin.ssl.httpPortRedirectTurnOn": "Turn On",
"admin.ssl.httpsPort": "HTTPS Port",
"admin.ssl.httpsPortHint": "SSL port the server will listen to for HTTPS requests. Usually 443.",
"admin.ssl.ports": "Ports",
"admin.ssl.provider": "Provider",
"admin.ssl.providerCustomCertificate": "Custom Certificate",
"admin.ssl.providerDisabled": "Disabled",
"admin.ssl.providerHint": "Select Custom Certificate if you have your own certificate already.",
"admin.ssl.providerLetsEncrypt": "Let's Encrypt",
"admin.ssl.providerOptions": "Provider Options",
"admin.ssl.renewCertificate": "Renew Certificate",
"admin.ssl.renewCertificateLoadingSubtitle": "Do not leave this page.",
"admin.ssl.renewCertificateLoadingTitle": "Renewing Certificate...",
"admin.ssl.renewCertificateSuccess": "Certificate renewed successfully.",
"admin.ssl.status": "Certificate Status",
"admin.ssl.subscriberEmail": "Subscriber Email",
"admin.ssl.subtitle": "Manage SSL configuration",
"admin.ssl.title": "SSL",
"admin.ssl.writableConfigFileWarning": "Note that your config file must be writable in order to persist ports configuration.",
"admin.stats.title": "Statistics",
"admin.storage.actionRun": "Run",
"admin.storage.actions": "Actions",
"admin.storage.actionsInactiveWarn": "You must enable this storage target and apply changes before you can run actions.",
"admin.storage.addTarget": "Add Storage Target",
"admin.storage.assetDelivery": "Asset Delivery",
"admin.storage.assetDeliveryHint": "Select how uploaded assets should be delivered to the user. Note that not all storage origins support asset delivery and can only be used for backup purposes.",
"admin.storage.assetDirectAccess": "Direct Access",
"admin.storage.assetDirectAccessHint": "Assets are accessed directly by the user using a secure / signed link. When enabled, takes priority over file streaming.",
"admin.storage.assetDirectAccessNotSupported": "Not supported by this storage target.",
"admin.storage.assetStreaming": "File Streaming",
"admin.storage.assetStreamingHint": "Assets will be streamed from the storage target, through the server, to the user.",
"admin.storage.assetStreamingNotSupported": "Not supported by this storage target.",
"admin.storage.assetsOnly": "Assets Only",
"admin.storage.cancelSetup": "Cancel",
"admin.storage.config": "Configuration",
"admin.storage.contentTypeDocuments": "Documents",
"admin.storage.contentTypeDocumentsHint": "Text or presentation documents in PDF, TXT, Word, Excel and Powerpoint formats.",
"admin.storage.contentTypeImages": "Images",
"admin.storage.contentTypeImagesHint": "Image Assets in JPG, PNG, GIF, WebP and SVG formats.",
"admin.storage.contentTypeLargeFiles": "Large Files",
"admin.storage.contentTypeLargeFilesDBWarn": "For performance reasons, large files should not be stored in the database. Consider using another storage type for these files.",
"admin.storage.contentTypeLargeFilesHint": "Large files such as videos, zip archives and binaries. Pages never fall into this category, irrespective of their size.",
"admin.storage.contentTypeLargeFilesThreshold": "Size Threshold",
"admin.storage.contentTypeOthers": "Others",
"admin.storage.contentTypeOthersHint": "Any other file types that don't match the other categories.",
"admin.storage.contentTypePages": "Pages",
"admin.storage.contentTypePagesHint": "Page content source, in Markdown, HTML or JSON format depending on the editor.",
"admin.storage.contentTypes": "Content Types",
"admin.storage.contentTypesHint": "Select the type of content that should be stored to this storage target:",
"admin.storage.currentState": "Current State",
"admin.storage.deliveryPaths": "Delivery Paths",
"admin.storage.deliveryPathsLegend": "Legend:",
"admin.storage.deliveryPathsPushToOrigin": "Push to Origin",
"admin.storage.deliveryPathsUser": "User",
"admin.storage.deliveryPathsUserRequest": "User Request",
"admin.storage.destroyConfirm": "Confirm Setup Reset",
"admin.storage.destroyConfirmInfo": "Are you sure you want to reset the storage target setup configuration? Note that this action cannot be undone and you will need to start the setup process over.",
"admin.storage.destroyingSetup": "Resetting storage target setup configuration...",
"admin.storage.enabled": "Enabled",
"admin.storage.enabledForced": "Cannot be disabled on the database target.",
"admin.storage.enabledHint": "Should this storage target be used for storing and accessing assets.",
"admin.storage.errorMsg": "Error Message",
"admin.storage.finishSetup": "Finish Setup",
"admin.storage.githubAccTypeOrg": "Organization",
"admin.storage.githubAccTypePersonal": "Personal",
"admin.storage.githubFinish": "Once you have installed the application on the GitHub repository of your choice, click the Finish Setup button below to validate the installation and start using it. Otherwise, click Destroy to delete any pending configuration and start over.",
"admin.storage.githubInstallApp": "Setup GitHub Connection - Step 2",
"admin.storage.githubInstallAppHint": "On the next screen, you will be prompted to install the app you just created onto one or more repositories. You may select a single one or all repositories.",
"admin.storage.githubOrg": "GitHub Organization",
"admin.storage.githubOrgHint": "Enter the GitHub organization account to be used.",
"admin.storage.githubPreparingManifest": "Preparing manifest...",
"admin.storage.githubPublicUrl": "Wiki Public URL",
"admin.storage.githubPublicUrlHint": "Enter the full URL to your wiki (e.g. https://wiki.example.com). Note that your wiki MUST be accessible from the internet!",
"admin.storage.githubRedirecting": "Redirecting to GitHub...",
"admin.storage.githubRepo": "GitHub Repository",
"admin.storage.githubRepoCreating": "Creating GitHub Repository...",
"admin.storage.githubRepoHint": "Enter the name of the repository to create on GitHub and use for this wiki:",
"admin.storage.githubSetupContinue": "Continue Setup",
"admin.storage.githubSetupDestroyFailed": "Failed to destroy setup configuration.",
"admin.storage.githubSetupDestroySuccess": "Setup configuration has been reset successfully.",
"admin.storage.githubSetupFailed": "GitHub Setup failed.",
"admin.storage.githubSetupInstallApp": "GitHub Connection Setup - Step 2",
"admin.storage.githubSetupInstallAppInfo": "On the next screen, you'll be prompted to install the app you just created onto one or more GitHub repositories.",
"admin.storage.githubSetupInstallAppReturn": "Once the installation on GitHub is completed, you will need to manually return to this page to finish the setup.",
"admin.storage.githubSetupInstallAppSelect": "IMPORTANT: Select only the repository that will be used to sync with this wiki.",
"admin.storage.githubSetupSuccess": "Success! Wiki.js is now connected to GitHub.",
"admin.storage.githubVerifying": "Verifying GitHub configuration...",
"admin.storage.inactiveTarget": "Inactive",
"admin.storage.lastSync": "Last synchronization {time}",
"admin.storage.lastSyncAttempt": "Last attempt was {time}",
"admin.storage.missingOrigin": "Missing Origin",
"admin.storage.noActions": "This storage target has no actions that you can execute.",
"admin.storage.noConfigOption": "This storage target has no configuration options you can modify.",
"admin.storage.noSyncModes": "This storage target has no synchronization options you can modify.",
"admin.storage.noTarget": "You don't have any active storage target.",
"admin.storage.notConfigured": "Not Configured",
"admin.storage.pagesAndAssets": "Pages and Assets",
"admin.storage.pagesOnly": "Pages Only",
"admin.storage.saveFailed": "Failed to save storage configuration.",
"admin.storage.saveSuccess": "Storage configuration saved successfully.",
"admin.storage.setup": "Setup",
"admin.storage.setupConfiguredHint": "This module is already configured. You can uninstall this module to start over.",
"admin.storage.setupHint": "This module requires a setup process to be completed in order to use it. Follow the instructions below to get started.",
"admin.storage.startSetup": "Start Setup",
"admin.storage.status": "Status",
"admin.storage.subtitle": "Set backup and sync targets for your content",
"admin.storage.sync": "Synchronization",
"admin.storage.syncDirBi": "Bi-directional",
"admin.storage.syncDirBiHint": "In bi-directional mode, content is first pulled from the storage target. Any newer content overwrites local content. New content since last sync is then pushed to the storage target, overwriting any content on target if present.",
"admin.storage.syncDirPull": "Pull from target",
"admin.storage.syncDirPullHint": "Content is always pulled from the storage target, overwriting any local content which already exists. This choice is usually reserved for single-use content import. Caution with this option as any local content will always be overwritten!",
"admin.storage.syncDirPush": "Push to target",
"admin.storage.syncDirPushHint": "Content is always pushed to the storage target, overwriting any existing content. This is safest choice for backup scenarios.",
"admin.storage.syncDirection": "Sync Direction",
"admin.storage.syncDirectionSubtitle": "Choose how content synchronization is handled for this storage target.",
"admin.storage.syncSchedule": "Sync Schedule",
"admin.storage.syncScheduleCurrent": "Currently set to every {schedule}.",
"admin.storage.syncScheduleDefault": "The default is every {schedule}.",
"admin.storage.syncScheduleHint": "For performance reasons, this storage target synchronize changes on an interval-based schedule, instead of on every change. Define at which interval should the synchronization occur.",
"admin.storage.targetConfig": "Target Configuration",
"admin.storage.targetState": "This storage target is {state}",
"admin.storage.targetStateActive": "active",
"admin.storage.targetStateInactive": "inactive",
"admin.storage.targets": "Targets",
"admin.storage.title": "Storage",
"admin.storage.uninstall": "Uninstall",
"admin.storage.unsupported": "Unsupported",
"admin.storage.useVersioning": "Use Versioning",
"admin.storage.useVersioningHint": "Should previous versions of assets be retained on the storage target.",
"admin.storage.vendor": "Vendor",
"admin.storage.vendorWebsite": "Website",
"admin.storage.versioning": "Asset Versioning",
"admin.storage.versioningForceEnabled": "Cannot be disabled on this storage target.",
"admin.storage.versioningHint": "Asset versioning allows for storage of all previous versions of the same file. Unless you have a requirement to store all versions of uploaded assets, it's recommended to leave this oftion off as it can consume significant storage space over time.",
"admin.storage.versioningNotSupported": "Not supported by this storage target.",
"admin.system.browser": "Browser",
"admin.system.browserHint": "The browser name and version.",
"admin.system.client": "Client",
"admin.system.clientCookies": "Cookies Support",
"admin.system.clientCookiesHint": "Whether cookies are enabled on this browser.",
"admin.system.clientLanguage": "Primary Language",
"admin.system.clientLanguageHint": "The main language advertised by the browser.",
"admin.system.clientPlatform": "Platform",
"admin.system.clientPlatformHint": "The OS platform the browser is running on.",
"admin.system.clientViewport": "Viewport",
"admin.system.clientViewportHint": "The viewport dimensions available to the website.",
"admin.system.configFile": "Configuration File",
"admin.system.configFileHint": "The path to the Wiki.js configuration file.",
"admin.system.cpuCores": "CPU Cores",
"admin.system.cpuCoresHint": "The number of CPU cores available to Wiki.js.",
"admin.system.currentVersion": "Current Version",
"admin.system.currentVersionHint": "The currently installed version.",
"admin.system.database": "Database",
"admin.system.databaseHint": "The version of the database in use.",
"admin.system.databaseHost": "Database Host",
"admin.system.databaseHostHint": "The hostname used to access the database.",
"admin.system.dbPartialSupport": "Your database version is not fully supported. Some functionality may be limited or not work as expected.",
"admin.system.engines": "Server Engines",
"admin.system.hostInfo": "Server Host Information",
"admin.system.hostname": "Hostname",
"admin.system.hostnameHint": "The hostname of the server / container.",
"admin.system.latestVersion": "Latest Version",
"admin.system.latestVersionHint": "The latest version available to install.",
"admin.system.nodejsHint": "The version of Node.js installed.",
"admin.system.os": "Operating System",
"admin.system.osHint": "The OS Wiki.js is running on.",
"admin.system.published": "Published",
"admin.system.ramUsage": "RAM Usage: {used} / {total}",
"admin.system.refreshSuccess": "System Info has been refreshed.",
"admin.system.subtitle": "Information about your server / client",
"admin.system.title": "System Info",
"admin.system.totalRAM": "Total RAM",
"admin.system.totalRAMHint": "The total amount of RAM available to Wiki.js.",
"admin.system.workingDirectory": "Working Directory",
"admin.system.workingDirectoryHint": "The directory path where Wiki.js is currently running from.",
"admin.tags.date": "Created {created} and last updated {updated}.",
"admin.tags.delete": "Delete this tag",
"admin.tags.deleteConfirm": "Delete Tag?",
"admin.tags.deleteConfirmText": "Are you sure you want to delete tag {tag}? The tag will also be unlinked from all pages.",
"admin.tags.deleteSuccess": "Tag deleted successfully.",
"admin.tags.edit": "Edit Tag",
"admin.tags.emptyList": "No tags to display.",
"admin.tags.filter": "Filter...",
"admin.tags.label": "Label",
"admin.tags.noItemsText": "Add a tag to a page to get started.",
"admin.tags.noSelectionText": "Select a tag from the list on the left.",
"admin.tags.refreshSuccess": "Tags have been refreshed.",
"admin.tags.saveSuccess": "Tag has been saved successfully.",
"admin.tags.subtitle": "Manage page tags",
"admin.tags.tag": "Tag",
"admin.tags.title": "Tags",
"admin.tags.viewLinkedPages": "View Linked Pages",
"admin.theme.accentColor": "Accent Color",
"admin.theme.accentColorHint": "The accent color for elements that need to stand out or grab the user attention.",
"admin.theme.bodyHtmlInjection": "Body HTML Injection",
"admin.theme.bodyHtmlInjectionHint": "HTML code to be injected just before the closing body tag.",
"admin.theme.codeInjection": "Code Injection",
"admin.theme.cssOverride": "CSS Override",
"admin.theme.cssOverrideHint": "CSS code to inject after system default CSS. Consider using custom themes if you have a large amount of css code. Injecting too much CSS code will result in poor page load performance! CSS will automatically be minified.",
"admin.theme.cssOverrideWarning": "{caution} When adding styles for page content, you must scope them to the {cssClass} class. Omitting this could break the layout of the editor!",
"admin.theme.cssOverrideWarningCaution": "CAUTION:",
"admin.theme.darkMode": "Dark Mode",
"admin.theme.darkModeHint": "Not recommended for accessibility. Can always be turned off by the user.",
"admin.theme.downloadAuthor": "Author",
"admin.theme.downloadDownload": "Download",
"admin.theme.downloadName": "Name",
"admin.theme.downloadThemes": "Download Themes",
"admin.theme.headHtmlInjection": "Head HTML Injection",
"admin.theme.headHtmlInjectionHint": "HTML code to be injected just before the closing head tag. Usually for script tags.",
"admin.theme.headerColor": "Header Color",
"admin.theme.headerColorHint": "The background color for the site top header.",
"admin.theme.iconset": "Icon Set",
"admin.theme.iconsetHint": "Set of icons to use for the sidebar navigation.",
"admin.theme.layout": "Theme Layout",
"admin.theme.options": "Theme Options",
"admin.theme.primaryColor": "Primary Color",
"admin.theme.primaryColorHint": "The main color for primary action buttons and most form elements.",
"admin.theme.reduceMotion": "Reduce Motion",
"admin.theme.reduceMotionHint": "Disable most site animations. This setting is automatically enforced when the reduced motion flag is enabled on the user OS.",
"admin.theme.resetDefaults": "Reset Defaults",
"admin.theme.saveSuccess": "Theme configuration saved successfully!",
"admin.theme.secondaryColor": "Secondary Color",
"admin.theme.secondaryColorHint": "The alternate color for secondary action buttons and for some other elements.",
"admin.theme.showPrintBtn": "Show Print Button",
"admin.theme.showPrintBtnHint": "Should the print button be displayed on all pages. Note that this doesn't prevent the user from printing the page using the system dialog.",
"admin.theme.showSharingMenu": "Show Sharing Menu",
"admin.theme.showSharingMenuHint": "Should the sharing menu be displayed on all pages.",
"admin.theme.sidebarColor": "Sidebar Color",
"admin.theme.sidebarColorHint": "The background color for the side navigation menu on content pages.",
"admin.theme.sidebarPosition": "Sidebar Position",
"admin.theme.sidebarPositionHint": "On which side should the main site navigation sidebar be displayed.",
"admin.theme.siteTheme": "Site Theme",
"admin.theme.siteThemeHint": "Themes affect how content pages are displayed. Other site sections (such as the editor or admin area) are not affected.",
"admin.theme.subtitle": "Modify the look & feel of your wiki",
"admin.theme.title": "Theme",
"admin.theme.tocPosition": "TOC Position",
"admin.theme.tocPositionHint": "On which side should the Table of Contents sidebar be displayed for content pages.",
"admin.users.active": "Active",
"admin.users.activity": "Activity",
"admin.users.assignGroup": "Assign Group",
"admin.users.auth": "Authentication",
"admin.users.authProvider": "Provider",
"admin.users.authProviderId": "Provider Id",
"admin.users.authentication": "Authentication",
"admin.users.ban": "Ban User",
"admin.users.banHint": "Block the user from signing in and invalidate any active sessions.",
"admin.users.banned": "Banned",
"admin.users.basicInfo": "Basic Info",
"admin.users.changePassword": "Change Password",
"admin.users.changePasswordHint": "Change the user password. Note that the current password cannot be recovered.",
"admin.users.create": "Create User",
"admin.users.createInvalidData": "Cannot create user as some fields are invalid or missing.",
"admin.users.createKeepOpened": "Keep dialog opened after create",
"admin.users.createSuccess": "User created successfully!",
"admin.users.createdAt": "Created {date}",
"admin.users.darkMode": "Dark Mode",
"admin.users.darkModeHint": "Display the user interface using dark mode.",
"admin.users.dateFormat": "Date Format",
"admin.users.dateFormatHint": "How dates should be formatted when displayed to the user.",
"admin.users.delete": "Delete User",
"admin.users.deleteConfirmForeignNotice": "Note that you cannot delete a user that already created content. You must instead either deactivate the user or delete all content that was created by that user.",
"admin.users.deleteConfirmReplaceWarn": "Any content (pages, uploads, comments, etc.) that was created by this user will be reassigned to the user selected below. It is recommended to create a dummy target user (e.g. Deleted User) if you don't want the content to be reassigned to any current active user.",
"admin.users.deleteConfirmText": "Are you sure you want to delete user {username}?",
"admin.users.deleteConfirmTitle": "Delete User?",
"admin.users.deleteHint": "Permanently remove the user from the database. This action cannot be undone!",
"admin.users.displayName": "Display Name",
"admin.users.edit": "Edit User",
"admin.users.email": "Email",
"admin.users.emailHint": "Email address of the user.",
"admin.users.emailInvalid": "Email address is invalid.",
"admin.users.emailMissing": "Email address is missing.",
"admin.users.extendedMetadata": "Extended Metadata",
"admin.users.groupAlreadyAssigned": "User is already assigned to this group.",
"admin.users.groupAssign": "Assign",
"admin.users.groupAssignNotice": "Note that you cannot assign users to the Administrators or Guests groups from this panel.",
"admin.users.groupSelected": "Assign to {group}",
"admin.users.groups": "Groups",
"admin.users.groupsMissing": "You must assign the user to at least 1 group.",
"admin.users.groupsSelected": "Assign to {count} groups",
"admin.users.id": "ID",
"admin.users.inactive": "Inactive",
"admin.users.info": "User Info",
"admin.users.invalidJSON": "Invalid JSON",
"admin.users.jobTitle": "Job Title",
"admin.users.jobTitleHint": "The job title of the user.",
"admin.users.joined": "Joined",
"admin.users.lastLoginAt": "Last login",
"admin.users.lastUpdated": "Last Updated",
"admin.users.linkedAccounts": "Linked Accounts",
"admin.users.linkedProviders": "Linked Providers",
"admin.users.loading": "Loading User...",
"admin.users.location": "Location",
"admin.users.locationHint": "The city / country of the user or the office location.",
"admin.users.metadata": "Metadata",
"admin.users.minimumGroupRequired": "Cannot unassign because user must be assigned to at least 1 group.",
"admin.users.mustChangePwd": "Must Change Password",
"admin.users.mustChangePwdHint": "User will be prompted to choose a new password upon login.",
"admin.users.name": "Display Name",
"admin.users.nameHint": "Usually the full name or nickname of the user.",
"admin.users.nameInvalidChars": "Name has invalid characters.",
"admin.users.nameMissing": "Name is missing.",
"admin.users.newPassword": "New Password",
"admin.users.noGroupAssigned": "This user is not assigned to any group yet. You must assign at least 1 group to a user.",
"admin.users.noGroupSelected": "You must select a group first.",
"admin.users.noLinkedProviders": "This user isn't linked to any authentication providers.",
"admin.users.noteHint": "Notes are not shown to the user and can only be edited here.",
"admin.users.notes": "Notes",
"admin.users.operations": "Operations",
"admin.users.overview": "Overview",
"admin.users.passAuth": "Password Authentication",
"admin.users.password": "Password",
"admin.users.passwordMissing": "Password is missing.",
"admin.users.passwordTooShort": "Password is too short.",
"admin.users.preferences": "User Preferences",
"admin.users.profile": "User Profile",
"admin.users.pwdAuthActive": "Can Use Password Authentication",
"admin.users.pwdAuthActiveHint": "Whether the user can login using the password authentication.",
"admin.users.pwdAuthRestrict": "Restrict Password Authentication",
"admin.users.pwdAuthRestrictHint": "Prevent the user from using password authentication for login.",
"admin.users.pwdNotSet": "Password Not Set",
"admin.users.pwdSet": "Password is set",
"admin.users.pwdStrengthGood": "Good",
"admin.users.pwdStrengthMedium": "Medium",
"admin.users.pwdStrengthPoor": "Poor",
"admin.users.pwdStrengthStrong": "Strong",
"admin.users.pwdStrengthWeak": "Weak",
"admin.users.refreshSuccess": "Users refreshed successfully.",
"admin.users.saveSuccess": "User saved successfully.",
"admin.users.selectGroup": "Select Group...",
"admin.users.sendWelcomeEmail": "Send Welcome Email",
"admin.users.sendWelcomeEmailAltHint": "An email will be sent to the user with link(s) to the wiki(s) the user has read access to.",
"admin.users.sendWelcomeEmailHint": "An email will be sent to the user with his login details.",
"admin.users.subtitle": "Manage Users",
"admin.users.tfa": "Two Factor Authentication (2FA)",
"admin.users.tfaInvalidate": "Invalidate 2FA",
"admin.users.tfaInvalidateConfirm": "Are you sure you want to invalidate the user current 2FA configuration? This action cannot be undone.",
"admin.users.tfaInvalidateHint": "Force the user to setup 2FA again. Any active configuration will no longer work.",
"admin.users.tfaInvalidateSuccess": "User TFA configuration has been invalidated.",
"admin.users.tfaNotSet": "2FA is awaiting setup",
"admin.users.tfaRequired": "Require 2FA",
"admin.users.tfaRequiredHint": "User will be forced to use 2FA during the next login. This setting will have no effect if 2FA is already enforced by the login provider.",
"admin.users.tfaSet": "2FA configured",
"admin.users.timeFormat": "Time Format",
"admin.users.timeFormatHint": "How time should be formatted when displayed to the user.",
"admin.users.timezone": "Timezone",
"admin.users.timezoneHint": "Used to adjust date and time displayed to the user.",
"admin.users.title": "Users",
"admin.users.toggle2FA": "Toggle 2FA",
"admin.users.unassignGroup": "Unassign from Group",
"admin.users.unban": "Unban User",
"admin.users.unbanHint": "Allow the user to sign in.",
"admin.users.unverified": "Unverified",
"admin.users.unverify": "Unverify User",
"admin.users.unverifyHint": "Set the user as unverified (state where the email has not been validated).",
"admin.users.updateUser": "Update User",
"admin.users.userActivateSuccess": "User has been activated successfully.",
"admin.users.userAlreadyAssignedToGroup": "User is already assigned to this group!",
"admin.users.userDeactivateSuccess": "User deactivated successfully.",
"admin.users.userTFADisableSuccess": "2FA was disabled successfully.",
"admin.users.userTFAEnableSuccess": "2FA was enabled successfully.",
"admin.users.userUpdateSuccess": "User updated successfully.",
"admin.users.userVerifySuccess": "User has been verified successfully.",
"admin.users.verified": "Verified",
"admin.users.verify": "Verify User",
"admin.users.verifyHint": "Set the user as verified (state where the email has been validated).",
"admin.utilities.authSubtitle": "Various tools for authentication / users",
"admin.utilities.authTitle": "Authentication",
"admin.utilities.cacheSubtitle": "Flush cache of various components",
"admin.utilities.cacheTitle": "Flush Cache",
"admin.utilities.contentSubtitle": "Various tools for pages",
"admin.utilities.contentTitle": "Content",
"admin.utilities.graphEndpointSubtitle": "Change the GraphQL endpoint for Wiki.js",
"admin.utilities.graphEndpointTitle": "GraphQL Endpoint",
"admin.utilities.importv1Subtitle": "Migrate data from a previous 1.x installation",
"admin.utilities.importv1Title": "Import from Wiki.js 1.x",
"admin.utilities.invalidAuthCertificates": "Invalidate Authentication Certificates",
"admin.utilities.invalidAuthCertificatesHint": "Regenerate the public and private keys used for authentication. This will instantly log everyone out.",
"admin.utilities.purgeHistory": "Purge History",
"admin.utilities.purgeHistoryHint": "Delete history (content versioning) older than the selected timeframe.",
"admin.utilities.purgeHistoryTimeframe": "Delete older than...",
"admin.utilities.subtitle": "Maintenance and miscellaneous tools",
"admin.utilities.telemetrySubtitle": "Enable/Disable telemetry or reset the client ID",
"admin.utilities.telemetryTitle": "Telemetry",
"admin.utilities.title": "Utilities",
"admin.utilities.tools": "Tools",
"admin.utitilies.purgeHistoryMonth": "1 Month | {count} Months",
"admin.utitilies.purgeHistoryToday": "Today",
"admin.utitilies.purgeHistoryYear": "1 Year | {count} Years",
"admin.webhooks.acceptUntrusted": "Accept untrusted SSL certificates",
"admin.webhooks.acceptUntrustedHint": "It is recommended that you leave this off for proper security.",
"admin.webhooks.authHeader": "Authentication Header",
"admin.webhooks.authHeaderHint": "(Optional) The value of the Authorization header to send along the request.",
"admin.webhooks.createInvalidData": "The webhook has some invalid or missing data.",
"admin.webhooks.createSuccess": "Webhook created successfully!",
"admin.webhooks.delete": "Delete Webhook",
"admin.webhooks.deleteConfirm": "Are you sure you want to delete webhook {name}?",
"admin.webhooks.deleteConfirmWarn": "This action cannot be undone!",
"admin.webhooks.deleteSuccess": "Webhook deleted successfully.",
"admin.webhooks.edit": "Edit Webhook",
"admin.webhooks.eventCreatePage": "Create a new page",
"admin.webhooks.eventDeleteAsset": "Delete an asset",
"admin.webhooks.eventDeleteComment": "Delete a comment",
"admin.webhooks.eventDeletePage": "Delete a page",
"admin.webhooks.eventEditAsset": "Edit an existing asset",
"admin.webhooks.eventEditComment": "Edit an existing comment",
"admin.webhooks.eventEditPage": "Update an existing page",
"admin.webhooks.eventNewComment": "Post a new comment",
"admin.webhooks.eventRenameAsset": "Rename / move an asset",
"admin.webhooks.eventRenamePage": "Rename / move a page",
"admin.webhooks.eventUploadAsset": "Upload a new asset",
"admin.webhooks.eventUserJoin": "Create / register a new user",
"admin.webhooks.eventUserLogin": "User logins",
"admin.webhooks.eventUserLogout": "User logouts",
"admin.webhooks.events": "Events",
"admin.webhooks.eventsMissing": "You must select at least 1 event.",
"admin.webhooks.eventsSelected": "No event selected | 1 event selected | {count} events selected",
"admin.webhooks.includeContent": "Include Content",
"admin.webhooks.includeContentHint": "Should the payload include content (e.g. the full page body). Make sure that your remote endpoint can accept large payloads!",
"admin.webhooks.includeMetadata": "Include Metadata",
"admin.webhooks.includeMetadataHint": "Should the payload include metadata such as title, description, author, etc.",
"admin.webhooks.nameInvalidChars": "The name contains invalid characters.",
"admin.webhooks.nameMissing": "A name for this webhook is required.",
"admin.webhooks.new": "New Webhook",
"admin.webhooks.none": "There are no webhooks yet.",
"admin.webhooks.stateError": "Failed",
"admin.webhooks.stateErrorExplain": "The last trigger failed to call the endpoint.",
"admin.webhooks.stateErrorHint": "The last event failed to call your endpoint. Click Edit for more details.",
"admin.webhooks.statePending": "Pending",
"admin.webhooks.statePendingHint": "Waiting for an event to trigger this webhook for the first time.",
"admin.webhooks.stateSuccess": "Healthy",
"admin.webhooks.stateSuccessHint": "The last webhook trigger completed successfully.",
"admin.webhooks.subtitle": "Manage webhooks to external services",
"admin.webhooks.title": "Webhooks",
"admin.webhooks.typeAsset": "asset",
"admin.webhooks.typeComment": "comment",
"admin.webhooks.typePage": "page",
"admin.webhooks.typeUser": "user",
"admin.webhooks.updateSuccess": "Webhook updated successfully.",
"admin.webhooks.url": "URL",
"admin.webhooks.urlHint": "Enter the remote endpoint URL",
"admin.webhooks.urlInvalidChars": "The URL contains invalid characters.",
"admin.webhooks.urlMissing": "The URL is missing or is not valid.",
"auth.actions.login": "Log In",
"auth.actions.register": "Register",
"auth.changePwd.instructions": "You must choose a new password:",
"auth.changePwd.loading": "Changing password...",
"auth.changePwd.newPasswordPlaceholder": "New Password",
"auth.changePwd.newPasswordVerifyPlaceholder": "Verify New Password",
"auth.changePwd.proceed": "Change Password",
"auth.changePwd.subtitle": "Choose a new password",
"auth.enterCredentials": "Enter your credentials",
"auth.errors.invalidLogin": "Invalid Login",
"auth.errors.invalidLoginMsg": "The email or password is invalid.",
"auth.errors.invalidUserEmail": "Invalid User Email",
"auth.errors.loginError": "Login error",
"auth.errors.notYetAuthorized": "You have not been authorized to login to this site yet.",
"auth.errors.tooManyAttempts": "Too many attempts!",
"auth.errors.tooManyAttemptsMsg": "You've made too many failed attempts in a short period of time, please try again {time}.",
"auth.errors.userNotFound": "User not found",
"auth.fields.email": "Email Address",
"auth.fields.emailUser": "Email / Username",
"auth.fields.name": "Name",
"auth.fields.password": "Password",
"auth.fields.username": "Username",
"auth.fields.verifyPassword": "Verify Password",
"auth.forgotPasswordCancel": "Cancel",
"auth.forgotPasswordLink": "Forgot your password?",
"auth.forgotPasswordLoading": "Requesting password reset...",
"auth.forgotPasswordSubtitle": "Enter your email address to receive the instructions to reset your password:",
"auth.forgotPasswordSuccess": "Check your emails for password reset instructions!",
"auth.forgotPasswordTitle": "Forgot your password",
"auth.genericError": "Authentication is unavailable.",
"auth.invalidEmail": "Email address is invalid.",
"auth.invalidEmailUsername": "Enter a valid email / username.",
"auth.invalidPassword": "Enter a valid password.",
"auth.loginRequired": "Login required",
"auth.loginSuccess": "Login Successful! Redirecting...",
"auth.loginUsingStrategy": "Login using {strategy}",
"auth.missingEmail": "Missing email address.",
"auth.missingName": "Name is missing.",
"auth.missingPassword": "Missing password.",
"auth.nameTooLong": "Name is too long.",
"auth.nameTooShort": "Name is too short.",
"auth.orLoginUsingStrategy": "or login using...",
"auth.passwordNotMatch": "Both passwords do not match.",
"auth.passwordTooShort": "Password is too short.",
"auth.pleaseWait": "Please wait",
"auth.providers.azure": "Azure Active Directory",
"auth.providers.facebook": "Facebook",
"auth.providers.github": "GitHub",
"auth.providers.google": "Google ID",
"auth.providers.ldap": "LDAP / Active Directory",
"auth.providers.local": "Local",
"auth.providers.slack": "Slack",
"auth.providers.windowslive": "Microsoft Account",
"auth.registerCheckEmail": "Check your emails to activate your account.",
"auth.registerSubTitle": "Fill-in the form below to create your account.",
"auth.registerSuccess": "Account created successfully!",
"auth.registerTitle": "Create an account",
"auth.registering": "Creating account...",
"auth.selectAuthProvider": "Select Authentication Provider",
"auth.sendResetPassword": "Reset Password",
"auth.signingIn": "Signing In...",
"auth.switchToLogin.link": "Login instead",
"auth.switchToLogin.text": "Already have an account? {link}",
"auth.switchToRegister.link": "Create an account",
"auth.switchToRegister.text": "Don't have an account yet? {link}",
"auth.tfa.placeholder": "XXXXXX",
"auth.tfa.subtitle": "Security code required:",
"auth.tfa.title": "Two Factor Authentication",
"auth.tfa.verifyToken": "Verify",
"auth.tfaFormTitle": "Enter the security code generated from your trusted device:",
"auth.tfaSetupInstrFirst": "1) Scan the QR code below from your mobile 2FA application:",
"auth.tfaSetupInstrSecond": "2) Enter the security code generated from your trusted device:",
"auth.tfaSetupTitle": "Your administrator has required Two-Factor Authentication (2FA) to be enabled on your account.",
"common.actions.activate": "Activate",
"common.actions.add": "Add",
"common.actions.apply": "Apply",
"common.actions.browse": "Browse...",
"common.actions.cancel": "Cancel",
"common.actions.clear": "Clear",
"common.actions.close": "Close",
"common.actions.commit": "Commit",
"common.actions.confirm": "Confirm",
"common.actions.copy": "Copy",
"common.actions.create": "Create",
"common.actions.deactivate": "Deactivate",
"common.actions.delete": "Delete",
"common.actions.discard": "Discard",
"common.actions.discardChanges": "Discard Changes",
"common.actions.download": "Download",
"common.actions.edit": "Edit",
"common.actions.exit": "Exit",
"common.actions.fetch": "Fetch",
"common.actions.filter": "Filter",
"common.actions.generate": "Generate",
"common.actions.howItWorks": "How it works",
"common.actions.insert": "Insert",
"common.actions.manage": "Manage",
"common.actions.move": "Move",
"common.actions.new": "New",
"common.actions.ok": "OK",
"common.actions.optimize": "Optimize",
"common.actions.page": "Page",
"common.actions.preview": "Preview",
"common.actions.proceed": "Proceed",
"common.actions.properties": "Properties",
"common.actions.refresh": "Refresh",
"common.actions.rename": "Rename",
"common.actions.returnToTop": "Return to top",
"common.actions.save": "Save",
"common.actions.saveChanges": "Save Changes",
"common.actions.select": "Select",
"common.actions.update": "Update",
"common.actions.upload": "Upload",
"common.clipboard.failure": "Failed to copy to clipboard.",
"common.clipboard.success": "Copied to clipboard successfully.",
"common.clipboard.uuid": "Copy UUID to clipboard.",
"common.clipboard.uuidFailure": "Failed to copy UUID to clipboard.",
"common.clipboard.uuidSuccess": "Copied UUID to clipboard successfully.",
"common.comments.beFirst": "Be the first to comment.",
"common.comments.contentMissingError": "Comment is empty or too short!",
"common.comments.deleteConfirmTitle": "Confirm Delete",
"common.comments.deletePermanentWarn": "This action cannot be undone!",
"common.comments.deleteSuccess": "Comment was deleted successfully.",
"common.comments.deleteWarn": "Are you sure you want to permanently delete this comment?",
"common.comments.fieldContent": "Comment Content",
"common.comments.fieldEmail": "Your Email Address",
"common.comments.fieldName": "Your Name",
"common.comments.loading": "Loading comments...",
"common.comments.markdownFormat": "Markdown Format",
"common.comments.modified": "modified {reldate}",
"common.comments.newComment": "New Comment",
"common.comments.newPlaceholder": "Write a new comment...",
"common.comments.none": "No comments yet.",
"common.comments.postComment": "Post Comment",
"common.comments.postSuccess": "New comment posted successfully.",
"common.comments.postingAs": "Posting as {name}",
"common.comments.sdTitle": "Talk",
"common.comments.title": "Comments",
"common.comments.updateComment": "Update Comment",
"common.comments.updateSuccess": "Comment was updated successfully.",
"common.comments.viewDiscussion": "View Discussion",
"common.duration.days": "Day(s)",
"common.duration.every": "Every",
"common.duration.hours": "Hour(s)",
"common.duration.minutes": "Minute(s)",
"common.duration.months": "Month(s)",
"common.duration.years": "Year(s)",
"common.error.unexpected": "An unexpected error occurred.",
"common.field.createdOn": "Created On",
"common.field.id": "ID",
"common.field.lastUpdated": "Last Updated",
"common.field.name": "Name",
"common.footer.copyright": "© {year} {company}. All rights reserved.",
"common.footer.license": "Content is available under the {license}, by {company}.",
"common.footer.poweredBy": "Powered by",
"common.header.account": "Account",
"common.header.admin": "Administration",
"common.header.assets": "Assets",
"common.header.browseTags": "Browse by Tags",
"common.header.currentPage": "Current Page",
"common.header.delete": "Delete",
"common.header.duplicate": "Duplicate",
"common.header.edit": "Edit",
"common.header.history": "History",
"common.header.home": "Home",
"common.header.imagesFiles": "Images & Files",
"common.header.language": "Language",
"common.header.login": "Login",
"common.header.logout": "Logout",
"common.header.move": "Move / Rename",
"common.header.myWiki": "My Wiki",
"common.header.newPage": "New Page",
"common.header.pageActions": "Page Actions",
"common.header.profile": "Profile",
"common.header.search": "Search...",
"common.header.searchClose": "Close",
"common.header.searchCopyLink": "Copy Search Link",
"common.header.searchDidYouMean": "Did you mean...",
"common.header.searchHint": "Type at least 2 characters to start searching...",
"common.header.searchLoading": "Searching...",
"common.header.searchNoResult": "No pages matching your query.",
"common.header.searchResultsCount": "Found {total} results",
"common.header.siteMap": "Site Map",
"common.header.view": "View",
"common.header.viewSource": "View Source",
"common.license.alr": "All Rights Reserved",
"common.license.cc0": "Public Domain",
"common.license.ccby": " Creative Commons Attribution License",
"common.license.ccbync": "Creative Commons Attribution-NonCommercial License",
"common.license.ccbyncnd": "Creative Commons Attribution-NonCommercial-NoDerivs License",
"common.license.ccbyncsa": "Creative Commons Attribution-NonCommercial-ShareAlike License",
"common.license.ccbynd": "Creative Commons Attribution-NoDerivs License",
"common.license.ccbysa": "Creative Commons Attribution-ShareAlike License",
"common.license.none": "None",
"common.loading": "Loading...",
"common.modernBrowser": "modern browser",
"common.newpage.create": "Create Page",
"common.newpage.goback": "Go back",
"common.newpage.subtitle": "Would you like to create it now?",
"common.newpage.title": "This page does not exist yet.",
"common.notfound.gohome": "Home",
"common.notfound.subtitle": "This page does not exist.",
"common.notfound.title": "Not Found",
"common.outdatedBrowserWarning": "Your browser is outdated. Upgrade to a {modernBrowser}.",
"common.page.bookmark": "Bookmark",
"common.page.delete": "Delete Page",
"common.page.deleteSubtitle": "The page can be restored from the administration area.",
"common.page.deleteTitle": "Are you sure you want to delete page {title}?",
"common.page.editPage": "Edit Page",
"common.page.global": "Global",
"common.page.id": "ID {id}",
"common.page.lastEditedBy": "Last edited by",
"common.page.loading": "Loading Page...",
"common.page.printFormat": "Print Format",
"common.page.private": "Private",
"common.page.published": "Published",
"common.page.returnNormalView": "Return to Normal View",
"common.page.share": "Share",
"common.page.tags": "Tags",
"common.page.tagsMatching": "Pages matching tags",
"common.page.toc": "Table of Contents",
"common.page.unpublished": "Unpublished",
"common.page.unpublishedWarning": "This page is not published.",
"common.page.versionId": "Version ID {id}",
"common.page.viewingSource": "Viewing source of page {path}",
"common.page.viewingSourceVersion": "Viewing source as of {date} of page {path}",
"common.pageSelector.createTitle": "Select New Page Location",
"common.pageSelector.folderEmptyWarning": "This folder is empty.",
"common.pageSelector.moveTitle": "Move / Rename Page Location",
"common.pageSelector.pages": "Pages",
"common.pageSelector.selectTitle": "Select a Page",
"common.pageSelector.virtualFolders": "Virtual Folders",
"common.password.average": "Average",
"common.password.strong": "Strong",
"common.password.veryStrong": "Very Strong",
"common.password.veryWeak": "Very Weak",
"common.password.weak": "Weak",
"common.sidebar.browse": "Browse",
"common.sidebar.currentDirectory": "Current Directory",
"common.sidebar.mainMenu": "Main Menu",
"common.sidebar.root": "(root)",
"common.unauthorized.action.create": "You cannot create the page.",
"common.unauthorized.action.download": "You cannot download the page content.",
"common.unauthorized.action.downloadVersion": "You cannot download the content for this page version.",
"common.unauthorized.action.edit": "You cannot edit the page.",
"common.unauthorized.action.history": "You cannot view the page history.",
"common.unauthorized.action.source": "You cannot view the page source.",
"common.unauthorized.action.sourceVersion": "You cannot view the source of this version of the page.",
"common.unauthorized.action.view": "You cannot view this page.",
"common.unauthorized.goback": "Go Back",
"common.unauthorized.login": "Login As...",
"common.unauthorized.title": "Unauthorized",
"common.user.search": "Search User",
"common.user.searchPlaceholder": "Search Users...",
"common.welcome.createhome": "Create Home Page",
"common.welcome.subtitle": "Let's get started and create the home page.",
"common.welcome.title": "Welcome to your wiki!",
"editor.assets.deleteAsset": "Delete Asset",
"editor.assets.deleteAssetConfirm": "Are you sure you want to delete asset",
"editor.assets.deleteAssetWarn": "This action cannot be undone!",
"editor.assets.deleteSuccess": "Asset deleted successfully.",
"editor.assets.fetchImage": "Fetch Remote Image",
"editor.assets.fileCount": "{count} files",
"editor.assets.folderCreateSuccess": "Asset folder created successfully.",
"editor.assets.folderEmpty": "This asset folder is empty.",
"editor.assets.folderName": "Folder Name",
"editor.assets.folderNameNamingRules": "Must follow the asset folder {namingRules}.",
"editor.assets.folderNameNamingRulesLink": "naming rules",
"editor.assets.headerActions": "Actions",
"editor.assets.headerAdded": "Added",
"editor.assets.headerFileSize": "File Size",
"editor.assets.headerFilename": "Filename",
"editor.assets.headerId": "ID",
"editor.assets.headerType": "Type",
"editor.assets.imageAlign": "Image Alignment",
"editor.assets.newFolder": "New Folder",
"editor.assets.noUploadError": "You must choose a file to upload first!",
"editor.assets.refreshSuccess": "List of assets refreshed successfully.",
"editor.assets.renameAsset": "Rename Asset",
"editor.assets.renameAssetSubtitle": "Enter the new name for this asset:",
"editor.assets.renameSuccess": "Asset renamed successfully.",
"editor.assets.title": "Assets",
"editor.assets.uploadAssets": "Upload Assets",
"editor.assets.uploadAssetsDropZone": "Browse or Drop files here...",
"editor.assets.uploadFailed": "File upload failed.",
"editor.backToEditor": "Back to Editor",
"editor.ckeditor.stats": "{chars} chars, {words} words",
"editor.conflict.editable": "(editable)",
"editor.conflict.infoGeneric": "A more recent version of this page was saved by {authorName}, {date}",
"editor.conflict.leftPanelInfo": "Your current edit, based on page version from {date}",
"editor.conflict.localVersion": "Local Version {refEditable}",
"editor.conflict.overwrite.description": "Are you sure you want to replace your current version with the latest remote content? {refEditsLost}",
"editor.conflict.overwrite.editsLost": "Your current edits will be lost.",
"editor.conflict.overwrite.title": "Overwrite with Remote Version?",
"editor.conflict.pageDescription": "Description:",
"editor.conflict.pageTitle": "Title:",
"editor.conflict.readonly": "(read-only)",
"editor.conflict.remoteVersion": "Remote Version {refReadOnly}",
"editor.conflict.rightPanelInfo": "Last edited by {authorName}, {date}",
"editor.conflict.title": "Resolve Save Conflict",
"editor.conflict.useLocal": "Use Local",
"editor.conflict.useLocalHint": "Use content in the left panel",
"editor.conflict.useRemote": "Use Remote",
"editor.conflict.useRemoteHint": "Discard local changes and use latest version",
"editor.conflict.viewLatestVersion": "View Latest Version",
"editor.conflict.warning": "Save conflict! Another user has already modified this page.",
"editor.conflict.whatToDo": "What do you want to do?",
"editor.conflict.whatToDoLocal": "Use your current local version and ignore the latest changes.",
"editor.conflict.whatToDoRemote": "Use the remote version (latest) and discard your changes.",
"editor.markup.blockquote": "Blockquote",
"editor.markup.blockquoteError": "Error Blockquote",
"editor.markup.blockquoteInfo": "Info Blockquote",
"editor.markup.blockquoteSuccess": "Success Blockquote",
"editor.markup.blockquoteWarning": "Warning Blockquote",
"editor.markup.bold": "Bold",
"editor.markup.distractionFreeMode": "Distraction Free Mode",
"editor.markup.heading": "Heading {level}",
"editor.markup.horizontalBar": "Horizontal Bar",
"editor.markup.inlineCode": "Inline Code",
"editor.markup.insertAssets": "Insert Assets",
"editor.markup.insertBlock": "Insert Block",
"editor.markup.insertCodeBlock": "Insert Code Block",
"editor.markup.insertDiagram": "Insert Diagram",
"editor.markup.insertLink": "Insert Link",
"editor.markup.insertMathExpression": "Insert Math Expression",
"editor.markup.insertVideoAudio": "Insert Video / Audio",
"editor.markup.italic": "Italic",
"editor.markup.keyboardKey": "Keyboard Key",
"editor.markup.markdownFormattingHelp": "Markdown Formatting Help",
"editor.markup.noSelectionError": "Text must be selected first!",
"editor.markup.orderedList": "Ordered List",
"editor.markup.strikethrough": "Strikethrough",
"editor.markup.subscript": "Subscript",
"editor.markup.superscript": "Superscript",
"editor.markup.tableHelper": "Table Helper",
"editor.markup.togglePreviewPane": "Hide / Show Preview Pane",
"editor.markup.toggleSpellcheck": "Toggle Spellcheck",
"editor.markup.unorderedList": "Unordered List",
"editor.page": "Page",
"editor.pageData.data": "Data",
"editor.pageData.dragDropHint": "Drag-n-drop fields from the left onto this area to build your template structure.",
"editor.pageData.duplicateTemplateKeys": "One or more fields have duplicate unique keys!",
"editor.pageData.emptyTemplateStructure": "Template Structure is empty!",
"editor.pageData.fieldTypeBoolean": "Boolean",
"editor.pageData.fieldTypeHeader": "Header",
"editor.pageData.fieldTypeImage": "Image",
"editor.pageData.fieldTypeLink": "Link",
"editor.pageData.fieldTypeNumber": "Number",
"editor.pageData.fieldTypeText": "Text",
"editor.pageData.invalidTemplateKeys": "One or more fields have missing or invalid unique keys!",
"editor.pageData.invalidTemplateLabels": "One or more fields have missing or invalid labels!",
"editor.pageData.invalidTemplateName": "Template name is missing or invalid!",
"editor.pageData.label": "Label",
"editor.pageData.manageTemplates": "Manage Templates",
"editor.pageData.noTemplate": "You don't have any template yet. Create one to get started.",
"editor.pageData.selectTemplateAbove": "Select a template to edit from the dropdown menu above.",
"editor.pageData.template": "Template",
"editor.pageData.templateDeleteConfirmText": "Any page currently using this template will revert to basic template rendering.",
"editor.pageData.templateDeleteConfirmTitle": "Are you sure?",
"editor.pageData.templateFullRowTypes": "Full Row Types",
"editor.pageData.templateKeyValueTypes": "Key-Value Types",
"editor.pageData.templateStructure": "Structure",
"editor.pageData.templateTitle": "Template Title",
"editor.pageData.templateUntitled": "Untitled Template",
"editor.pageData.title": "Page Data",
"editor.pageData.uniqueKey": "Unique Key",
"editor.pageRel.button": "Button Appearance",
"editor.pageRel.caption": "Caption (optional)",
"editor.pageRel.center": "Center",
"editor.pageRel.label": "Label",
"editor.pageRel.left": "Left",
"editor.pageRel.position": "Button Position",
"editor.pageRel.preview": "Preview",
"editor.pageRel.right": "Right",
"editor.pageRel.selectIcon": "Select Icon...",
"editor.pageRel.selectPage": "Select Page...",
"editor.pageRel.target": "Target",
"editor.pageRel.title": "Add Page Relation",
"editor.pageRel.titleEdit": "Edit Page Relation",
"editor.pageScripts.title": "Page Scripts",
"editor.props.allowComments": "Allow Comments",
"editor.props.allowCommentsHint": "Enable commenting abilities on this page.",
"editor.props.allowContributions": "Allow Contributions",
"editor.props.allowRatings": "Allow Ratings",
"editor.props.allowRatingsHint": "Enable rating capabilities on this page.",
"editor.props.dateRange": "Date Range",
"editor.props.dateRangeHint": "Select the start and end date for this page publication. The page will only be accessible to users with read access within the selected date range.",
"editor.props.draft": "Draft",
"editor.props.draftHint": "Visible to users with write access only.",
"editor.props.info": "Info",
"editor.props.jsLoad": "Javascript - On Load",
"editor.props.jsLoadHint": "Execute javascript once the page is loaded",
"editor.props.jsUnload": "Javascript - On Unload",
"editor.props.jsUnloadHint": "Execute javascript before the page content is destroyed",
"editor.props.pageProperties": "Page Properties",
"editor.props.password": "Password",
"editor.props.passwordHint": "The page must be published and the user must have read access rights.",
"editor.props.publishState": "Publishing State",
"editor.props.published": "Published",
"editor.props.publishedHint": "Visible to all users with read access.",
"editor.props.relationAdd": "Add Relation...",
"editor.props.relationAddHint": "Add links to other pages in the footer (e.g. as part of a series of articles)",
"editor.props.relations": "Relations",
"editor.props.requirePassword": "Require Password",
"editor.props.scripts": "Scripts",
"editor.props.shortDescription": "Short Description",
"editor.props.showInTree": "Show in Site Navigation",
"editor.props.showSidebar": "Show Sidebar",
"editor.props.showTags": "Show Tags",
"editor.props.showToc": "Show Table of Contents",
"editor.props.sidebar": "Sidebar",
"editor.props.social": "Social",
"editor.props.styles": "CSS Styles",
"editor.props.stylesHint": "CSS Rules to add to the page",
"editor.props.tags": "Tags",
"editor.props.tagsHint": "Use tags to categorize your pages and make them easier to find.",
"editor.props.title": "Title",
"editor.props.tocMinMaxDepth": "Min/Max Depth",
"editor.props.visibility": "Visibility",
"editor.save.createSuccess": "Page created successfully.",
"editor.save.error": "An error occurred while creating the page",
"editor.save.pleaseWait": "Please wait...",
"editor.save.processing": "Rendering",
"editor.save.saved": "Saved",
"editor.save.updateSuccess": "Page updated successfully.",
"editor.select.cannotChange": "This cannot be changed once the page is created.",
"editor.select.customView": "or create a custom view?",
"editor.select.title": "Which editor do you want to use for this page?",
"editor.unsaved.body": "You have unsaved changes. Are you sure you want to leave the editor and discard any modifications you made since the last save?",
"editor.unsaved.title": "Discard Unsaved Changes?",
"editor.unsavedWarning": "You have unsaved edits. Are you sure you want to leave the editor?",
"history.restore.confirmButton": "Restore",
"history.restore.confirmText": "Are you sure you want to restore this page content as it was on {date}? This version will be copied on top of the current history. As such, newer versions will still be preserved.",
"history.restore.confirmTitle": "Restore page version?",
"history.restore.success": "Page version restored succesfully!",
"profile.activity.commentsPosted": "Comments posted",
"profile.activity.joinedOn": "Joined on",
"profile.activity.lastLoginOn": "Last login on",
"profile.activity.lastUpdatedOn": "Profile last updated on",
"profile.activity.pagesCreated": "Pages created",
"profile.activity.title": "Activity",
"profile.appearance": "Appearance",
"profile.appearanceDark": "Dark",
"profile.appearanceDefault": "Site Default",
"profile.appearanceLight": "Light",
"profile.auth.changePassSuccess": "Password changed successfully.",
"profile.auth.changePassword": "Change Password",
"profile.auth.currentPassword": "Current Password",
"profile.auth.newPassword": "New Password",
"profile.auth.provider": "Provider",
"profile.auth.title": "Authentication",
"profile.auth.verifyPassword": "Confirm New Password",
"profile.comments.title": "Comments",
"profile.darkMode": "Dark Mode",
"profile.darkModeHint": "Change the appareance of the site to a dark theme.",
"profile.dateFormat": "Date Format",
"profile.dateFormatHint": "Set your preferred format to display dates.",
"profile.displayName": "Display Name",
"profile.displayNameHint": "Your full name; shown when authoring content (e.g. pages, comments, etc.).",
"profile.email": "Email Address",
"profile.emailHint": "The email address used for login.",
"profile.groups.title": "Groups",
"profile.jobTitle": "Job Title",
"profile.jobTitleHint": "Your position in your organization; shown on your profile page.",
"profile.localeDefault": "Locale Default",
"profile.location": "Location",
"profile.locationHint": "Your city and country; shown on your profile page.",
"profile.myInfo": "My Info",
"profile.pages.emptyList": "No pages to display.",
"profile.pages.headerCreatedAt": "Created",
"profile.pages.headerPath": "Path",
"profile.pages.headerTitle": "Title",
"profile.pages.headerUpdatedAt": "Last Updated",
"profile.pages.refreshSuccess": "Page list has been refreshed.",
"profile.pages.subtitle": "List of pages I created or last modified",
"profile.pages.title": "Pages",
"profile.preferences": "Preferences",
"profile.pronouns": "Pronouns",
"profile.pronounsHint": "Let people know which pronouns should they use when referring to you.",
"profile.save.success": "Profile saved successfully.",
"profile.subtitle": "My personal info",
"profile.timeFormat": "Time Format",
"profile.timeFormat12h": "12 hour",
"profile.timeFormat24h": "24 hour",
"profile.timeFormatHint": "Set your preferred format to display time.",
"profile.timezone": "Timezone",
"profile.timezoneHint": "Set your timezone to display local time correctly.",
"profile.title": "Profile",
"profile.viewPublicProfile": "View Public Profile",
"tags.clearSelection": "Clear Selection",
"tags.currentSelection": "Current Selection",
"tags.locale": "Locale",
"tags.localeAny": "Any",
"tags.noResults": "Couldn't find any page with the selected tags.",
"tags.noResultsWithFilter": "Couldn't find any page matching the current filtering options.",
"tags.orderBy": "Order By",
"tags.orderByField.ID": "ID",
"tags.orderByField.creationDate": "Creation Date",
"tags.orderByField.lastModified": "Last Modified",
"tags.orderByField.path": "Path",
"tags.orderByField.title": "Title",
"tags.pageLastUpdated": "Last Updated {date}",
"tags.retrievingResultsLoading": "Retrieving page results...",
"tags.searchWithinResultsPlaceholder": "Search within results...",
"tags.selectOneMoreTags": "Select one or more tags",
"tags.selectOneMoreTagsHint": "Select one or more tags on the left."
}
<template lang='pug'>
q-layout.admin(view='hHh Lpr lff')
q-header.bg-black.text-white
.row.no-wrap
q-toolbar(style='height: 64px;', dark)
q-btn(dense, flat, to='/')
q-avatar(size='34px', square)
img(src='/_assets/logo-wikijs.svg')
q-toolbar-title.text-h6.font-poppins Wiki.js
q-toolbar.gt-sm.justify-center(style='height: 64px;', dark)
.text-overline.text-uppercase.text-grey {{t('admin.adminArea')}}
q-toolbar(style='height: 64px;', dark)
q-space
q-spinner-tail(
v-show='siteStore.routerLoading'
color='blue'
size='sm'
)
q-btn.q-ml-md(flat, dense, icon='las la-times-circle', label='Exit' color='pink', to='/')
account-menu
q-drawer.admin-sidebar(v-model='leftDrawerOpen', show-if-above, bordered)
q-scroll-area.admin-nav(
:thumb-style='thumbStyle'
:bar-style='barStyle'
)
q-list.text-white(padding, dense)
q-item.q-mb-sm
q-item-section
q-btn.acrylic-btn(
flat
color='pink'
icon='las la-heart'
:label='t(`admin.contribute.title`)'
no-caps
href='https://js.wiki/donate'
target='_blank'
type='a'
)
q-item(to='/_admin/dashboard', v-ripple, active-class='bg-primary text-white')
q-item-section(avatar)
q-icon(name='img:/_assets/icons/fluent-apps-tab.svg')
q-item-section {{ t('admin.dashboard.title') }}
q-item(to='/_admin/sites', v-ripple, active-class='bg-primary text-white')
q-item-section(avatar)
q-icon(name='img:/_assets/icons/fluent-change-theme.svg')
q-item-section {{ t('admin.sites.title') }}
q-item-label.q-mt-sm(header).text-caption.text-blue-grey-4 {{ t('admin.nav.site') }}
q-item.q-mb-md
q-item-section
q-select(
dark
standout
dense
v-model='adminStore.currentSiteId'
:options='adminStore.sites'
option-value='id'
option-label='title'
emit-value
map-options
)
q-item(:to='`/_admin/` + adminStore.currentSiteId + `/general`', v-ripple, active-class='bg-primary text-white')
q-item-section(avatar)
q-icon(name='img:/_assets/icons/fluent-web.svg')
q-item-section {{ t('admin.general.title') }}
q-item(:to='`/_admin/` + adminStore.currentSiteId + `/analytics`', v-ripple, active-class='bg-primary text-white', disabled)
q-item-section(avatar)
q-icon(name='img:/_assets/icons/fluent-bar-chart.svg')
q-item-section {{ t('admin.analytics.title') }}
q-item(:to='`/_admin/` + adminStore.currentSiteId + `/approvals`', v-ripple, active-class='bg-primary text-white', disabled)
q-item-section(avatar)
q-icon(name='img:/_assets/icons/fluent-inspection.svg')
q-item-section {{ t('admin.approval.title') }}
q-item(:to='`/_admin/` + adminStore.currentSiteId + `/comments`', v-ripple, active-class='bg-primary text-white', disabled)
q-item-section(avatar)
q-icon(name='img:/_assets/icons/fluent-comments.svg')
q-item-section {{ t('admin.comments.title') }}
q-item(:to='`/_admin/` + adminStore.currentSiteId + `/editors`', v-ripple, active-class='bg-primary text-white')
q-item-section(avatar)
q-icon(name='img:/_assets/icons/fluent-cashbook.svg')
q-item-section {{ t('admin.editors.title') }}
q-item(:to='`/_admin/` + adminStore.currentSiteId + `/locale`', v-ripple, active-class='bg-primary text-white')
q-item-section(avatar)
q-icon(name='img:/_assets/icons/fluent-language.svg')
q-item-section {{ t('admin.locale.title') }}
q-item(:to='`/_admin/` + adminStore.currentSiteId + `/login`', v-ripple, active-class='bg-primary text-white')
q-item-section(avatar)
q-icon(name='img:/_assets/icons/fluent-bunch-of-keys.svg')
q-item-section {{ t('admin.login.title') }}
q-item(:to='`/_admin/` + adminStore.currentSiteId + `/navigation`', v-ripple, active-class='bg-primary text-white')
q-item-section(avatar)
q-icon(name='img:/_assets/icons/fluent-tree-structure.svg')
q-item-section {{ t('admin.navigation.title') }}
q-item(:to='`/_admin/` + adminStore.currentSiteId + `/rendering`', v-ripple, active-class='bg-primary text-white')
q-item-section(avatar)
q-icon(name='img:/_assets/icons/fluent-rich-text-converter.svg')
q-item-section {{ t('admin.rendering.title') }}
q-item(:to='`/_admin/` + adminStore.currentSiteId + `/storage`', v-ripple, active-class='bg-primary text-white')
q-item-section(avatar)
q-icon(name='img:/_assets/icons/fluent-ssd.svg')
q-item-section {{ t('admin.storage.title') }}
q-item(:to='`/_admin/` + adminStore.currentSiteId + `/theme`', v-ripple, active-class='bg-primary text-white')
q-item-section(avatar)
q-icon(name='img:/_assets/icons/fluent-paint-roller.svg')
q-item-section {{ t('admin.theme.title') }}
q-item-label.q-mt-sm(header).text-caption.text-blue-grey-4 {{ t('admin.nav.users') }}
q-item(to='/_admin/auth', v-ripple, active-class='bg-primary text-white')
q-item-section(avatar)
q-icon(name='img:/_assets/icons/fluent-security-lock.svg')
q-item-section {{ t('admin.auth.title') }}
q-item(to='/_admin/groups', v-ripple, active-class='bg-primary text-white')
q-item-section(avatar)
q-icon(name='img:/_assets/icons/fluent-people.svg')
q-item-section {{ t('admin.groups.title') }}
q-item-section(side)
q-badge(color='dark-3', :label='info.groupsTotal')
q-item(to='/_admin/users', v-ripple, active-class='bg-primary text-white')
q-item-section(avatar)
q-icon(name='img:/_assets/icons/fluent-account.svg')
q-item-section {{ t('admin.users.title') }}
q-item-section(side)
q-badge(color='dark-3', :label='info.usersTotal')
q-item-label.q-mt-sm(header).text-caption.text-blue-grey-4 {{ t('admin.nav.system') }}
q-item(to='/_admin/api', v-ripple, active-class='bg-primary text-white')
q-item-section(avatar)
q-icon(name='img:/_assets/icons/fluent-rest-api.svg')
q-item-section {{ t('admin.api.title') }}
q-item(to='/_admin/audit', v-ripple, active-class='bg-primary text-white', disabled)
q-item-section(avatar)
q-icon(name='img:/_assets/icons/fluent-event-log.svg')
q-item-section {{ t('admin.audit.title') }}
q-item(to='/_admin/extensions', v-ripple, active-class='bg-primary text-white')
q-item-section(avatar)
q-icon(name='img:/_assets/icons/fluent-module.svg')
q-item-section {{ t('admin.extensions.title') }}
q-item(to='/_admin/mail', v-ripple, active-class='bg-primary text-white')
q-item-section(avatar)
q-icon(name='img:/_assets/icons/fluent-message-settings.svg')
q-item-section {{ t('admin.mail.title') }}
q-item(to='/_admin/security', v-ripple, active-class='bg-primary text-white')
q-item-section(avatar)
q-icon(name='img:/_assets/icons/fluent-protect.svg')
q-item-section {{ t('admin.security.title') }}
q-item(to='/_admin/ssl', v-ripple, active-class='bg-primary text-white', disabled)
q-item-section(avatar)
q-icon(name='img:/_assets/icons/fluent-security-ssl.svg')
q-item-section {{ t('admin.ssl.title') }}
q-item(to='/_admin/system', v-ripple, active-class='bg-primary text-white')
q-item-section(avatar)
q-icon(name='img:/_assets/icons/fluent-processor.svg')
q-item-section {{ t('admin.system.title') }}
q-item(to='/_admin/utilities', v-ripple, active-class='bg-primary text-white')
q-item-section(avatar)
q-icon(name='img:/_assets/icons/fluent-swiss-army-knife.svg')
q-item-section {{ t('admin.utilities.title') }}
q-item(to='/_admin/webhooks', v-ripple, active-class='bg-primary text-white')
q-item-section(avatar)
q-icon(name='img:/_assets/icons/fluent-lightning-bolt.svg')
q-item-section {{ t('admin.webhooks.title') }}
q-item(to='/_admin/flags', v-ripple, active-class='bg-primary text-white')
q-item-section(avatar)
q-icon(name='img:/_assets/icons/fluent-windsock.svg')
q-item-section {{ t('admin.dev.flags.title') }}
q-page-container.admin-container
router-view(v-slot='{ Component }')
transition(name='fade')
component(:is='Component')
q-dialog.admin-overlay(
v-model='overlayIsShown'
persistent
full-width
full-height
no-shake
transition-show='jump-up'
transition-hide='jump-down'
)
component(:is='adminStore.overlay')
q-footer.admin-footer
q-bar.justify-center(dense)
span(style='font-size: 11px;') Powered by #[a(href='https://js.wiki', target='_blank'): strong Wiki.js], an open source project.
</template>
<script setup>
import { useMeta, setCssVar } from 'quasar'
import { defineAsyncComponent, onMounted, reactive, ref, watch } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useI18n } from 'vue-i18n'
import { useAdminStore } from '../stores/admin'
import { useSiteStore } from '../stores/site'
// COMPONENTS
import AccountMenu from '../components/AccountMenu.vue'
const GroupEditOverlay = defineAsyncComponent(() => import('../components/GroupEditOverlay.vue'))
const UserEditOverlay = defineAsyncComponent(() => import('../components/UserEditOverlay.vue'))
// STORES
const adminStore = useAdminStore()
const siteStore = useSiteStore()
// ROUTER
const router = useRouter()
const route = useRoute()
// I18N
const { t } = useI18n()
// META
useMeta({
titleTemplate: title => `${title} - ${t('admin.adminArea')} - Wiki.js`
})
// DATA
const leftDrawerOpen = ref(true)
const overlayIsShown = ref(false)
const search = ref('')
const user = reactive({
name: 'John Doe',
email: 'test@example.com',
picture: null
})
const info = reactive({
groupsTotal: 3,
usersTotal: 2
})
const thumbStyle = {
right: '1px',
borderRadius: '5px',
backgroundColor: '#666',
width: '5px',
opacity: 0.5
}
const barStyle = {
width: '7px'
}
// WATCHERS
watch(() => adminStore.sites, (newValue) => {
if (adminStore.currentSiteId === null && newValue.length > 0) {
adminStore.$patch({
currentSiteId: siteStore.id
})
}
})
watch(() => adminStore.overlay, (newValue) => {
overlayIsShown.value = !!newValue
})
watch(() => adminStore.currentSiteId, (newValue) => {
if (newValue && route.params.siteid !== newValue) {
router.push({ params: { siteid: newValue } })
}
})
setCssVar('primary', '#1976D2')
setCssVar('secondary', '#02C39A')
setCssVar('accent', '#f03a47')
// MOUNTED
onMounted(async () => {
await adminStore.fetchSites()
if (route.params.siteid) {
adminStore.$patch({
currentSiteId: route.params.siteid
})
}
})
</script>
<style lang="scss">
.admin-nav {
height: 100%;
}
.admin-icon {
height: 64px;
}
.admin-sidebar {
@at-root .body--light & {
background-color: $dark-4;
}
@at-root .body--dark & {
background-color: $dark-5;
}
.q-item__label--header {
box-shadow: 0 -1px 0 0 rgba(255,255,255,.15), 0 -2px 0 0 darken($dark-6, 1%);
padding-top: 16px;
}
}
.admin-container {
@at-root .body--light & {
background-color: $grey-1;
}
@at-root .body--dark & {
background-color: $dark-4;
}
.q-card {
@at-root .body--light & {
background-color: #FFF;
}
@at-root .body--dark & {
background-color: $dark-3;
}
}
}
.admin-overlay {
> .q-dialog__backdrop {
background-color: rgba(0,0,0,.6);
}
> .q-dialog__inner {
padding: 24px 64px;
@media (max-width: $breakpoint-sm-max) {
padding: 0;
}
> .q-layout-container {
@at-root .body--light & {
background-image: linear-gradient(to bottom, $dark-5 10px, $grey-3 11px, $grey-4);
}
@at-root .body--dark & {
background-image: linear-gradient(to bottom, $dark-4 10px, $dark-4 11px, $dark-3);
}
border-radius: 6px;
box-shadow: 0 0 0 2px rgba(0,0,0,.5);
}
}
}
.admin-footer > .q-bar {
@at-root .body--light & {
background-color: #FFF !important;
color: $blue-grey-5 !important;
a {
color: $blue-grey-9 !important;
text-decoration: none;
}
}
@at-root .body--dark & {
background-color: $dark-6 !important;
color: $blue-grey-5 !important;
a {
color: $blue-grey-5 !important;
text-decoration: none;
}
}
}
</style>
<template lang='pug'>
q-layout(view='hHh lpr lff')
q-page-container
router-view
</template>
<script>
export default {
name: 'AuthLayout',
data () {
return {
bgUrl: '_assets/bg/login-v3.jpg'
// bgUrl: 'https://docs.requarks.io/_assets/img/splash/1.jpg'
}
}
}
</script>
<style lang="scss">
.auth {
background-color: #FFF;
background-size: cover;
background-position: center center;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
&-box {
background-color: rgba(255,255,255,.25);
backdrop-filter: blur(5px);
-webkit-backdrop-filter: blur(5px);
padding: 32px;
border-radius: 8px;
width: 500px;
max-width: 95vw;
@at-root .no-backdropfilter & {
background-color: rgba(255,255,255,.95);
}
@media (max-width: $breakpoint-md-max) {
margin-left: 0;
width: 100%;
}
}
}
</style>
<template lang='pug'>
q-layout(view='hHh Lpr lff')
header-nav
q-drawer.bg-sidebar(
v-model='showSideNav'
show-if-above
:width='255'
)
.sidebar-actions.flex.items-stretch
q-btn.q-px-sm.col(
flat
dense
icon='las la-globe'
color='blue-7'
text-color='blue-2'
label='EN'
aria-label='EN'
size='sm'
)
q-separator(vertical)
q-btn.q-px-sm.col(
flat
dense
icon='las la-sitemap'
color='blue-7'
text-color='blue-2'
label='Browse'
aria-label='Browse'
size='sm'
)
q-scroll-area.sidebar-nav(
:thumb-style='thumbStyle'
:bar-style='barStyle'
)
q-list(
clickable
dense
dark
)
q-item-label.text-blue-2.text-caption(header) Getting Started
q-item(to='/install')
q-item-section(side)
q-icon(name='las la-dog', color='white')
q-item-section Requirements
q-item(to='/install')
q-item-section(side)
q-icon(name='las la-cat', color='white')
q-item-section Installation
q-separator.q-my-sm(dark)
q-item(to='/install')
q-item-section(side)
q-icon(name='las la-cat', color='white')
q-item-section Installation
q-bar.bg-blue-9.text-white(dense)
q-btn.col(
icon='las la-dharmachakra'
label='History'
flat
)
q-separator(vertical)
q-btn.col(
icon='las la-bookmark'
label='Bookmarks'
flat
)
q-page-container
router-view
q-page-scroller(
position='bottom-right'
:scroll-offset='150'
:offset='[15, 15]'
)
q-btn(
icon='las la-arrow-up'
color='primary'
round
size='md'
)
q-footer
q-bar.justify-center(dense)
span(style='font-size: 11px;') &copy; Cyberdyne Systems Corp. 2020 | Powered by #[strong Wiki.js]
</template>
<script>
import { get, sync } from 'vuex-pathify'
import { setCssVar } from 'quasar'
import HeaderNav from '../components/HeaderNav.vue'
export default {
name: 'MainLayout',
components: {
HeaderNav
},
data () {
return {
leftDrawerOpen: true,
search: '',
thumbStyle: {
right: '2px',
borderRadius: '5px',
backgroundColor: '#FFF',
width: '5px',
opacity: 0.5
},
barStyle: {
backgroundColor: '#000',
width: '9px',
opacity: 0.1
}
}
},
computed: {
showSideNav: sync('site/showSideNav', false),
isSyncing: get('isLoading', false)
},
created () {
setCssVar('primary', this.$store.get('site/theme@colorPrimary'))
setCssVar('secondary', this.$store.get('site/theme@colorSecondary'))
setCssVar('accent', this.$store.get('site/theme@colorAccent'))
setCssVar('header', this.$store.get('site/theme@colorHeader'))
setCssVar('sidebar', this.$store.get('site/theme@colorSidebar'))
}
}
</script>
<style lang="scss">
.sidebar-actions {
background: linear-gradient(to bottom, rgba(255,255,255,.1) 0%, rgba(0,0,0, .05) 100%);
border-bottom: 1px solid rgba(0,0,0,.2);
height: 38px;
}
.sidebar-nav {
border-top: 1px solid rgba(255,255,255,.15);
height: calc(100% - 38px - 24px);
}
body.body--dark {
background-color: $dark-6;
}
.q-footer {
.q-bar {
@at-root .body--light & {
background-color: $grey-3;
color: $grey-7;
}
@at-root .body--dark & {
background-color: $dark-4;
color: rgba(255,255,255,.3);
}
}
}
.syncing-enter-active {
animation: syncing-anim .1s;
}
.syncing-leave-active {
animation: syncing-anim 1s reverse;
}
@keyframes syncing-anim {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
</style>
<template lang='pug'>
q-layout(view='hHh Lpr lff')
header-nav
q-page-container.layout-profile
.layout-profile-card
.layout-profile-sd
q-list
q-item(
v-for='navItem of sidenav'
:key='navItem.key'
clickable
:to='`/p/` + navItem.key'
active-class='is-active'
v-ripple
)
q-item-section(side)
q-icon(:name='navItem.icon')
q-item-section
q-item-label {{navItem.label}}
q-separator.q-my-sm(inset)
q-item(
clickable
v-ripple
to='/p/me'
)
q-item-section(side)
q-icon(name='las la-id-card')
q-item-section
q-item-label View Public Profile
q-separator.q-my-sm(inset)
q-item(
clickable
v-ripple
)
q-item-section(side)
q-icon(name='las la-sign-out-alt', color='negative')
q-item-section
q-item-label.text-negative Logout
router-view
q-footer
q-bar.justify-center(dense)
span(style='font-size: 11px;') &copy; Cyberdyne Systems Corp. 2020 | Powered by #[strong Wiki.js]
</template>
<script>
import HeaderNav from '../components/HeaderNav.vue'
export default {
name: 'ProfileLayout',
components: {
HeaderNav
},
data () {
return {
sidenav: [
{
key: 'profile',
label: 'Profile',
icon: 'las la-user-circle'
},
{
key: 'avatar',
label: 'Avatar',
icon: 'las la-otter'
},
{
key: 'password',
label: 'Password',
icon: 'las la-key'
},
{
key: 'groups',
label: 'Groups',
icon: 'las la-users'
},
{
key: 'notifications',
label: 'Notifications',
icon: 'las la-bell'
},
{
key: 'pages',
label: 'My Pages',
icon: 'las la-file-alt'
},
{
key: 'activity',
label: 'Activity',
icon: 'las la-history'
}
],
thumbStyle: {
right: '2px',
borderRadius: '5px',
backgroundColor: '#FFF',
width: '5px',
opacity: 0.5
},
barStyle: {
backgroundColor: '#000',
width: '9px',
opacity: 0.1
}
}
}
}
</script>
<style lang="scss">
.layout-profile {
@at-root .body--light & {
background-color: $grey-3;
}
@at-root .body--dark & {
background-color: $dark-6;
}
&:before {
content: '';
height: 350px;
position: fixed;
top: 0;
width: 100%;
background: radial-gradient(ellipse at bottom, $dark-3, $dark-6);
border-bottom: 1px solid #FFF;
@at-root .body--dark & {
border-bottom-color: $dark-3;
}
}
&:after {
content: '';
height: 1px;
position: fixed;
top: 64px;
width: 100%;
background: linear-gradient(to right, transparent 0%, rgba(255,255,255,.1) 50%, transparent 100%);
}
&-card {
position: relative;
width: 90%;
max-width: 1400px;
margin: 50px auto;
box-shadow: $shadow-2;
border-radius: 7px;
display: flex;
align-items: stretch;
height: 100%;
@at-root .body--light & {
background-color: #FFF;
}
@at-root .body--dark & {
background-color: $dark-3;
}
}
&-sd {
flex: 0 0 300px;
border-radius: 8px 0 0 8px;
overflow: hidden;
@at-root .body--light & {
background-color: $grey-1;
border-right: 1px solid rgba($dark-3, .1);
box-shadow: inset -1px 0 0 #FFF;
}
@at-root .body--dark & {
background-color: $dark-4;
border-right: 1px solid rgba(#FFF, .12);
box-shadow: inset -1px 0 0 rgba($dark-6, .5);
}
.q-list .q-item {
font-weight: 500;
color: $grey-9;
@at-root .body--dark & {
color: rgba(255,255,255,.75);
}
&.is-active {
background: linear-gradient(to bottom, rgba($primary, .25), rgba($primary, .1));
color: $primary;
.q-icon {
color: $primary;
}
}
}
}
.q-page {
flex: 1 1;
@at-root .body--light & {
border-left: 1px solid #FFF;
}
@at-root .body--dark & {
border-left: 1px solid rgba($dark-6, .75);
}
}
.text-header {
font-weight: 500;
font-size: 17px;
padding: 0 16px 6px 16px;
color: $primary;
position: relative;
background: linear-gradient(to left, #FFF, transparent), linear-gradient(to top, rgba($primary, .075), transparent);
margin-bottom: 10px;
@at-root .body--dark & {
background: linear-gradient(to left, $dark-3, transparent), linear-gradient(to top, rgba($primary, .075), transparent);
}
&:before {
content: '';
width: 100%;
height: 10px;
background: linear-gradient(to left, #FFF, transparent), linear-gradient(to bottom, rgba($primary, .05), transparent);
position: absolute;
bottom: -13px;
left: 0;
z-index: 0;
@at-root .body--dark & {
background: linear-gradient(to left,$dark-3, transparent), linear-gradient(to bottom, rgba($primary, .05), transparent);
}
}
&:after {
content: '';
width: 100%;
height: 1px;
background: linear-gradient(to left, transparent, rgba($primary, .25));
position: absolute;
bottom: -2px;
left: 0;
z-index: 0;
}
}
.actions-bar {
display: flex;
padding: 16px;
background: linear-gradient(to right, #FFF, transparent), linear-gradient(to bottom, rgba($secondary, .1), transparent);
justify-content: flex-end;
position: relative;
@at-root .body--dark & {
background: linear-gradient(to right, $dark-3, transparent), linear-gradient(to bottom, rgba($secondary, .1), transparent);
}
&:before {
content: '';
width: 100%;
height: 10px;
background: linear-gradient(to right, #FFF, transparent), linear-gradient(to top, rgba($secondary, .05), transparent);
position: absolute;
top: -13px;
left: 0;
z-index: 0;
@at-root .body--dark & {
background: linear-gradient(to right, $dark-3, transparent), linear-gradient(to top, rgba($secondary, .05), transparent);
}
}
&:after {
content: '';
width: 100%;
height: 1px;
background: linear-gradient(to right, transparent, rgba($secondary, .25));
position: absolute;
top: -2px;
left: 0;
z-index: 0;
}
}
}
body.body--dark {
background-color: $dark-6;
}
.q-footer {
.q-bar {
@at-root .body--light & {
background-color: $grey-3;
color: $grey-7;
}
@at-root .body--dark & {
background-color: $dark-4;
color: rgba(255,255,255,.3);
}
}
}
</style>
<template lang='pug'>
v-container(fluid, grid-list-lg)
v-layout(row, wrap)
v-flex(xs12)
.admin-header
img.animated.fadeInUp(src='/_assets/svg/icon-line-chart.svg', alt='Analytics', style='width: 80px;')
.admin-header-title
.headline.primary--text.animated.fadeInLeft {{ $t('admin.analytics.title') }}
.subtitle-1.grey--text.animated.fadeInLeft.wait-p4s {{ $t('admin.analytics.subtitle') }}
v-spacer
v-btn.animated.fadeInDown.wait-p2s.mr-3(icon, outlined, color='grey', @click='refresh')
v-icon mdi-refresh
v-btn.animated.fadeInDown(color='success', @click='save', depressed, large)
v-icon(left) mdi-check
span {{$t('common.actions.apply')}}
v-flex(lg3, xs12)
v-card.animated.fadeInUp
v-toolbar(flat, color='primary', dark, dense)
.subtitle-1 {{$t('admin.analytics.providers')}}
v-list(two-line, dense).py-0
template(v-for='(str, idx) in providers')
v-list-item(:key='str.key', @click='selectedProvider = str.key', :disabled='!str.isAvailable')
v-list-item-avatar(size='24')
v-icon(color='grey', v-if='!str.isAvailable') mdi-minus-box-outline
v-icon(color='primary', v-else-if='str.isEnabled', v-ripple, @click='str.isEnabled = false') mdi-checkbox-marked-outline
v-icon(color='grey', v-else, v-ripple, @click='str.isEnabled = true') mdi-checkbox-blank-outline
v-list-item-content
v-list-item-title.body-2(:class='!str.isAvailable ? `grey--text` : (selectedProvider === str.key ? `primary--text` : ``)') {{ str.title }}
v-list-item-subtitle: .caption(:class='!str.isAvailable ? `grey--text text--lighten-1` : (selectedProvider === str.key ? `blue--text ` : ``)') {{ str.description }}
v-list-item-avatar(v-if='selectedProvider === str.key', size='24')
v-icon.animated.fadeInLeft(color='primary', large) mdi-chevron-right
v-divider(v-if='idx < providers.length - 1')
v-flex(xs12, lg9)
v-card.animated.fadeInUp.wait-p2s
v-toolbar(color='primary', dense, flat, dark)
.subtitle-1 {{provider.title}}
v-spacer
v-switch(
dark
color='blue lighten-5'
label='Active'
v-model='provider.isEnabled'
hide-details
inset
)
v-card-info(color='blue')
div
div {{provider.description}}
span.caption: a(:href='provider.website') {{provider.website}}
v-spacer
.admin-providerlogo
img(:src='provider.logo', :alt='provider.title')
v-card-text
v-form
.overline.pb-5 {{$t('admin.analytics.providerConfiguration')}}
.body-1.ml-3(v-if='!provider.config || provider.config.length < 1'): em {{$t('admin.analytics.providerNoConfiguration')}}
template(v-else, v-for='cfg in provider.config')
v-select(
v-if='cfg.value.type === "string" && cfg.value.enum'
outlined
:items='cfg.value.enum'
:key='cfg.key'
:label='cfg.value.title'
v-model='cfg.value.value'
prepend-icon='mdi-cog-box'
:hint='cfg.value.hint ? cfg.value.hint : ""'
persistent-hint
:class='cfg.value.hint ? "mb-2" : ""'
)
v-switch.mb-3(
v-else-if='cfg.value.type === "boolean"'
:key='cfg.key'
:label='cfg.value.title'
v-model='cfg.value.value'
color='primary'
prepend-icon='mdi-cog-box'
:hint='cfg.value.hint ? cfg.value.hint : ""'
persistent-hint
inset
)
v-textarea(
v-else-if='cfg.value.type === "string" && cfg.value.multiline'
outlined
:key='cfg.key'
:label='cfg.value.title'
v-model='cfg.value.value'
prepend-icon='mdi-cog-box'
:hint='cfg.value.hint ? cfg.value.hint : ""'
persistent-hint
:class='cfg.value.hint ? "mb-2" : ""'
)
v-text-field(
v-else
outlined
:key='cfg.key'
:label='cfg.value.title'
v-model='cfg.value.value'
prepend-icon='mdi-cog-box'
:hint='cfg.value.hint ? cfg.value.hint : ""'
persistent-hint
:class='cfg.value.hint ? "mb-2" : ""'
)
</template>
<script>
import _ from 'lodash'
import providersQuery from 'gql/admin/analytics/analytics-query-providers.gql'
import providersSaveMutation from 'gql/admin/analytics/analytics-mutation-save-providers.gql'
export default {
data() {
return {
providers: [],
selectedProvider: '',
provider: {}
}
},
watch: {
selectedProvider(newValue, oldValue) {
this.provider = _.find(this.providers, ['key', newValue]) || {}
},
providers(newValue, oldValue) {
this.selectedProvider = 'google'
}
},
methods: {
async refresh() {
await this.$apollo.queries.providers.refetch()
this.$store.commit('showNotification', {
message: this.$t('admin.analytics.refreshSuccess'),
style: 'success',
icon: 'cached'
})
},
async save() {
this.$store.commit(`loadingStart`, 'admin-analytics-saveproviders')
try {
await this.$apollo.mutate({
mutation: providersSaveMutation,
variables: {
providers: this.providers.map(str => _.pick(str, [
'isEnabled',
'key',
'config'
])).map(str => ({...str, config: str.config.map(cfg => ({...cfg, value: JSON.stringify({ v: cfg.value.value })}))}))
}
})
this.$store.commit('showNotification', {
message: this.$t('admin.analytics.saveSuccess'),
style: 'success',
icon: 'check'
})
} catch (err) {
this.$store.commit('pushGraphError', err)
}
this.$store.commit(`loadingStop`, 'admin-analytics-saveproviders')
}
},
apollo: {
providers: {
query: providersQuery,
fetchPolicy: 'network-only',
update: (data) => _.cloneDeep(data.analytics.providers).map(str => ({
...str,
config: _.sortBy(str.config.map(cfg => ({
...cfg,
value: JSON.parse(cfg.value)
})), [t => t.value.order])
})),
watchLoading (isLoading) {
this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-analytics-refresh')
}
}
}
}
</script>
<template lang='pug'>
q-page.admin-api
.row.q-pa-md.items-center
.col-auto
img.admin-icon.animated.fadeInLeft(src='/_assets/icons/fluent-rest-api.svg')
.col.q-pl-md
.text-h5.text-primary.animated.fadeInLeft {{ $t('admin.api.title') }}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s {{ $t('admin.api.subtitle') }}
.col
.flex.items-center
template(v-if='enabled')
q-spinner-rings.q-mr-sm(color='green')
.text-caption.text-green {{$t('admin.api.enabled')}}
template(v-else)
q-spinner-rings.q-mr-sm(color='red', size='md')
.text-caption.text-red {{$t('admin.api.disabled')}}
.col-auto
q-btn.q-mr-sm.q-ml-md.acrylic-btn(
icon='las la-question-circle'
flat
color='grey'
href='https://docs.js.wiki/admin/api'
target='_blank'
type='a'
)
q-btn.acrylic-btn.q-mr-sm(
icon='las la-redo-alt'
flat
color='secondary'
:loading='loading > 0'
@click='load'
)
q-btn.q-mr-sm(
unelevated
icon='las la-power-off'
:label='!enabled ? $t(`admin.api.enableButton`) : $t(`admin.api.disableButton`)'
:color='!enabled ? `positive` : `negative`'
@click='globalSwitch'
:disabled='loading > 0'
)
q-btn(
unelevated
icon='las la-plus'
:label='$t(`admin.api.newKeyButton`)'
color='primary'
@click='newKey'
:disabled='loading > 0'
)
q-separator(inset)
.row.q-pa-md.q-col-gutter-md
.col-12.col-lg-7
q-card.shadow-1
//- v-container(fluid, grid-list-lg)
//- v-layout(row, wrap)
//- v-flex(xs12)
//- .admin-header
//- img.animated.fadeInUp(src='/_assets/svg/icon-rest-api.svg', alt='API', style='width: 80px;')
//- .admin-header-title
//- .headline.primary--text.animated.fadeInLeft {{$t('admin.api.title')}}
//- .subtitle-1.grey--text.animated.fadeInLeft {{$t('admin.api.subtitle')}}
//- v-spacer
//- template(v-if='enabled')
//- status-indicator.mr-3(positive, pulse)
//- .caption.green--text.animated.fadeInLeft {{$t('admin.api.enabled')}}
//- template(v-else)
//- status-indicator.mr-3(negative, pulse)
//- .caption.red--text.animated.fadeInLeft {{$t('admin.api.disabled')}}
//- v-spacer
//- v-btn.mr-3.animated.fadeInDown.wait-p2s(outlined, color='grey', icon, @click='refresh')
//- v-icon mdi-refresh
//- v-btn.mr-3.animated.fadeInDown.wait-p1s(:color='enabled ? `red` : `green`', depressed, @click='globalSwitch', dark, :loading='isToggleLoading')
//- v-icon(left) mdi-power
//- span(v-if='!enabled') {{$t('admin.api.enableButton')}}
//- span(v-else) {{$t('admin.api.disableButton')}}
//- v-btn.animated.fadeInDown(color='primary', depressed, large, @click='newKey', dark)
//- v-icon(left) mdi-plus
//- span {{$t('admin.api.newKeyButton')}}
//- v-card.mt-3.animated.fadeInUp
//- v-simple-table(v-if='keys && keys.length > 0')
//- template(v-slot:default)
//- thead
//- tr.grey(:class='$vuetify.theme.dark ? `darken-4-d5` : `lighten-5`')
//- th {{$t('admin.api.headerName')}}
//- th {{$t('admin.api.headerKeyEnding')}}
//- th {{$t('admin.api.headerExpiration')}}
//- th {{$t('admin.api.headerCreated')}}
//- th {{$t('admin.api.headerLastUpdated')}}
//- th(width='100') {{$t('admin.api.headerRevoke')}}
//- tbody
//- tr(v-for='key of keys', :key='`key-` + key.id')
//- td
//- strong(:class='key.isRevoked ? `red--text` : ``') {{ key.name }}
//- em.caption.ml-1.red--text(v-if='key.isRevoked') (revoked)
//- td.caption {{ key.keyShort }}
//- td(:style='key.isRevoked ? `text-decoration: line-through;` : ``') {{ key.expiration | moment('LL') }}
//- td {{ key.createdAt | moment('calendar') }}
//- td {{ key.updatedAt | moment('calendar') }}
//- td: v-btn(icon, @click='revoke(key)', :disabled='key.isRevoked'): v-icon(color='error') mdi-cancel
//- v-card-text(v-else)
//- v-alert.mb-0(icon='mdi-information', :value='true', outlined, color='info') {{$t('admin.api.noKeyInfo')}}
//- create-api-key(v-model='isCreateDialogShown', @refresh='refresh(false)')
//- v-dialog(v-model='isRevokeConfirmDialogShown', max-width='500', persistent)
//- v-card
//- .dialog-header.is-red {{$t('admin.api.revokeConfirm')}}
//- v-card-text.pa-4
//- i18next(tag='span', path='admin.api.revokeConfirmText')
//- strong(place='name') {{ current.name }}
//- v-card-actions
//- v-spacer
//- v-btn(text, @click='isRevokeConfirmDialogShown = false', :disabled='revokeLoading') {{$t('common.actions.cancel')}}
//- v-btn(color='red', dark, @click='revokeConfirm', :loading='revokeLoading') {{$t('admin.api.revoke')}}
</template>
<script>
import _get from 'lodash/get'
import cloneDeep from 'lodash/cloneDeep'
import gql from 'graphql-tag'
import { createMetaMixin } from 'quasar'
// import { StatusIndicator } from 'vue-status-indicator'
// import CreateApiKey from './admin-api-create.vue'
export default {
components: {
// StatusIndicator,
// CreateApiKey
},
mixins: [
createMetaMixin(function () {
return {
title: this.$t('admin.api.title')
}
})
],
data () {
return {
enabled: false,
loading: 0,
keys: [],
isCreateDialogShown: false,
isRevokeConfirmDialogShown: false,
revokeLoading: false,
current: {}
}
},
mounted () {
this.load()
},
methods: {
async load () {
this.loading++
this.$q.loading.show()
const resp = await this.$apollo.query({
query: gql`
query getHooks {
apiKeys {
id
name
keyShort
expiration
isRevoked
createdAt
updatedAt
}
apiState
}
`,
fetchPolicy: 'network-only'
})
this.keys = cloneDeep(resp?.data?.apiKeys) ?? []
this.enabled = resp?.data?.apiState === true
this.$q.loading.hide()
this.loading--
},
async globalSwitch () {
this.isToggleLoading = true
try {
const resp = await this.$apollo.mutate({
mutation: gql`
mutation ($enabled: Boolean!) {
authentication {
setApiState (enabled: $enabled) {
responseResult {
succeeded
errorCode
slug
message
}
}
}
}
`,
variables: {
enabled: !this.enabled
},
watchLoading (isLoading) {
this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-api-toggle')
}
})
if (_get(resp, 'data.authentication.setApiState.responseResult.succeeded', false)) {
this.$store.commit('showNotification', {
style: 'success',
message: this.enabled ? this.$t('admin.api.toggleStateDisabledSuccess') : this.$t('admin.api.toggleStateEnabledSuccess'),
icon: 'check'
})
await this.load()
} else {
this.$store.commit('showNotification', {
style: 'red',
message: _get(resp, 'data.authentication.setApiState.responseResult.message', 'An unexpected error occurred.'),
icon: 'alert'
})
}
} catch (err) {
this.$store.commit('pushGraphError', err)
}
this.isToggleLoading = false
},
async newKey () {
this.isCreateDialogShown = true
},
revoke (key) {
this.current = key
this.isRevokeConfirmDialogShown = true
},
async revokeConfirm () {
this.revokeLoading = true
try {
const resp = await this.$apollo.mutate({
mutation: gql`
mutation ($id: Int!) {
authentication {
revokeApiKey (id: $id) {
responseResult {
succeeded
errorCode
slug
message
}
}
}
}
`,
variables: {
id: this.current.id
},
watchLoading (isLoading) {
this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-api-revoke')
}
})
if (_get(resp, 'data.authentication.revokeApiKey.responseResult.succeeded', false)) {
this.$store.commit('showNotification', {
style: 'success',
message: this.$t('admin.api.revokeSuccess'),
icon: 'check'
})
this.load()
} else {
this.$store.commit('showNotification', {
style: 'red',
message: _get(resp, 'data.authentication.revokeApiKey.responseResult.message', 'An unexpected error occurred.'),
icon: 'alert'
})
}
} catch (err) {
this.$store.commit('pushGraphError', err)
}
this.isRevokeConfirmDialogShown = false
this.revokeLoading = false
}
}
}
</script>
<style lang='scss'>
</style>
<template lang="pug">
div
v-dialog(v-model='isShown', max-width='650', persistent)
v-card
.dialog-header.is-short
v-icon.mr-3(color='white') mdi-plus
span {{$t('admin.api.newKeyTitle')}}
v-card-text.pt-5
v-text-field(
outlined
prepend-icon='mdi-format-title'
v-model='name'
:label='$t(`admin.api.newKeyName`)'
persistent-hint
ref='keyNameInput'
:hint='$t(`admin.api.newKeyNameHint`)'
counter='255'
)
v-select.mt-3(
:items='expirations'
outlined
prepend-icon='mdi-clock'
v-model='expiration'
:label='$t(`admin.api.newKeyExpiration`)'
:hint='$t(`admin.api.newKeyExpirationHint`)'
persistent-hint
)
v-divider.mt-4
v-subheader.pl-2: strong.indigo--text {{$t('admin.api.newKeyPermissionScopes')}}
v-list.pl-8(nav)
v-list-item-group(v-model='fullAccess')
v-list-item(
:value='true'
active-class='indigo--text'
)
template(v-slot:default='{ active, toggle }')
v-list-item-action
v-checkbox(
:input-value='active'
:true-value='true'
color='indigo'
@click='toggle'
)
v-list-item-content
v-list-item-title {{$t('admin.api.newKeyFullAccess')}}
v-divider.mt-3
v-subheader.caption.indigo--text {{$t('admin.api.newKeyGroupPermissions')}}
v-list-item
v-select(
:disabled='fullAccess'
:items='groups'
item-text='name'
item-value='id'
outlined
color='indigo'
v-model='group'
:label='$t(`admin.api.newKeyGroup`)'
:hint='$t(`admin.api.newKeyGroupHint`)'
persistent-hint
)
v-card-chin
v-spacer
v-btn(text, @click='isShown = false', :disabled='loading') {{$t('common.actions.cancel')}}
v-btn.px-3(depressed, color='primary', @click='generate', :loading='loading')
v-icon(left) mdi-chevron-right
span {{$t('common.actions.generate')}}
v-dialog(
v-model='isCopyKeyDialogShown'
max-width='750'
persistent
overlay-color='blue darken-5'
overlay-opacity='.9'
)
v-card
v-toolbar(dense, flat, color='primary', dark) {{$t('admin.api.newKeyTitle')}}
v-card-text.pt-5
.body-2.text-center
i18next(tag='span', path='admin.api.newKeyCopyWarn')
strong(place='bold') {{$t('admin.api.newKeyCopyWarnBold')}}
v-textarea.mt-3(
ref='keyContentsIpt'
filled
no-resize
readonly
v-model='key'
:rows='10'
hide-details
)
v-card-chin
v-spacer
v-btn.px-3(depressed, dark, color='primary', @click='isCopyKeyDialogShown = false') {{$t('common.actions.close')}}
</template>
<script>
import _ from 'lodash'
import gql from 'graphql-tag'
import groupsQuery from 'gql/admin/users/users-query-groups.gql'
export default {
props: {
value: {
type: Boolean,
default: false
}
},
data() {
return {
loading: false,
name: '',
expiration: '1y',
fullAccess: true,
groups: [],
group: null,
isCopyKeyDialogShown: false,
key: ''
}
},
computed: {
isShown: {
get() { return this.value },
set(val) { this.$emit('input', val) }
},
expirations() {
return [
{ value: '30d', text: this.$t('admin.api.expiration30d') },
{ value: '90d', text: this.$t('admin.api.expiration90d') },
{ value: '180d', text: this.$t('admin.api.expiration180d') },
{ value: '1y', text: this.$t('admin.api.expiration1y') },
{ value: '3y', text: this.$t('admin.api.expiration3y') }
]
}
},
watch: {
value (newValue, oldValue) {
if (newValue) {
setTimeout(() => {
this.$refs.keyNameInput.focus()
}, 400)
}
}
},
methods: {
async generate () {
try {
if (_.trim(this.name).length < 2 || this.name.length > 255) {
throw new Error(this.$t('admin.api.newKeyNameError'))
} else if (!this.fullAccess && !this.group) {
throw new Error(this.$t('admin.api.newKeyGroupError'))
} else if (!this.fullAccess && this.group === 2) {
throw new Error(this.$t('admin.api.newKeyGuestGroupError'))
}
} catch (err) {
return this.$store.commit('showNotification', {
style: 'red',
message: err,
icon: 'alert'
})
}
this.loading = true
try {
const resp = await this.$apollo.mutate({
mutation: gql`
mutation ($name: String!, $expiration: String!, $fullAccess: Boolean!, $group: Int) {
authentication {
createApiKey (name: $name, expiration: $expiration, fullAccess: $fullAccess, group: $group) {
key
responseResult {
succeeded
errorCode
slug
message
}
}
}
}
`,
variables: {
name: this.name,
expiration: this.expiration,
fullAccess: (this.fullAccess === true),
group: this.group
},
watchLoading (isLoading) {
this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-api-create')
}
})
if (_.get(resp, 'data.authentication.createApiKey.responseResult.succeeded', false)) {
this.$store.commit('showNotification', {
style: 'success',
message: this.$t('admin.api.newKeySuccess'),
icon: 'check'
})
this.name = ''
this.expiration = '1y'
this.fullAccess = true
this.group = null
this.isShown = false
this.$emit('refresh')
this.key = _.get(resp, 'data.authentication.createApiKey.key', '???')
this.isCopyKeyDialogShown = true
setTimeout(() => {
this.$refs.keyContentsIpt.$refs.input.select()
}, 400)
} else {
this.$store.commit('showNotification', {
style: 'red',
message: _.get(resp, 'data.authentication.createApiKey.responseResult.message', 'An unexpected error occurred.'),
icon: 'alert'
})
}
} catch (err) {
this.$store.commit('pushGraphError', err)
}
this.loading = false
}
},
apollo: {
groups: {
query: groupsQuery,
fetchPolicy: 'network-only',
update: (data) => data.groups.list,
watchLoading (isLoading) {
this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-api-groups-refresh')
}
}
}
}
</script>
<template lang='pug'>
q-page.admin-mail
.row.q-pa-md.items-center
.col-auto
img.admin-icon.animated.fadeInLeft(src='/_assets/icons/fluent-security-lock.svg')
.col.q-pl-md
.text-h5.text-primary.animated.fadeInLeft {{ $t('admin.auth.title') }}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s {{ $t('admin.auth.subtitle') }}
.col-auto
q-btn.q-mr-sm.acrylic-btn(
icon='las la-question-circle'
flat
color='grey'
href='https://docs.js.wiki/admin/auth'
target='_blank'
type='a'
)
q-btn(
unelevated
icon='mdi-check'
:label='$t(`common.actions.apply`)'
color='secondary'
@click='save'
:loading='loading'
)
q-separator(inset)
.row.q-pa-md.q-col-gutter-md
.col-auto
q-card.rounded-borders.bg-dark
q-list(
style='min-width: 350px;'
padding
dark
)
q-item(
v-for='str of activeStrategies'
:key='str.key'
active-class='bg-primary text-white'
:active='selectedStrategy === str.key'
@click='selectedStrategy = str.key'
clickable
)
q-item-section(side)
q-icon(
:name='`img:` + str.strategy.icon'
)
q-item-section
q-item-label {{str.displayName}}
q-item-label(caption) {{str.strategy.title}}
q-item-section(side)
q-spinner-rings(:color='str.isEnabled ? `positive` : `negative`', size='sm')
q-btn.q-mt-sm.full-width(
color='primary'
icon='las la-plus'
:label='$t(`admin.auth.addStrategy`)'
)
q-menu(auto-close)
q-list(style='min-width: 350px;')
q-item(clickable)
.col Doude
//- v-flex(lg3, xs12)
//- v-card.animated.fadeInUp
//- v-toolbar(flat, color='teal', dark, dense)
//- .subtitle-1 {{$t('admin.auth.activeStrategies')}}
//- v-list(two-line, dense).py-0
//- draggable(
//- v-model='activeStrategies'
//- handle='.is-handle'
//- direction='vertical'
//- )
//- transition-group
//- v-list-item(
//- v-for='(str, idx) in activeStrategies'
//- :key='str.key'
//- @click='selectedStrategy = str.key'
//- :class='selectedStrategy === str.key ? ($vuetify.theme.dark ? `grey darken-5` : `teal lighten-5`) : ``'
//- )
//- v-list-item-avatar.is-handle(size='24')
//- v-icon(:color='selectedStrategy === str.key ? `teal` : `grey`') mdi-drag-horizontal
//- v-list-item-content
//- v-list-item-title.body-2(:class='selectedStrategy === str.key ? `teal--text` : ``') {{ str.displayName }}
//- v-list-item-subtitle: .caption(:class='selectedStrategy === str.key ? `teal--text ` : ``') {{ str.strategy.title }}
//- v-list-item-avatar(v-if='selectedStrategy === str.key', size='24')
//- v-icon.animated.fadeInLeft(color='teal', large) mdi-chevron-right
//- v-card-chin
//- v-menu(offset-y, bottom, min-width='250px', max-width='550px', max-height='50vh', style='flex: 1 1;', center)
//- template(v-slot:activator='{ on }')
//- v-btn(v-on='on', color='primary', depressed, block)
//- v-icon(left) mdi-plus
//- span {{$t('admin.auth.addStrategy')}}
//- v-list(dense)
//- template(v-for='(str, idx) of strategies')
//- v-list-item(
//- :key='str.key'
//- :disabled='str.isDisabled'
//- @click='addStrategy(str)'
//- )
//- v-list-item-avatar(height='24', width='48', tile)
//- v-img(:src='str.logo', width='48px', height='24px', contain, :style='str.isDisabled ? `opacity: .25;` : ``')
//- v-list-item-content
//- v-list-item-title {{str.title}}
//- v-list-item-subtitle: .caption(:style='str.isDisabled ? `opacity: .4;` : ``') {{str.description}}
//- v-divider(v-if='idx < strategies.length - 1')
//- v-flex(xs12, lg9)
//- v-card.animated.fadeInUp.wait-p2s
//- v-toolbar(color='primary', dense, flat, dark)
//- .subtitle-1 {{strategy.displayName}} #[em ({{strategy.strategy.title}})]
//- v-spacer
//- v-btn(small, outlined, dark, color='white', :disabled='strategy.key === `local`', @click='deleteStrategy()')
//- v-icon(left) mdi-close
//- span {{$t('common.actions.delete')}}
//- v-card-info(color='blue')
//- div
//- span {{strategy.strategy.description}}
//- .caption: a(:href='strategy.strategy.website') {{strategy.strategy.website}}
//- v-spacer
//- .admin-providerlogo
//- img(:src='strategy.strategy.logo', :alt='strategy.strategy.title')
//- v-card-text
//- .row
//- .col-8
//- v-text-field(
//- outlined
//- :label='$t(`admin.auth.displayName`)'
//- v-model='strategy.displayName'
//- prepend-icon='mdi-format-title'
//- :hint='$t(`admin.auth.displayNameHint`)'
//- persistent-hint
//- )
//- .col-4
//- v-switch.mt-1(
//- :label='$t(`admin.auth.strategyIsEnabled`)'
//- v-model='strategy.isEnabled'
//- color='primary'
//- prepend-icon='mdi-power'
//- :hint='$t(`admin.auth.strategyIsEnabledHint`)'
//- persistent-hint
//- inset
//- :disabled='strategy.key === `local`'
//- )
//- template(v-if='strategy.config && Object.keys(strategy.config).length > 0')
//- v-divider
//- .overline.my-5 {{$t('admin.auth.strategyConfiguration')}}
//- .pr-3
//- template(v-for='cfg in strategy.config')
//- v-select.mb-3(
//- v-if='cfg.value.type === "string" && cfg.value.enum'
//- outlined
//- :items='cfg.value.enum'
//- :key='cfg.key'
//- :label='cfg.value.title'
//- v-model='cfg.value.value'
//- prepend-icon='mdi-cog-box'
//- :hint='cfg.value.hint ? cfg.value.hint : ""'
//- persistent-hint
//- :class='cfg.value.hint ? "mb-2" : ""'
//- :style='cfg.value.maxWidth > 0 ? `max-width:` + cfg.value.maxWidth + `px;` : ``'
//- )
//- v-switch.mb-6(
//- v-else-if='cfg.value.type === "boolean"'
//- :key='cfg.key'
//- :label='cfg.value.title'
//- v-model='cfg.value.value'
//- color='primary'
//- prepend-icon='mdi-cog-box'
//- :hint='cfg.value.hint ? cfg.value.hint : ""'
//- persistent-hint
//- inset
//- )
//- v-textarea.mb-3(
//- v-else-if='cfg.value.type === "string" && cfg.value.multiline'
//- outlined
//- :key='cfg.key'
//- :label='cfg.value.title'
//- v-model='cfg.value.value'
//- prepend-icon='mdi-cog-box'
//- :hint='cfg.value.hint ? cfg.value.hint : ""'
//- persistent-hint
//- :class='cfg.value.hint ? "mb-2" : ""'
//- )
//- v-text-field.mb-3(
//- v-else
//- outlined
//- :key='cfg.key'
//- :label='cfg.value.title'
//- v-model='cfg.value.value'
//- prepend-icon='mdi-cog-box'
//- :hint='cfg.value.hint ? cfg.value.hint : ""'
//- persistent-hint
//- :class='cfg.value.hint ? "mb-2" : ""'
//- :style='cfg.value.maxWidth > 0 ? `max-width:` + cfg.value.maxWidth + `px;` : ``'
//- )
//- v-divider
//- .overline.my-5 {{$t('admin.auth.registration')}}
//- .pr-3
//- v-switch.ml-3(
//- v-model='strategy.selfRegistration'
//- :label='$t(`admin.auth.selfRegistration`)'
//- color='primary'
//- :hint='$t(`admin.auth.selfRegistrationHint`)'
//- persistent-hint
//- inset
//- )
//- v-combobox.ml-3.mt-5(
//- :label='$t(`admin.auth.domainsWhitelist`)'
//- v-model='strategy.domainWhitelist'
//- prepend-icon='mdi-email-check-outline'
//- outlined
//- :disabled='!strategy.selfRegistration'
//- :hint='$t(`admin.auth.domainsWhitelistHint`)'
//- persistent-hint
//- small-chips
//- deletable-chips
//- clearable
//- multiple
//- chips
//- )
//- v-autocomplete.mt-3.ml-3(
//- outlined
//- :disabled='!strategy.selfRegistration'
//- :items='groups'
//- item-text='name'
//- item-value='id'
//- :label='$t(`admin.auth.autoEnrollGroups`)'
//- v-model='strategy.autoEnrollGroups'
//- prepend-icon='mdi-account-group'
//- :hint='$t(`admin.auth.autoEnrollGroupsHint`)'
//- small-chips
//- persistent-hint
//- deletable-chips
//- clearable
//- multiple
//- chips
//- )
//- v-card.mt-4.wiki-form.animated.fadeInUp.wait-p4s(v-if='selectedStrategy !== `local`')
//- v-toolbar(color='primary', dense, flat, dark)
//- .subtitle-1 {{$t('admin.auth.configReference')}}
//- v-card-text
//- .body-2 {{$t('admin.auth.configReferenceSubtitle')}}
//- v-alert.mt-3.radius-7(v-if='host.length < 8', color='red', outlined, :value='true', icon='mdi-alert')
//- i18next(path='admin.auth.siteUrlNotSetup', tag='span')
//- strong(place='siteUrl') {{$t('admin.general.siteUrl')}}
//- strong(place='general') {{$t('admin.general.title')}}
//- .pa-3.mt-3.radius-7.grey(v-else, :class='$vuetify.theme.dark ? `darken-3-d5` : `lighten-3`')
//- .body-2: strong {{$t('admin.auth.allowedWebOrigins')}}
//- .body-2 {{host}}
//- v-divider.my-3
//- .body-2: strong {{$t('admin.auth.callbackUrl')}}
//- .body-2 {{host}}/login/{{strategy.key}}/callback
//- v-divider.my-3
//- .body-2: strong {{$t('admin.auth.loginUrl')}}
//- .body-2 {{host}}/login
//- v-divider.my-3
//- .body-2: strong {{$t('admin.auth.logoutUrl')}}
//- .body-2 {{host}}
//- v-divider.my-3
//- .body-2: strong {{$t('admin.auth.tokenEndpointAuthMethod')}}
//- .body-2 HTTP-POST
</template>
<script>
import _ from 'lodash'
import gql from 'graphql-tag'
import { v4 as uuid } from 'uuid'
import { createMetaMixin } from 'quasar'
import draggable from 'vuedraggable'
export default {
mixins: [
createMetaMixin(function () {
return {
title: this.$t('admin.auth.title')
}
})
],
components: {
draggable
},
filters: {
startCase (val) { return _.startCase(val) }
},
data () {
return {
groups: [],
strategies: [],
activeStrategies: [
{
key: 'local',
strategy: {
key: 'local',
title: 'Username-Password Authentication',
description: '',
useForm: true,
icon: '/_assets/icons/ultraviolet-data-protection.svg',
website: ''
},
config: [],
isEnabled: true,
displayName: 'Local Database',
selfRegistration: false,
domainWhitelist: '',
autoEnrollGroups: []
},
{
key: 'google',
strategy: {
key: 'google',
title: 'Google',
description: '',
useForm: true,
icon: '/_assets/icons/ultraviolet-google.svg',
website: ''
},
config: [],
isEnabled: true,
displayName: 'Google',
selfRegistration: false,
domainWhitelist: '',
autoEnrollGroups: []
},
{
key: 'slack',
strategy: {
key: 'slack',
title: 'Slack',
description: '',
useForm: true,
icon: '/_assets/icons/ultraviolet-slack.svg',
website: ''
},
config: [],
isEnabled: false,
displayName: 'Slack',
selfRegistration: false,
domainWhitelist: '',
autoEnrollGroups: []
}
],
selectedStrategy: '',
host: '',
strategy: {
strategy: {}
}
}
},
watch: {
selectedStrategy (newValue, oldValue) {
this.strategy = _.find(this.activeStrategies, ['key', newValue]) || {}
},
activeStrategies (newValue, oldValue) {
this.selectedStrategy = 'local'
}
},
methods: {
async refresh () {
await this.$apollo.queries.strategies.refetch()
await this.$apollo.queries.activeStrategies.refetch()
this.$store.commit('showNotification', {
message: this.$t('admin.auth.refreshSuccess'),
style: 'success',
icon: 'cached'
})
},
addStrategy (str) {
const newStr = {
key: uuid(),
strategy: str,
config: str.props.map(c => ({
key: c.key,
value: {
...c,
value: c.default
}
})),
order: this.activeStrategies.length,
isEnabled: true,
displayName: str.title,
selfRegistration: false,
domainWhitelist: [],
autoEnrollGroups: []
}
this.activeStrategies = [...this.activeStrategies, newStr]
this.$nextTick(() => {
this.selectedStrategy = newStr.key
})
},
deleteStrategy () {
this.activeStrategies = _.reject(this.activeStrategies, ['key', this.strategy.key])
},
async save () {
this.$store.commit('loadingStart', 'admin-auth-savestrategies')
try {
const resp = await this.$apollo.mutate({
mutation: gql`
mutation($strategies: [AuthenticationStrategyInput]!) {
authentication {
updateStrategies(strategies: $strategies) {
responseResult {
succeeded
errorCode
slug
message
}
}
}
}
`,
variables: {
strategies: this.activeStrategies.map((str, idx) => ({
key: str.key,
strategyKey: str.strategy.key,
displayName: str.displayName,
order: idx,
isEnabled: str.isEnabled,
config: str.config.map(cfg => ({ ...cfg, value: JSON.stringify({ v: cfg.value.value }) })),
selfRegistration: str.selfRegistration,
domainWhitelist: str.domainWhitelist,
autoEnrollGroups: str.autoEnrollGroups
}))
}
})
if (_.get(resp, 'data.authentication.updateStrategies.responseResult.succeeded', false)) {
this.$store.commit('showNotification', {
message: this.$t('admin.auth.saveSuccess'),
style: 'success',
icon: 'check'
})
} else {
throw new Error(_.get(resp, 'data.authentication.updateStrategies.responseResult.message', this.$t('common.error.unexpected')))
}
} catch (err) {
this.$store.commit('pushGraphError', err)
}
this.$store.commit('loadingStop', 'admin-auth-savestrategies')
}
},
apollo: {
strategies: {
query: gql`
query {
authentication {
strategies {
key
title
description
isAvailable
useForm
logo
website
props {
key
value
}
}
}
}
`,
skip: true,
fetchPolicy: 'network-only',
update: (data) => _.get(data, 'authentication.strategies', []).map(str => ({
...str,
isDisabled: !str.isAvailable || str.key === 'local',
props: _.sortBy(str.props.map(cfg => ({
key: cfg.key,
...JSON.parse(cfg.value)
})), [t => t.order])
})),
watchLoading (isLoading) {
this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-auth-strategies-refresh')
}
},
activeStrategies: {
query: gql`
query {
authentication {
activeStrategies {
key
strategy {
key
title
description
useForm
logo
website
}
config {
key
value
}
order
isEnabled
displayName
selfRegistration
domainWhitelist
autoEnrollGroups
}
}
}
`,
skip: true,
fetchPolicy: 'network-only',
update: (data) => _.sortBy(_.get(data, 'authentication.activeStrategies', []).map(str => ({
...str,
config: _.sortBy(str.config.map(cfg => ({
...cfg,
value: JSON.parse(cfg.value)
})), [t => t.value.order])
})), ['order']),
watchLoading (isLoading) {
this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-auth-activestrategies-refresh')
}
},
groups: {
query: gql`{ test }`,
fetchPolicy: 'network-only',
update: (data) => data.groups.list,
watchLoading (isLoading) {
this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-auth-groups-refresh')
}
},
host: {
query: gql`{ test }`,
fetchPolicy: 'network-only',
update: (data) => _.cloneDeep(data.site.config.host),
watchLoading (isLoading) {
this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-auth-host-refresh')
}
}
}
}
</script>
<template lang='pug'>
v-container(fluid, grid-list-lg)
v-layout(row, wrap)
v-flex(xs12)
.admin-header
img.animated.fadeInUp(src='/_assets/svg/icon-chat-bubble.svg', alt='Comments', style='width: 80px;')
.admin-header-title
.headline.primary--text.animated.fadeInLeft {{$t('admin.comments.title')}}
.subtitle-1.grey--text.animated.fadeInLeft.wait-p2s {{$t('admin.comments.subtitle')}}
v-spacer
v-btn.animated.fadeInDown.wait-p3s(icon, outlined, color='grey', href='https://docs.requarks.io/comments', target='_blank')
v-icon mdi-help-circle
v-btn.mx-3.animated.fadeInDown.wait-p2s(icon, outlined, color='grey', @click='refresh')
v-icon mdi-refresh
v-btn.animated.fadeInDown(color='success', @click='save', depressed, large)
v-icon(left) mdi-check
span {{$t('common.actions.apply')}}
v-flex(lg3, xs12)
v-card.animated.fadeInUp
v-toolbar(flat, color='primary', dark, dense)
.subtitle-1 {{$t('admin.comments.provider')}}
v-list.py-0(two-line, dense)
template(v-for='(provider, idx) in providers')
v-list-item(:key='provider.key', @click='selectedProvider = provider.key', :disabled='!provider.isAvailable')
v-list-item-avatar(size='24')
v-icon(color='grey', v-if='!provider.isAvailable') mdi-minus-box-outline
v-icon(color='primary', v-else-if='provider.key === selectedProvider') mdi-checkbox-marked-circle-outline
v-icon(color='grey', v-else) mdi-checkbox-blank-circle-outline
v-list-item-content
v-list-item-title.body-2(:class='!provider.isAvailable ? `grey--text` : (selectedProvider === provider.key ? `primary--text` : ``)') {{ provider.title }}
v-list-item-subtitle: .caption(:class='!provider.isAvailable ? `grey--text text--lighten-1` : (selectedProvider === provider.key ? `blue--text ` : ``)') {{ provider.description }}
v-list-item-avatar(v-if='selectedProvider === provider.key', size='24')
v-icon.animated.fadeInLeft(color='primary', large) mdi-chevron-right
v-divider(v-if='idx < providers.length - 1')
v-flex(lg9, xs12)
v-card.animated.fadeInUp.wait-p2s
v-toolbar(color='primary', dense, flat, dark)
.subtitle-1 {{provider.title}}
v-card-info(color='blue')
div
div {{provider.description}}
span.caption: a(:href='provider.website') {{provider.website}}
v-spacer
.admin-providerlogo
img(:src='provider.logo', :alt='provider.title')
v-card-text
.overline.my-5 {{$t('admin.comments.providerConfig')}}
.body-2.ml-3(v-if='!provider.config || provider.config.length < 1'): em {{$t('admin.comments.providerNoConfig')}}
template(v-else, v-for='cfg in provider.config')
v-select.mb-3(
v-if='cfg.value.type === "string" && cfg.value.enum'
outlined
:items='cfg.value.enum'
:key='cfg.key'
:label='cfg.value.title'
v-model='cfg.value.value'
prepend-icon='mdi-cog-box'
:hint='cfg.value.hint ? cfg.value.hint : ""'
persistent-hint
:class='cfg.value.hint ? "mb-2" : ""'
:style='cfg.value.maxWidth > 0 ? `max-width:` + cfg.value.maxWidth + `px;` : ``'
)
v-switch.mb-6(
v-else-if='cfg.value.type === "boolean"'
:key='cfg.key'
:label='cfg.value.title'
v-model='cfg.value.value'
color='primary'
prepend-icon='mdi-cog-box'
:hint='cfg.value.hint ? cfg.value.hint : ""'
persistent-hint
inset
)
v-textarea.mb-3(
v-else-if='cfg.value.type === "string" && cfg.value.multiline'
outlined
:key='cfg.key'
:label='cfg.value.title'
v-model='cfg.value.value'
prepend-icon='mdi-cog-box'
:hint='cfg.value.hint ? cfg.value.hint : ""'
persistent-hint
:class='cfg.value.hint ? "mb-2" : ""'
)
v-text-field.mb-3(
v-else
outlined
:key='cfg.key'
:label='cfg.value.title'
v-model='cfg.value.value'
prepend-icon='mdi-cog-box'
:hint='cfg.value.hint ? cfg.value.hint : ""'
persistent-hint
:class='cfg.value.hint ? "mb-2" : ""'
:style='cfg.value.maxWidth > 0 ? `max-width:` + cfg.value.maxWidth + `px;` : ``'
)
</template>
<script>
import _ from 'lodash'
import gql from 'graphql-tag'
export default {
data() {
return {
providers: [],
selectedProvider: '',
provider: {}
}
},
watch: {
selectedProvider(newValue, oldValue) {
this.provider = _.find(this.providers, ['key', newValue]) || {}
},
providers(newValue, oldValue) {
this.selectedProvider = _.get(_.find(this.providers, 'isEnabled'), 'key', 'db')
}
},
methods: {
async refresh() {
await this.$apollo.queries.providers.refetch()
this.$store.commit('showNotification', {
message: this.$t('admin.comments.listRefreshSuccess'),
style: 'success',
icon: 'cached'
})
},
async save() {
this.$store.commit(`loadingStart`, 'admin-comments-saveproviders')
try {
const resp = await this.$apollo.mutate({
mutation: gql`
mutation($providers: [CommentProviderInput]!) {
comments {
updateProviders(providers: $providers) {
responseResult {
succeeded
errorCode
slug
message
}
}
}
}
`,
variables: {
providers: this.providers.map(tgt => ({
isEnabled: tgt.key === this.selectedProvider,
key: tgt.key,
config: tgt.config.map(cfg => ({...cfg, value: JSON.stringify({ v: cfg.value.value })}))
}))
}
})
if (_.get(resp, 'data.comments.updateProviders.responseResult.succeeded', false)) {
this.$store.commit('showNotification', {
message: this.$t('admin.comments.configSaveSuccess'),
style: 'success',
icon: 'check'
})
} else {
throw new Error(_.get(resp, 'data.comments.updateProviders.responseResult.message', this.$t('common.error.unexpected')))
}
} catch (err) {
this.$store.commit('pushGraphError', err)
}
this.$store.commit(`loadingStop`, 'admin-comments-saveproviders')
}
},
apollo: {
providers: {
query: gql`
query {
comments {
providers {
isEnabled
key
title
description
logo
website
isAvailable
config {
key
value
}
}
}
}
`,
fetchPolicy: 'network-only',
update: (data) => _.cloneDeep(data.comments.providers).map(str => ({
...str,
config: _.sortBy(str.config.map(cfg => ({
...cfg,
value: JSON.parse(cfg.value)
})), [t => t.value.order])
})),
watchLoading (isLoading) {
this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-comments-refresh')
}
}
}
}
</script>
<template lang='pug'>
q-page.admin-dashboard
.row.q-pa-md.items-center
.col-auto
img.admin-icon.animated.fadeInLeft(src='/_assets/icons/fluent-apps-tab.svg')
.col.q-pl-md
.text-h5.text-primary.animated.fadeInLeft {{ t('admin.dashboard.title') }}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s {{ t('admin.dashboard.subtitle') }}
.row.q-px-md.q-col-gutter-md
.col-12 ---
//- v-container(fluid, grid-list-lg)
//- v-layout(row, wrap)
//- v-flex(xs12)
//- .admin-header
//- img.animated.fadeInUp(src='/_assets/svg/icon-browse-page.svg', alt='Dashboard', style='width: 80px;')
//- .admin-header-title
//- .headline.primary--text.animated.fadeInLeft {{ $t('admin.dashboard.title') }}
//- .subtitle-1.grey--text.animated.fadeInLeft.wait-p2s {{ $t('admin.dashboard.subtitle') }}
//- v-flex(xs12 md6 lg4 xl3 d-flex)
//- v-card.primary.dashboard-card.animated.fadeInUp(dark)
//- v-card-text
//- v-icon.dashboard-icon mdi-file-document-outline
//- .overline {{$t('admin.dashboard.pages')}}
//- animated-number.display-1(
//- :value='info.pagesTotal'
//- :duration='2000'
//- :formatValue='round'
//- easing='easeOutQuint'
//- )
//- v-flex(xs12 md6 lg4 xl3 d-flex)
//- v-card.blue.darken-3.dashboard-card.animated.fadeInUp.wait-p2s(dark)
//- v-card-text
//- v-icon.dashboard-icon mdi-account
//- .overline {{$t('admin.dashboard.users')}}
//- animated-number.display-1(
//- :value='info.usersTotal'
//- :duration='2000'
//- :formatValue='round'
//- easing='easeOutQuint'
//- )
//- v-flex(xs12 md6 lg4 xl3 d-flex)
//- v-card.blue.darken-4.dashboard-card.animated.fadeInUp.wait-p4s(dark)
//- v-card-text
//- v-icon.dashboard-icon mdi-account-group
//- .overline {{$t('admin.dashboard.groups')}}
//- animated-number.display-1(
//- :value='info.groupsTotal'
//- :duration='2000'
//- :formatValue='round'
//- easing='easeOutQuint'
//- )
//- v-flex(xs12 md6 lg12 xl3 d-flex)
//- v-card.dashboard-card.animated.fadeInUp.wait-p6s(
//- :class='isLatestVersion ? "green" : "red lighten-2"'
//- dark
//- )
//- v-btn.btn-animate-wrench(fab, absolute, :right='!$vuetify.rtl', :left='$vuetify.rtl', top, small, light, to='system', v-if='hasPermission(`manage:system`)')
//- v-icon(:color='isLatestVersion ? `green` : `red darken-4`', small) mdi-wrench
//- v-card-text
//- v-icon.dashboard-icon mdi-blur
//- .subtitle-1 Wiki.js {{info.currentVersion}}
//- .body-2(v-if='isLatestVersion') {{$t('admin.dashboard.versionLatest')}}
//- .body-2(v-else) {{$t('admin.dashboard.versionNew', { version: info.latestVersion })}}
//- v-flex(xs12, xl6)
//- v-card.radius-7.animated.fadeInUp.wait-p2s
//- v-toolbar(:color='$q.dark.isActive ? `grey darken-2` : `grey lighten-5`', dense, flat)
//- v-spacer
//- .overline {{$t('admin.dashboard.recentPages')}}
//- v-spacer
//- v-data-table.pb-2(
//- :items='recentPages'
//- :headers='recentPagesHeaders'
//- :loading='recentPagesLoading'
//- hide-default-footer
//- hide-default-header
//- )
//- template(slot='item', slot-scope='props')
//- tr.is-clickable(:active='props.selected', @click='$router.push(`/pages/` + props.item.id)')
//- td
//- .body-2: strong {{ props.item.title }}
//- td.admin-pages-path
//- v-chip(label, small, :color='$q.dark.isActive ? `grey darken-4` : `grey lighten-4`') {{ props.item.locale }}
//- span.ml-2.grey--text(:class='$q.dark.isActive ? `text--lighten-1` : `text--darken-2`') / {{ props.item.path }}
//- td.text-right.caption(width='250') {{ props.item.updatedAt | moment('calendar') }}
//- v-flex(xs12, xl6)
//- v-card.radius-7.animated.fadeInUp.wait-p4s
//- v-toolbar(:color='$q.dark.isActive ? `grey darken-2` : `grey lighten-5`', dense, flat)
//- v-spacer
//- .overline {{$t('admin.dashboard.lastLogins')}}
//- v-spacer
//- v-data-table.pb-2(
//- :items='lastLogins'
//- :headers='lastLoginsHeaders'
//- :loading='lastLoginsLoading'
//- hide-default-footer
//- hide-default-header
//- )
//- template(slot='item', slot-scope='props')
//- tr.is-clickable(:active='props.selected', @click='$router.push(`/users/` + props.item.id)')
//- td
//- .body-2: strong {{ props.item.name }}
//- td.text-right.caption(width='250') {{ props.item.lastLoginAt | moment('calendar') }}
//- v-flex(xs12)
//- v-card.dashboard-contribute.animated.fadeInUp.wait-p4s
//- v-card-text
//- img(src='/_assets/svg/icon-heart-health.svg', alt='Contribute', style='height: 80px;')
//- .pl-5
//- .subtitle-1 {{$t('admin.contribute.title')}}
//- .body-2.mt-3: strong {{$t('admin.dashboard.contributeSubtitle')}}
//- .body-2 {{$t('admin.dashboard.contributeHelp')}}
//- v-btn.mx-0.mt-4(:color='$q.dark.isActive ? `indigo lighten-3` : `indigo`', outlined, small, to='/contribute')
//- .caption: strong {{$t('admin.dashboard.contributeLearnMore')}}
</template>
<script setup>
import { useMeta } from 'quasar'
import { useI18n } from 'vue-i18n'
// STORES / ROUTERS / i18n
const { t } = useI18n()
// META
useMeta({
title: t('admin.dashboard.title')
})
</script>
<style lang='scss'>
.dashboard-card {
display: flex;
width: 100%;
border-radius: 7px;
.v-card__text {
overflow: hidden;
position: relative;
}
}
.dashboard-contribute {
background-color: #FFF;
background-image: linear-gradient(to bottom, #FFF 0%, lighten($indigo-1, 3%) 100%);
border-radius: 7px;
@at-root .theme--dark & {
background-color: $grey-8;
background-image: linear-gradient(to bottom, $grey-8 0%, darken($grey-8, 6%) 100%);
}
.v-card__text {
display: flex;
align-items: center;
color: $indigo !important;
@at-root .theme--dark & {
color: $grey-4 !important;
}
}
}
.v-icon.dashboard-icon {
position: absolute !important;
right: 0;
top: 12px;
font-size: 100px !important;
opacity: .25;
@at-root .v-application--is-rtl & {
left: 0;
right: initial;
}
}
</style>
<template lang='pug'>
q-page.admin-flags
.row.q-pa-md.items-center
.col-auto
img.admin-icon.animated.fadeInLeft(src='/_assets/icons/fluent-cashbook.svg')
.col.q-pl-md
.text-h5.text-primary.animated.fadeInLeft {{ $t('admin.editors.title') }}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s {{ $t('admin.editors.subtitle') }}
.col-auto
q-btn.q-mr-sm.acrylic-btn(
icon='las la-question-circle'
flat
color='grey'
href='https://docs.js.wiki/admin/editors'
target='_blank'
type='a'
)
q-btn.q-mr-sm.acrylic-btn(
icon='las la-redo-alt'
flat
color='secondary'
:loading='loading > 0'
@click='load'
)
q-btn(
unelevated
icon='mdi-check'
:label='$t(`common.actions.apply`)'
color='secondary'
@click='save'
:disabled='loading > 0'
)
q-separator(inset)
.q-pa-md.q-gutter-md
q-card.shadow-1
q-list(separator)
q-item(v-for='editor of editors', :key='editor.id')
blueprint-icon(:icon='editor.icon')
q-item-section
q-item-label: strong {{$t(`admin.editors.` + editor.id + `Name`)}}
q-item-label.flex.items-center(caption)
span {{$t(`admin.editors.` + editor.id + `Description`)}}
template(v-if='editor.config')
q-item-section(
side
)
q-btn(
icon='las la-cog'
:label='$t(`admin.editors.configuration`)'
:color='$q.dark.isActive ? `blue-grey-3` : `blue-grey-8`'
outline
no-caps
padding='xs md'
)
q-separator.q-ml-md(vertical)
q-item-section(side)
q-toggle.q-pr-sm(
v-model='editor.isActive'
:color='editor.isDisabled ? `grey` : `primary`'
checked-icon='las la-check'
unchecked-icon='las la-times'
:label='$t(`admin.sites.isActive`)'
:aria-label='$t(`admin.sites.isActive`)'
:disabled='editor.isDisabled'
)
</template>
<script>
import { createMetaMixin } from 'quasar'
export default {
mixins: [
createMetaMixin(function () {
return {
title: this.$t('admin.editors.title')
}
})
],
data () {
return {
loading: false,
editors: [
{
id: 'wysiwyg',
icon: 'google-presentation',
isActive: true
},
{
id: 'markdown',
icon: 'markdown',
config: {},
isActive: true
},
{
id: 'channel',
icon: 'chat',
isActive: true
},
{
id: 'blog',
icon: 'typewriter-with-paper',
isActive: true,
isDisabled: true
},
{
id: 'api',
icon: 'api',
isActive: true,
isDisabled: true
},
{
id: 'redirect',
icon: 'advance',
isActive: true
}
]
}
},
methods: {
async load () {},
save () {},
refresh () {}
}
}
</script>
<style lang='scss'>
</style>
<template lang='pug'>
q-page.admin-extensions
.row.q-pa-md.items-center
.col-auto
img.admin-icon.animated.fadeInLeft(src='/_assets/icons/fluent-module.svg')
.col.q-pl-md
.text-h5.text-primary.animated.fadeInLeft {{ $t('admin.extensions.title') }}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s {{ $t('admin.extensions.subtitle') }}
.col-auto
q-btn.acrylic-btn.q-mr-sm(
icon='las la-question-circle'
flat
color='grey'
href='https://docs.js.wiki/admin/extensions'
target='_blank'
type='a'
)
q-btn.acrylic-btn(
icon='las la-redo-alt'
flat
color='secondary'
:loading='loading > 0'
@click='load'
)
q-separator(inset)
.row.q-pa-md.q-col-gutter-md
.col-12
q-card.shadow-1
q-list(separator)
q-item(
v-for='(ext, idx) of extensions'
:key='`ext-` + ext.key'
)
blueprint-icon(icon='module')
q-item-section
q-item-label {{ext.title}}
q-item-label(caption) {{ext.description}}
q-item-section(side)
.row
q-btn-group(unelevated)
q-btn(
icon='las la-check'
size='sm'
color='positive'
padding='xs sm'
v-if='ext.isInstalled'
:ripple='false'
)
q-tooltip(
anchor='center left'
self='center right'
) {{$t('admin.extensions.installed')}}
q-btn(
:label='$t(`admin.extensions.install`)'
color='blue-7'
v-if='ext.isCompatible && !ext.isInstalled && ext.isInstallable'
@click='install(ext)'
no-caps
)
q-btn(
v-else-if='ext.isCompatible && ext.isInstalled && ext.isInstallable'
:label='$t(`admin.extensions.reinstall`)'
color='blue-7'
@click='install(ext)'
no-caps
)
q-btn(
v-else-if='ext.isCompatible && ext.isInstalled && !ext.isInstallable'
:label='$t(`admin.extensions.installed`)'
color='positive'
no-caps
:ripple='false'
)
q-btn(
v-else-if='ext.isCompatible'
:label='$t(`admin.extensions.instructions`)'
icon='las la-info-circle'
color='indigo'
outline
type='a'
:href='`https://docs.js.wiki/admin/extensions/` + ext.key'
target='_blank'
no-caps
)
q-tooltip(
anchor='center left'
self='center right'
) {{$t('admin.extensions.instructionsHint')}}
q-btn(
v-else
color='negative'
outline
:label='$t(`admin.extensions.incompatible`)'
no-caps
:ripple='false'
)
</template>
<script>
import gql from 'graphql-tag'
import cloneDeep from 'lodash/cloneDeep'
import { createMetaMixin } from 'quasar'
export default {
mixins: [
createMetaMixin(function () {
return {
title: this.$t('admin.extensions.title')
}
})
],
data () {
return {
loading: false,
extensions: []
}
},
mounted () {
this.load()
},
methods: {
async load () {
this.loading++
this.$q.loading.show()
const resp = await this.$apollo.query({
query: gql`
query fetchExtensions {
systemExtensions {
key
title
description
isInstalled
isInstallable
isCompatible
}
}
`,
fetchPolicy: 'network-only'
})
this.extensions = cloneDeep(resp?.data?.systemExtensions)
this.$q.loading.hide()
this.loading--
},
async install (ext) {
this.$q.loading.show({
message: this.$t('admin.extensions.installing') + '<br>' + this.$t('admin.extensions.installingHint'),
html: true
})
try {
const respRaw = await this.$apollo.mutate({
mutation: gql`
mutation installExtension (
$key: String!
) {
installExtension (
key: $key
) {
status {
succeeded
message
}
}
}
`,
variables: {
key: ext.key
}
})
if (respRaw.data?.installExtension?.status?.succeeded) {
this.$q.notify({
type: 'positive',
message: this.$t('admin.extensions.installSuccess')
})
ext.isInstalled = true
this.$forceUpdate()
} else {
throw new Error(respRaw.data?.installExtension?.status?.message || 'An unexpected error occured')
}
} catch (err) {
this.$q.notify({
type: 'negative',
message: this.$t('admin.extensions.installFailed'),
caption: err.message
})
}
this.$q.loading.hide()
}
}
}
</script>
<style lang='scss'>
.admin-extensions {
.q-expansion-item__content .q-card {
@at-root .body--light & {
background-color: $grey-1;
}
@at-root .body--dark & {
background-color: $dark-3;
}
}
}
</style>
<template lang='pug'>
q-page.admin-flags
.row.q-pa-md.items-center
.col-auto
img.admin-icon.animated.fadeInLeft(src='/_assets/icons/fluent-windsock.svg')
.col.q-pl-md
.text-h5.text-primary.animated.fadeInLeft {{ $t('admin.flags.title') }}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s {{ $t('admin.flags.subtitle') }}
.col-auto
q-btn.q-mr-sm.acrylic-btn(
icon='las la-question-circle'
flat
color='grey'
href='https://docs.requarks.io/admin/flags'
target='_blank'
type='a'
)
q-btn(
unelevated
icon='mdi-check'
:label='$t(`common.actions.apply`)'
color='secondary'
@click='save'
:loading='loading'
)
q-separator(inset)
.row.q-pa-md.q-col-gutter-md
.col-12.col-lg-7
q-card.shadow-1.q-py-sm
q-item
q-item-section
q-card.bg-negative.text-white.rounded-borders(flat)
q-card-section.items-center(horizontal)
q-card-section.col-auto.q-pr-none
q-icon(name='las la-exclamation-triangle', size='sm')
q-card-section
span {{ $t('admin.flags.warn.label') }}
.text-caption.text-red-1 {{ $t('admin.flags.warn.hint') }}
q-item(tag='label', v-ripple)
blueprint-icon(icon='flag-filled')
q-item-section
q-item-label {{$t(`admin.flags.ldapdebug.label`)}}
q-item-label(caption) {{$t(`admin.flags.ldapdebug.hint`)}}
q-item-section(avatar)
q-toggle(
v-model='flags.ldapdebug'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.flags.ldapdebug.label`)'
)
q-separator.q-my-sm(inset)
q-item(tag='label', v-ripple)
blueprint-icon(icon='flag-filled')
q-item-section
q-item-label {{$t(`admin.flags.sqllog.label`)}}
q-item-label(caption) {{$t(`admin.flags.sqllog.hint`)}}
q-item-section(avatar)
q-toggle(
v-model='flags.sqllog'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.flags.sqllog.label`)'
)
q-card.shadow-1.q-py-sm.q-mt-md
q-item(tag='label', v-ripple)
blueprint-icon(icon='heart-outline')
q-item-section
q-item-label {{$t(`admin.flags.hidedonatebtn.label`)}}
q-item-label(caption) {{$t(`admin.flags.hidedonatebtn.hint`)}}
q-item-section(avatar)
q-toggle(
v-model='flags.hidedonatebtn'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.flags.hidedonatebtn.label`)'
)
</template>
<script>
import gql from 'graphql-tag'
import _transform from 'lodash/transform'
import { createMetaMixin } from 'quasar'
export default {
mixins: [
createMetaMixin(function () {
return {
title: this.$t('admin.flags.title')
}
})
],
data () {
return {
loading: false,
flags: {
ldapdebug: false,
sqllog: false,
hidedonatebtn: false
}
}
},
methods: {
async save () {
try {
await this.$apollo.mutate({
mutation: gql`
mutation updateFlags (
$flags: [SystemFlagInput]!
) {
updateSystemFlags(
flags: $flags
) {
status {
succeeded
slug
message
}
}
}
`,
variables: {
flags: _transform(this.flags, (result, value, key) => {
result.push({ key, value })
}, [])
},
watchLoading (isLoading) {
this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-flags-update')
}
})
this.$store.commit('showNotification', {
style: 'success',
message: 'Flags applied successfully.',
icon: 'check'
})
} catch (err) {
this.$store.commit('pushGraphError', err)
}
}
}
// apollo: {
// flags: {
// query: gql``,
// fetchPolicy: 'network-only',
// update: (data) => _transform(data.system.flags, (result, row) => {
// _set(result, row.key, row.value)
// }, {}),
// watchLoading (isLoading) {
// this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-flags-refresh')
// }
// }
// }
}
</script>
<style lang='scss'>
</style>
<template lang='pug'>
q-page.admin-general
.row.q-pa-md.items-center
.col-auto
img.admin-icon.animated.fadeInLeft(src='/_assets/icons/fluent-web.svg')
.col.q-pl-md
.text-h5.text-primary.animated.fadeInLeft {{ $t('admin.general.title') }}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s {{ $t('admin.general.subtitle') }}
.col-auto
q-btn.q-mr-sm.acrylic-btn(
icon='las la-question-circle'
flat
color='grey'
href='https://docs.js.wiki/admin/general'
target='_blank'
type='a'
)
q-btn.q-mr-sm.acrylic-btn(
icon='las la-redo-alt'
flat
color='secondary'
:loading='loading > 0'
@click='load'
)
q-btn(
unelevated
icon='mdi-check'
:label='$t(`common.actions.apply`)'
color='secondary'
@click='save'
:disabled='loading > 0'
)
q-separator(inset)
.row.q-pa-md.q-col-gutter-md
.col-12.col-lg-7
//- -----------------------
//- Site Info
//- -----------------------
q-card.shadow-1.q-pb-sm
q-card-section
.text-subtitle1 {{$t('admin.general.siteInfo')}}
q-item
blueprint-icon(icon='home')
q-item-section
q-item-label {{$t(`admin.general.siteTitle`)}}
q-item-label(caption) {{$t(`admin.general.siteTitleHint`)}}
q-item-section
q-input(
outlined
v-model='config.title'
dense
:rules=`[
val => /^[^<>"]+$/.test(val) || $t('admin.general.siteTitleInvalidChars')
]`
hide-bottom-space
:aria-label='$t(`admin.general.siteTitle`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='select-all')
q-item-section
q-item-label {{$t(`admin.general.siteDescription`)}}
q-item-label(caption) {{$t(`admin.general.siteDescriptionHint`)}}
q-item-section
q-input(
outlined
v-model='config.description'
dense
:aria-label='$t(`admin.general.siteDescription`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='dns')
q-item-section
q-item-label {{$t(`admin.general.siteHostname`)}}
q-item-label(caption) {{$t(`admin.general.siteHostnameHint`)}}
q-item-section
q-input(
outlined
v-model='config.hostname'
dense
:rules=`[
val => /^(([a-z0-9.-]+)|([*]{1}))$/.test(val) || $t('admin.general.siteHostnameInvalid')
]`
hide-bottom-space
:aria-label='$t(`admin.general.siteHostname`)'
)
//- -----------------------
//- Footer / Copyright
//- -----------------------
q-card.shadow-1.q-pb-sm.q-mt-md
q-card-section
.text-subtitle1 {{$t('admin.general.footerCopyright')}}
q-item
blueprint-icon(icon='building')
q-item-section
q-item-label {{$t(`admin.general.companyName`)}}
q-item-label(caption) {{$t(`admin.general.companyNameHint`)}}
q-item-section
q-input(
outlined
v-model='config.company'
dense
:aria-label='$t(`admin.general.companyName`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='copyright')
q-item-section
q-item-label {{$t(`admin.general.contentLicense`)}}
q-item-label(caption) {{$t(`admin.general.contentLicenseHint`)}}
q-item-section
q-select(
outlined
v-model='config.contentLicense'
:options='contentLicenses'
option-value='value'
option-label='text'
emit-value
map-options
dense
:aria-label='$t(`admin.general.contentLicense`)'
)
//- -----------------------
//- FEATURES
//- -----------------------
q-card.shadow-1.q-pb-sm.q-mt-md
q-card-section
.text-subtitle1 {{$t('admin.general.features')}}
q-item(tag='label')
blueprint-icon(icon='discussion-forum')
q-item-section
q-item-label {{$t(`admin.general.allowComments`)}}
q-item-label(caption) {{$t(`admin.general.allowCommentsHint`)}}
q-item-section(avatar)
q-toggle(
v-model='config.features.comments'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.general.allowComments`)'
)
q-separator.q-my-sm(inset)
q-item(tag='label')
blueprint-icon(icon='pen')
q-item-section
q-item-label {{$t(`admin.general.allowContributions`)}}
q-item-label(caption) {{$t(`admin.general.allowContributionsHint`)}}
q-item-section(avatar)
q-toggle(
v-model='config.features.contributions'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.general.allowContributions`)'
)
q-separator.q-my-sm(inset)
q-item(tag='label')
blueprint-icon(icon='administrator-male')
q-item-section
q-item-label {{$t(`admin.general.allowProfile`)}}
q-item-label(caption) {{$t(`admin.general.allowProfileHint`)}}
q-item-section(avatar)
q-toggle(
v-model='config.features.profile'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.general.allowProfile`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='star-half-empty')
q-item-section
q-item-label {{$t(`admin.general.allowRatings`)}}
q-item-label(caption) {{$t(`admin.general.allowRatingsHint`)}}
q-item-section.col-auto
q-btn-toggle(
v-model='config.features.ratingsMode'
push
glossy
no-caps
toggle-color='primary'
:options=`[
{ label: $t('admin.general.ratingsOff'), value: 'off' },
{ label: $t('admin.general.ratingsThumbs'), value: 'thumbs' },
{ label: $t('admin.general.ratingsStars'), value: 'stars' }
]`
)
q-separator.q-my-sm(inset)
q-item(tag='label')
blueprint-icon(icon='search')
q-item-section
q-item-label {{$t(`admin.general.allowSearch`)}}
q-item-label(caption) {{$t(`admin.general.allowSearchHint`)}}
q-item-section(avatar)
q-toggle(
v-model='config.features.search'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.general.allowSearch`)'
)
.col-12.col-lg-5
//- -----------------------
//- Logo
//- -----------------------
q-card.shadow-1.q-pb-sm
q-card-section
.text-subtitle1 {{$t('admin.general.logo')}}
q-item
blueprint-icon.self-start(icon='butterfly', indicator, :indicator-text='$t(`admin.extensions.requiresSharp`)')
q-item-section
.flex
q-item-section
q-item-label {{$t(`admin.general.logoUpl`)}}
q-item-label(caption) {{$t(`admin.general.logoUplHint`)}}
q-item-section.col-auto
q-btn(
label='Upload'
unelevated
icon='las la-upload'
color='primary'
text-color='white'
@click='uploadLogo'
)
q-toolbar.bg-header.q-mt-md.rounded-borders.text-white(
dark
style='height: 64px;'
)
q-btn(dense, flat, to='/')
q-avatar(
v-if='config.logoText'
size='34px'
square
)
img(src='/_assets/logo-wikijs.svg')
img(
v-else
src='https://m.media-amazon.com/images/G/01/audibleweb/arya/navigation/audible_logo._V517446980_.svg'
style='height: 34px;'
)
q-toolbar-title.text-h6.font-poppins(v-if='config.logoText') {{config.title}}
q-separator.q-my-sm(inset)
q-item(tag='label')
blueprint-icon(icon='information')
q-item-section
q-item-label {{$t(`admin.general.displaySiteTitle`)}}
q-item-label(caption) {{$t(`admin.general.displaySiteTitleHint`)}}
q-item-section(avatar)
q-toggle(
v-model='config.logoText'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.general.displaySiteTitle`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon.self-start(icon='starfish', indicator, :indicator-text='$t(`admin.extensions.requiresSharp`)')
q-item-section
.flex
q-item-section
q-item-label {{$t(`admin.general.favicon`)}}
q-item-label(caption) {{$t(`admin.general.faviconHint`)}}
q-item-section.col-auto
q-btn(
label='Upload'
unelevated
icon='las la-upload'
color='primary'
text-color='white'
@click='uploadFavicon'
)
.admin-general-favicontabs.q-mt-md
div
q-avatar(
size='24px'
square
)
img(src='/_assets/logo-wikijs.svg')
.text-caption.q-ml-sm {{config.title}}
div
q-icon(name='las la-otter', size='24px', color='grey')
.text-caption.q-ml-sm Lorem ipsum
div
q-icon(name='las la-mountain', size='24px', color='grey')
.text-caption.q-ml-sm Dolor sit amet...
//- -----------------------
//- Defaults
//- -----------------------
q-card.shadow-1.q-pb-sm.q-mt-md(v-if='config.defaults')
q-card-section
.text-subtitle1 {{$t('admin.general.defaults')}}
q-item
blueprint-icon(icon='timezone')
q-item-section
q-item-label {{$t(`admin.general.defaultTimezone`)}}
q-item-label(caption) {{$t(`admin.general.defaultTimezoneHint`)}}
q-item-section
q-select(
outlined
v-model='config.defaults.timezone'
:options='timezones'
option-value='value'
option-label='text'
emit-value
map-options
dense
options-dense
:virtual-scroll-slice-size='1000'
:aria-label='$t(`admin.general.defaultTimezone`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='calendar')
q-item-section
q-item-label {{$t(`admin.general.defaultDateFormat`)}}
q-item-label(caption) {{$t(`admin.general.defaultDateFormatHint`)}}
q-item-section
q-select(
outlined
v-model='config.defaults.dateFormat'
emit-value
map-options
dense
:aria-label='$t(`admin.general.defaultDateFormat`)'
:options=`[
{ label: $t('profile.localeDefault'), value: '' },
{ label: 'DD/MM/YYYY', value: 'DD/MM/YYYY' },
{ label: 'DD.MM.YYYY', value: 'DD.MM.YYYY' },
{ label: 'MM/DD/YYYY', value: 'MM/DD/YYYY' },
{ label: 'YYYY-MM-DD', value: 'YYYY-MM-DD' },
{ label: 'YYYY/MM/DD', value: 'YYYY/MM/DD' }
]`
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='clock')
q-item-section
q-item-label {{$t(`admin.general.defaultTimeFormat`)}}
q-item-label(caption) {{$t(`admin.general.defaultTimeFormatHint`)}}
q-item-section.col-auto
q-btn-toggle(
v-model='config.defaults.timeFormat'
push
glossy
no-caps
toggle-color='primary'
:options=`[
{ label: $t('admin.general.defaultTimeFormat12h'), value: '12h' },
{ label: $t('admin.general.defaultTimeFormat24h'), value: '24h' }
]`
)
//- -----------------------
//- SEO
//- -----------------------
q-card.shadow-1.q-pb-sm.q-mt-md(v-if='config.robots')
q-card-section
.text-subtitle1 SEO
q-item(tag='label')
blueprint-icon(icon='bot')
q-item-section
q-item-label {{$t(`admin.general.searchAllowIndexing`)}}
q-item-label(caption) {{$t(`admin.general.searchAllowIndexingHint`)}}
q-item-section(avatar)
q-toggle(
v-model='config.robots.index'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.general.searchAllowIndexing`)'
)
q-separator.q-my-sm(inset)
q-item(tag='label')
blueprint-icon(icon='polyline')
q-item-section
q-item-label {{$t(`admin.general.searchAllowFollow`)}}
q-item-label(caption) {{$t(`admin.general.searchAllowFollowHint`)}}
q-item-section(avatar)
q-toggle(
v-model='config.robots.follow'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.general.searchAllowFollow`)'
)
</template>
<script>
import { get } from 'vuex-pathify'
import gql from 'graphql-tag'
import cloneDeep from 'lodash/cloneDeep'
import { createMetaMixin } from 'quasar'
export default {
mixins: [
createMetaMixin(function () {
return {
title: this.$t('admin.general.title')
}
})
],
data () {
return {
loading: 0,
config: {
hostname: '',
title: '',
description: '',
company: '',
contentLicense: '',
logoText: false,
ratings: {
index: false,
follow: false
},
features: {
ratings: false,
ratingsMode: 'off',
comments: false,
contributions: false,
profile: false
},
defaults: {
timezone: '',
dateFormat: '',
timeFormat: ''
}
}
}
},
computed: {
currentSiteId: get('admin/currentSiteId', false),
contentLicenses () {
return [
{ value: '', text: this.$t('common.license.none') },
{ value: 'alr', text: this.$t('common.license.alr') },
{ value: 'cc0', text: this.$t('common.license.cc0') },
{ value: 'ccby', text: this.$t('common.license.ccby') },
{ value: 'ccbysa', text: this.$t('common.license.ccbysa') },
{ value: 'ccbynd', text: this.$t('common.license.ccbynd') },
{ value: 'ccbync', text: this.$t('common.license.ccbync') },
{ value: 'ccbyncsa', text: this.$t('common.license.ccbyncsa') },
{ value: 'ccbyncnd', text: this.$t('common.license.ccbyncnd') }
]
},
timezones: get('data/timezones', false)
},
watch: {
currentSiteId (newValue) {
this.load()
}
},
mounted () {
if (this.currentSiteId) {
this.load()
}
},
methods: {
async load () {
this.loading++
this.$q.loading.show()
const resp = await this.$apollo.query({
query: gql`
query getSite (
$id: UUID!
) {
siteById(
id: $id
) {
id
hostname
isEnabled
title
description
company
contentLicense
logoText
robots {
index
follow
}
features {
comments
ratings
ratingsMode
contributions
profile
search
}
defaults {
timezone
dateFormat
timeFormat
}
}
}
`,
variables: {
id: this.currentSiteId
},
fetchPolicy: 'network-only'
})
this.config = cloneDeep(resp?.data?.siteById)
this.$q.loading.hide()
this.loading--
},
async save () {
this.loading++
try {
await this.$apollo.mutate({
mutation: gql`
mutation saveSite (
$id: UUID!
$patch: SiteUpdateInput!
) {
updateSite (
id: $id
patch: $patch
) {
status {
succeeded
slug
message
}
}
}
`,
variables: {
id: this.currentSiteId,
patch: {
hostname: this.config.hostname ?? '',
title: this.config.title ?? '',
description: this.config.description ?? '',
company: this.config.company ?? '',
contentLicense: this.config.contentLicense ?? '',
logoText: this.config.logoText ?? false,
robots: {
index: this.config.robots?.index ?? false,
follow: this.config.robots?.follow ?? false
},
features: {
comments: this.config.features?.comments ?? false,
ratings: (this.config.features?.ratings || 'off') !== 'off',
ratingsMode: this.config.features?.ratingsMode ?? 'off',
contributions: this.config.features?.contributions ?? false,
profile: this.config.features?.profile ?? false,
search: this.config.features?.search ?? false
},
defaults: {
timezone: this.config.defaults?.timezone ?? 'America/New_York',
dateFormat: this.config.defaults?.dateFormat ?? 'YYYY-MM-DD',
timeFormat: this.config.defaults?.timeFormat ?? '12h'
}
}
}
})
this.$q.notify({
type: 'positive',
message: this.$t('admin.general.saveSuccess')
})
if (this.currentSiteId === this.$store.get('site/id')) {
await this.$store.dispatch('admin/fetchSites')
this.$store.set('site/title', this.config.title)
this.$store.set('site/description', this.config.description)
this.$store.set('site/company', this.config.company)
this.$store.set('site/contentLicense', this.config.contentLicense)
}
} catch (err) {
this.$q.notify({
type: 'negative',
message: 'Failed to save site configuration.',
caption: err.message
})
}
this.loading--
},
async uploadLogo () {
const input = document.createElement('input')
input.type = 'file'
input.onchange = async e => {
this.loading++
try {
await this.$apollo.mutate({
mutation: gql`
mutation uploadLogo (
$id: UUID!
$image: Upload!
) {
uploadSiteLogo (
id: $id
image: $image
) {
status {
succeeded
slug
message
}
}
}
`,
variables: {
id: this.currentSiteId,
image: e.target.files[0]
}
})
this.$q.notify({
type: 'positive',
message: this.$t('admin.general.logoUploadSuccess')
})
} catch (err) {
this.$q.notify({
type: 'negative',
message: 'Failed to upload site logo.',
caption: err.message
})
}
this.loading--
}
input.click()
},
refreshLogo () {
this.$forceUpdate()
},
async uploadFavicon () {
const input = document.createElement('input')
input.type = 'file'
input.onchange = async e => {
this.loading++
try {
await this.$apollo.mutate({
mutation: gql`
mutation uploadFavicon (
$id: UUID!
$image: Upload!
) {
uploadSiteFavicon (
id: $id
image: $image
) {
status {
succeeded
slug
message
}
}
}
`,
variables: {
id: this.currentSiteId,
image: e.target.files[0]
}
})
this.$q.notify({
type: 'positive',
message: this.$t('admin.general.faviconUploadSuccess')
})
} catch (err) {
this.$q.notify({
type: 'negative',
message: 'Failed to upload site favicon.',
caption: err.message
})
}
this.loading--
}
input.click()
}
}
}
</script>
<style lang='scss'>
.admin-general {
&-favicontabs {
overflow: hidden;
border-radius: 5px;
background-color: rgba(0,0,0,.1);
display: flex;
padding: 5px 5px 0 12px;
> div {
display: flex;
padding: 4px 12px;
position: relative;
align-items: center;
&:first-child {
border: 1px solid #FFF;
border-bottom: none;
border-radius: 7px 7px 0 0;
box-shadow: 0 0 5px 0 rgba(0,0,0,.2);
@at-root .body--light & {
background: linear-gradient(to top, #FFF, rgba(255,255,255,.75));
border-color: #FFF;
}
@at-root .body--dark & {
background: linear-gradient(to top, $dark-6, $dark-5);
border-color: $dark-6;
}
}
}
}
}
</style>
<template lang='pug'>
q-page.admin-groups
.row.q-pa-md.items-center
.col-auto
img.admin-icon.animated.fadeInLeft(src='/_assets/icons/fluent-people.svg')
.col.q-pl-md
.text-h5.text-primary.animated.fadeInLeft {{ $t('admin.groups.title') }}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s {{ $t('admin.groups.subtitle') }}
.col-auto.flex.items-center
q-input.denser.q-mr-sm(
outlined
v-model='search'
dense
:class='$q.dark.isActive ? `bg-dark` : `bg-white`'
)
template(#prepend)
q-icon(name='las la-search')
q-btn.acrylic-btn.q-mr-sm(
icon='las la-question-circle'
flat
color='grey'
type='a'
href='https://docs.js.wiki/admin/groups'
target='_blank'
)
q-btn.q-mr-sm.acrylic-btn(
icon='las la-redo-alt'
flat
color='secondary'
@click='load'
:loading='loading > 0'
)
q-btn(
unelevated
icon='las la-plus'
:label='$t(`admin.groups.create`)'
color='primary'
@click='createGroup'
)
q-separator(inset)
.row.q-pa-md.q-col-gutter-md
.col-12
q-card.shadow-1
q-table(
:rows='groups'
:columns='headers'
row-key='id'
flat
hide-header
hide-bottom
:rows-per-page-options='[0]'
:loading='loading > 0'
:filter='search'
)
template(v-slot:body-cell-id='props')
q-td(:props='props')
q-icon(name='las la-users', color='primary', size='sm')
template(v-slot:body-cell-name='props')
q-td(:props='props')
.flex.items-center
strong {{props.value}}
q-icon.q-ml-sm(
v-if='props.row.isSystem'
name='las la-lock'
color='pink'
)
template(v-slot:body-cell-usercount='props')
q-td(:props='props')
q-chip.text-caption(
square
:color='$q.dark.isActive ? `dark-6` : `grey-2`'
:text-color='$q.dark.isActive ? `white` : `grey-8`'
dense
) {{$t('admin.groups.usersCount', { count: props.value })}}
template(v-slot:body-cell-edit='props')
q-td(:props='props')
q-btn.acrylic-btn.q-mr-sm(
flat
:to='`/_admin/groups/` + props.row.id'
icon='las la-pen'
color='indigo'
:label='$t(`common.actions.edit`)'
no-caps
)
q-btn.acrylic-btn(
flat
icon='las la-trash'
:color='props.row.isSystem ? `grey` : `accent`'
:disabled='props.row.isSystem'
@click='deleteGroup(props.row)'
)
</template>
<script>
import gql from 'graphql-tag'
import cloneDeep from 'lodash/cloneDeep'
import { createMetaMixin } from 'quasar'
import { sync } from 'vuex-pathify'
import GroupCreateDialog from '../components/GroupCreateDialog.vue'
import GroupDeleteDialog from '../components/GroupDeleteDialog.vue'
export default {
mixins: [
createMetaMixin(function () {
return {
title: this.$t('admin.groups.title')
}
})
],
data () {
return {
groups: [],
loading: 0,
search: ''
}
},
computed: {
overlay: sync('admin/overlay', false),
headers () {
return [
{
align: 'center',
field: 'id',
name: 'id',
sortable: false,
style: 'width: 20px'
},
{
label: this.$t('common.field.name'),
align: 'left',
field: 'name',
name: 'name',
sortable: true
},
{
label: this.$t('admin.groups.userCount'),
align: 'center',
field: 'userCount',
name: 'usercount',
sortable: false,
style: 'width: 150px'
},
{
label: '',
align: 'right',
field: 'edit',
name: 'edit',
sortable: false,
style: 'width: 250px'
}
]
}
},
watch: {
overlay (newValue, oldValue) {
if (newValue === '' && oldValue === 'GroupEditOverlay') {
this.$router.push('/_admin/groups')
this.load()
}
},
$route: 'checkOverlay'
},
mounted () {
this.checkOverlay()
this.load()
},
beforeUnmount () {
this.overlay = ''
},
methods: {
async load () {
this.loading++
this.$q.loading.show()
const resp = await this.$apollo.query({
query: gql`
query getGroups {
groups {
id
name
isSystem
userCount
createdAt
updatedAt
}
}
`,
fetchPolicy: 'network-only'
})
this.groups = cloneDeep(resp?.data?.groups)
this.$q.loading.hide()
this.loading--
},
checkOverlay () {
if (this.$route.params && this.$route.params.id) {
this.$store.set('admin/overlayOpts', { id: this.$route.params.id })
this.$store.set('admin/overlay', 'GroupEditOverlay')
} else {
this.$store.set('admin/overlay', '')
}
},
createGroup () {
this.$q.dialog({
component: GroupCreateDialog
}).onOk(() => {
this.load()
})
},
editGroup (gr) {
this.$router.push(`/_admin/groups/${gr.id}`)
},
deleteGroup (gr) {
this.$q.dialog({
component: GroupDeleteDialog,
componentProps: {
group: gr
}
}).onOk(() => {
this.load()
})
}
}
}
</script>
<style lang='scss'>
</style>
<template lang='pug'>
q-page.admin-locale
.row.q-pa-md.items-center
.col-auto
img.admin-icon.animated.fadeInLeft(src='/_assets/icons/fluent-language.svg')
.col.q-pl-md
.text-h5.text-primary.animated.fadeInLeft {{ $t('admin.locale.title') }}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s {{ $t('admin.locale.subtitle') }}
.col-auto.flex
q-btn.q-mr-md(
icon='las la-download'
:label='$t(`admin.locale.downloadNew`)'
unelevated
color='primary'
:disabled='loading > 0'
@click='installNewLocale'
)
q-separator.q-mr-md(vertical)
q-btn.q-mr-sm.acrylic-btn(
icon='las la-question-circle'
flat
color='grey'
href='https://docs.requarks.io/admin/locale'
target='_blank'
type='a'
)
q-btn.q-mr-sm.acrylic-btn(
icon='las la-redo-alt'
flat
color='secondary'
:loading='loading > 0'
@click='load'
)
q-btn(
unelevated
icon='mdi-check'
:label='$t(`common.actions.apply`)'
color='secondary'
@click='save'
:disabled='loading > 0'
)
q-separator(inset)
.row.q-pa-md.q-col-gutter-md
.col-7
//- -----------------------
//- Locale Options
//- -----------------------
q-card.shadow-1.q-pb-sm
q-card-section
.text-subtitle1 {{$t('admin.locale.settings')}}
q-item
blueprint-icon(icon='translation')
q-item-section
q-item-label {{namespacing ? $t(`admin.locale.base.labelWithNS`) : $t(`admin.locale.base.label`)}}
q-item-label(caption) {{$t(`admin.locale.base.hint`)}}
q-item-section
q-select(
outlined
v-model='selectedLocale'
:options='installedLocales'
option-value='code'
option-label='name'
emit-value
map-options
dense
:aria-label='$t(`admin.locale.base.label`)'
)
q-separator.q-my-sm(inset)
q-item(tag='label', v-ripple)
blueprint-icon(icon='unit')
q-item-section
q-item-label {{$t(`admin.locale.namespaces.label`)}}
q-item-label(caption) {{$t(`admin.locale.namespaces.hint`)}}
q-item-section(avatar)
q-toggle(
v-model='namespacing'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.locale.namespaces.label`)'
)
q-item
q-item-section
q-card.bg-info.text-white.rounded-borders(flat)
q-card-section.items-center(horizontal)
q-card-section.col-auto.q-pr-none
q-icon(name='las la-info-circle', size='sm')
q-card-section
span {{ $t('admin.locale.namespacingPrefixWarning.title', { langCode: selectedLocale }) }}
.text-caption.text-yellow-1 {{ $t('admin.locale.namespacingPrefixWarning.subtitle') }}
.col-5
//- -----------------------
//- Namespacing
//- -----------------------
q-card.shadow-1.q-pb-sm(v-if='namespacing')
q-card-section
.text-subtitle1 {{$t('admin.locale.activeNamespaces')}}
q-item(
v-for='(lc, idx) of installedLocales'
:key='lc.code'
:tag='lc.code !== selectedLocale ? `label` : null'
)
blueprint-icon(:text='lc.code')
q-item-section
q-item-label {{lc.name}}
q-item-label(caption) {{lc.nativeName}}
q-item-section(avatar)
q-toggle(
:disable='lc.code === selectedLocale'
v-model='namespaces'
:val='lc.code'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='lc.name'
)
//- q-separator.q-my-sm(inset)
//- q-item
//- blueprint-icon(icon='test-passed')
//- q-item-section
//- q-item-label {{$t(`admin.locale.activeNamespaces.label`)}}
//- q-item-label(caption) {{$t(`admin.locale.activeNamespaces.hint`)}}
//- q-item-section
//- q-select(
//- outlined
//- :disable='!namespacing'
//- v-model='namespaces'
//- :options='installedLocales'
//- multiple
//- use-chips
//- option-value='code'
//- option-label='name'
//- emit-value
//- map-options
//- dense
//- :aria-label='$t(`admin.locale.activeNamespaces.label`)'
//- )
</template>
<script>
import { get } from 'vuex-pathify'
import gql from 'graphql-tag'
import filter from 'lodash/filter'
import _get from 'lodash/get'
import cloneDeep from 'lodash/cloneDeep'
import { createMetaMixin } from 'quasar'
import LocaleInstallDialog from '../components/LocaleInstallDialog.vue'
export default {
mixins: [
createMetaMixin(function () {
return {
title: this.$t('admin.locale.title')
}
})
],
data () {
return {
loading: 0,
locales: [],
selectedLocale: 'en',
namespacing: false,
namespaces: []
}
},
computed: {
currentSiteId: get('admin/currentSiteId', false),
installedLocales () {
return filter(this.locales, ['isInstalled', true])
}
},
watch: {
currentSiteId (newValue) {
this.load()
},
selectedLocale (newValue) {
if (!this.namespaces.includes(newValue)) {
this.namespaces.push(newValue)
}
}
},
mounted () {
if (this.currentSiteId) {
this.load()
}
},
methods: {
installNewLocale () {
this.$q.dialog({
component: LocaleInstallDialog
}).onOk(() => {
this.load()
})
},
async load () {
this.loading++
this.$q.loading.show()
const resp = await this.$apollo.query({
query: gql`
query getLocales ($siteId: UUID!) {
locales {
availability
code
createdAt
isInstalled
installDate
isRTL
name
nativeName
updatedAt
}
siteById(
id: $siteId
) {
id
locale
localeNamespacing
localeNamespaces
}
}
`,
variables: {
siteId: this.currentSiteId
},
fetchPolicy: 'network-only'
})
this.locales = cloneDeep(resp?.data?.locales)
this.selectedLocale = cloneDeep(resp?.data?.siteById?.locale)
this.namespacing = cloneDeep(resp?.data?.siteById?.localeNamespacing)
this.namespaces = cloneDeep(resp?.data?.siteById?.localeNamespaces)
if (!this.namespaces.includes(this.selectedLocale)) {
this.namespaces.push(this.selectedLocale)
}
this.$q.loading.hide()
this.loading--
},
async download (lc) {
lc.isDownloading = true
const respRaw = await this.$apollo.mutate({
mutation: gql`
mutation downloadLocale ($locale: String!) {
localization {
downloadLocale (locale: $locale) {
responseResult {
succeeded
errorCode
slug
message
}
}
}
}
`,
variables: {
locale: lc.code
}
})
const resp = _get(respRaw, 'data.localization.downloadLocale.responseResult', {})
if (resp.succeeded) {
lc.isDownloading = false
lc.isInstalled = true
lc.updatedAt = new Date().toISOString()
lc.installDate = lc.updatedAt
this.$store.commit('showNotification', {
message: `Locale ${lc.name} has been installed successfully.`,
style: 'success',
icon: 'get_app'
})
} else {
this.$q.notify({
type: 'negative',
message: resp.message
})
}
this.isDownloading = false
},
async save () {
this.loading = true
const respRaw = await this.$apollo.mutate({
mutation: gql`
mutation saveLocaleSettings (
$locale: String!
$autoUpdate: Boolean!
$namespacing: Boolean!
$namespaces: [String]!
) {
localization {
updateLocale(
locale: $locale
autoUpdate: $autoUpdate
namespacing: $namespacing
namespaces: $namespaces
) {
responseResult {
succeeded
errorCode
slug
message
}
}
}
}
`,
variables: {
locale: this.selectedLocale,
autoUpdate: this.autoUpdate,
namespacing: this.namespacing,
namespaces: this.namespaces
}
})
const resp = _get(respRaw, 'data.localization.updateLocale.responseResult', {})
if (resp.succeeded) {
// Change UI language
this.$i18n.locale = this.selectedLocale
this.$q.notify({
type: 'positive',
message: 'Locale settings updated successfully.'
})
setTimeout(() => {
window.location.reload(true)
}, 1000)
} else {
this.$q.notify({
type: 'negative',
message: resp.message
})
}
this.loading = false
}
}
}
</script>
<template lang='pug'>
q-page.admin-login
.row.q-pa-md.items-center
.col-auto
img.admin-icon.animated.fadeInLeft(src='/_assets/icons/fluent-bunch-of-keys.svg')
.col.q-pl-md
.text-h5.text-primary.animated.fadeInLeft {{ $t('admin.login.title') }}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s {{ $t('admin.login.subtitle') }}
.col-auto
q-btn.q-mr-sm.acrylic-btn(
icon='las la-question-circle'
flat
color='grey'
href='https://docs.js.wiki/admin/login'
target='_blank'
type='a'
)
q-btn.q-mr-sm.acrylic-btn(
icon='las la-redo-alt'
flat
color='secondary'
:loading='loading > 0'
@click='load'
)
q-btn(
unelevated
icon='mdi-check'
:label='$t(`common.actions.apply`)'
color='secondary'
@click='save'
:disabled='loading > 0'
)
q-separator(inset)
.row.q-pa-md.q-col-gutter-md
.col-12.col-lg-6
//- -----------------------
//- Experience
//- -----------------------
q-card.shadow-1.q-pb-sm
q-card-section
.text-subtitle1 {{$t('admin.login.experience')}}
q-item(tag='label', v-ripple)
blueprint-icon(icon='full-image', indicator, :indicator-text='$t(`admin.extensions.requiresSharp`)')
q-item-section
q-item-label {{$t(`admin.login.background`)}}
q-item-label(caption) {{$t(`admin.login.backgroundHint`)}}
q-item-section.col-auto
q-btn(
label='Upload'
unelevated
icon='las la-upload'
color='primary'
text-color='white'
)
q-separator.q-my-sm(inset)
q-item(tag='label', v-ripple)
blueprint-icon(icon='close-pane')
q-item-section
q-item-label {{$t(`admin.login.bypassScreen`)}}
q-item-label(caption) {{$t(`admin.login.bypassScreenHint`)}}
q-item-section(avatar)
q-toggle(
v-model='config.authAutoLogin'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.login.bypassScreen`)'
)
q-separator.q-my-sm(inset)
q-item(tag='label', v-ripple)
blueprint-icon(icon='no-access')
q-item-section
q-item-label {{$t(`admin.login.bypassUnauthorized`)}}
q-item-label(caption) {{$t(`admin.login.bypassUnauthorizedHint`)}}
q-item-section(avatar)
q-toggle(
v-model='config.authBypassUnauthorized'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.login.bypassUnauthorized`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='double-right')
q-item-section
q-item-label {{$t(`admin.login.loginRedirect`)}}
q-item-label(caption) {{$t(`admin.login.loginRedirectHint`)}}
q-item-section
q-input(
outlined
v-model='config.loginRedirect'
dense
:rules=`[
val => invalidCharsRegex.test(val) || $t('admin.login.loginRedirectInvalidChars')
]`
hide-bottom-space
:aria-label='$t(`admin.login.loginRedirect`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='chevron-right')
q-item-section
q-item-label {{$t(`admin.login.welcomeRedirect`)}}
q-item-label(caption) {{$t(`admin.login.welcomeRedirectHint`)}}
q-item-section
q-input(
outlined
v-model='config.welcomeRedirect'
dense
:rules=`[
val => invalidCharsRegex.test(val) || $t('admin.login.welcomeRedirectInvalidChars')
]`
hide-bottom-space
:aria-label='$t(`admin.login.welcomeRedirect`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='exit')
q-item-section
q-item-label {{$t(`admin.login.logoutRedirect`)}}
q-item-label(caption) {{$t(`admin.login.logoutRedirectHint`)}}
q-item-section
q-input(
outlined
v-model='config.logoutRedirect'
dense
:rules=`[
val => invalidCharsRegex.test(val) || $t('admin.login.logoutRedirectInvalidChars')
]`
hide-bottom-space
:aria-label='$t(`admin.login.logoutRedirect`)'
)
.col-12.col-lg-6
//- -----------------------
//- Providers
//- -----------------------
q-card.shadow-1.q-pb-sm
q-card-section
.text-subtitle1 {{$t('admin.login.providers')}}
q-card-section.admin-login-providers.q-pt-none
draggable(
class='q-list rounded-borders'
:list='providers'
:animation='150'
handle='.handle'
@end='dragStarted = false'
item-key='id'
)
template(#item='{element}')
q-item
q-item-section(side)
q-icon.handle(name='las la-bars')
blueprint-icon(:icon='element.icon')
q-item-section
q-item-label {{element.label}}
q-item-label(caption) {{element.provider}}
q-item-section(side)
q-toggle(
v-model='element.isActive'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
label='Visible'
:aria-label='element.label'
)
q-item.q-pt-none
q-item-section
q-card.bg-info.text-white.rounded-borders(flat)
q-card-section.items-center(horizontal)
q-card-section.col-auto.q-pr-none
q-icon(name='las la-info-circle', size='sm')
q-card-section.text-caption {{ $t('admin.login.providersVisbleWarning') }}
</template>
<script>
import { get } from 'vuex-pathify'
import cloneDeep from 'lodash/cloneDeep'
import gql from 'graphql-tag'
import draggable from 'vuedraggable'
import { createMetaMixin } from 'quasar'
export default {
mixins: [
createMetaMixin(function () {
return {
title: this.$t('admin.login.title')
}
})
],
components: {
draggable
},
data () {
return {
invalidCharsRegex: /^[^<>"]+$/,
loading: 0,
config: {
authAutoLogin: false,
authHideLocal: false,
authBypassUnauthorized: false,
loginRedirect: '/',
welcomeRedirect: '/',
logoutRedirect: '/'
},
providers: [
{ id: 'local', label: 'Local Authentication', provider: 'Username-Password', icon: 'database', isActive: true },
{ id: 'google', label: 'Google', provider: 'Google', icon: 'google', isActive: true },
{ id: 'slack', label: 'Slack', provider: 'Slack', icon: 'slack', isActive: false }
]
}
},
computed: {
currentSiteId: get('admin/currentSiteId', false)
},
methods: {
async load () {
this.loading++
this.$q.loading.show()
// const resp = await this.$apollo.query({
// query: gql`
// query getSite (
// $id: UUID!
// ) {
// siteById(
// id: $id
// ) {
// id
// }
// }
// `,
// variables: {
// id: this.currentSiteId
// },
// fetchPolicy: 'network-only'
// })
// this.config = cloneDeep(resp?.data?.siteById)
this.$q.loading.hide()
this.loading--
},
async save () {
try {
await this.$apollo.mutate({
mutation: gql`
mutation saveLoginSettings (
$authAutoLogin: Boolean
$authEnforce2FA: Boolean
) {
site {
updateConfig(
authAutoLogin: $authAutoLogin,
authEnforce2FA: $authEnforce2FA
) {
responseResult {
succeeded
errorCode
slug
message
}
}
}
}
`,
variables: {
authAutoLogin: this.config.authAutoLogin ?? false,
authEnforce2FA: this.config.authEnforce2FA ?? false
},
watchLoading (isLoading) {
this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-site-update')
}
})
this.$store.commit('showNotification', {
style: 'success',
message: 'Configuration saved successfully.',
icon: 'check'
})
} catch (err) {
this.$store.commit('pushGraphError', err)
}
}
}
}
</script>
<style lang='scss'>
.admin-login-providers {
.q-item {
border-radius: 5px;
@at-root .body--light & {
background-color: $grey-2;
}
@at-root .body--dark & {
background-color: $dark-5;
}
& + .q-item {
margin-top: 8px;
}
}
.handle {
cursor: ns-resize;
}
}
</style>
<template lang='pug'>
q-page.admin-mail
.row.q-pa-md.items-center
.col-auto
img.admin-icon.animated.fadeInLeft(src='/_assets/icons/fluent-message-settings.svg')
.col.q-pl-md
.text-h5.text-primary.animated.fadeInLeft {{ $t('admin.mail.title') }}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s {{ $t('admin.mail.subtitle') }}
.col-auto
q-btn.q-mr-sm.acrylic-btn(
icon='las la-question-circle'
flat
color='grey'
href='https://docs.js.wiki/admin/mail'
target='_blank'
type='a'
)
q-btn.q-mr-sm.acrylic-btn(
icon='las la-redo-alt'
flat
color='secondary'
:loading='loading > 0'
@click='load'
)
q-btn(
unelevated
icon='mdi-check'
:label='$t(`common.actions.apply`)'
color='secondary'
@click='save'
:disabled='loading > 0'
)
q-separator(inset)
.row.q-pa-md.q-col-gutter-md
.col-12.col-lg-7
//- -----------------------
//- Configuration
//- -----------------------
q-card.shadow-1.q-pb-sm
q-card-section
.text-subtitle1 {{$t('admin.mail.configuration')}}
q-item
blueprint-icon(icon='contact')
q-item-section
q-item-label {{$t(`admin.mail.senderName`)}}
q-item-label(caption) {{$t(`admin.general.senderNameHint`)}}
q-item-section
q-input(
outlined
v-model='config.senderName'
dense
hide-bottom-space
:aria-label='$t(`admin.mail.senderName`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='envelope')
q-item-section
q-item-label {{$t(`admin.mail.senderEmail`)}}
q-item-label(caption) {{$t(`admin.general.senderEmailHint`)}}
q-item-section
q-input(
outlined
v-model='config.senderEmail'
dense
:aria-label='$t(`admin.mail.senderEmail`)'
)
//- -----------------------
//- SMTP
//- -----------------------
q-card.shadow-1.q-pb-sm.q-mt-md
q-card-section
.text-subtitle1 {{$t('admin.mail.smtp')}}
q-item
blueprint-icon(icon='dns')
q-item-section
q-item-label {{$t(`admin.mail.smtpHost`)}}
q-item-label(caption) {{$t(`admin.mail.smtpHostHint`)}}
q-item-section
q-input(
outlined
v-model='config.host'
dense
hide-bottom-space
:aria-label='$t(`admin.mail.smtpHost`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='ethernet-off')
q-item-section
q-item-label {{$t(`admin.mail.smtpPort`)}}
q-item-label(caption) {{$t(`admin.mail.smtpPortHint`)}}
q-item-section(style='flex: 0 0 120px;')
q-input(
outlined
v-model='config.port'
dense
:aria-label='$t(`admin.mail.smtpPort`)'
)
q-separator.q-my-sm(inset)
q-item(tag='label', v-ripple)
blueprint-icon(icon='secure')
q-item-section
q-item-label {{$t(`admin.mail.smtpTLS`)}}
q-item-label(caption) {{$t(`admin.mail.smtpTLSHint`)}}
q-item-section(avatar)
q-toggle(
v-model='config.secure'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.mail.smtpTLS`)'
)
q-separator.q-my-sm(inset)
q-item(tag='label', v-ripple)
blueprint-icon(icon='security-ssl')
q-item-section
q-item-label {{$t(`admin.mail.smtpVerifySSL`)}}
q-item-label(caption) {{$t(`admin.mail.smtpVerifySSLHint`)}}
q-item-section(avatar)
q-toggle(
v-model='config.verifySSL'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.mail.smtpVerifySSL`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='test-account')
q-item-section
q-item-label {{$t(`admin.mail.smtpUser`)}}
q-item-label(caption) {{$t(`admin.mail.smtpUserHint`)}}
q-item-section
q-input(
outlined
v-model='config.user'
dense
:aria-label='$t(`admin.mail.smtpUser`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='password')
q-item-section
q-item-label {{$t(`admin.mail.smtpPwd`)}}
q-item-label(caption) {{$t(`admin.mail.smtpPwdHint`)}}
q-item-section
q-input(
outlined
v-model='config.pass'
dense
:aria-label='$t(`admin.mail.smtpPwd`)'
)
//- -----------------------
//- DKIM
//- -----------------------
q-card.shadow-1.q-pb-sm.q-mt-md
q-card-section
.text-subtitle1 {{$t('admin.mail.dkim')}}
q-item.q-pt-none
q-item-section
q-card.bg-info.text-white.rounded-borders(flat)
q-card-section.items-center(horizontal)
q-card-section.col-auto.q-pr-none
q-icon(name='las la-info-circle', size='sm')
q-card-section.text-caption {{ $t('admin.mail.dkimHint') }}
q-item(tag='label', v-ripple)
blueprint-icon(icon='received')
q-item-section
q-item-label {{$t(`admin.mail.dkimUse`)}}
q-item-label(caption) {{$t(`admin.mail.dkimUseHint`)}}
q-item-section(avatar)
q-toggle(
v-model='config.useDKIM'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.mail.dkimUse`)'
)
template(v-if='config.useDKIM')
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='dns')
q-item-section
q-item-label {{$t(`admin.mail.dkimDomainName`)}}
q-item-label(caption) {{$t(`admin.mail.dkimDomainNameHint`)}}
q-item-section
q-input(
outlined
v-model='config.dkimDomainName'
dense
:aria-label='$t(`admin.mail.dkimDomainName`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='access')
q-item-section
q-item-label {{$t(`admin.mail.dkimKeySelector`)}}
q-item-label(caption) {{$t(`admin.mail.dkimKeySelectorHint`)}}
q-item-section
q-input(
outlined
v-model='config.dkimKeySelector'
dense
:aria-label='$t(`admin.mail.dkimKeySelector`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='grand-master-key')
q-item-section
q-item-label {{$t(`admin.mail.dkimPrivateKey`)}}
q-item-label(caption) {{$t(`admin.mail.dkimPrivateKeyHint`)}}
q-item-section
q-input(
outlined
v-model='config.dkimPrivateKey'
dense
:aria-label='$t(`admin.mail.dkimPrivateKey`)'
type='textarea'
)
.col-12.col-lg-5
//- -----------------------
//- MAIL TEMPLATES
//- -----------------------
q-card.shadow-1.q-pb-sm
q-card-section
.text-subtitle1 {{$t('admin.mail.templates')}}
q-list
q-item
blueprint-icon(icon='resume-template')
q-item-section
q-item-label {{$t(`admin.mail.templateWelcome`)}}
q-item-section(side)
q-btn(
outline
no-caps
icon='las la-edit'
color='primary'
@click=''
:label='$t(`common.actions.edit`)'
)
q-separator(inset)
q-item
blueprint-icon(icon='resume-template')
q-item-section
q-item-label {{$t(`admin.mail.templateResetPwd`)}}
q-item-section(side)
q-btn(
outline
no-caps
icon='las la-edit'
color='primary'
@click=''
:label='$t(`common.actions.edit`)'
)
//- -----------------------
//- SMTP TEST
//- -----------------------
q-card.shadow-1.q-pb-sm.q-mt-md
q-card-section
.text-subtitle1 {{$t('admin.mail.test')}}
q-item
blueprint-icon.self-start(icon='email')
q-item-section
q-item-label {{$t(`admin.mail.testRecipient`)}}
q-item-label(caption) {{$t(`admin.mail.testRecipientHint`)}}
q-input.q-mt-md(
outlined
v-model='testEmail'
dense
:aria-label='$t(`admin.mail.testRecipient`)'
)
.flex.justify-end.q-pr-md.q-py-sm
q-btn(
unelevated
color='primary'
icon='las la-paper-plane'
:label='$t(`admin.mail.testSend`)'
@click='sendTest'
:loading='testLoading'
)
</template>
<script>
import toSafeInteger from 'lodash/toSafeInteger'
import _get from 'lodash/get'
import cloneDeep from 'lodash/cloneDeep'
import gql from 'graphql-tag'
import { createMetaMixin } from 'quasar'
export default {
mixins: [
createMetaMixin(function () {
return {
title: this.$t('admin.mail.title')
}
})
],
data () {
return {
config: {
senderName: '',
senderEmail: '',
host: '',
port: 0,
secure: false,
verifySSL: false,
user: '',
pass: '',
useDKIM: false,
dkimDomainName: '',
dkimKeySelector: '',
dkimPrivateKey: ''
},
testEmail: '',
testLoading: false,
loading: 0
}
},
mounted () {
this.load()
},
methods: {
async load () {
this.loading++
try {
const resp = await this.$apollo.query({
query: gql`
query getMailConfig {
mailConfig {
senderName
senderEmail
host
port
secure
verifySSL
user
pass
useDKIM
dkimDomainName
dkimKeySelector
dkimPrivateKey
}
}
`,
fetchPolicy: 'no-cache'
})
if (!resp?.data?.mailConfig) {
throw new Error('Failed to fetch mail config.')
}
this.config = cloneDeep(resp.data.mailConfig)
} catch (err) {
this.$q.notify({
type: 'negative',
message: 'Failed to fetch mail config',
caption: err.message
})
}
this.loading--
},
async save () {
if (this.loading > 0) { return }
this.loading++
try {
await this.$apollo.mutate({
mutation: gql`
mutation saveMailConfig (
$senderName: String!
$senderEmail: String!
$host: String!
$port: Int!
$secure: Boolean!
$verifySSL: Boolean!
$user: String!
$pass: String!
$useDKIM: Boolean!
$dkimDomainName: String!
$dkimKeySelector: String!
$dkimPrivateKey: String!
) {
updateMailConfig (
senderName: $senderName
senderEmail: $senderEmail
host: $host
port: $port
secure: $secure
verifySSL: $verifySSL
user: $user
pass: $pass
useDKIM: $useDKIM
dkimDomainName: $dkimDomainName
dkimKeySelector: $dkimKeySelector
dkimPrivateKey: $dkimPrivateKey
) {
status {
succeeded
slug
message
}
}
}
`,
variables: {
senderName: this.config.senderName || '',
senderEmail: this.config.senderEmail || '',
host: this.config.host || '',
port: toSafeInteger(this.config.port) || 0,
secure: this.config.secure ?? false,
verifySSL: this.config.verifySSL ?? false,
user: this.config.user || '',
pass: this.config.pass || '',
useDKIM: this.config.useDKIM ?? false,
dkimDomainName: this.config.dkimDomainName || '',
dkimKeySelector: this.config.dkimKeySelector || '',
dkimPrivateKey: this.config.dkimPrivateKey || ''
}
})
this.$q.notify({
type: 'positive',
message: this.$t('admin.mail.saveSuccess')
})
} catch (err) {
this.$store.commit('pushGraphError', err)
}
this.loading--
},
async sendTest () {
this.loading++
try {
const resp = await this.$apollo.mutate({
mutation: gql`
mutation sentMailTest (
$recipientEmail: String!
) {
sendMailTest(
recipientEmail: $recipientEmail
) {
status {
succeeded
slug
message
}
}
}
`,
variables: {
recipientEmail: this.testEmail
}
})
if (!_get(resp, 'data.sendMailTest.status.succeeded', false)) {
throw new Error(_get(resp, 'data.sendMailTest.status.message', 'An unexpected error occurred.'))
}
this.testEmail = ''
this.$q.notify({
type: 'positive',
message: this.$t('admin.mail.sendTestSuccess')
})
} catch (err) {
this.$store.commit('pushGraphError', err)
}
this.loading--
}
}
}
</script>
<style lang='scss'>
</style>
<template lang='pug'>
q-page.admin-navigation
.row.q-pa-md.items-center
.col-auto
img.admin-icon.animated.fadeInLeft(src='/_assets/icons/fluent-tree-structure.svg')
.col.q-pl-md
.text-h5.text-primary.animated.fadeInLeft {{ $t('admin.navigation.title') }}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s {{ $t('admin.navigation.subtitle') }}
.col-auto
q-btn.acrylic-btn.q-mr-sm(
icon='las la-question-circle'
flat
color='grey'
href='https://docs.requarks.io/admin/navigation'
target='_blank'
type='a'
)
q-btn.q-mr-sm.acrylic-btn(
icon='las la-redo-alt'
flat
color='secondary'
:loading='loading > 0'
@click='load'
)
q-btn(
unelevated
icon='mdi-check'
:label='$t(`common.actions.apply`)'
color='secondary'
@click='save'
:disabled='loading > 0'
)
q-separator(inset)
.row.q-pa-md.q-col-gutter-md
.col-6
//- v-container(fluid, grid-list-lg)
//- v-layout(row wrap)
//- v-flex(xs12)
//- .admin-header
//- img.animated.fadeInUp(src='/_assets/svg/icon-triangle-arrow.svg', alt='Navigation', style='width: 80px;')
//- .admin-header-title
//- .headline.primary--text.animated.fadeInLeft {{$t('navigation.title')}}
//- .subtitle-1.grey--text.animated.fadeInLeft.wait-p4s {{$t('navigation.subtitle')}}
//- v-spacer
//- v-btn.animated.fadeInDown.wait-p3s(icon, outlined, color='grey', href='https://docs.requarks.io/navigation', target='_blank')
//- v-icon mdi-help-circle
//- v-btn.mx-3.animated.fadeInDown.wait-p2s.mr-3(icon, outlined, color='grey', @click='refresh')
//- v-icon mdi-refresh
//- v-btn.animated.fadeInDown(color='success', depressed, @click='save', large)
//- v-icon(left) mdi-check
//- span {{$t('common.actions.apply')}}
//- v-container.pa-0.mt-3(fluid, grid-list-lg)
//- v-row(dense)
//- v-col(cols='3')
//- v-card.animated.fadeInUp
//- v-toolbar(color='teal', dark, dense, flat, height='56')
//- v-toolbar-title.subtitle-1 {{$t('admin.navigation.mode')}}
//- v-list(nav, two-line)
//- v-list-item-group(v-model='config.mode', mandatory, :color='$vuetify.theme.dark ? `teal lighten-3` : `teal`')
//- v-list-item(value='TREE')
//- v-list-item-avatar
//- img(src='/_assets/svg/icon-tree-structure-dotted.svg', alt='Site Tree')
//- v-list-item-content
//- v-list-item-title {{$t('admin.navigation.modeSiteTree.title')}}
//- v-list-item-subtitle {{$t('admin.navigation.modeSiteTree.description')}}
//- v-list-item-avatar
//- v-icon(v-if='$vuetify.theme.dark', :color='config.mode === `TREE` ? `teal lighten-3` : `grey darken-2`') mdi-check-circle
//- v-icon(v-else, :color='config.mode === `TREE` ? `teal` : `grey lighten-3`') mdi-check-circle
//- v-list-item(value='STATIC')
//- v-list-item-avatar
//- img(src='/_assets/svg/icon-features-list.svg', alt='Static Navigation')
//- v-list-item-content
//- v-list-item-title {{$t('admin.navigation.modeStatic.title')}}
//- v-list-item-subtitle {{$t('admin.navigation.modeStatic.description')}}
//- v-list-item-avatar
//- v-icon(v-if='$vuetify.theme.dark', :color='config.mode === `STATIC` ? `teal lighten-3` : `grey darken-2`') mdi-check-circle
//- v-icon(v-else, :color='config.mode === `STATIC` ? `teal` : `grey lighten-3`') mdi-check-circle
//- v-list-item(value='MIXED')
//- v-list-item-avatar
//- img(src='/_assets/svg/icon-user-menu-male-dotted.svg', alt='Custom Navigation')
//- v-list-item-content
//- v-list-item-title {{$t('admin.navigation.modeCustom.title')}}
//- v-list-item-subtitle {{$t('admin.navigation.modeCustom.description')}}
//- v-list-item-avatar
//- v-icon(v-if='$vuetify.theme.dark', :color='config.mode === `MIXED` ? `teal lighten-3` : `grey darken-2`') mdi-check-circle
//- v-icon(v-else, :color='config.mode === `MIXED` ? `teal` : `grey lighten-3`') mdi-check-circle
//- v-list-item(value='NONE')
//- v-list-item-avatar
//- img(src='/_assets/svg/icon-cancel-dotted.svg', alt='None')
//- v-list-item-content
//- v-list-item-title {{$t('admin.navigation.modeNone.title')}}
//- v-list-item-subtitle {{$t('admin.navigation.modeNone.description')}}
//- v-list-item-avatar
//- v-icon(v-if='$vuetify.theme.dark', :color='config.mode === `none` ? `teal lighten-3` : `grey darken-2`') mdi-check-circle
//- v-icon(v-else, :color='config.mode === `none` ? `teal` : `grey lighten-3`') mdi-check-circle
//- v-col(cols='9', v-if='config.mode === `MIXED` || config.mode === `STATIC`')
//- v-card.animated.fadeInUp.wait-p2s
//- v-row(no-gutters, align='stretch')
//- v-col(style='flex: 0 0 350px;')
//- v-card.grey(flat, style='height: 100%; border-radius: 4px 0 0 4px;', :class='$vuetify.theme.dark ? `darken-4-l5` : `lighten-3`')
//- .teal.lighten-1.pa-2.d-flex(style='margin-bottom: 1px; height:56px;')
//- v-select(
//- :disabled='locales.length < 2'
//- label='Locale'
//- hide-details
//- solo
//- flat
//- background-color='teal darken-2'
//- dark
//- dense
//- v-model='currentLang'
//- :items='locales'
//- item-text='nativeName'
//- item-value='code'
//- )
//- v-tooltip(top)
//- template(v-slot:activator='{ on }')
//- v-btn.ml-2(icon, tile, color='white', v-on='on', @click='copyFromLocaleDialogIsShown = true')
//- v-icon mdi-arrange-send-backward
//- span {{$t('admin.navigation.copyFromLocale')}}
//- v-list.py-2(dense, nav, dark, class='blue darken-2', style='border-radius: 0;')
//- v-list-item(v-if='currentTree.length < 1')
//- v-list-item-avatar(size='24'): v-icon(color='blue lighten-3') mdi-alert
//- v-list-item-content
//- em.caption.blue--text.text--lighten-4 {{$t('navigation.emptyList')}}
//- draggable(v-model='currentTree')
//- template(v-for='navItem in currentTree')
//- v-list-item(
//- v-if='navItem.kind === "link"'
//- :key='navItem.id'
//- :class='(navItem === current) ? "blue" : ""'
//- @click='selectItem(navItem)'
//- )
//- v-list-item-avatar(size='24', tile)
//- v-icon(v-if='navItem.icon.match(/fa[a-z] fa-/)', size='19') {{ navItem.icon }}
//- v-icon(v-else) {{ navItem.icon }}
//- v-list-item-title {{navItem.label}}
//- .py-2.clickable(
//- v-else-if='navItem.kind === "divider"'
//- :key='navItem.id'
//- :class='(navItem === current) ? "blue" : ""'
//- @click='selectItem(navItem)'
//- )
//- v-divider
//- v-subheader.pl-4.clickable(
//- v-else-if='navItem.kind === "header"'
//- :key='navItem.id'
//- :class='(navItem === current) ? "blue" : ""'
//- @click='selectItem(navItem)'
//- ) {{navItem.label}}
//- v-card-chin
//- v-menu(offset-y, bottom, min-width='200px', style='flex: 1 1;')
//- template(v-slot:activator='{ on }')
//- v-btn(v-on='on', color='primary', depressed, block)
//- v-icon(left) mdi-plus
//- span {{$t('common.actions.add')}}
//- v-list
//- v-list-item(@click='addItem("link")')
//- v-list-item-avatar(size='24'): v-icon mdi-link
//- v-list-item-title {{$t('navigation.link')}}
//- v-list-item(@click='addItem("header")')
//- v-list-item-avatar(size='24'): v-icon mdi-format-title
//- v-list-item-title {{$t('navigation.header')}}
//- v-list-item(@click='addItem("divider")')
//- v-list-item-avatar(size='24'): v-icon mdi-minus
//- v-list-item-title {{$t('navigation.divider')}}
//- v-col
//- v-card(flat, style='border-radius: 0 4px 4px 0;')
//- template(v-if='current.kind === "link"')
//- v-toolbar(height='56', color='teal lighten-1', flat, dark)
//- .subtitle-1 {{$t('navigation.edit', { kind: $t('navigation.link') })}}
//- v-spacer
//- v-btn.px-5(color='white', outlined, @click='deleteItem(current)')
//- v-icon(left) mdi-delete
//- span {{$t('navigation.delete', { kind: $t('navigation.link') })}}
//- v-card-text
//- v-text-field(
//- outlined
//- :label='$t("navigation.label")'
//- prepend-icon='mdi-format-title'
//- v-model='current.label'
//- counter='255'
//- )
//- v-text-field(
//- outlined
//- :label='$t("navigation.icon")'
//- prepend-icon='mdi-dice-5'
//- v-model='current.icon'
//- hide-details
//- )
//- .caption.pt-3.pl-5 The default icon set is #[strong Material Design Icons]. In order to use another icon set, you must first select it in the Theme administration section.
//- .caption.pt-3.pl-5: strong Material Design Icons
//- .caption.pl-5 Refer to the #[a(href='https://materialdesignicons.com/', target='_blank') Material Design Icons Reference] for the list of all possible values. You must prefix all values with #[code mdi-], e.g. #[code mdi-home]
//- .caption.pt-3.pl-5: strong Font Awesome 5
//- .caption.pl-5 Refer to the #[a(href='https://fontawesome.com/icons?d=gallery&m=free', target='_blank') Font Awesome 5 Reference] for the list of all possible values. You must prefix all values with #[code fas fa-], e.g. #[code fas fa-home]. Note that some icons use different prefixes (e.g. #[code fab], #[code fad], #[code fal], #[code far]).
//- .caption.pt-3.pl-5: strong Font Awesome 4
//- .caption.pl-5 Refer to the #[a(href='https://fontawesome.com/v4.7.0/icons/', target='_blank') Font Awesome 4 Reference] for the list of all possible values. You must prefix all values with #[code fa fa-], e.g. #[code fa fa-home]
//- v-divider
//- v-card-text
//- v-select(
//- outlined
//- :label='$t("navigation.targetType")'
//- prepend-icon='mdi-near-me'
//- :items='navTypes'
//- v-model='current.targetType'
//- hide-details
//- )
//- v-text-field.mt-4(
//- v-if='current.targetType === `external` || current.targetType === `externalblank`'
//- outlined
//- :label='$t("navigation.target")'
//- prepend-icon='mdi-near-me'
//- v-model='current.target'
//- hide-details
//- )
//- .d-flex.align-center.mt-4(v-else-if='current.targetType === "page"')
//- v-btn.ml-8(
//- color='primary'
//- dark
//- @click='selectPage'
//- )
//- v-icon(left) mdi-magnify
//- span {{$t('admin.navigation.selectPageButton')}}
//- .caption.ml-4.primary--text {{current.target}}
//- v-text-field(
//- v-else-if='current.targetType === `search`'
//- outlined
//- :label='$t("navigation.navType.searchQuery")'
//- prepend-icon='search'
//- v-model='current.target'
//- )
//- v-divider
//- template(v-else-if='current.kind === "header"')
//- v-toolbar(height='56', color='teal lighten-1', flat, dark)
//- .subtitle-1 {{$t('navigation.edit', { kind: $t('navigation.header') })}}
//- v-spacer
//- v-btn.px-5(color='white', outlined, @click='deleteItem(current)')
//- v-icon(left) mdi-delete
//- span {{$t('navigation.delete', { kind: $t('navigation.header') })}}
//- v-card-text
//- v-text-field(
//- outlined
//- :label='$t("navigation.label")'
//- prepend-icon='mdi-format-title'
//- v-model='current.label'
//- )
//- v-divider
//- div(v-else-if='current.kind === "divider"')
//- v-toolbar(height='56', color='teal lighten-1', flat, dark)
//- .subtitle-1 {{$t('navigation.edit', { kind: $t('navigation.divider') })}}
//- v-spacer
//- v-btn.px-5(color='white', outlined, @click='deleteItem(current)')
//- v-icon(left) mdi-delete
//- span {{$t('navigation.delete', { kind: $t('navigation.divider') })}}
//- v-card-text(v-if='current.kind')
//- v-radio-group.pl-8(v-model='current.visibilityMode', mandatory, hide-details)
//- v-radio(:label='$t("admin.navigation.visibilityMode.all")', value='all', color='primary')
//- v-radio.mt-3(:label='$t("admin.navigation.visibilityMode.restricted")', value='restricted', color='primary')
//- .pl-8
//- v-select.pl-8.mt-3(
//- item-text='name'
//- item-value='id'
//- outlined
//- prepend-icon='mdi-account-group'
//- label='Groups'
//- :disabled='current.visibilityMode !== `restricted`'
//- v-model='current.visibilityGroups'
//- :items='groups'
//- persistent-hint
//- clearable
//- multiple
//- )
//- template(v-else)
//- v-toolbar(height='56', color='teal lighten-1', flat, dark)
//- v-card-text.grey--text(v-if='currentTree.length > 0') {{$t('navigation.noSelectionText')}}
//- v-card-text.grey--text(v-else) {{$t('navigation.noItemsText')}}
//- v-dialog(v-model='copyFromLocaleDialogIsShown', max-width='650', persistent)
//- v-card
//- .dialog-header.is-short.is-teal
//- v-icon.mr-3(color='white') mdi-arrange-send-backward
//- span {{$t('admin.navigation.copyFromLocale')}}
//- v-card-text.pt-5
//- .body-2 {{$t('admin.navigation.copyFromLocaleInfoText')}}
//- v-select.mt-3(
//- :items='locales'
//- item-text='nativeName'
//- item-value='code'
//- outlined
//- prepend-icon='mdi-web'
//- v-model='copyFromLocaleCode'
//- :label='$t(`admin.navigation.sourceLocale`)'
//- :hint='$t(`admin.navigation.sourceLocaleHint`)'
//- persistent-hint
//- )
//- v-card-chin
//- v-spacer
//- v-btn(text, @click='copyFromLocaleDialogIsShown = false') {{$t('common.actions.cancel')}}
//- v-btn.px-3(depressed, color='primary', @click='copyFromLocale')
//- v-icon(left) mdi-chevron-right
//- span {{$t('common.actions.copy')}}
//- page-selector(mode='select', v-model='selectPageModal', :open-handler='selectPageHandle', path='home', :locale='currentLang')
</template>
<script>
import _ from 'lodash'
import gql from 'graphql-tag'
import { v4 as uuid } from 'uuid'
import { createMetaMixin } from 'quasar'
import draggable from 'vuedraggable'
const siteConfig = { lang: 'en' }
const siteLangs = [{ code: 'en' }]
export default {
mixins: [
createMetaMixin(function () {
return {
title: this.$t('admin.navigation.title')
}
})
],
components: {
draggable
},
meta () {
return {
title: this.$t('admin.navigation.title')
}
},
data () {
return {
loading: false,
selectPageModal: false,
trees: [],
current: {},
currentLang: siteConfig.lang,
groups: [],
copyFromLocaleDialogIsShown: false,
config: {
mode: 'NONE'
},
allLocales: [],
copyFromLocaleCode: 'en'
}
},
computed: {
navTypes () {
return [
{ text: this.$t('navigation.navType.external'), value: 'external' },
{ text: this.$t('navigation.navType.externalblank'), value: 'externalblank' },
{ text: this.$t('navigation.navType.home'), value: 'home' },
{ text: this.$t('navigation.navType.page'), value: 'page' }
// { text: this.$t('navigation.navType.searchQuery'), value: 'search' }
]
},
locales () {
return _.intersectionBy(this.allLocales, _.unionBy(siteLangs, [{ code: 'en' }, { code: siteConfig.lang }], 'code'), 'code')
},
currentTree: {
get () {
return _.get(_.find(this.trees, ['locale', this.currentLang]), 'items', null) || []
},
set (val) {
const tree = _.find(this.trees, ['locale', this.currentLang])
if (tree) {
tree.items = val
} else {
this.trees = [...this.trees, {
locale: this.currentLang,
items: val
}]
}
}
}
},
watch: {
currentLang (newValue, oldValue) {
this.$nextTick(() => {
if (this.currentTree.length > 0) {
this.current = this.currentTree[0]
} else {
this.current = {}
}
})
}
},
methods: {
async load () {
},
addItem (kind) {
let newItem = {
id: uuid(),
kind,
visibilityMode: 'all',
visibilityGroups: []
}
switch (kind) {
case 'link':
newItem = {
...newItem,
label: this.$t('navigation.untitled', { kind: this.$t('navigation.link') }),
icon: 'mdi-chevron-right',
targetType: 'home',
target: ''
}
break
case 'header':
newItem.label = this.$t('navigation.untitled', { kind: this.$t('navigation.header') })
break
}
this.currentTree = [...this.currentTree, newItem]
this.current = newItem
},
deleteItem (item) {
this.currentTree = _.pull(this.currentTree, item)
this.current = {}
},
selectItem (item) {
this.current = item
},
selectPage () {
this.selectPageModal = true
},
selectPageHandle ({ path, locale }) {
this.current.target = `/${locale}/${path}`
},
copyFromLocale () {
this.copyFromLocaleDialogIsShown = false
this.currentTree = [...this.currentTree, ..._.get(_.find(this.trees, ['locale', this.copyFromLocaleCode]), 'items', null) || []]
},
async save () {
this.$store.commit('loadingStart', 'admin-navigation-save')
try {
const resp = await this.$apollo.mutate({
mutation: gql`
mutation ($tree: [NavigationTreeInput]!, $mode: NavigationMode!) {
navigation{
updateTree(tree: $tree) {
responseResult {
succeeded
errorCode
slug
message
}
},
updateConfig(mode: $mode) {
responseResult {
succeeded
errorCode
slug
message
}
}
}
}
`,
variables: {
tree: this.trees,
mode: this.config.mode
}
})
if (_.get(resp, 'data.navigation.updateTree.responseResult.succeeded', false) && _.get(resp, 'data.navigation.updateConfig.responseResult.succeeded', false)) {
this.$store.commit('showNotification', {
message: this.$t('navigation.saveSuccess'),
style: 'success',
icon: 'check'
})
} else {
throw new Error(_.get(resp, 'data.navigation.updateTree.responseResult.message', 'An unexpected error occurred.'))
}
} catch (err) {
this.$store.commit('pushGraphError', err)
}
this.$store.commit('loadingStop', 'admin-navigation-save')
},
async refresh () {
await this.$apollo.queries.trees.refetch()
this.current = {}
this.$store.commit('showNotification', {
message: 'Navigation has been refreshed.',
style: 'success',
icon: 'cached'
})
}
}
// apollo: {
// config: {
// query: gql`
// {
// navigation {
// config {
// mode
// }
// }
// }
// `,
// fetchPolicy: 'network-only',
// update: (data) => _.cloneDeep(data.navigation.config),
// watchLoading (isLoading) {
// this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-navigation-config')
// }
// },
// trees: {
// query: gql`
// {
// navigation {
// tree {
// locale
// items {
// id
// kind
// label
// icon
// targetType
// target
// visibilityMode
// visibilityGroups
// }
// }
// }
// }
// `,
// fetchPolicy: 'network-only',
// update: (data) => _.cloneDeep(data.navigation.tree),
// watchLoading (isLoading) {
// this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-navigation-tree')
// }
// },
// groups: {
// query: gql`
// query {
// groups {
// list {
// id
// name
// isSystem
// userCount
// createdAt
// updatedAt
// }
// }
// }
// `,
// fetchPolicy: 'network-only',
// update: (data) => data.groups.list,
// watchLoading (isLoading) {
// this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-navigation-groups')
// }
// },
// allLocales: {
// query: gql`
// {
// localization {
// locales {
// code
// name
// nativeName
// }
// }
// }
// `,
// fetchPolicy: 'network-only',
// update: (data) => data.localization.locales,
// watchLoading (isLoading) {
// this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-navigation-locales')
// }
// }
// }
}
</script>
<style lang='scss' scoped>
.clickable {
cursor: pointer;
&:hover {
background-color: rgba($blue-5, .25);
}
}
</style>
<template lang='pug'>
v-container(fluid, grid-list-lg)
v-layout(row wrap)
v-flex(xs12)
.admin-header
img.animated.fadeInUp(src='/_assets/svg/icon-file.svg', alt='Page', style='width: 80px;')
.admin-header-title
.headline.blue--text.text--darken-2.animated.fadeInLeft Pages
.subtitle-1.grey--text.animated.fadeInLeft.wait-p2s Manage pages
v-spacer
v-btn.animated.fadeInDown.wait-p1s(icon, color='grey', outlined, @click='refresh')
v-icon.grey--text mdi-refresh
v-btn.animated.fadeInDown.mx-3(color='primary', outlined, @click='recyclebin', disabled)
v-icon(left) mdi-delete-outline
span Recycle Bin
v-btn.animated.fadeInDown(color='primary', depressed, large, to='pages/visualize')
v-icon(left) mdi-graph
span Visualize
v-card.mt-3.animated.fadeInUp
.pa-2.d-flex.align-center(:class='$vuetify.theme.dark ? `grey darken-3-d5` : `grey lighten-3`')
v-text-field(
solo
flat
v-model='search'
prepend-inner-icon='mdi-file-search-outline'
label='Search Pages...'
hide-details
dense
style='max-width: 400px;'
)
v-spacer
v-select.ml-2(
solo
flat
hide-details
dense
label='Locale'
:items='langs'
v-model='selectedLang'
style='max-width: 250px;'
)
v-select.ml-2(
solo
flat
hide-details
dense
label='Publish State'
:items='states'
v-model='selectedState'
style='max-width: 250px;'
)
v-divider
v-data-table(
:items='filteredPages'
:headers='headers'
:search='search'
:page.sync='pagination'
:items-per-page='15'
:loading='loading'
must-sort,
sort-by='updatedAt',
sort-desc,
hide-default-footer
)
template(slot='item', slot-scope='props')
tr.is-clickable(:active='props.selected', @click='$router.push(`/pages/` + props.item.id)')
td.text-xs-right {{ props.item.id }}
td
.body-2: strong {{ props.item.title }}
.caption {{ props.item.description }}
td.admin-pages-path
v-chip(label, small, :color='$vuetify.theme.dark ? `grey darken-4` : `grey lighten-4`') {{ props.item.locale }}
span.ml-2.grey--text(:class='$vuetify.theme.dark ? `text--lighten-1` : `text--darken-2`') / {{ props.item.path }}
td {{ props.item.createdAt | moment('calendar') }}
td {{ props.item.updatedAt | moment('calendar') }}
template(slot='no-data')
v-alert.ma-3(icon='mdi-alert', :value='true', outlined) No pages to display.
.text-center.py-2.animated.fadeInDown(v-if='this.pageTotal > 1')
v-pagination(v-model='pagination', :length='pageTotal')
</template>
<script>
import _ from 'lodash'
import pagesQuery from 'gql/admin/pages/pages-query-list.gql'
export default {
data() {
return {
selectedPage: {},
pagination: 1,
pages: [],
headers: [
{ text: 'ID', value: 'id', width: 80, sortable: true },
{ text: 'Title', value: 'title' },
{ text: 'Path', value: 'path' },
{ text: 'Created', value: 'createdAt', width: 250 },
{ text: 'Last Updated', value: 'updatedAt', width: 250 }
],
search: '',
selectedLang: null,
selectedState: null,
states: [
{ text: 'All Publishing States', value: null },
{ text: 'Published', value: true },
{ text: 'Not Published', value: false }
],
loading: false
}
},
computed: {
pageTotal () {
return Math.ceil(this.filteredPages.length / 15)
},
filteredPages () {
return _.filter(this.pages, pg => {
if (this.selectedLang !== null && this.selectedLang !== pg.locale) {
return false
}
if (this.selectedState !== null && this.selectedState !== pg.isPublished) {
return false
}
return true
})
},
langs () {
return _.concat({
text: 'All Locales',
value: null
}, _.uniqBy(this.pages, 'locale').map(pg => ({
text: pg.locale,
value: pg.locale
})))
}
},
methods: {
async refresh() {
await this.$apollo.queries.pages.refetch()
this.$store.commit('showNotification', {
message: 'Page list has been refreshed.',
style: 'success',
icon: 'cached'
})
},
newpage() {
this.pageSelectorShown = true
},
recyclebin () { }
},
apollo: {
pages: {
query: pagesQuery,
fetchPolicy: 'network-only',
update: (data) => data.pages.list,
watchLoading (isLoading) {
this.loading = isLoading
this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-pages-refresh')
}
}
}
}
</script>
<style lang='scss'>
.admin-pages-path {
display: flex;
justify-content: flex-start;
align-items: center;
font-family: 'Roboto Mono', monospace;
}
</style>
<template lang='pug'>
v-container(fluid, grid-list-lg)
v-layout(row, wrap, v-if='page.id')
v-flex(xs12)
.admin-header
img.animated.fadeInUp(src='/_assets/svg/icon-view-details.svg', alt='Edit Page', style='width: 80px;')
.admin-header-title
.headline.blue--text.text--darken-2.animated.fadeInLeft Page Details
.subtitle-1.grey--text.animated.fadeInLeft.wait-p2s
v-chip.ml-0.mr-2(label, small).caption ID {{page.id}}
span /{{page.locale}}/{{page.path}}
v-spacer
template(v-if='page.isPublished')
status-indicator.mr-3(positive, pulse)
.caption.green--text {{$t('common.page.published')}}
template(v-else)
status-indicator.mr-3(negative, pulse)
.caption.red--text {{$t('common.page.unpublished')}}
template(v-if='page.isPrivate')
status-indicator.mr-3.ml-4(intermediary, pulse)
.caption.deep-orange--text {{$t('common.page.private')}}
template(v-else)
status-indicator.mr-3.ml-4(active, pulse)
.caption.blue--text {{$t('common.page.global')}}
v-spacer
v-btn.animated.fadeInDown.wait-p3s(color='grey', icon, outlined, to='/pages')
v-icon mdi-arrow-left
v-menu(offset-y, origin='top right')
template(v-slot:activator='{ on }')
v-btn.mx-3.animated.fadeInDown.wait-p2s(color='black', v-on='on', depressed, dark)
span Actions
v-icon(right) mdi-chevron-down
v-list(dense, nav)
v-list-item(:href='`/` + page.locale + `/` + page.path')
v-list-item-icon
v-icon(color='indigo') mdi-text-subject
v-list-item-title View
v-list-item(:href='`/e/` + page.locale + `/` + page.path')
v-list-item-icon
v-icon(color='indigo') mdi-pencil
v-list-item-title Edit
v-list-item(@click='', disabled)
v-list-item-icon
v-icon(color='grey') mdi-cube-scan
v-list-item-title Re-Render
v-list-item(@click='', disabled)
v-list-item-icon
v-icon(color='grey') mdi-earth-remove
v-list-item-title Unpublish
v-list-item(:href='`/s/` + page.locale + `/` + page.path')
v-list-item-icon
v-icon(color='indigo') mdi-code-tags
v-list-item-title View Source
v-list-item(:href='`/h/` + page.locale + `/` + page.path')
v-list-item-icon
v-icon(color='indigo') mdi-history
v-list-item-title View History
v-list-item(@click='', disabled)
v-list-item-icon
v-icon(color='grey') mdi-content-duplicate
v-list-item-title Duplicate
v-list-item(@click='', disabled)
v-list-item-icon
v-icon(color='grey') mdi-content-save-move-outline
v-list-item-title Move / Rename
v-dialog(v-model='deletePageDialog', max-width='500')
template(v-slot:activator='{ on }')
v-list-item(v-on='on')
v-list-item-icon
v-icon(color='red') mdi-trash-can-outline
v-list-item-title Delete
v-card
.dialog-header.is-short.is-red
v-icon.mr-2(color='white') mdi-file-document-box-remove-outline
span {{$t('common.page.delete')}}
v-card-text.pt-5
i18next.body-2(path='common.page.deleteTitle', tag='div')
span.red--text.text--darken-2(place='title') {{page.title}}
.caption {{$t('common.page.deleteSubtitle')}}
v-chip.mt-3.ml-0.mr-1(label, color='red lighten-4', disabled, small)
.caption.red--text.text--darken-2 {{page.locale.toUpperCase()}}
v-chip.mt-3.mx-0(label, color='red lighten-5', disabled, small)
span.red--text.text--darken-2 /{{page.path}}
v-card-chin
v-spacer
v-btn(text, @click='deletePageDialog = false', :disabled='loading') {{$t('common.actions.cancel')}}
v-btn(color='red darken-2', @click='deletePage', :loading='loading').white--text {{$t('common.actions.delete')}}
v-btn.animated.fadeInDown(color='success', large, depressed, disabled)
v-icon(left) mdi-check
span Save Changes
v-flex(xs12, lg6)
v-card.animated.fadeInUp
v-toolbar(color='primary', dense, dark, flat)
v-icon.mr-2 mdi-text-subject
span Properties
v-list.py-0(two-line, dense)
v-list-item
v-list-item-content
v-list-item-title: .overline.grey--text Title
v-list-item-subtitle.body-2(:class='$vuetify.theme.dark ? `grey--text text--lighten-2` : `grey--text text--darken-3`') {{ page.title }}
v-divider
v-list-item
v-list-item-content
v-list-item-title: .overline.grey--text Description
v-list-item-subtitle.body-2(:class='$vuetify.theme.dark ? `grey--text text--lighten-2` : `grey--text text--darken-3`') {{ page.description || '-' }}
v-divider
v-list-item
v-list-item-content
v-list-item-title: .overline.grey--text Locale
v-list-item-subtitle.body-2(:class='$vuetify.theme.dark ? `grey--text text--lighten-2` : `grey--text text--darken-3`') {{ page.locale }}
v-divider
v-list-item
v-list-item-content
v-list-item-title: .overline.grey--text Path
v-list-item-subtitle.body-2(:class='$vuetify.theme.dark ? `grey--text text--lighten-2` : `grey--text text--darken-3`') {{ page.path }}
v-divider
v-list-item
v-list-item-content
v-list-item-title: .overline.grey--text Editor
v-list-item-subtitle.body-2(:class='$vuetify.theme.dark ? `grey--text text--lighten-2` : `grey--text text--darken-3`') {{ page.editor || '?' }}
v-divider
v-list-item
v-list-item-content
v-list-item-title: .overline.grey--text Content Type
v-list-item-subtitle.body-2(:class='$vuetify.theme.dark ? `grey--text text--lighten-2` : `grey--text text--darken-3`') {{ page.contentType || '?' }}
v-divider
v-list-item
v-list-item-content
v-list-item-title: .overline.grey--text Page Hash
v-list-item-subtitle.body-2(:class='$vuetify.theme.dark ? `grey--text text--lighten-2` : `grey--text text--darken-3`') {{ page.hash }}
v-flex(xs12, lg6)
v-card.animated.fadeInUp.wait-p2s
v-toolbar(color='primary', dense, dark, flat)
v-icon.mr-2 mdi-account-multiple
span Users
v-list.py-0(two-line, dense)
v-list-item
v-list-item-avatar(size='24')
v-btn(icon, :to='`/users/` + page.creatorId')
v-icon(color='grey') mdi-account
v-list-item-content
v-list-item-title: .overline.grey--text Creator
v-list-item-subtitle.body-2(:class='$vuetify.theme.dark ? `grey--text text--lighten-2` : `grey--text text--darken-3`') {{ page.creatorName }} #[em.caption ({{ page.creatorEmail }})]
v-list-item-action
v-list-item-action-text {{ page.createdAt | moment('calendar') }}
v-divider
v-list-item
v-list-item-avatar(size='24')
v-btn(icon, :to='`/users/` + page.authorId')
v-icon(color='grey') mdi-account
v-list-item-content
v-list-item-title: .overline.grey--text Last Editor
v-list-item-subtitle.body-2(:class='$vuetify.theme.dark ? `grey--text text--lighten-2` : `grey--text text--darken-3`') {{ page.authorName }} #[em.caption ({{ page.authorEmail }})]
v-list-item-action
v-list-item-action-text {{ page.updatedAt | moment('calendar') }}
v-layout(row, align-center, v-else)
v-progress-circular(indeterminate, width='2', color='grey')
.body-2.pl-3.grey--text {{ $t('common.page.loading') }}
</template>
<script>
import _ from 'lodash'
import { StatusIndicator } from 'vue-status-indicator'
import pageQuery from 'gql/admin/pages/pages-query-single.gql'
import deletePageMutation from 'gql/common/common-pages-mutation-delete.gql'
export default {
components: {
StatusIndicator
},
data() {
return {
deletePageDialog: false,
page: {},
loading: false
}
},
methods: {
async deletePage() {
this.loading = true
this.$store.commit(`loadingStart`, 'page-delete')
try {
const resp = await this.$apollo.mutate({
mutation: deletePageMutation,
variables: {
id: this.page.id
}
})
if (_.get(resp, 'data.pages.delete.responseResult.succeeded', false)) {
this.$store.commit('showNotification', {
style: 'green',
message: `Page deleted successfully.`,
icon: 'check'
})
this.$router.replace('/pages')
} else {
throw new Error(_.get(resp, 'data.pages.delete.responseResult.message', this.$t('common.error.unexpected')))
}
} catch (err) {
this.$store.commit('pushGraphError', err)
}
this.$store.commit(`loadingStop`, 'page-delete')
},
async rerenderPage() {
this.$store.commit('showNotification', {
style: 'indigo',
message: `Coming soon...`,
icon: 'directions_boat'
})
}
},
apollo: {
page: {
query: pageQuery,
variables() {
return {
id: _.toSafeInteger(this.$route.params.id)
}
},
fetchPolicy: 'network-only',
update: (data) => data.pages.single,
watchLoading (isLoading) {
this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-pages-refresh')
}
}
}
}
</script>
<style lang='scss'>
</style>
<template lang='pug'>
v-container(fluid, grid-list-lg)
v-layout(row wrap)
v-flex(xs12)
.admin-header
img.animated.fadeInUp(src='/_assets/svg/icon-venn-diagram.svg', alt='Visualize Pages', style='width: 80px;')
.admin-header-title
.headline.blue--text.text--darken-2.animated.fadeInLeft Visualize Pages
.subtitle-1.grey--text.animated.fadeInLeft.wait-p2s Dendrogram representation of your pages
v-spacer
v-select.mx-5.animated.fadeInDown.wait-p1s(
v-if='locales.length > 0'
v-model='currentLocale'
:items='locales'
style='flex: 0 1 120px;'
solo
dense
hide-details
item-value='code'
item-text='name'
)
v-btn-toggle.animated.fadeInDown(v-model='graphMode', color='primary', dense, rounded)
v-btn.px-5(value='htree')
v-icon(left, :color='graphMode === `htree` ? `primary` : `grey darken-3`') mdi-sitemap
span.text-none Hierarchical Tree
v-btn.px-5(value='hradial')
v-icon(left, :color='graphMode === `hradial` ? `primary` : `grey darken-3`') mdi-chart-donut-variant
span.text-none Hierarchical Radial
v-btn.px-5(value='rradial')
v-icon(left, :color='graphMode === `rradial` ? `primary` : `grey darken-3`') mdi-blur-radial
span.text-none Relational Radial
.admin-pages-visualize-svg(ref='svgContainer', v-show='pages.length >= 1')
v-alert(v-if='pages.length < 1', outlined, type='warning', style='max-width: 650px; margin: 0 auto;') Looks like there's no data yet to graph!
</template>
<script>
import _ from 'lodash'
import * as d3 from 'd3'
import gql from 'graphql-tag'
/* global siteConfig, siteLangs */
export default {
data() {
return {
graphMode: 'htree',
width: 800,
radius: 400,
pages: [],
locales: siteLangs,
currentLocale: siteConfig.lang
}
},
watch: {
pages () {
this.redraw()
},
graphMode () {
this.redraw()
}
},
methods: {
goToPage (d) {
const id = d.data.id
if (id) {
if (d3.event.ctrlKey || d3.event.metaKey) {
const { href } = this.$router.resolve(String(id))
window.open(href, '_blank')
} else {
this.$router.push(String(id))
}
}
},
bilink (root) {
const map = new Map(root.descendants().map(d => [d.data.path, d]))
for (const d of root.descendants()) {
d.incoming = []
d.outgoing = []
d.data.links.forEach(i => {
const relNode = map.get(i)
if (relNode) {
d.outgoing.push([d, relNode])
}
})
}
for (const d of root.descendants()) {
for (const o of d.outgoing) {
if (o[1]) {
o[1].incoming.push(o)
}
}
}
return root
},
hierarchy (pages) {
const map = new Map(pages.map(p => [p.path, p]))
const getPage = path => map.get(path) || {
path: path,
title: path.split('/').slice(-1)[0],
links: []
}
function recurse (depth, [parent, descendants]) {
const truncatePath = path => _.take(path.split('/'), depth).join('/')
const descendantsByChild =
Object.entries(_.groupBy(descendants, page => truncatePath(page.path)))
.map(([childPath, descendantsGroup]) => [getPage(childPath), descendantsGroup])
.map(([child, descendantsGroup]) =>
[child, _.filter(descendantsGroup, d => d.path !== child.path)])
return {
...parent,
children: descendantsByChild.map(_.partial(recurse, depth + 1))
}
}
const root = { path: this.currentLocale, title: this.currentLocale, links: [] }
// start at depth=2 because we're taking {locale} as the root and
// all paths start with {locale}/
return recurse(2, [root, pages])
},
/**
* Relational Radial
*/
drawRelations () {
const data = this.hierarchy(this.pages)
const line = d3.lineRadial()
.curve(d3.curveBundle.beta(0.85))
.radius(d => d.y)
.angle(d => d.x)
const tree = d3.cluster()
.size([2 * Math.PI, this.radius - 100])
const root = tree(this.bilink(d3.hierarchy(data)
.sort((a, b) => d3.ascending(a.height, b.height) || d3.ascending(a.data.path, b.data.path))))
const svg = d3.create('svg')
.attr('viewBox', [-this.width / 2, -this.width / 2, this.width, this.width])
const g = svg.append('g')
svg.call(d3.zoom().on('zoom', function() {
g.attr('transform', d3.event.transform)
}))
const link = g.append('g')
.attr('stroke', '#CCC')
.attr('fill', 'none')
.selectAll('path')
.data(root.descendants().flatMap(leaf => leaf.outgoing))
.join('path')
.style('mix-blend-mode', 'multiply')
.attr('d', ([i, o]) => line(i.path(o)))
.each(function(d) { d.path = this })
g.append('g')
.attr('font-family', 'sans-serif')
.attr('font-size', 10)
.selectAll('g')
.data(root.descendants())
.join('g')
.attr('transform', d => `rotate(${d.x * 180 / Math.PI - 90}) translate(${d.y},0)`)
.append('text')
.attr('dy', '0.31em')
.attr('x', d => d.x < Math.PI ? 6 : -6)
.attr('text-anchor', d => d.x < Math.PI ? 'start' : 'end')
.attr('transform', d => d.x >= Math.PI ? 'rotate(180)' : null)
.attr('fill', this.$vuetify.theme.dark ? 'white' : '')
.attr('cursor', 'pointer')
.text(d => d.data.title)
.each(function(d) { d.text = this })
.on('mouseover', overed)
.on('mouseout', outed)
.on('click', d => this.goToPage(d))
.call(text => text.append('title').text(d => `${d.data.path}
${d.outgoing.length} outgoing
${d.incoming.length} incoming`))
.clone(true).lower()
.attr('stroke', this.$vuetify.theme.dark ? '#222' : 'white')
function overed(d) {
link.style('mix-blend-mode', null)
d3.select(this).attr('font-weight', 'bold')
d3.selectAll(d.incoming.map(d => d.path)).attr('stroke', '#2196F3').raise()
d3.selectAll(d.incoming.map(([d]) => d.text)).attr('fill', '#2196F3').attr('font-weight', 'bold')
d3.selectAll(d.outgoing.map(d => d.path)).attr('stroke', '#E91E63').raise()
d3.selectAll(d.outgoing.map(([, d]) => d.text)).attr('fill', '#E91E63').attr('font-weight', 'bold')
}
function outed(d) {
link.style('mix-blend-mode', 'multiply')
d3.select(this).attr('font-weight', null)
d3.selectAll(d.incoming.map(d => d.path)).attr('stroke', null)
d3.selectAll(d.incoming.map(([d]) => d.text)).attr('fill', null).attr('font-weight', null)
d3.selectAll(d.outgoing.map(d => d.path)).attr('stroke', null)
d3.selectAll(d.outgoing.map(([, d]) => d.text)).attr('fill', null).attr('font-weight', null)
}
this.$refs.svgContainer.appendChild(svg.node())
},
/**
* Hierarchical Tree
*/
drawTree () {
const data = this.hierarchy(this.pages)
const treeRoot = d3.hierarchy(data)
treeRoot.dx = 10
treeRoot.dy = this.width / (treeRoot.height + 1)
const root = d3.tree().nodeSize([treeRoot.dx, treeRoot.dy])(treeRoot)
let x0 = Infinity
let x1 = -x0
root.each(d => {
if (d.x > x1) x1 = d.x
if (d.x < x0) x0 = d.x
})
const svg = d3.create('svg')
.attr('viewBox', [0, 0, this.width, x1 - x0 + root.dx * 2])
// this extra level is necessary because the element that we
// apply the zoom tranform to must be above the element where
// we apply the translation (`g`), or else zoom is wonky
const gZoom = svg.append('g')
svg.call(d3.zoom().on('zoom', function() {
gZoom.attr('transform', d3.event.transform)
}))
const g = gZoom.append('g')
.attr('font-family', 'sans-serif')
.attr('font-size', 10)
.attr('transform', `translate(${root.dy / 3},${root.dx - x0})`)
g.append('g')
.attr('fill', 'none')
.attr('stroke', this.$vuetify.theme.dark ? '#999' : '#555')
.attr('stroke-opacity', 0.4)
.attr('stroke-width', 1.5)
.selectAll('path')
.data(root.links())
.join('path')
.attr('d', d3.linkHorizontal()
.x(d => d.y)
.y(d => d.x))
const node = g.append('g')
.attr('stroke-linejoin', 'round')
.attr('stroke-width', 3)
.selectAll('g')
.data(root.descendants())
.join('g')
.attr('transform', d => `translate(${d.y},${d.x})`)
node.append('circle')
.attr('fill', d => d.children ? '#555' : '#999')
.attr('r', 2.5)
node.append('text')
.attr('dy', '0.31em')
.attr('x', d => d.children ? -6 : 6)
.attr('text-anchor', d => d.children ? 'end' : 'start')
.attr('fill', this.$vuetify.theme.dark ? 'white' : '')
.attr('cursor', 'pointer')
.text(d => d.data.title)
.on('click', d => this.goToPage(d))
.clone(true).lower()
.attr('stroke', this.$vuetify.theme.dark ? '#222' : 'white')
this.$refs.svgContainer.appendChild(svg.node())
},
/**
* Hierarchical Radial
*/
drawRadialTree () {
const data = this.hierarchy(this.pages)
const tree = d3.tree()
.size([2 * Math.PI, this.radius])
.separation((a, b) => (a.parent === b.parent ? 1 : 2) / a.depth)
const root = tree(d3.hierarchy(data)
.sort((a, b) => d3.ascending(a.data.title, b.data.title)))
const svg = d3.create('svg')
.style('font', '10px sans-serif')
const g = svg.append('g')
svg.call(d3.zoom().on('zoom', function () {
g.attr('transform', d3.event.transform)
}))
// eslint-disable-next-line no-unused-vars
const link = g.append('g')
.attr('fill', 'none')
.attr('stroke', this.$vuetify.theme.dark ? 'white' : '#555')
.attr('stroke-opacity', 0.4)
.attr('stroke-width', 1.5)
.selectAll('path')
.data(root.links())
.join('path')
.attr('d', d3.linkRadial()
.angle(d => d.x)
.radius(d => d.y))
const node = g.append('g')
.attr('stroke-linejoin', 'round')
.attr('stroke-width', 3)
.selectAll('g')
.data(root.descendants().reverse())
.join('g')
.attr('transform', d => `
rotate(${d.x * 180 / Math.PI - 90})
translate(${d.y},0)
`)
node.append('circle')
.attr('fill', d => d.children ? '#555' : '#999')
.attr('r', 2.5)
node.append('text')
.attr('dy', '0.31em')
/* eslint-disable no-mixed-operators */
.attr('x', d => d.x < Math.PI === !d.children ? 6 : -6)
.attr('text-anchor', d => d.x < Math.PI === !d.children ? 'start' : 'end')
.attr('transform', d => d.x >= Math.PI ? 'rotate(180)' : null)
/* eslint-enable no-mixed-operators */
.attr('fill', this.$vuetify.theme.dark ? 'white' : '')
.attr('cursor', 'pointer')
.text(d => d.data.title)
.on('click', d => this.goToPage(d))
.clone(true).lower()
.attr('stroke', this.$vuetify.theme.dark ? '#222' : 'white')
this.$refs.svgContainer.appendChild(svg.node())
function autoBox() {
const {x, y, width, height} = this.getBBox()
return [x, y, width, height]
}
svg.attr('viewBox', autoBox)
},
redraw () {
while (this.$refs.svgContainer.firstChild) {
this.$refs.svgContainer.firstChild.remove()
}
if (this.pages.length > 0) {
switch (this.graphMode) {
case 'rradial':
this.drawRelations()
break
case 'htree':
this.drawTree()
break
case 'hradial':
this.drawRadialTree()
break
}
}
}
},
apollo: {
pages: {
query: gql`
query ($locale: String!) {
pages {
links(locale: $locale) {
id
path
title
links
}
}
}
`,
variables () {
return {
locale: this.currentLocale
}
},
fetchPolicy: 'network-only',
update: (data) => data.pages.links,
watchLoading (isLoading) {
this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-pages-refresh')
}
}
}
}
</script>
<style lang='scss'>
.admin-pages-visualize-svg {
text-align: center;
// 100vh - header - title section - footer - content padding
height: calc(100vh - 64px - 92px - 32px - 16px);
> svg {
height: 100%;
width: 100%;
}
}
</style>
<template lang='pug'>
q-page.admin-mail
.row.q-pa-md.items-center
.col-auto
img.admin-icon.animated.fadeInLeft(src='/_assets/icons/fluent-rich-text-converter.svg')
.col.q-pl-md
.text-h5.text-primary.animated.fadeInLeft {{ $t('admin.rendering.title') }}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s {{ $t('admin.rendering.subtitle') }}
.col-auto
q-btn.q-mr-sm.acrylic-btn(
icon='las la-question-circle'
flat
color='grey'
href='https://docs.js.wiki/admin/rendering'
target='_blank'
type='a'
)
q-btn.q-mr-sm.acrylic-btn(
icon='las la-redo-alt'
flat
color='secondary'
:loading='loading > 0'
@click='load'
)
q-btn(
unelevated
icon='mdi-check'
:label='$t(`common.actions.apply`)'
color='secondary'
@click='save'
:disabled='loading > 0'
)
q-separator(inset)
//- v-container(fluid, grid-list-lg)
//- v-layout(row, wrap)
//- v-flex(xs12)
//- .admin-header
//- img.animated.fadeInUp(src='/_assets/svg/icon-process.svg', alt='Rendering', style='width: 80px;')
//- .admin-header-title
//- .headline.primary--text.animated.fadeInLeft {{ $t('admin.rendering.title') }}
//- .subtitle-1.grey--text.animated.fadeInLeft.wait-p4s {{ $t('admin.rendering.subtitle') }}
//- v-spacer
//- v-btn.animated.fadeInDown.wait-p3s(icon, outlined, color='grey', href='https://docs.requarks.io/rendering', target='_blank')
//- v-icon mdi-help-circle
//- v-btn.mx-3.animated.fadeInDown.wait-p2s(icon, outlined, color='grey', @click='refresh')
//- v-icon mdi-refresh
//- v-btn.animated.fadeInDown(color='success', @click='save', depressed, large)
//- v-icon(left) mdi-check
//- span {{$t('common.actions.apply')}}
//- v-flex.animated.fadeInUp(lg3, xs12)
//- v-toolbar(
//- color='blue darken-2'
//- dense
//- flat
//- dark
//- )
//- .subtitle-1 Pipeline
//- v-expansion-panels.adm-rendering-pipeline(
//- v-model='selectedCore'
//- accordion
//- mandatory
//- )
//- v-expansion-panel(
//- v-for='core in renderers'
//- :key='core.key'
//- )
//- v-expansion-panel-header(
//- hide-actions
//- ripple
//- )
//- v-toolbar(
//- color='blue'
//- dense
//- dark
//- flat
//- )
//- v-spacer
//- .body-2 {{core.input}}
//- v-icon.mx-2 mdi-arrow-right-circle
//- .caption {{core.output}}
//- v-spacer
//- v-expansion-panel-content
//- v-list.py-0(two-line, dense)
//- template(v-for='(rdr, n) in core.children')
//- v-list-item(
//- :key='rdr.key'
//- @click='selectRenderer(rdr.key)'
//- :class='currentRenderer.key === rdr.key ? ($vuetify.theme.dark ? `grey darken-4-l4` : `blue lighten-5`) : ``'
//- )
//- v-list-item-avatar(size='24', tile)
//- v-icon(:color='currentRenderer.key === rdr.key ? "primary" : "grey"') {{rdr.icon}}
//- v-list-item-content
//- v-list-item-title {{rdr.title}}
//- v-list-item-subtitle: .caption {{rdr.description}}
//- v-list-item-avatar(size='24')
//- status-indicator(v-if='rdr.isEnabled', positive, pulse)
//- status-indicator(v-else, negative, pulse)
//- v-divider.my-0(v-if='n < core.children.length - 1')
//- v-flex(lg9, xs12)
//- v-card.wiki-form.animated.fadeInUp
//- v-toolbar(
//- color='indigo'
//- dark
//- flat
//- dense
//- )
//- v-icon.mr-2 {{currentRenderer.icon}}
//- .subtitle-1 {{currentRenderer.title}}
//- v-spacer
//- v-switch(
//- dark
//- color='white'
//- label='Enabled'
//- v-model='currentRenderer.isEnabled'
//- hide-details
//- inset
//- )
//- v-card-info(color='blue')
//- div
//- div {{currentRenderer.description}}
//- span.caption: a(href='https://docs.requarks.io/en/rendering', target='_blank') Documentation
//- v-card-text.pb-4.pl-4
//- .overline.mb-5 Rendering Module Configuration
//- .body-2.ml-3(v-if='!currentRenderer.config || currentRenderer.config.length < 1'): em This rendering module has no configuration options you can modify.
//- template(v-else, v-for='(cfg, idx) in currentRenderer.config')
//- v-select(
//- v-if='cfg.value.type === "string" && cfg.value.enum'
//- outlined
//- :items='cfg.value.enum'
//- :key='cfg.key'
//- :label='cfg.value.title'
//- v-model='cfg.value.value'
//- :hint='cfg.value.hint ? cfg.value.hint : ""'
//- persistent-hint
//- :class='cfg.value.hint ? "mb-2" : ""'
//- color='indigo'
//- )
//- v-switch(
//- v-else-if='cfg.value.type === "boolean"'
//- :key='cfg.key'
//- :label='cfg.value.title'
//- v-model='cfg.value.value'
//- color='indigo'
//- :hint='cfg.value.hint ? cfg.value.hint : ""'
//- persistent-hint
//- inset
//- )
//- v-text-field(
//- v-else
//- outlined
//- :key='cfg.key'
//- :label='cfg.value.title'
//- v-model='cfg.value.value'
//- :hint='cfg.value.hint ? cfg.value.hint : ""'
//- persistent-hint
//- :class='cfg.value.hint ? "mb-2" : ""'
//- color='indigo'
//- )
//- v-divider.my-5(v-if='idx < currentRenderer.config.length - 1')
//- v-card-chin
//- v-spacer
//- .caption.pr-3.grey--text Module: {{ currentRenderer.key }}
</template>
<script>
import cloneDeep from 'lodash/cloneDeep'
import concat from 'lodash/concat'
import filter from 'lodash/filter'
import find from 'lodash/find'
import findIndex from 'lodash/findIndex'
import reduce from 'lodash/reduce'
import reverse from 'lodash/reverse'
import sortBy from 'lodash/sortBy'
import { DepGraph } from 'dependency-graph'
import gql from 'graphql-tag'
export default {
data () {
return {
selectedCore: -1,
renderers: [],
currentRenderer: {}
}
},
watch: {
renderers (newValue, oldValue) {
setTimeout(() => {
this.selectedCore = findIndex(newValue, ['key', 'markdownCore'])
this.selectRenderer('markdownCore')
}, 500)
}
},
methods: {
async load () {
this.loading++
try {
const resp = await this.$apollo.query({
query: gql`
query getRenderingConfig {
mailConfig {
senderName
senderEmail
host
port
secure
verifySSL
user
pass
useDKIM
dkimDomainName
dkimKeySelector
dkimPrivateKey
}
}
`,
fetchPolicy: 'no-cache'
})
if (!resp?.data?.mailConfig) {
throw new Error('Failed to fetch mail config.')
}
const renderers = cloneDeep(resp.data.rendering.renderers).map(str => ({
...str,
config: sortBy(str.config.map(cfg => ({
...cfg,
value: JSON.parse(cfg.value)
})), [t => t.value.order])
}))
// Build tree
const graph = new DepGraph({ circular: true })
const rawCores = filter(renderers, ['dependsOn', null]).map(core => {
core.children = concat([cloneDeep(core)], filter(renderers, ['dependsOn', core.key]))
return core
})
// Build dependency graph
rawCores.forEach(core => { graph.addNode(core.key) })
rawCores.forEach(core => {
rawCores.forEach(coreTarget => {
if (core.key !== coreTarget.key) {
if (core.output === coreTarget.input) {
graph.addDependency(core.key, coreTarget.key)
}
}
})
})
// Reorder cores in reverse dependency order
const orderedCores = []
reverse(graph.overallOrder()).forEach(coreKey => {
orderedCores.push(find(rawCores, ['key', coreKey]))
})
this.renderers = orderedCores
} catch (err) {
this.$q.notify({
type: 'negative',
message: 'Failed to fetch mail config',
caption: err.message
})
}
this.loading--
},
selectRenderer (key) {
this.renderers.forEach(rdr => {
if (rdr.children.some(c => c.key === key)) {
this.currentRenderer = find(rdr.children, ['key', key])
}
})
},
async refresh () {
await this.$apollo.queries.renderers.refetch()
this.$store.commit('showNotification', {
message: 'Rendering active configuration has been reloaded.',
style: 'success',
icon: 'cached'
})
},
async save () {
this.$store.commit('loadingStart', 'admin-rendering-saverenderers')
await this.$apollo.mutate({
mutation: null,
variables: {
renderers: reduce(this.renderers, (result, core) => {
result.push(...core.children.map(rd => ({
key: rd.key,
isEnabled: rd.isEnabled,
config: rd.config.map(cfg => ({ key: cfg.key, value: JSON.stringify({ v: cfg.value.value }) }))
})))
return result
}, [])
}
})
this.$store.commit('showNotification', {
message: 'Rendering configuration saved successfully.',
style: 'success',
icon: 'check'
})
this.$store.commit('loadingStop', 'admin-rendering-saverenderers')
}
}
}
</script>
<style lang='scss'>
.adm-rendering-pipeline {
.v-expansion-panel--active .v-expansion-panel-header {
min-height: 0;
}
.v-expansion-panel-header {
padding: 0;
margin-top: 1px;
}
.v-expansion-panel-content__wrap {
padding: 0;
}
}
</style>
<template lang='pug'>
q-page.admin-mail
.row.q-pa-md.items-center
.col-auto
img.admin-icon.animated.fadeInLeft(src='/_assets/icons/fluent-protect.svg')
.col.q-pl-md
.text-h5.text-primary.animated.fadeInLeft {{ $t('admin.security.title') }}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s {{ $t('admin.security.subtitle') }}
.col-auto
q-btn.q-mr-sm.acrylic-btn(
icon='las la-question-circle'
flat
color='grey'
href='https://docs.js.wiki/admin/security'
target='_blank'
type='a'
)
q-btn.q-mr-sm.acrylic-btn(
icon='las la-redo-alt'
flat
color='secondary'
:loading='loading > 0'
@click='load'
)
q-btn(
unelevated
icon='mdi-check'
:label='$t(`common.actions.apply`)'
color='secondary'
@click='save'
:loading='loading > 0'
)
q-separator(inset)
.row.q-pa-md.q-col-gutter-md
.col-12.col-lg-6
//- -----------------------
//- Security
//- -----------------------
q-card.shadow-1.q-pb-sm
q-card-section
.text-subtitle1 {{$t('admin.security.title')}}
q-item.q-pt-none
q-item-section
q-card.bg-negative.text-white.rounded-borders(flat)
q-card-section.items-center(horizontal)
q-card-section.col-auto.q-pr-none
q-icon(name='las la-exclamation-triangle', size='sm')
q-card-section.text-caption {{ $t('admin.security.warn') }}
q-item(tag='label', v-ripple)
blueprint-icon(icon='rfid-signal')
q-item-section
q-item-label {{$t(`admin.security.disallowFloc`)}}
q-item-label(caption) {{$t(`admin.security.disallowFlocHint`)}}
q-item-section(avatar)
q-toggle(
v-model='config.disallowFloc'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.security.disallowFloc`)'
)
q-separator.q-my-sm(inset)
q-item(tag='label', v-ripple)
blueprint-icon(icon='maximize-window')
q-item-section
q-item-label {{$t(`admin.security.disallowIframe`)}}
q-item-label(caption) {{$t(`admin.security.disallowIframeHint`)}}
q-item-section(avatar)
q-toggle(
v-model='config.disallowIframe'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.security.disallowIframe`)'
)
q-separator.q-my-sm(inset)
q-item(tag='label', v-ripple)
blueprint-icon(icon='do-not-touch')
q-item-section
q-item-label {{$t(`admin.security.enforceSameOriginReferrerPolicy`)}}
q-item-label(caption) {{$t(`admin.security.enforceSameOriginReferrerPolicyHint`)}}
q-item-section(avatar)
q-toggle(
v-model='config.enforceSameOriginReferrerPolicy'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.security.enforceSameOriginReferrerPolicy`)'
)
q-separator.q-my-sm(inset)
q-item(tag='label', v-ripple)
blueprint-icon(icon='curly-arrow')
q-item-section
q-item-label {{$t(`admin.security.disallowOpenRedirect`)}}
q-item-label(caption) {{$t(`admin.security.disallowOpenRedirectHint`)}}
q-item-section(avatar)
q-toggle(
v-model='config.disallowOpenRedirect'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.security.disallowOpenRedirect`)'
)
q-separator.q-my-sm(inset)
q-item(tag='label', v-ripple)
blueprint-icon(icon='download-from-cloud')
q-item-section
q-item-label {{$t(`admin.security.forceAssetDownload`)}}
q-item-label(caption) {{$t(`admin.security.forceAssetDownloadHint`)}}
q-item-section(avatar)
q-toggle(
v-model='config.forceAssetDownload'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.security.forceAssetDownload`)'
)
q-separator.q-my-sm(inset)
q-item(tag='label', v-ripple)
blueprint-icon(icon='door-sensor-alarmed')
q-item-section
q-item-label {{$t(`admin.security.trustProxy`)}}
q-item-label(caption) {{$t(`admin.security.trustProxyHint`)}}
q-item-section(avatar)
q-toggle(
v-model='config.trustProxy'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.security.trustProxy`)'
)
//- -----------------------
//- HSTS
//- -----------------------
q-card.shadow-1.q-pb-sm.q-mt-md
q-card-section
.text-subtitle1 {{$t('admin.security.hsts')}}
q-item(tag='label', v-ripple)
blueprint-icon(icon='hips')
q-item-section
q-item-label {{$t(`admin.security.enforceHsts`)}}
q-item-label(caption) {{$t(`admin.security.enforceHstsHint`)}}
q-item-section(avatar)
q-toggle(
v-model='config.enforceHsts'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.security.enforceHsts`)'
)
template(v-if='config.enforceHsts')
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='timer')
q-item-section
q-item-label {{$t(`admin.security.hstsDuration`)}}
q-item-label(caption) {{$t(`admin.security.hstsDurationHint`)}}
q-item-section(style='flex: 0 0 200px;')
q-select(
outlined
v-model='config.hstsDuration'
:options='hstsDurations'
option-value='value'
option-label='text'
emit-value
map-options
dense
:aria-label='$t(`admin.security.hstsDuration`)'
)
.col-12.col-lg-6
//- -----------------------
//- Uploads
//- -----------------------
q-card.shadow-1.q-pb-sm
q-card-section
.text-subtitle1 {{$t('admin.security.uploads')}}
q-item.q-pt-none
q-item-section
q-card.bg-info.text-white.rounded-borders(flat)
q-card-section.items-center(horizontal)
q-card-section.col-auto.q-pr-none
q-icon(name='las la-info-circle', size='sm')
q-card-section.text-caption {{ $t('admin.security.uploadsInfo') }}
q-item
blueprint-icon(icon='upload-to-the-cloud')
q-item-section
q-item-label {{$t(`admin.security.maxUploadSize`)}}
q-item-label(caption) {{$t(`admin.security.maxUploadSizeHint`)}}
q-item-section(style='flex: 0 0 200px;')
q-input(
outlined
v-model.number='humanUploadMaxFileSize'
dense
:aria-label='$t(`admin.security.maxUploadSize`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='upload-to-ftp')
q-item-section
q-item-label {{$t(`admin.security.maxUploadBatch`)}}
q-item-label(caption) {{$t(`admin.security.maxUploadBatchHint`)}}
q-item-section(style='flex: 0 0 200px;')
q-input(
outlined
v-model.number='config.uploadMaxFiles'
dense
:suffix='$t(`admin.security.maxUploadBatchSuffix`)'
:aria-label='$t(`admin.security.maxUploadBatch`)'
)
q-separator.q-my-sm(inset)
q-item(tag='label', v-ripple)
blueprint-icon(icon='scan-stock')
q-item-section
q-item-label {{$t(`admin.security.scanSVG`)}}
q-item-label(caption) {{$t(`admin.security.scanSVGHint`)}}
q-item-section(avatar)
q-toggle(
v-model='config.uploadScanSVG'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.security.scanSVG`)'
)
//- -----------------------
//- CORS
//- -----------------------
q-card.shadow-1.q-pb-sm.q-mt-md
q-card-section
.text-subtitle1 {{$t('admin.security.cors')}}
q-item
blueprint-icon(icon='firewall')
q-item-section
q-item-label {{$t(`admin.security.corsMode`)}}
q-item-label(caption) {{$t(`admin.security.corsModeHint`)}}
q-item-section
q-select(
outlined
v-model='config.corsMode'
:options='corsModes'
option-value='value'
option-label='text'
emit-value
map-options
dense
:aria-label='$t(`admin.security.corsMode`)'
)
template(v-if='config.corsMode === `HOSTNAMES`')
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='todo-list', key='corsHostnames')
q-item-section
q-item-label {{$t(`admin.security.corsHostnames`)}}
q-item-label(caption) {{$t(`admin.security.corsHostnamesHint`)}}
q-item-section
q-input(
outlined
v-model='config.corsConfig'
dense
type='textarea'
:aria-label='$t(`admin.security.corsHostnames`)'
)
template(v-else-if='config.corsMode === `REGEX`')
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='validation', key='corsRegex')
q-item-section
q-item-label {{$t(`admin.security.corsRegex`)}}
q-item-label(caption) {{$t(`admin.security.corsRegexHint`)}}
q-item-section
q-input(
outlined
v-model='config.corsConfig'
dense
:aria-label='$t(`admin.security.corsRegex`)'
)
//- -----------------------
//- JWT
//- -----------------------
q-card.shadow-1.q-pb-sm.q-mt-md
q-card-section
.text-subtitle1 {{$t('admin.security.jwt')}}
q-item
blueprint-icon(icon='ticket')
q-item-section
q-item-label {{$t(`admin.security.jwtAudience`)}}
q-item-label(caption) {{$t(`admin.security.jwtAudienceHint`)}}
q-item-section(style='flex: 0 0 250px;')
q-input(
outlined
v-model='config.authJwtAudience'
dense
:aria-label='$t(`admin.security.jwtAudience`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='expired')
q-item-section
q-item-label {{$t(`admin.security.tokenExpiration`)}}
q-item-label(caption) {{$t(`admin.security.tokenExpirationHint`)}}
q-item-section(style='flex: 0 0 140px;')
q-input(
outlined
v-model='config.authJwtExpiration'
dense
:aria-label='$t(`admin.security.tokenExpiration`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='future')
q-item-section
q-item-label {{$t(`admin.security.tokenRenewalPeriod`)}}
q-item-label(caption) {{$t(`admin.security.tokenRenewalPeriodHint`)}}
q-item-section(style='flex: 0 0 140px;')
q-input(
outlined
v-model='config.authJwtRenewablePeriod'
dense
:aria-label='$t(`admin.security.tokenRenewalPeriod`)'
)
</template>
<script>
import cloneDeep from 'lodash/cloneDeep'
import gql from 'graphql-tag'
import _get from 'lodash/get'
import filesize from 'filesize'
import filesizeParser from 'filesize-parser'
import { createMetaMixin } from 'quasar'
export default {
mixins: [
createMetaMixin(function () {
return {
title: this.$t('admin.security.title')
}
})
],
data () {
return {
loading: false,
config: {
corsConfig: '',
corsMode: 'OFF',
cspDirectives: '',
disallowFloc: false,
disallowIframe: false,
disallowOpenRedirect: false,
enforceCsp: false,
enforceHsts: false,
enforceSameOriginReferrerPolicy: false,
forceAssetDownload: false,
hstsDuration: 0,
trustProxy: false,
authJwtAudience: 'urn:wiki.js',
authJwtExpiration: '30m',
authJwtRenewablePeriod: '14d',
uploadMaxFileSize: 0,
uploadMaxFiles: 0,
uploadScanSVG: false
},
humanUploadMaxFileSize: '0',
hstsDurations: [
{ value: 300, text: '5 minutes' },
{ value: 86400, text: '1 day' },
{ value: 604800, text: '1 week' },
{ value: 2592000, text: '1 month' },
{ value: 31536000, text: '1 year' },
{ value: 63072000, text: '2 years' }
]
}
},
computed: {
corsModes () {
return [
{ value: 'OFF', text: 'Off / Same-Origin' },
{ value: 'REFLECT', text: 'Reflect Request Origin' },
{ value: 'HOSTNAMES', text: 'Hostnames Whitelist' },
{ value: 'REGEX', text: 'Regex Pattern Match' }
]
}
},
mounted () {
this.load()
},
methods: {
async load () {
this.loading++
this.$q.loading.show()
const resp = await this.$apollo.query({
query: gql`
query getSecurityConfig {
systemSecurity {
authJwtAudience
authJwtExpiration
authJwtRenewablePeriod
corsConfig
corsMode
cspDirectives
disallowFloc
disallowIframe
disallowOpenRedirect
enforceCsp
enforceHsts
enforceSameOriginReferrerPolicy
forceAssetDownload
hstsDuration
trustProxy
uploadMaxFileSize
uploadMaxFiles
uploadScanSVG
}
}
`,
fetchPolicy: 'network-only'
})
this.config = cloneDeep(resp?.data?.systemSecurity)
this.humanUploadMaxFileSize = filesize(this.config.uploadMaxFileSize ?? 0, { base: 2, standard: 'jedec' })
this.$q.loading.hide()
this.loading--
},
async save () {
this.loading = true
try {
const respRaw = await this.$apollo.mutate({
mutation: gql`
mutation saveSecurityConfig (
$authJwtAudience: String
$authJwtExpiration: String
$authJwtRenewablePeriod: String
$corsConfig: String
$corsMode: SystemSecurityCorsMode
$cspDirectives: String
$disallowFloc: Boolean
$disallowIframe: Boolean
$disallowOpenRedirect: Boolean
$enforceCsp: Boolean
$enforceHsts: Boolean
$enforceSameOriginReferrerPolicy: Boolean
$hstsDuration: Int
$trustProxy: Boolean
$uploadMaxFiles: Int
$uploadMaxFileSize: Int
) {
updateSystemSecurity(
authJwtAudience: $authJwtAudience
authJwtExpiration: $authJwtExpiration
authJwtRenewablePeriod: $authJwtRenewablePeriod
corsConfig: $corsConfig
corsMode: $corsMode
cspDirectives: $cspDirectives
disallowFloc: $disallowFloc
disallowIframe: $disallowIframe
disallowOpenRedirect: $disallowOpenRedirect
enforceCsp: $enforceCsp
enforceHsts: $enforceHsts
enforceSameOriginReferrerPolicy: $enforceSameOriginReferrerPolicy
hstsDuration: $hstsDuration
trustProxy: $trustProxy
uploadMaxFiles: $uploadMaxFiles
uploadMaxFileSize: $uploadMaxFileSize
) {
status {
succeeded
slug
message
}
}
}
`,
variables: {
...this.config,
uploadMaxFileSize: filesizeParser(this.humanUploadMaxFileSize || '0')
}
})
const resp = _get(respRaw, 'data.updateSystemSecurity.status', {})
if (resp.succeeded) {
this.$q.notify({
type: 'positive',
message: this.$t('admin.security.saveSuccess')
})
} else {
throw new Error(resp.message)
}
} catch (err) {
this.$q.notify({
type: 'negative',
message: 'Failed to save security config',
caption: err.message
})
}
this.loading = false
}
}
}
</script>
<style lang='scss'>
</style>
<template lang='pug'>
q-page.admin-locale
.row.q-pa-md.items-center
.col-auto
img.admin-icon.animated.fadeInLeft(src='/_assets/icons/fluent-change-theme.svg')
.col.q-pl-md
.text-h5.text-primary.animated.fadeInLeft {{ $t('admin.sites.title') }}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s {{ $t('admin.sites.subtitle') }}
.col-auto
q-btn.q-mr-sm.acrylic-btn(
icon='las la-question-circle'
flat
color='grey'
type='a'
href='https://docs.js.wiki/admin/sites'
target='_blank'
)
q-btn.q-mr-sm.acrylic-btn(
icon='las la-redo-alt'
flat
color='secondary'
@click='refresh'
)
q-btn(
unelevated
icon='las la-plus'
:label='$t(`admin.sites.new`)'
color='primary'
@click='createSite'
)
q-separator(inset)
.row.q-pa-md.q-col-gutter-md
.col-12
q-card.shadow-1
q-list(separator)
q-item(
v-for='site of sites'
:key='site.id'
)
q-item-section(side)
q-icon(name='las la-chalkboard', color='primary')
q-item-section
strong {{site.title}}
q-item-section
div
q-chip.q-mx-none(
v-if='site.hostname !== `*`'
square
color='blue-7'
text-color='white'
size='sm'
)
q-avatar(
icon='las la-angle-right'
color='blue-5'
text-color='white'
)
span {{site.hostname}}
q-chip.q-mx-none(
v-else
square
color='indigo-7'
text-color='white'
size='sm'
)
q-avatar(
icon='las la-asterisk'
color='indigo-5'
text-color='white'
)
span catch-all
q-item-section(side)
q-toggle(
:model-value='site.isEnabled'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:label='$t(`admin.sites.isActive`)'
:aria-label='$t(`admin.sites.isActive`)'
@update:model-value ='(val) => { toggleSiteState(site, val) }'
)
q-separator.q-ml-md(vertical)
q-item-section(side, style='flex-direction: row; align-items: center;')
q-btn.acrylic-btn.q-mr-sm(
flat
@click='editSite(site)'
icon='las la-pen'
color='indigo'
:label='$t(`common.actions.edit`)'
no-caps
)
q-btn.acrylic-btn(
flat
icon='las la-trash'
color='accent'
@click='deleteSite(site)'
)
</template>
<script>
import { get } from 'vuex-pathify'
import { copyToClipboard, createMetaMixin } from 'quasar'
import SiteActivateDialog from '../components/SiteActivateDialog.vue'
import SiteCreateDialog from '../components/SiteCreateDialog.vue'
import SiteDeleteDialog from '../components/SiteDeleteDialog.vue'
export default {
mixins: [
createMetaMixin(function () {
return {
title: this.$t('admin.sites.title')
}
})
],
data () {
return {
loading: false
}
},
computed: {
sites: get('admin/sites', false)
},
methods: {
copyID (uid) {
copyToClipboard(uid).then(() => {
this.$q.notify({
type: 'positive',
message: this.$t('common.clipboard.uuidSuccess')
})
}).catch(() => {
this.$q.notify({
type: 'negative',
message: this.$t('common.clipboard.uuidFailure')
})
})
},
async refresh () {
await this.$store.dispatch('admin/fetchSites')
this.$q.notify({
type: 'positive',
message: this.$t('admin.sites.refreshSuccess')
})
},
createSite () {
this.$q.dialog({
component: SiteCreateDialog
})
},
editSite (st) {
this.$store.set('admin/currentSiteId', st.id)
this.$nextTick(() => {
this.$router.push(`/_admin/${st.id}/general`)
})
},
toggleSiteState (st, newState) {
this.$q.dialog({
component: SiteActivateDialog,
componentProps: {
site: st,
value: newState
}
})
},
deleteSite (st) {
this.$q.dialog({
component: SiteDeleteDialog,
componentProps: {
site: st
}
})
}
},
mounted () {
this.$store.dispatch('admin/fetchSites')
}
}
</script>
<template lang='pug'>
v-container(fluid, grid-list-lg)
v-layout(row wrap)
v-flex(xs12)
.admin-header
img.animated.fadeInUp(src='/_assets/svg/icon-validation.svg', alt='SSL', style='width: 80px;')
.admin-header-title
.headline.primary--text.animated.fadeInLeft {{ $t('admin.ssl.title') }}
.subtitle-1.grey--text.animated.fadeInLeft {{ $t('admin.ssl.subtitle') }}
v-spacer
v-btn.animated.fadeInDown(
v-if='info.sslProvider === `letsencrypt` && info.httpsPort > 0'
color='black'
dark
depressed
@click='renewCertificate'
large
:loading='loadingRenew'
)
v-icon(left) mdi-cached
span {{$t('admin.ssl.renewCertificate')}}
v-form.pt-3
v-layout(row wrap)
v-flex(lg6 xs12)
v-card.animated.fadeInUp
v-subheader {{ $t('admin.ssl.currentState') }}
v-list(two-line, dense)
v-list-item
v-list-item-avatar
v-icon.indigo.white--text mdi-handshake
v-list-item-content
v-list-item-title {{ $t(`admin.ssl.provider`) }}
v-list-item-subtitle {{ providerTitle }}
template(v-if='info.sslProvider === `letsencrypt` && info.httpsPort > 0')
v-list-item
v-list-item-avatar
v-icon.indigo.white--text mdi-application
v-list-item-content
v-list-item-title {{ $t(`admin.ssl.domain`) }}
v-list-item-subtitle {{ info.sslDomain }}
v-list-item
v-list-item-avatar
v-icon.indigo.white--text mdi-at
v-list-item-content
v-list-item-title {{ $t('admin.ssl.subscriberEmail') }}
v-list-item-subtitle {{ info.sslSubscriberEmail }}
v-list-item
v-list-item-avatar
v-icon.indigo.white--text mdi-calendar-remove-outline
v-list-item-content
v-list-item-title {{ $t('admin.ssl.expiration') }}
v-list-item-subtitle {{ info.sslExpirationDate | moment('calendar') }}
v-list-item
v-list-item-avatar
v-icon.indigo.white--text mdi-traffic-light
v-list-item-content
v-list-item-title {{ $t(`admin.ssl.status`) }}
v-list-item-subtitle {{ info.sslStatus }}
v-flex(lg6 xs12)
v-card.animated.fadeInUp.wait-p2s
v-subheader {{ $t('admin.ssl.ports') }}
v-list(two-line, dense)
v-list-item
v-list-item-avatar
v-icon.blue.white--text mdi-lock-open-variant
v-list-item-content
v-list-item-title {{ $t(`admin.ssl.httpPort`) }}
v-list-item-subtitle {{ info.httpPort }}
template(v-if='info.httpsPort > 0')
v-divider
v-list-item
v-list-item-avatar
v-icon.green.white--text mdi-lock
v-list-item-content
v-list-item-title {{ $t(`admin.ssl.httpsPort`) }}
v-list-item-subtitle {{ info.httpsPort }}
v-divider
v-list-item
v-list-item-avatar
v-icon.indigo.white--text mdi-sign-direction
v-list-item-content
v-list-item-title {{ $t(`admin.ssl.httpPortRedirect`) }}
v-list-item-subtitle {{ info.httpRedirection }}
v-list-item-action
v-btn.red--text(
v-if='info.httpRedirection'
depressed
:color='$vuetify.theme.dark ? `red darken-4` : `red lighten-5`'
:class='$vuetify.theme.dark ? `text--lighten-5` : `text--darken-2`'
@click='toggleRedir'
:loading='loadingRedir'
)
v-icon(left) mdi-power
span {{$t('admin.ssl.httpPortRedirectTurnOff')}}
v-btn.green--text(
v-else
depressed
:color='$vuetify.theme.dark ? `green darken-4` : `green lighten-5`'
:class='$vuetify.theme.dark ? `text--lighten-5` : `text--darken-2`'
@click='toggleRedir'
:loading='loadingRedir'
)
v-icon(left) mdi-power
span {{$t('admin.ssl.httpPortRedirectTurnOn')}}
v-dialog(
v-model='loadingRenew'
persistent
max-width='450'
)
v-card(color='black', dark)
v-card-text.pa-10.text-center
semipolar-spinner.animated.fadeIn(
:animation-duration='1500'
:size='65'
color='#FFF'
style='margin: 0 auto;'
)
.mt-5.body-1.white--text {{$t('admin.ssl.renewCertificateLoadingTitle')}}
.caption.mt-4 {{$t('admin.ssl.renewCertificateLoadingSubtitle')}}
</template>
<script>
import _ from 'lodash'
import gql from 'graphql-tag'
import { SemipolarSpinner } from 'epic-spinners'
export default {
components: {
SemipolarSpinner
},
data() {
return {
loadingRenew: false,
loadingRedir: false,
info: {
sslDomain: '',
sslProvider: '',
sslSubscriberEmail: '',
sslExpirationDate: false,
sslStatus: '',
httpPort: 0,
httpRedirection: false,
httpsPort: 0
}
}
},
computed: {
providerTitle () {
switch (this.info.sslProvider) {
case 'custom':
return this.$t('admin.ssl.providerCustomCertificate')
case 'letsencrypt':
return this.$t('admin.ssl.providerLetsEncrypt')
default:
return this.$t('admin.ssl.providerDisabled')
}
}
},
methods: {
async toggleRedir () {
this.loadingRedir = true
try {
this.info.httpRedirection = !this.info.httpRedirection
await this.$apollo.mutate({
mutation: gql`
mutation ($enabled: Boolean!) {
system {
setHTTPSRedirection(enabled: $enabled) {
responseResult {
succeeded
errorCode
slug
message
}
}
}
}
`,
variables: {
enabled: _.get(this.info, 'httpRedirection', false)
},
watchLoading (isLoading) {
this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-ssl-toggleRedirection')
}
})
this.$store.commit('showNotification', {
style: 'success',
message: this.$t('admin.ssl.httpPortRedirectSaveSuccess'),
icon: 'check'
})
} catch (err) {
this.info.httpRedirection = !this.info.httpRedirection
this.$store.commit('pushGraphError', err)
}
this.loadingRedir = false
},
async renewCertificate () {
this.loadingRenew = true
try {
const respRaw = await this.$apollo.mutate({
mutation: gql`
mutation {
system {
renewHTTPSCertificate {
responseResult {
succeeded
errorCode
slug
message
}
}
}
}
`,
watchLoading (isLoading) {
this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-ssl-renew')
}
})
const resp = _.get(respRaw, 'data.system.renewHTTPSCertificate.responseResult', {})
if (resp.succeeded) {
this.$store.commit('showNotification', {
style: 'success',
message: this.$t('admin.ssl.renewCertificateSuccess'),
icon: 'check'
})
} else {
throw new Error(resp.message)
}
} catch (err) {
this.$store.commit('pushGraphError', err)
}
this.loadingRenew = false
}
},
apollo: {
info: {
query: gql`
{
system {
info {
httpPort
httpRedirection
httpsPort
sslDomain
sslExpirationDate
sslProvider
sslStatus
sslSubscriberEmail
}
}
}
`,
fetchPolicy: 'network-only',
update: (data) => _.cloneDeep(data.system.info),
watchLoading (isLoading) {
this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-ssl-refresh')
}
}
}
}
</script>
<style lang='scss'>
</style>
<template lang='pug'>
v-container(fluid, fill-height)
v-layout(row wrap)
v-flex(xs12)
.admin-header-icon: v-icon(size='80', color='grey lighten-2') show_chart
.headline.primary--text Statistics
.subtitle-1.grey--text Useful information about your wiki
.pa-3
fingerprint-spinner(
:animation-duration='1500'
:size='128'
color='#e91e63'
)
.caption.pink--text.mt-3 Compiling latest data...
</template>
<script>
import { FingerprintSpinner } from 'epic-spinners'
export default {
components: {
FingerprintSpinner
},
data() {
return {}
}
}
</script>
<style lang='scss'>
</style>
<template lang='pug'>
q-page.admin-storage
.row.q-pa-md.items-center
.col-auto
img.admin-icon.animated.fadeInLeft(src='/_assets/icons/fluent-ssd.svg')
.col.q-pl-md
.text-h5.text-primary.animated.fadeInLeft {{ $t('admin.storage.title') }}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s {{ $t('admin.storage.subtitle') }}
.col-auto.flex
q-spinner-tail.q-mr-md(
v-show='loading > 0'
color='accent'
size='sm'
)
q-btn-toggle.q-mr-md(
v-model='displayMode'
push
no-caps
toggle-color='black'
:options=`[
{ label: $t('admin.storage.targets'), value: 'targets' },
{ label: $t('admin.storage.deliveryPaths'), value: 'delivery' }
]`
)
q-separator.q-mr-md(vertical)
q-btn.q-mr-sm.acrylic-btn(
icon='las la-question-circle'
flat
color='grey'
href='https://docs.js.wiki/admin/storage'
target='_blank'
type='a'
)
q-btn(
unelevated
icon='mdi-check'
:label='$t(`common.actions.apply`)'
color='secondary'
@click='save'
:loading='loading > 0'
)
q-separator(inset)
//- ==========================================
//- TARGETS
//- ==========================================
.row.q-pa-md.q-col-gutter-md(v-if='displayMode === `targets`')
.col-auto
q-card.rounded-borders.bg-dark
q-list(
style='min-width: 350px;'
padding
dark
)
q-item(
v-for='tgt of targets'
:key='tgt.key'
active-class='bg-primary text-white'
:active='selectedTarget === tgt.id'
:to='`/_admin/` + currentSiteId + `/storage/` + tgt.id'
clickable
)
q-item-section(side)
q-icon(
:name='`img:` + tgt.icon'
)
q-item-section
q-item-label {{tgt.title}}
q-item-label(caption, :class='getTargetSubtitleColor(tgt)') {{getTargetSubtitle(tgt)}}
q-item-section(side)
q-spinner-rings(:color='tgt.isEnabled ? `positive` : `negative`', size='sm')
.col(v-if='target')
//- -----------------------
//- Content Types
//- -----------------------
q-card.shadow-1.q-pb-sm
q-card-section
.text-subtitle1 {{$t('admin.storage.contentTypes')}}
.text-body2.text-grey {{ $t('admin.storage.contentTypesHint') }}
q-item(tag='label')
q-item-section(avatar)
q-checkbox(
v-model='target.contentTypes.activeTypes'
:color='target.module === `db` ? `grey` : `primary`'
val='pages'
:aria-label='$t(`admin.storage.contentTypePages`)'
:disable='target.module === `db`'
)
q-item-section
q-item-label {{$t(`admin.storage.contentTypePages`)}}
q-item-label(caption) {{$t(`admin.storage.contentTypePagesHint`)}}
q-item(tag='label')
q-item-section(avatar)
q-checkbox(
v-model='target.contentTypes.activeTypes'
color='primary'
val='images'
:aria-label='$t(`admin.storage.contentTypeImages`)'
)
q-item-section
q-item-label {{$t(`admin.storage.contentTypeImages`)}}
q-item-label(caption) {{$t(`admin.storage.contentTypeImagesHint`)}}
q-item(tag='label')
q-item-section(avatar)
q-checkbox(
v-model='target.contentTypes.activeTypes'
color='primary'
val='documents'
:aria-label='$t(`admin.storage.contentTypeDocuments`)'
)
q-item-section
q-item-label {{$t(`admin.storage.contentTypeDocuments`)}}
q-item-label(caption) {{$t(`admin.storage.contentTypeDocumentsHint`)}}
q-item(tag='label')
q-item-section(avatar)
q-checkbox(
v-model='target.contentTypes.activeTypes'
color='primary'
val='others'
:aria-label='$t(`admin.storage.contentTypeOthers`)'
)
q-item-section
q-item-label {{$t(`admin.storage.contentTypeOthers`)}}
q-item-label(caption) {{$t(`admin.storage.contentTypeOthersHint`)}}
q-item(tag='label')
q-item-section(avatar)
q-checkbox(
v-model='target.contentTypes.activeTypes'
color='primary'
val='large'
:aria-label='$t(`admin.storage.contentTypeLargeFiles`)'
)
q-item-section
q-item-label {{$t(`admin.storage.contentTypeLargeFiles`)}}
q-item-label(caption) {{$t(`admin.storage.contentTypeLargeFilesHint`)}}
q-item-label.text-deep-orange(v-if='target.module === `db`', caption) {{$t(`admin.storage.contentTypeLargeFilesDBWarn`)}}
q-item-section(side)
q-input(
outlined
:label='$t(`admin.storage.contentTypeLargeFilesThreshold`)'
v-model='target.contentTypes.largeThreshold'
style='min-width: 150px;'
dense
)
//- -----------------------
//- Content Delivery
//- -----------------------
q-card.shadow-1.q-pb-sm.q-mt-md
q-card-section
.text-subtitle1 {{$t('admin.storage.assetDelivery')}}
.text-body2.text-grey {{ $t('admin.storage.assetDeliveryHint') }}
q-item(:tag='target.assetDelivery.isStreamingSupported ? `label` : null')
q-item-section(avatar)
q-checkbox(
v-model='target.assetDelivery.streaming'
:color='target.module === `db` || !target.assetDelivery.isStreamingSupported ? `grey` : `primary`'
:aria-label='$t(`admin.storage.contentTypePages`)'
:disable='target.module === `db` || !target.assetDelivery.isStreamingSupported'
)
q-item-section
q-item-label {{$t(`admin.storage.assetStreaming`)}}
q-item-label(caption) {{$t(`admin.storage.assetStreamingHint`)}}
q-item-label.text-deep-orange(v-if='!target.assetDelivery.isStreamingSupported', caption) {{$t(`admin.storage.assetStreamingNotSupported`)}}
q-item(:tag='target.assetDelivery.isDirectAccessSupported ? `label` : null')
q-item-section(avatar)
q-checkbox(
v-model='target.assetDelivery.directAccess'
:color='!target.assetDelivery.isDirectAccessSupported ? `grey` : `primary`'
:aria-label='$t(`admin.storage.contentTypePages`)'
:disable='!target.assetDelivery.isDirectAccessSupported'
)
q-item-section
q-item-label {{$t(`admin.storage.assetDirectAccess`)}}
q-item-label(caption) {{$t(`admin.storage.assetDirectAccessHint`)}}
q-item-label.text-deep-orange(v-if='!target.assetDelivery.isDirectAccessSupported', caption) {{$t(`admin.storage.assetDirectAccessNotSupported`)}}
//- -----------------------
//- Setup
//- -----------------------
q-card.shadow-1.q-pb-sm.q-mt-md(v-if='target.setup && target.setup.handler && target.setup.state !== `configured`')
q-card-section
.text-subtitle1 {{$t('admin.storage.setup')}}
.text-body2.text-grey {{ $t('admin.storage.setupHint') }}
template(v-if='target.setup.handler === `github` && target.setup.state === `notconfigured`')
q-item
blueprint-icon(icon='test-account')
q-item-section
q-item-label GitHub Account Type
q-item-label(caption) Whether to use an organization or personal GitHub account during setup.
q-item-section.col-auto
q-btn-toggle(
v-model='target.setup.values.accountType'
push
glossy
no-caps
toggle-color='primary'
:options=`[
{ label: $t('admin.storage.githubAccTypeOrg'), value: 'org' },
{ label: $t('admin.storage.githubAccTypePersonal'), value: 'personal' }
]`
)
q-separator.q-my-sm(inset)
template(v-if='target.setup.values.accountType === `org`')
q-item
blueprint-icon(icon='github')
q-item-section
q-item-label {{ $t('admin.storage.githubOrg') }}
q-item-label(caption) {{ $t('admin.storage.githubOrgHint') }}
q-item-section
q-input(
outlined
v-model='target.setup.values.org'
dense
:aria-label='$t(`admin.storage.githubOrg`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='dns')
q-item-section
q-item-label {{ $t('admin.storage.githubPublicUrl') }}
q-item-label(caption) {{ $t('admin.storage.githubPublicUrlHint') }}
q-item-section
q-input(
outlined
v-model='target.setup.values.publicUrl'
dense
:aria-label='$t(`admin.storage.githubPublicUrl`)'
)
q-card-section.q-pt-sm.text-right
form(
ref='githubSetupForm'
method='POST'
:action='setupCfg.action'
)
input(
type='hidden'
name='manifest'
:value='setupCfg.manifest'
)
q-btn(
unelevated
icon='las la-angle-double-right'
:label='$t(`admin.storage.startSetup`)'
color='secondary'
@click='setupGitHub'
:loading='setupCfg.loading'
)
template(v-else-if='target.setup.handler === `github` && target.setup.state === `pendinginstall`')
q-card-section.q-py-none
q-banner(
rounded
:class='$q.dark.isActive ? `bg-teal-9 text-white` : `bg-teal-1 text-teal-9`'
) {{$t('admin.storage.githubFinish')}}
q-card-section.q-pt-sm.text-right
q-btn.q-mr-sm(
unelevated
icon='las la-times-circle'
:label='$t(`admin.storage.cancelSetup`)'
color='negative'
@click='setupDestroy'
)
q-btn(
unelevated
icon='las la-angle-double-right'
:label='$t(`admin.storage.finishSetup`)'
color='secondary'
@click='setupGitHubStep(`verify`)'
:loading='setupCfg.loading'
)
q-card.shadow-1.q-pb-sm.q-mt-md(v-if='target.setup && target.setup.handler && target.setup.state === `configured`')
q-card-section
.text-subtitle1 {{$t('admin.storage.setup')}}
.text-body2.text-grey {{ $t('admin.storage.setupConfiguredHint') }}
q-item
blueprint-icon.self-start(icon='matches', :hue-rotate='140')
q-item-section
q-item-label Uninstall
q-item-label(caption) Delete the active configuration and start over the setup process.
q-item-label.text-red(caption): strong This action cannot be undone!
q-item-section(side)
q-btn.acrylic-btn(
flat
icon='las la-arrow-circle-right'
color='negative'
@click='setupDestroy'
:label='$t(`admin.storage.uninstall`)'
)
//- -----------------------
//- Configuration
//- -----------------------
q-card.shadow-1.q-pb-sm.q-mt-md
q-card-section
.text-subtitle1 {{$t('admin.storage.config')}}
q-banner.q-mt-md(
v-if='!target.config || Object.keys(target.config).length < 1'
rounded
:class='$q.dark.isActive ? `bg-negative text-white` : `bg-grey-2 text-grey-7`'
) {{$t('admin.storage.noConfigOption')}}
template(
v-for='(cfg, cfgKey, idx) in target.config'
)
template(
v-if='configIfCheck(cfg.if)'
)
q-separator.q-my-sm(inset, v-if='idx > 0')
q-item(v-if='cfg.type === `Boolean`', tag='label')
blueprint-icon(:icon='cfg.icon', :hue-rotate='cfg.readOnly ? -45 : 0')
q-item-section
q-item-label {{cfg.title}}
q-item-label(caption) {{cfg.hint}}
q-item-section(avatar)
q-toggle(
v-model='cfg.value'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.general.allowComments`)'
:disable='cfg.readOnly'
)
q-item(v-else)
blueprint-icon(:icon='cfg.icon', :hue-rotate='cfg.readOnly ? -45 : 0')
q-item-section
q-item-label {{cfg.title}}
q-item-label(caption) {{cfg.hint}}
q-item-section(
:style='cfg.type === `Number` ? `flex: 0 0 150px;` : ``'
:class='{ "col-auto": cfg.enum && cfg.enumDisplay === `buttons` }'
)
q-btn-toggle(
v-if='cfg.enum && cfg.enumDisplay === `buttons`'
v-model='cfg.value'
push
glossy
no-caps
toggle-color='primary'
:options=`cfg.enum`
:disable='cfg.readOnly'
)
q-select(
v-else-if='cfg.enum'
outlined
v-model='cfg.value'
:options='cfg.enum'
emit-value
map-options
dense
options-dense
:aria-label='cfg.title'
:disable='cfg.readOnly'
)
q-input(
v-else
outlined
v-model='cfg.value'
dense
:type='cfg.multiline ? `textarea` : `input`'
:aria-label='cfg.title'
:disable='cfg.readOnly'
)
//- -----------------------
//- Sync
//- -----------------------
q-card.shadow-1.q-pb-sm.q-mt-md(v-if='target.sync && Object.keys(target.sync).length > 0')
q-card-section
.text-subtitle1 {{$t('admin.storage.sync')}}
q-banner.q-mt-md(
rounded
:class='$q.dark.isActive ? `bg-negative text-white` : `bg-grey-2 text-grey-7`'
) {{$t('admin.storage.noSyncModes')}}
//- -----------------------
//- Actions
//- -----------------------
q-card.shadow-1.q-pb-sm.q-mt-md
q-card-section
.text-subtitle1 {{$t('admin.storage.actions')}}
q-banner.q-mt-md(
v-if='!target.actions || target.actions.length < 1'
rounded
:class='$q.dark.isActive ? `bg-negative text-white` : `bg-grey-2 text-grey-7`'
) {{$t('admin.storage.noActions')}}
q-banner.q-mt-md(
v-else-if='!target.isEnabled'
rounded
:class='$q.dark.isActive ? `bg-negative text-white` : `bg-grey-2 text-grey-7`'
) {{$t('admin.storage.actionsInactiveWarn')}}
template(
v-if='target.isEnabled'
v-for='(act, idx) in target.actions'
)
q-separator.q-my-sm(inset, v-if='idx > 0')
q-item
blueprint-icon.self-start(:icon='act.icon', :hue-rotate='45')
q-item-section
q-item-label {{act.label}}
q-item-label(caption) {{act.hint}}
q-item-label.text-red(v-if='act.warn', caption): strong {{act.warn}}
q-item-section(side)
q-btn.acrylic-btn(
flat
icon='las la-arrow-circle-right'
color='primary'
@click=''
:label='$t(`common.actions.proceed`)'
)
.col-auto(v-if='target')
//- -----------------------
//- Infobox
//- -----------------------
q-card.rounded-borders.q-pb-md(style='width: 350px;')
q-card-section
.text-subtitle1 {{target.title}}
q-img.q-mt-sm.rounded-borders(
:src='target.banner'
fit='cover'
no-spinner
)
.text-body2.q-mt-md {{target.description}}
q-separator.q-mb-sm(inset)
q-item
q-item-section
q-item-label.text-grey {{$t(`admin.storage.vendor`)}}
q-item-label {{target.vendor}}
q-separator.q-my-sm(inset)
q-item
q-item-section
q-item-label.text-grey {{$t(`admin.storage.vendorWebsite`)}}
q-item-label: a(:href='target.website', target='_blank', rel='noreferrer') {{target.website}}
//- -----------------------
//- Status
//- -----------------------
q-card.rounded-borders.q-pb-md.q-mt-md(style='width: 350px;')
q-card-section
.text-subtitle1 Status
template(v-if='target.module !== `db` && !(target.setup && target.setup.handler && target.setup.state !== `configured`)')
q-item(tag='label')
q-item-section
q-item-label {{$t(`admin.storage.enabled`)}}
q-item-label(caption) {{$t(`admin.storage.enabledHint`)}}
q-item-label.text-deep-orange(v-if='target.module === `db`', caption) {{$t(`admin.storage.enabledForced`)}}
q-item-section(avatar)
q-toggle(
v-model='target.isEnabled'
:disable='target.module === `db` || (target.setup && target.setup.handler && target.setup.state !== `configured`)'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.general.allowSearch`)'
)
q-separator.q-my-sm(inset)
q-item
q-item-section
q-item-label.text-grey {{$t(`admin.storage.currentState`)}}
q-item-label.text-positive No issues detected.
//- -----------------------
//- Versioning
//- -----------------------
q-card.rounded-borders.q-pb-md.q-mt-md(style='width: 350px;')
q-card-section
.text-subtitle1 {{$t(`admin.storage.versioning`)}}
.text-body2.text-grey {{$t(`admin.storage.versioningHint`)}}
q-item(:tag='target.versioning.isSupported ? `label` : null')
q-item-section
q-item-label {{$t(`admin.storage.useVersioning`)}}
q-item-label(caption) {{$t(`admin.storage.useVersioningHint`)}}
q-item-label.text-deep-orange(v-if='!target.versioning.isSupported', caption) {{$t(`admin.storage.versioningNotSupported`)}}
q-item-label.text-deep-orange(v-if='target.versioning.isForceEnabled', caption) {{$t(`admin.storage.versioningForceEnabled`)}}
q-item-section(avatar)
q-toggle(
v-model='target.versioning.enabled'
:disable='!target.versioning.isSupported || target.versioning.isForceEnabled'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.storage.useVersioning`)'
)
//- ==========================================
//- DELIVERY PATHS
//- ==========================================
.row.q-pa-md.q-col-gutter-md(v-if='displayMode === `delivery`')
.col
q-card.rounded-borders
q-card-section.flex.items-center
.text-caption.q-mr-sm {{ $t('admin.storage.deliveryPathsLegend') }}
q-chip(square, dense, color='blue-1', text-color='blue-8')
q-avatar(icon='las la-ellipsis-h', color='blue', text-color='white')
span.text-caption.q-px-sm {{ $t('admin.storage.deliveryPathsUserRequest') }}
q-chip(square, dense, color='teal-1', text-color='teal-8')
q-avatar(icon='las la-ellipsis-h', color='positive', text-color='white')
span.text-caption.q-px-sm {{ $t('admin.storage.deliveryPathsPushToOrigin') }}
q-chip(square, dense, color='red-1', text-color='red-8')
q-avatar(icon='las la-minus', color='negative', text-color='white')
span.text-caption.q-px-sm {{ $t('admin.storage.missingOrigin') }}
q-separator
v-network-graph(
:zoom-level='2'
:configs='deliveryConfig'
:nodes='deliveryNodes'
:edges='deliveryEdges'
:paths='deliveryPaths'
:layouts='deliveryLayouts'
style='height: 600px;'
)
template(#override-node='{ nodeId, scale, config, ...slotProps }')
rect(
:rx='config.borderRadius * scale'
:x='-config.radius * scale'
:y='-config.radius * scale'
:width='config.radius * scale * 2'
:height='config.radius * scale * 2'
:fill='config.color'
v-bind='slotProps'
)
image(
v-if='deliveryNodes[nodeId].icon && deliveryNodes[nodeId].icon.endsWith(`.svg`)'
:x='(-config.radius + 5) * scale'
:y='(-config.radius + 5) * scale'
:width='(config.radius - 5) * scale * 2'
:height='(config.radius - 5) * scale * 2'
:xlink:href='deliveryNodes[nodeId].icon'
)
text(
v-if='deliveryNodes[nodeId].icon && deliveryNodes[nodeId].iconText'
:class='deliveryNodes[nodeId].icon'
:font-size='22 * scale'
fill='#ffffff'
text-anchor='middle'
dominant-baseline='central'
v-html='deliveryNodes[nodeId].iconText'
)
//- .overline.my-5 {{$t('admin.storage.syncDirection')}}
//- .body-2.ml-3 {{$t('admin.storage.syncDirectionSubtitle')}}
//- .pr-3.pt-3
//- v-radio-group.ml-3.py-0(v-model='target.mode')
//- v-radio(
//- :label='$t(`admin.storage.syncDirBi`)'
//- color='primary'
//- value='sync'
//- :disabled='target.supportedModes.indexOf(`sync`) < 0'
//- )
//- v-radio(
//- :label='$t(`admin.storage.syncDirPush`)'
//- color='primary'
//- value='push'
//- :disabled='target.supportedModes.indexOf(`push`) < 0'
//- )
//- v-radio(
//- :label='$t(`admin.storage.syncDirPull`)'
//- color='primary'
//- value='pull'
//- :disabled='target.supportedModes.indexOf(`pull`) < 0'
//- )
//- .body-2.ml-3
//- strong {{$t('admin.storage.syncDirBi')}} #[em.red--text.text--lighten-2(v-if='target.supportedModes.indexOf(`sync`) < 0') {{$t('admin.storage.unsupported')}}]
//- .pb-3 {{$t('admin.storage.syncDirBiHint')}}
//- strong {{$t('admin.storage.syncDirPush')}} #[em.red--text.text--lighten-2(v-if='target.supportedModes.indexOf(`push`) < 0') {{$t('admin.storage.unsupported')}}]
//- .pb-3 {{$t('admin.storage.syncDirPushHint')}}
//- strong {{$t('admin.storage.syncDirPull')}} #[em.red--text.text--lighten-2(v-if='target.supportedModes.indexOf(`pull`) < 0') {{$t('admin.storage.unsupported')}}]
//- .pb-3 {{$t('admin.storage.syncDirPullHint')}}
//- template(v-if='target.hasSchedule')
//- v-divider.mt-3
//- .overline.my-5 {{$t('admin.storage.syncSchedule')}}
//- .body-2.ml-3 {{$t('admin.storage.syncScheduleHint')}}
//- .pa-3
//- duration-picker(v-model='target.syncInterval')
//- i18next.caption.mt-3(path='admin.storage.syncScheduleCurrent', tag='div')
//- strong(place='schedule') {{getDefaultSchedule(target.syncInterval)}}
//- i18next.caption(path='admin.storage.syncScheduleDefault', tag='div')
//- strong(place='schedule') {{getDefaultSchedule(target.syncIntervalDefault)}}
</template>
<script>
import find from 'lodash/find'
import cloneDeep from 'lodash/cloneDeep'
import gql from 'graphql-tag'
import { get } from 'vuex-pathify'
import transform from 'lodash/transform'
import * as vNG from 'v-network-graph'
import GithubSetupInstallDialog from '../components/GithubSetupInstallDialog.vue'
export default {
data () {
return {
loading: 0,
displayMode: 'targets',
runningAction: false,
runningActionHandler: '',
selectedTarget: '',
desiredTarget: '',
target: null,
targets: [],
setupCfg: {
action: '',
manifest: '',
loading: false
},
deliveryNodes: {},
deliveryEdges: {},
deliveryLayouts: {
nodes: {}
},
deliveryPaths: [],
deliveryConfig: vNG.defineConfigs({
view: {
layoutHandler: new vNG.GridLayout({ grid: 15 }),
fit: true,
mouseWheelZoomEnabled: false,
grid: {
visible: true,
interval: 2.5,
thickIncrements: 0
}
},
node: {
draggable: false,
selectable: true,
normal: {
type: 'rect',
color: node => node.color || '#1976D2',
borderRadius: node => node.borderRadius || 5
},
label: {
margin: 8
}
},
edge: {
normal: {
width: 3,
dasharray: edge => edge.animate === false ? 20 : 3,
animate: edge => !(edge.animate === false),
animationSpeed: edge => edge.animationSpeed || 50,
color: edge => edge.color || '#1976D2'
},
type: 'straight',
gap: 7,
margin: 4,
marker: {
source: {
type: 'none'
},
target: {
type: 'none'
}
}
},
path: {
visible: true,
end: 'edgeOfNode',
margin: 4,
path: {
width: 7,
color: p => p.color,
linecap: 'square'
}
}
})
}
},
computed: {
currentSiteId: get('admin/currentSiteId', false)
},
watch: {
async currentSiteId (newValue) {
await this.load()
this.$nextTick(() => {
this.$router.replace(`/_admin/${newValue}/storage/${this.selectedTarget}`)
})
},
displayMode (newValue) {
if (newValue === 'delivery') {
this.generateGraph()
}
},
selectedTarget (newValue) {
this.target = find(this.targets, ['id', newValue]) || null
},
targets (newValue) {
if (newValue && newValue.length > 0) {
if (this.desiredTarget) {
this.selectedTarget = this.desiredTarget
this.desiredTarget = ''
} else {
this.selectedTarget = find(this.targets, ['module', 'db'])?.id || null
if (!this.$route.params.id) {
this.$router.replace(`/_admin/${this.currentSiteId}/storage/${this.selectedTarget}`)
}
}
this.handleSetupCallback()
}
},
$route (to, from) {
if (!to.params.id) {
return
}
if (this.targets.length < 1) {
this.desiredTarget = to.params.id
} else {
this.selectedTarget = to.params.id
}
}
},
mounted () {
if (!this.selectedTarget && this.$route.params.id) {
if (this.targets.length < 1) {
this.desiredTarget = this.$route.params.id
} else {
this.selectedTarget = this.$route.params.id
}
}
if (this.currentSiteId) {
this.load()
}
this.handleSetupCallback()
},
methods: {
async load () {
this.loading++
this.$q.loading.show()
const resp = await this.$apollo.query({
query: gql`
query getStorageTargets (
$siteId: UUID!
) {
storageTargets (
siteId: $siteId
) {
id
isEnabled
module
title
description
icon
banner
vendor
website
contentTypes
assetDelivery
versioning
sync
status
setup
config
actions
}
}`,
variables: {
siteId: this.currentSiteId
},
fetchPolicy: 'network-only'
})
this.targets = cloneDeep(resp?.data?.storageTargets)
this.$q.loading.hide()
this.loading--
},
configIfCheck (ifs) {
if (!ifs || ifs.length < 1) { return true }
return ifs.every(s => this.target.config[s.key]?.value === s.eq)
},
async refresh () {
await this.$apollo.queries.targets.refetch()
this.$store.commit('showNotification', {
message: 'List of storage targets has been refreshed.',
style: 'success',
icon: 'cached'
})
},
async save ({ silent }) {
let saveSuccess = false
if (!silent) { this.$q.loading.show() }
try {
const resp = await this.$apollo.mutate({
mutation: gql`
mutation (
$siteId: UUID!
$targets: [StorageTargetInput]!
) {
updateStorageTargets(
siteId: $siteId
targets: $targets
) {
status {
succeeded
message
}
}
}
`,
variables: {
siteId: this.currentSiteId,
targets: this.targets.map(tgt => ({
id: tgt.id,
module: tgt.module,
isEnabled: tgt.isEnabled,
contentTypes: tgt.contentTypes.activeTypes,
largeThreshold: tgt.contentTypes.largeThreshold,
assetDeliveryFileStreaming: tgt.assetDelivery.streaming,
assetDeliveryDirectAccess: tgt.assetDelivery.directAccess,
useVersioning: tgt.versioning.enabled,
config: transform(tgt.config, (r, v, k) => { r[k] = v.value }, {})
}))
}
})
if (resp?.data?.updateStorageTargets?.status?.succeeded) {
saveSuccess = true
if (!silent) {
this.$q.notify({
type: 'positive',
message: this.$t('admin.storage.saveSuccess')
})
}
} else {
throw new Error(resp?.data?.updateStorageTargets?.status?.message || 'Unexpected error')
}
} catch (err) {
this.$q.notify({
type: 'negative',
message: this.$t('admin.storage.saveFailed'),
caption: err.message
})
}
if (!silent) { this.$q.loading.hide() }
return saveSuccess
},
getTargetSubtitle (target) {
if (!target.isEnabled) {
return this.$t('admin.storage.inactiveTarget')
}
const hasPages = target.contentTypes?.activeTypes?.includes('pages')
const hasAssets = target.contentTypes?.activeTypes?.filter(c => c !== 'pages')?.length > 0
if (hasPages && hasAssets) {
return this.$t('admin.storage.pagesAndAssets')
} else if (hasPages) {
return this.$t('admin.storage.pagesOnly')
} else if (hasAssets) {
return this.$t('admin.storage.assetsOnly')
} else {
return this.$t('admin.storage.notConfigured')
}
},
getTargetSubtitleColor (target) {
if (this.selectedTarget === target.id) {
return 'text-blue-2'
} else if (target.isEnabled) {
return 'text-positive'
} else {
return 'text-grey-7'
}
},
getDefaultSchedule (val) {
if (!val) { return 'N/A' }
return '' // moment.duration(val).format('y [years], M [months], d [days], h [hours], m [minutes]')
},
async executeAction (targetKey, handler) {
this.$store.commit('loadingStart', 'admin-storage-executeaction')
this.runningAction = true
this.runningActionHandler = handler
try {
await this.$apollo.mutate({
mutation: gql`{}`,
variables: {
targetKey,
handler
}
})
this.$store.commit('showNotification', {
message: 'Action completed.',
style: 'success',
icon: 'check'
})
} catch (err) {
console.warn(err)
}
this.runningAction = false
this.runningActionHandler = ''
this.$store.commit('loadingStop', 'admin-storage-executeaction')
},
async handleSetupCallback () {
if (this.targets.length < 1 || !this.selectedTarget) { return }
this.$nextTick(() => {
if (this.target?.setup?.handler === 'github' && this.$route.query.code) {
this.setupGitHubStep('connect', this.$route.query.code)
}
})
},
async setupDestroy () {
this.$q.dialog({
title: this.$t('admin.storage.destroyConfirm'),
message: this.$t('admin.storage.destroyConfirmInfo'),
cancel: true,
persistent: true
}).onOk(async () => {
this.$q.loading.show({
message: this.$t('admin.storage.destroyingSetup')
})
try {
const resp = await this.$apollo.mutate({
mutation: gql`
mutation (
$targetId: UUID!
) {
destroyStorageTargetSetup(
targetId: $targetId
) {
status {
succeeded
message
}
}
}
`,
variables: {
targetId: this.selectedTarget
}
})
if (resp?.data?.destroyStorageTargetSetup?.status?.succeeded) {
this.target.setup.state = 'notconfigured'
setTimeout(() => {
this.$q.loading.hide()
this.$q.notify({
type: 'positive',
message: this.$t('admin.storage.githubSetupDestroySuccess')
})
}, 2000)
} else {
throw new Error(resp?.data?.destroyStorageTargetSetup?.status?.message || 'Unexpected error')
}
} catch (err) {
this.$q.notify({
type: 'negative',
message: this.$t('admin.storage.githubSetupDestroyFailed'),
caption: err.message
})
this.$q.loading.hide()
}
})
},
async setupGitHub () {
// -> Format values
this.target.setup.values.publicUrl = this.target.setup.values.publicUrl.toLowerCase()
// -> Basic input check
if (this.target.setup.values.accountType === 'org' && this.target.setup.values.org.length < 1) {
return this.$q.notify({
type: 'negative',
message: 'Invalid GitHub Organization',
caption: 'Enter a valid github organization.'
})
}
if (this.target.setup.values.publicUrl.length < 11 || !/^https?:\/\/.{4,}$/.test(this.target.setup.values.publicUrl)) {
return this.$q.notify({
type: 'negative',
message: 'Invalid Wiki Public URL',
caption: 'Enter a valid public URL for your wiki.'
})
}
if (this.target.setup.values.publicUrl.endsWith('/')) {
this.target.setup.values.publicUrl = this.target.setup.values.publicUrl.slice(0, -1)
}
// -> Generate manifest
this.setupCfg.loading = true
if (this.target.setup.values.accountType === 'org') {
this.setupCfg.action = `https://github.com/organizations/${this.target.setup.values.org}/settings/apps/new`
} else {
this.setupCfg.action = 'https://github.com/settings/apps/new'
}
this.setupCfg.manifest = JSON.stringify({
name: `Wiki.js - ${this.currentSiteId.slice(-12)}`,
description: 'Connects your Wiki.js to GitHub repositories and synchronize their contents.',
url: this.target.setup.values.publicUrl,
hook_attributes: {
url: `${this.target.setup.values.publicUrl}/_github/${this.currentSiteId}/events`
},
redirect_url: `${this.target.setup.values.publicUrl}/_admin/${this.currentSiteId}/storage/${this.target.id}`,
callback_urls: [
`${this.target.setup.values.publicUrl}/_admin/${this.currentSiteId}/storage/${this.target.id}`
],
public: false,
default_permissions: {
contents: 'write',
metadata: 'read',
members: 'read'
},
default_events: [
'create',
'delete',
'push'
]
})
this.$q.loading.show({
message: this.$t('admin.storage.githubPreparingManifest')
})
if (await this.save({ silent: true })) {
this.$refs.githubSetupForm.submit()
} else {
this.setupCfg.loading = false
this.$q.loading.hide()
}
},
async setupGitHubStep (step, code) {
this.$q.loading.show({
message: this.$t('admin.storage.githubVerifying')
})
try {
const resp = await this.$apollo.mutate({
mutation: gql`
mutation (
$targetId: UUID!
$state: JSON!
) {
setupStorageTarget(
targetId: $targetId
state: $state
) {
status {
succeeded
message
}
state
}
}
`,
variables: {
targetId: this.selectedTarget,
state: {
step,
...code && { code }
}
}
})
if (resp?.data?.setupStorageTarget?.status?.succeeded) {
switch (resp.data.setupStorageTarget.state?.nextStep) {
case 'installApp': {
this.$router.replace({ query: null })
this.$q.loading.hide()
this.$q.dialog({
component: GithubSetupInstallDialog,
persistent: true
}).onOk(() => {
this.$q.loading.show({
message: this.$t('admin.storage.githubRedirecting')
})
window.location.assign(resp.data.setupStorageTarget.state?.url)
}).onCancel(() => {
throw new Error('Setup was aborted prematurely.')
})
break
}
case 'completed': {
this.target.isEnabled = true
this.target.setup.state = 'configured'
setTimeout(() => {
this.$q.loading.hide()
this.$q.notify({
type: 'positive',
message: this.$t('admin.storage.githubSetupSuccess')
})
}, 2000)
break
}
default: {
throw new Error('Unknown Setup Step')
}
}
} else {
throw new Error(resp?.data?.setupStorageTarget?.status?.message || 'Unexpected error')
}
} catch (err) {
this.$q.loading.hide()
this.$q.notify({
type: 'negative',
message: this.$t('admin.storage.githubSetupFailed'),
caption: err.message
})
}
},
generateGraph () {
const types = [
{ key: 'images', label: this.$t('admin.storage.contentTypeImages'), icon: 'las', iconText: '&#xf1c5;' },
{ key: 'documents', label: this.$t('admin.storage.contentTypeDocuments'), icon: 'las', iconText: '&#xf1c1;' },
{ key: 'others', label: this.$t('admin.storage.contentTypeOthers'), icon: 'las', iconText: '&#xf15b;' },
{ key: 'large', label: this.$t('admin.storage.contentTypeLargeFiles'), icon: 'las', iconText: '&#xf1c6;' }
]
// -> Create PagesNodes
this.deliveryNodes = {
user: { name: this.$t('admin.storage.deliveryPathsUser'), borderRadius: 16, icon: '/_assets/icons/fluent-account.svg' },
pages: { name: this.$t('admin.storage.contentTypePages'), color: '#3f51b5', icon: 'las', iconText: '&#xf15c;' },
pages_wiki: { name: 'Wiki.js', icon: '/_assets/logo-wikijs.svg', color: '#161b22' }
}
this.deliveryEdges = {
user_pages: { source: 'user', target: 'pages' },
pages_in: { source: 'pages', target: 'pages_wiki' },
pages_out: { source: 'pages_wiki', target: 'pages' }
}
this.deliveryLayouts.nodes = {
user: { x: -30, y: 30 },
pages: { x: 0, y: 0 },
pages_wiki: { x: 60, y: 0 }
}
this.deliveryPaths = []
// -> Create Asset Nodes
for (const [i, t] of types.entries()) {
this.deliveryNodes[t.key] = { name: t.label, color: '#3f51b5', icon: t.icon, iconText: t.iconText }
this.deliveryEdges[`user_${t.key}`] = { source: 'user', target: t.key }
this.deliveryLayouts.nodes[t.key] = { x: 0, y: (i + 1) * 15 }
// -> Find target with direct access
const dt = find(this.targets, tgt => {
return tgt.module !== 'db' && tgt.contentTypes.activeTypes.includes(t.key) && tgt.isEnabled && tgt.assetDelivery.isDirectAccessSupported && tgt.assetDelivery.directAccess
})
if (dt) {
this.deliveryNodes[`${t.key}_${dt.module}`] = { name: dt.title, icon: dt.icon }
this.deliveryNodes[`${t.key}_wiki`] = { name: 'Wiki.js', icon: '/_assets/logo-wikijs.svg', color: '#161b22' }
this.deliveryLayouts.nodes[`${t.key}_${dt.module}`] = { x: 60, y: (i + 1) * 15 }
this.deliveryLayouts.nodes[`${t.key}_wiki`] = { x: 120, y: (i + 1) * 15 }
this.deliveryEdges[`${t.key}_${dt.module}_in`] = { source: t.key, target: `${t.key}_${dt.module}` }
this.deliveryEdges[`${t.key}_${dt.module}_out`] = { source: `${t.key}_${dt.module}`, target: t.key }
this.deliveryEdges[`${t.key}_${dt.module}_wiki`] = { source: `${t.key}_wiki`, target: `${t.key}_${dt.module}`, color: '#02c39a', animationSpeed: 25 }
continue
}
// -> Find target with streaming
const st = find(this.targets, tgt => {
return tgt.module !== 'db' && tgt.contentTypes.activeTypes.includes(t.key) && tgt.isEnabled && tgt.assetDelivery.isStreamingSupported && tgt.assetDelivery.streaming
})
if (st) {
this.deliveryNodes[`${t.key}_${st.module}`] = { name: st.title, icon: st.icon }
this.deliveryNodes[`${t.key}_wiki`] = { name: 'Wiki.js', icon: '/_assets/logo-wikijs.svg', color: '#161b22' }
this.deliveryLayouts.nodes[`${t.key}_${st.module}`] = { x: 120, y: (i + 1) * 15 }
this.deliveryLayouts.nodes[`${t.key}_wiki`] = { x: 60, y: (i + 1) * 15 }
this.deliveryEdges[`${t.key}_wiki_in`] = { source: t.key, target: `${t.key}_wiki` }
this.deliveryEdges[`${t.key}_wiki_out`] = { source: `${t.key}_wiki`, target: t.key }
this.deliveryEdges[`${t.key}_${st.module}_out`] = { source: `${t.key}_${st.module}`, target: `${t.key}_wiki` }
this.deliveryEdges[`${t.key}_${st.module}_in`] = { source: `${t.key}_wiki`, target: `${t.key}_${st.module}` }
this.deliveryEdges[`${t.key}_${st.module}_wiki`] = { source: `${t.key}_wiki`, target: `${t.key}_${st.module}`, color: '#02c39a', animationSpeed: 25 }
continue
}
// -> Check DB fallback
const dbt = find(this.targets, ['module', 'db'])
if (dbt.contentTypes.activeTypes.includes(t.key)) {
this.deliveryNodes[`${t.key}_wiki`] = { name: 'Wiki.js', icon: '/_assets/logo-wikijs.svg', color: '#161b22' }
this.deliveryLayouts.nodes[`${t.key}_wiki`] = { x: 60, y: (i + 1) * 15 }
this.deliveryEdges[`${t.key}_db_in`] = { source: t.key, target: `${t.key}_wiki` }
this.deliveryEdges[`${t.key}_db_out`] = { source: `${t.key}_wiki`, target: t.key }
} else {
this.deliveryNodes[`${t.key}_wiki`] = { name: this.$t('admin.storage.missingOrigin'), color: '#f03a47', icon: 'las', iconText: '&#xf071;' }
this.deliveryLayouts.nodes[`${t.key}_wiki`] = { x: 60, y: (i + 1) * 15 }
this.deliveryEdges[`${t.key}_db_in`] = { source: t.key, target: `${t.key}_wiki`, color: '#f03a47', animate: false }
this.deliveryPaths.push({ edges: [`${t.key}_db_in`], color: '#f03a4755' })
}
}
}
}
}
</script>
<style lang='scss' scoped>
.admin-storage-logo {
border-radius: 5px;
}
</style>
<template lang='pug'>
q-page.admin-system
.row.q-pa-md.items-center
.col-auto
img.admin-icon.animated.fadeInLeft(src='/_assets/icons/fluent-processor.svg')
.col.q-pl-md
.text-h5.text-primary.animated.fadeInLeft {{ $t('admin.system.title') }}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s {{ $t('admin.system.subtitle') }}
.col-auto
q-btn.q-mr-sm.acrylic-btn(
icon='las la-question-circle'
flat
color='grey'
href='https://docs.js.wiki/admin/system'
target='_blank'
type='a'
)
q-btn.q-mr-sm.acrylic-btn(
icon='las la-redo-alt'
flat
color='secondary'
:loading='loading > 0'
@click='load'
)
q-btn.acrylic-btn(
ref='copySysInfoBtn'
flat
icon='las la-clipboard'
label='Copy System Info'
color='primary'
@click=''
:disabled='loading > 0'
)
q-separator(inset)
.row.q-pa-md.q-col-gutter-md
.col-6
//- -----------------------
//- WIKI.JS
//- -----------------------
q-card.q-pb-sm.shadow-1
q-card-section
.text-subtitle1 Wiki.js
q-item
blueprint-icon(icon='breakable', :hue-rotate='-45')
q-item-section
q-item-label {{ $t('admin.system.currentVersion') }}
q-item-label(caption) {{$t('admin.system.currentVersionHint')}}
q-item-section
q-item-label.dark-value(caption) {{ info.currentVersion }}
q-separator(inset)
q-item
blueprint-icon(icon='cloud-checked', :hue-rotate='-45')
q-item-section
q-item-label {{ $t('admin.system.latestVersion') }}
q-item-label(caption) {{$t('admin.system.latestVersionHint')}}
q-item-section
q-item-label.dark-value(caption) {{ info.latestVersion }}
//- -----------------------
//- CLIENT
//- -----------------------
q-no-ssr
q-card.q-mt-md.q-pb-sm.shadow-1
q-card-section
.text-subtitle1 {{$t('admin.system.client')}}
q-item
blueprint-icon(icon='navigation-toolbar-top', :hue-rotate='-45')
q-item-section
q-item-label {{$t('admin.system.browser')}}
q-item-label(caption) {{$t('admin.system.browserHint')}}
q-item-section
q-item-label.dark-value(caption) {{ clientBrowser }}
q-separator(inset)
q-item
blueprint-icon(icon='computer', :hue-rotate='-45')
q-item-section
q-item-label {{$t('admin.system.clientPlatform')}}
q-item-label(caption) {{$t('admin.system.clientPlatformHint')}}
q-item-section
q-item-label.dark-value(caption) {{ clientPlatform }}
q-separator(inset)
q-item
blueprint-icon(icon='translation', :hue-rotate='-45')
q-item-section
q-item-label {{$t('admin.system.clientLanguage')}}
q-item-label(caption) {{$t('admin.system.clientLanguageHint')}}
q-item-section
q-item-label.dark-value(caption) {{ clientLanguage }}
q-separator(inset)
q-item
blueprint-icon(icon='cookies', :hue-rotate='-45')
q-item-section
q-item-label {{$t('admin.system.clientCookies')}}
q-item-label(caption) {{$t('admin.system.clientCookiesHint')}}
q-item-section
q-item-label.dark-value(caption) {{ clientCookies }}
q-separator(inset)
q-item
blueprint-icon(icon='widescreen', :hue-rotate='-45')
q-item-section
q-item-label {{$t('admin.system.clientViewport')}}
q-item-label(caption) {{$t('admin.system.clientViewportHint')}}
q-item-section
q-item-label.dark-value(caption) {{ clientViewport }}
.col-6
//- -----------------------
//- ENGINES
//- -----------------------
q-card.q-pb-sm.shadow-1
q-card-section
.text-subtitle1 {{$t('admin.system.engines')}}
q-item
blueprint-icon(icon='nodejs', :hue-rotate='-45')
q-item-section
q-item-label Node.js
q-item-label(caption) {{$t('admin.system.nodejsHint')}}
q-item-section
q-item-label.dark-value(caption) {{ info.nodeVersion }}
q-separator(inset)
q-item
blueprint-icon(icon='postgresql', :hue-rotate='-45')
q-item-section
q-item-label {{$t('admin.system.database')}}
q-item-label(caption) {{$t('admin.system.databaseHint')}}
q-item-section
q-item-label.dark-value(caption) PostgreSQL {{dbVersion}}
q-separator(inset)
q-item
blueprint-icon(icon='database', :hue-rotate='-45')
q-item-section
q-item-label {{$t('admin.system.databaseHost')}}
q-item-label(caption) {{$t('admin.system.databaseHostHint')}}
q-item-section
q-item-label.dark-value(caption) {{ info.dbHost }}
//- -----------------------
//- HOST INFORMATION
//- -----------------------
q-card.q-mt-md.q-pb-sm.shadow-1
q-card-section
.text-subtitle1 {{ $t('admin.system.hostInfo') }}
q-item
blueprint-icon(:icon='platformLogo', :hue-rotate='-45')
q-item-section
q-item-label {{ $t('admin.system.os') }}
q-item-label(caption) {{$t('admin.system.osHint')}}
q-item-section
q-item-label.dark-value(caption) {{ (info.platform === 'docker') ? 'Docker Container (Linux)' : info.operatingSystem }}
q-separator(inset)
q-item
blueprint-icon(icon='server', :hue-rotate='-45')
q-item-section
q-item-label {{ $t('admin.system.hostname') }}
q-item-label(caption) {{$t('admin.system.hostnameHint')}}
q-item-section
q-item-label.dark-value(caption) {{ info.hostname }}
q-separator(inset)
q-item
blueprint-icon(icon='processor', :hue-rotate='-45')
q-item-section
q-item-label {{ $t('admin.system.cpuCores') }}
q-item-label(caption) {{$t('admin.system.cpuCoresHint')}}
q-item-section
q-item-label.dark-value(caption) {{ info.cpuCores }}
q-separator(inset)
q-item
blueprint-icon(icon='memory-slot', :hue-rotate='-45')
q-item-section
q-item-label {{ $t('admin.system.totalRAM') }}
q-item-label(caption) {{$t('admin.system.totalRAMHint')}}
q-item-section
q-item-label.dark-value(caption) {{ info.ramTotal }}
q-separator(inset)
q-item
blueprint-icon(icon='program', :hue-rotate='-45')
q-item-section
q-item-label {{ $t('admin.system.workingDirectory') }}
q-item-label(caption) {{$t('admin.system.workingDirectoryHint')}}
q-item-section
q-item-label.dark-value(caption) {{ info.workingDirectory }}
q-separator(inset)
q-item
blueprint-icon(icon='automation', :hue-rotate='-45')
q-item-section
q-item-label {{ $t('admin.system.configFile') }}
q-item-label(caption) {{$t('admin.system.configFileHint')}}
q-item-section
q-item-label.dark-value(caption) {{ info.configFile }}
//- v-list-item-action-text {{ $t('admin.system.published') }} {{ info.latestVersionReleaseDate | moment('from') }}
//- v-card-actions(v-if='info.upgradeCapable && !isLatestVersion && info.platform === `docker`', :class='$vuetify.theme.dark ? `grey darken-3-d5` : `indigo lighten-5`')
//- .caption.indigo--text.pl-3(:class='$vuetify.theme.dark ? `text--lighten-4` : ``') Wiki.js can perform the upgrade to the latest version for you.
//- v-spacer
//- v-btn.px-3(
//- color='indigo'
//- dark
//- @click='performUpgrade'
//- )
//- v-icon(left) mdi-upload
//- span Perform Upgrade
//- v-dialog(
//- v-model='isUpgrading'
//- persistent
//- width='450'
//- )
//- v-card.blue.darken-5(dark)
//- v-card-text.text-center.pa-10
//- self-building-square-spinner(
//- :animation-duration='4000'
//- :size='40'
//- color='#FFF'
//- style='margin: 0 auto;'
//- )
//- .body-2.mt-5.blue--text.text--lighten-4 Your Wiki.js container is being upgraded...
//- .caption.blue--text.text--lighten-2 Please wait
//- v-progress-linear.mt-5(
//- color='blue lighten-2'
//- :value='upgradeProgress'
//- :buffer-value='upgradeProgress'
//- rounded
//- :stream='isUpgradingStarted'
//- query
//- :indeterminate='!isUpgradingStarted'
//- )
</template>
<script>
import _get from 'lodash/get'
import cloneDeep from 'lodash/cloneDeep'
import gql from 'graphql-tag'
import { createMetaMixin } from 'quasar'
import ClipboardJS from 'clipboard'
// import { SelfBuildingSquareSpinner } from 'epic-spinners'
export default {
mixins: [
createMetaMixin(function () {
return {
title: this.$t('admin.system.title')
}
})
],
components: {
// SelfBuildingSquareSpinner
},
data () {
return {
clip: null,
loading: 0,
isUpgrading: false,
isUpgradingStarted: false,
upgradeProgress: 0,
info: {
platform: ''
}
}
},
computed: {
dbVersion () {
return _get(this.info, 'dbVersion', '').replace(/(?:\r\n|\r|\n)/g, ', ')
},
platformLogo () {
switch (this.info.platform) {
case 'docker':
return 'docker-container'
case 'darwin':
return 'apple-logo'
case 'linux':
if (this.info.operatingSystem.indexOf('Ubuntu') >= 0) {
return 'ubuntu'
} else {
return 'linux'
}
case 'win32':
return 'windows8'
default:
return 'washing-machine'
}
},
isLatestVersion () {
return this.info.currentVersion === this.info.latestVersion
},
clientBrowser () {
return !import.meta.env.SSR ? navigator.userAgent : ''
},
clientPlatform () {
return !import.meta.env.SSR ? navigator.platform : ''
},
clientLanguage () {
return !import.meta.env.SSR ? navigator.language : ''
},
clientCookies () {
return !import.meta.env.SSR ? navigator.cookieEnabled : ''
},
clientViewport () {
return !import.meta.env.SSR ? `${document.documentElement.clientWidth}x${document.documentElement.clientHeight}` : ''
}
},
mounted () {
this.load()
this.clip = new ClipboardJS(this.$refs.copySysInfoBtn.$el, {
text: () => {
return `Wiki.js ${this.info.currentVersion}
Postgres ${this.dbVersion}
Node.js ${this.info.nodeVersion}
OS: ${this.info.operatingSystem}
Platform: ${this.info.platform}
CPU Cores: ${this.info.cpuCores}
Total RAM: ${this.info.ramTotal}`
}
})
this.clip.on('success', () => {
this.$q.notify({
message: 'Info copied successfully',
icon: 'las la-clipboard'
})
})
this.clip.on('error', () => {
this.$q.notify({
type: 'negative',
message: 'Failed to copy to system info'
})
})
},
methods: {
async load () {
this.loading++
this.$q.loading.show()
const resp = await this.$apollo.query({
query: gql`
query getSystemInfo {
systemInfo {
configFile
cpuCores
currentVersion
dbHost
dbVersion
hostname
latestVersion
latestVersionReleaseDate
nodeVersion
operatingSystem
platform
ramTotal
upgradeCapable
workingDirectory
}
}
`,
fetchPolicy: 'network-only'
})
this.info = cloneDeep(resp?.data?.systemInfo)
this.$q.loading.hide()
this.loading--
},
async performUpgrade () {
this.isUpgrading = true
this.isUpgradingStarted = false
this.upgradeProgress = 0
this.$store.commit('loadingStart', 'admin-system-upgrade')
try {
const respRaw = await this.$apollo.mutate({
mutation: gql`
mutation performUpdate {
system {
performUpgrade {
responseResult {
succeeded
errorCode
slug
message
}
}
}
}
`
})
const resp = _get(respRaw, 'data.system.performUpgrade.responseResult', {})
if (resp.succeeded) {
this.isUpgradingStarted = true
const progressInterval = setInterval(() => {
this.upgradeProgress += 0.83
}, 500)
setTimeout(() => {
clearInterval(progressInterval)
window.location.reload(true)
}, 60000)
} else {
throw new Error(resp.message)
}
} catch (err) {
this.$store.commit('pushGraphError', err)
this.$store.commit('loadingStop', 'admin-system-upgrade')
this.isUpgrading = false
}
}
}
}
</script>
<style lang='scss'>
.admin-system {
.v-list-item-title, .v-list-item__subtitle {
user-select: text;
}
.dark-value {
background-color: #F8F8F8;
color: #333;
padding: 8px 12px;
border-radius: 4px;
font-family: 'Roboto Mono', Consolas, "Liberation Mono", Courier, monospace;
}
}
</style>
<template lang='pug'>
v-container(fluid, grid-list-lg)
v-layout(row wrap)
v-flex(xs12)
.admin-header
img.animated.fadeInUp(src='/_assets/svg/icon-tags.svg', alt='Tags', style='width: 80px;')
.admin-header-title
.headline.primary--text.animated.fadeInLeft {{$t('tags.title')}}
.subtitle-1.grey--text.animated.fadeInLeft.wait-p4s {{$t('tags.subtitle')}}
v-spacer
v-btn.animated.fadeInDown(outlined, color='grey', @click='refresh', icon)
v-icon mdi-refresh
v-container.pa-0.mt-3(fluid, grid-list-lg)
v-layout(row)
v-flex(style='flex: 0 0 350px;')
v-card.animated.fadeInUp
v-toolbar(:color='$vuetify.theme.dark ? `grey darken-3-d5` : `grey lighten-4`', flat)
v-text-field(
v-model='filter'
:label='$t(`admin.tags.filter`)'
hide-details
single-line
solo
flat
dense
color='teal'
:background-color='$vuetify.theme.dark ? `grey darken-4` : `grey lighten-2`'
prepend-inner-icon='mdi-magnify'
)
v-divider
v-list.py-2(dense, nav)
v-list-item(v-if='tags.length < 1')
v-list-item-avatar(size='24'): v-icon(color='grey') mdi-compass-off
v-list-item-content
.caption.grey--text {{$t('tags.emptyList')}}
v-list-item(
v-for='tag of filteredTags'
:key='tag.id'
:class='(tag.id === current.id) ? "teal" : ""'
@click='selectTag(tag)'
)
v-list-item-avatar(size='24', tile): v-icon(size='18', :color='tag.id === current.id ? `white` : `teal`') mdi-tag
v-list-item-title(:class='tag.id === current.id ? `white--text` : ``') {{tag.tag}}
v-flex.animated.fadeInUp.wait-p2s
template(v-if='current.id')
v-card
v-toolbar(dense, color='teal', flat, dark)
.subtitle-1 {{$t('tags.edit')}}
v-spacer
v-btn.pl-4(
color='white'
dark
outlined
small
:href='`/t/` + current.tag'
)
span.text-none {{$t('admin.tags.viewLinkedPages')}}
v-icon(right) mdi-chevron-right
v-card-text
v-text-field(
outlined
:label='$t("tags.tag")'
prepend-icon='mdi-tag'
v-model='current.tag'
counter='255'
)
v-text-field(
outlined
:label='$t("tags.label")'
prepend-icon='mdi-format-title'
v-model='current.title'
hide-details
)
v-card-chin
i18next.caption.pl-3(path='admin.tags.date', tag='div')
strong(place='created') {{current.createdAt | moment('from')}}
strong(place='updated') {{current.updatedAt | moment('from')}}
v-spacer
v-dialog(v-model='deleteTagDialog', max-width='500')
template(v-slot:activator='{ on }')
v-btn(color='red', outlined, v-on='on')
v-icon(color='red') mdi-trash-can-outline
v-card
.dialog-header.is-red {{$t('admin.tags.deleteConfirm')}}
v-card-text.pa-4
i18next(tag='span', path='admin.tags.deleteConfirmText')
strong(place='tag') {{ current.tag }}
v-card-actions
v-spacer
v-btn(text, @click='deleteTagDialog = false') {{$t('common.actions.cancel')}}
v-btn(color='red', dark, @click='deleteTag(current)') {{$t('common.actions.delete')}}
v-btn.px-5.mr-2(color='success', depressed, dark, @click='saveTag(current)')
v-icon(left) mdi-content-save
span {{$t('common.actions.save')}}
v-card(v-else)
v-card-text.grey--text(v-if='tags.length > 0') {{$t('tags.noSelectionText')}}
v-card-text.grey--text(v-else) {{$t('tags.noItemsText')}}
</template>
<script>
import _ from 'lodash'
import gql from 'graphql-tag'
export default {
data() {
return {
tags: [],
current: {},
filter: '',
deleteTagDialog: false
}
},
computed: {
filteredTags () {
if (this.filter.length > 0) {
return _.filter(this.tags, t => t.tag.indexOf(this.filter) >= 0 || t.title.indexOf(this.filter) >= 0)
} else {
return this.tags
}
}
},
methods: {
selectTag(tag) {
this.current = tag
},
async deleteTag(tag) {
this.$store.commit(`loadingStart`, 'admin-tags-delete')
try {
const resp = await this.$apollo.mutate({
mutation: gql`
mutation ($id: Int!) {
pages {
deleteTag (id: $id) {
responseResult {
succeeded
errorCode
slug
message
}
}
}
}
`,
variables: {
id: tag.id
}
})
if (_.get(resp, 'data.pages.deleteTag.responseResult.succeeded', false)) {
this.$store.commit('showNotification', {
message: this.$t('tags.deleteSuccess'),
style: 'success',
icon: 'check'
})
this.refresh()
} else {
throw new Error(_.get(resp, 'data.pages.deleteTag.responseResult.message', 'An unexpected error occurred.'))
}
} catch (err) {
this.$store.commit('pushGraphError', err)
}
this.deleteTagDialog = false
this.$store.commit(`loadingStop`, 'admin-tags-delete')
},
async saveTag(tag) {
this.$store.commit(`loadingStart`, 'admin-tags-save')
try {
const resp = await this.$apollo.mutate({
mutation: gql`
mutation ($id: Int!, $tag: String!, $title: String!) {
pages {
updateTag (id: $id, tag: $tag, title: $title) {
responseResult {
succeeded
errorCode
slug
message
}
}
}
}
`,
variables: {
id: tag.id,
tag: tag.tag,
title: tag.title
}
})
if (_.get(resp, 'data.pages.updateTag.responseResult.succeeded', false)) {
this.$store.commit('showNotification', {
message: this.$t('tags.saveSuccess'),
style: 'success',
icon: 'check'
})
this.current.updatedAt = new Date()
} else {
throw new Error(_.get(resp, 'data.pages.updateTag.responseResult.message', 'An unexpected error occurred.'))
}
} catch (err) {
this.$store.commit('pushGraphError', err)
}
this.$store.commit(`loadingStop`, 'admin-tags-save')
},
async refresh() {
await this.$apollo.queries.tags.refetch()
this.current = {}
this.$store.commit('showNotification', {
message: this.$t('tags.refreshSuccess'),
style: 'success',
icon: 'cached'
})
}
},
apollo: {
tags: {
query: gql`
{
pages {
tags {
id
tag
title
createdAt
updatedAt
}
}
}
`,
fetchPolicy: 'network-only',
update: (data) => _.cloneDeep(data.pages.tags),
watchLoading (isLoading) {
this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-tags-refresh')
}
}
}
}
</script>
<style lang='scss' scoped>
.clickable {
cursor: pointer;
&:hover {
background-color: rgba(mc('blue', '500'), .25);
}
}
</style>
<template lang='pug'>
q-page.admin-theme
.row.q-pa-md.items-center
.col-auto
img.admin-icon.animated.fadeInLeft(src='/_assets/icons/fluent-paint-roller.svg')
.col.q-pl-md
.text-h5.text-primary.animated.fadeInLeft {{ $t('admin.theme.title') }}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s {{ $t('admin.theme.subtitle') }}
.col-auto
q-btn.q-mr-sm.acrylic-btn(
icon='las la-question-circle'
flat
color='grey'
type='a'
href='https://docs.js.wiki/admin/theme'
target='_blank'
)
q-btn.q-mr-sm.acrylic-btn(
icon='las la-redo-alt'
flat
color='secondary'
:loading='loading > 0'
@click='load'
)
q-btn(
unelevated
icon='mdi-check'
:label='$t(`common.actions.apply`)'
color='secondary'
@click='save'
:loading='loading > 0'
)
q-separator(inset)
.row.q-pa-md.q-col-gutter-md
.col-6
//- -----------------------
//- Theme Options
//- -----------------------
q-card.shadow-1.q-pb-sm
q-card-section.flex.items-center
.text-subtitle1 {{$t('admin.theme.options')}}
q-space
q-btn.acrylic-btn(
icon='las la-redo-alt'
:label='$t(`admin.theme.resetDefaults`)'
flat
size='sm'
color='pink'
@click='resetColors'
)
q-item(tag='label', v-ripple)
blueprint-icon(icon='light-on')
q-item-section
q-item-label {{$t(`admin.theme.darkMode`)}}
q-item-label(caption) {{$t(`admin.theme.darkModeHint`)}}
q-item-section(avatar)
q-toggle(
v-model='config.dark'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.theme.darkMode`)'
)
template(v-for='(cl, idx) of colorKeys', :key='cl')
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='fill-color')
q-item-section
q-item-label {{$t(`admin.theme.` + cl + `Color`)}}
q-item-label(caption) {{$t(`admin.theme.` + cl + `ColorHint`)}}
q-item-section(side)
.text-caption.text-grey-6 {{config[`color` + startCase(cl)]}}
q-item-section(side)
q-btn.q-mr-sm(
:key='`btnpick-` + cl'
glossy
padding='xs md'
no-caps
size='sm'
:style='`background-color: ` + config[`color` + startCase(cl)] + `;`'
text-color='white'
)
q-icon(name='las la-fill', size='xs', left)
span Pick...
q-menu
q-color(
v-model='config[`color` + startCase(cl)]'
)
//- -----------------------
//- Theme Layout
//- -----------------------
q-card.shadow-1.q-pb-sm.q-mt-md
q-card-section
.text-subtitle1 {{$t('admin.theme.layout')}}
q-item
blueprint-icon(icon='right-navigation-toolbar')
q-item-section
q-item-label {{$t(`admin.theme.sidebarPosition`)}}
q-item-label(caption) {{$t(`admin.theme.sidebarPositionHint`)}}
q-item-section.col-auto
q-btn-toggle(
v-model='config.sidebarPosition'
push
glossy
no-caps
toggle-color='primary'
:options=`[
{ label: 'Left', value: 'left' },
{ label: 'Right', value: 'right' }
]`
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='index')
q-item-section
q-item-label {{$t(`admin.theme.tocPosition`)}}
q-item-label(caption) {{$t(`admin.theme.tocPositionHint`)}}
q-item-section.col-auto
q-btn-toggle(
v-model='config.tocPosition'
push
glossy
no-caps
toggle-color='primary'
:options=`[
{ label: 'Left', value: 'left' },
{ label: 'Right', value: 'right' }
]`
)
q-separator.q-my-sm(inset)
q-item(tag='label', v-ripple)
blueprint-icon(icon='share')
q-item-section
q-item-label {{$t(`admin.theme.showSharingMenu`)}}
q-item-label(caption) {{$t(`admin.theme.showSharingMenuHint`)}}
q-item-section(avatar)
q-toggle(
v-model='config.showSharingMenu'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.theme.showSharingMenu`)'
)
q-separator.q-my-sm(inset)
q-item(tag='label', v-ripple)
blueprint-icon(icon='print')
q-item-section
q-item-label {{$t(`admin.theme.showPrintBtn`)}}
q-item-label(caption) {{$t(`admin.theme.showPrintBtnHint`)}}
q-item-section(avatar)
q-toggle(
v-model='config.showPrintBtn'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`admin.theme.showPrintBtn`)'
)
.col-6
//- -----------------------
//- Code Injection
//- -----------------------
q-card.shadow-1.q-pb-sm
q-card-section
.text-subtitle1 {{$t('admin.theme.codeInjection')}}
q-item
blueprint-icon(icon='css')
q-item-section
q-item-label {{$t(`admin.theme.cssOverride`)}}
q-item-label(caption) {{$t(`admin.theme.cssOverrideHint`)}}
q-item
q-item-section
q-no-ssr(:placeholder='$t(`common.loading`)')
util-code-editor.admin-theme-cm(
ref='cmCSS'
v-model='config.injectCSS'
language='css'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='html')
q-item-section
q-item-label {{$t(`admin.theme.headHtmlInjection`)}}
q-item-label(caption) {{$t(`admin.theme.headHtmlInjectionHint`)}}
q-item
q-item-section
q-no-ssr(:placeholder='$t(`common.loading`)')
util-code-editor.admin-theme-cm(
ref='cmHead'
v-model='config.injectHead'
language='html'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='html')
q-item-section
q-item-label {{$t(`admin.theme.bodyHtmlInjection`)}}
q-item-label(caption) {{$t(`admin.theme.bodyHtmlInjectionHint`)}}
q-item
q-item-section
q-no-ssr(:placeholder='$t(`common.loading`)')
util-code-editor.admin-theme-cm(
ref='cmBody'
v-model='config.injectBody'
language='html'
)
</template>
<script>
import gql from 'graphql-tag'
import { get } from 'vuex-pathify'
import _get from 'lodash/get'
import cloneDeep from 'lodash/cloneDeep'
import startCase from 'lodash/startCase'
import { createMetaMixin, useQuasar } from 'quasar'
import UtilCodeEditor from '../components/UtilCodeEditor.vue'
export default {
components: {
UtilCodeEditor
},
mixins: [
createMetaMixin(function () {
return {
title: this.$t('admin.theme.title')
}
})
],
data () {
return {
qsr: useQuasar(),
loading: 0,
colorKeys: [
'primary',
'secondary',
'accent',
'header',
'sidebar'
],
config: {
dark: false,
injectCSS: '',
injectHead: '',
injectBody: '',
colorPrimary: '#1976D2',
colorSecondary: '#02C39A',
colorAccent: '#f03a47',
colorHeader: '#000',
colorSidebar: '#1976D2',
sidebarPosition: 'left',
tocPosition: 'right',
showSharingMenu: true,
showPrintBtn: true
}
}
},
computed: {
currentSiteId: get('admin/currentSiteId', false)
},
watch: {
currentSiteId () {
this.load()
}
},
mounted () {
this.load()
},
methods: {
startCase,
resetColors () {
this.config.dark = false
this.config.colorPrimary = '#1976D2'
this.config.colorSecondary = '#02C39A'
this.config.colorAccent = '#f03a47'
this.config.colorHeader = '#000'
this.config.colorSidebar = '#1976D2'
},
async load () {
if (!this.currentSiteId) { return }
this.loading++
try {
const resp = await this.$apollo.query({
query: gql`
query fetchThemeConfig (
$id: UUID!
) {
siteById(
id: $id
) {
theme {
dark
colorPrimary
colorSecondary
colorAccent
colorHeader
colorSidebar
injectCSS
injectHead
injectBody
sidebarPosition
tocPosition
showSharingMenu
showPrintBtn
}
}
}
`,
variables: {
id: this.currentSiteId
},
fetchPolicy: 'network-only'
})
if (!resp?.data?.siteById?.theme) {
throw new Error('Failed to fetch theme config.')
}
this.config = cloneDeep(resp.data.siteById.theme)
} catch (err) {
this.$q.notify({
type: 'negative',
message: 'Failed to fetch site theme config'
})
}
this.loading--
},
async save () {
this.loading++
try {
const patchTheme = {
dark: this.config.dark,
colorPrimary: this.config.colorPrimary,
colorSecondary: this.config.colorSecondary,
colorAccent: this.config.colorAccent,
colorHeader: this.config.colorHeader,
colorSidebar: this.config.colorSidebar,
injectCSS: this.config.injectCSS,
injectHead: this.config.injectHead,
injectBody: this.config.injectBody,
sidebarPosition: this.config.sidebarPosition,
tocPosition: this.config.tocPosition,
showSharingMenu: this.config.showSharingMenu,
showPrintBtn: this.config.showPrintBtn
}
const respRaw = await this.$apollo.mutate({
mutation: gql`
mutation saveTheme (
$id: UUID!
$patch: SiteUpdateInput!
) {
updateSite (
id: $id,
patch: $patch
) {
status {
succeeded
slug
message
}
}
}
`,
variables: {
id: this.currentSiteId,
patch: {
theme: patchTheme
}
}
})
const resp = _get(respRaw, 'data.updateSite.status', {})
if (resp.succeeded) {
if (this.currentSiteId === this.$store.get('site/id')) {
this.$store.set('site/theme', patchTheme)
this.$q.dark.set(this.config.dark)
}
this.$q.notify({
type: 'positive',
message: this.$t('admin.theme.saveSuccess')
})
} else {
throw new Error(resp.message)
}
} catch (err) {
this.$q.notify({
type: 'negative',
message: 'Failed to save site theme config',
caption: err.message
})
}
this.loading--
}
}
}
</script>
<style lang='scss'>
.admin-theme-cm {
border: 1px solid #CCC;
border-radius: 5px;
overflow: hidden;
> .CodeMirror {
height: 150px;
}
}
</style>
<template lang='pug'>
q-page.admin-groups
.row.q-pa-md.items-center
.col-auto
img.admin-icon.animated.fadeInLeft(src='/_assets/icons/fluent-account.svg')
.col.q-pl-md
.text-h5.text-primary.animated.fadeInLeft {{ $t('admin.users.title') }}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s {{ $t('admin.users.subtitle') }}
.col-auto.flex.items-center
q-input.denser.q-mr-sm(
outlined
v-model='search'
dense
:class='$q.dark.isActive ? `bg-dark` : `bg-white`'
)
template(#prepend)
q-icon(name='las la-search')
q-btn.acrylic-btn.q-mr-sm(
icon='las la-question-circle'
flat
color='grey'
type='a'
href='https://docs.js.wiki/admin/users'
target='_blank'
)
q-btn.q-mr-sm.acrylic-btn(
icon='las la-redo-alt'
flat
color='secondary'
@click='load'
:loading='loading > 0'
)
q-btn(
unelevated
icon='las la-plus'
:label='$t(`admin.users.create`)'
color='primary'
@click='createUser'
:disabled='loading > 0'
)
q-separator(inset)
.row.q-pa-md.q-col-gutter-md
.col-12
q-card.shadow-1
q-table(
:rows='users'
:columns='headers'
row-key='id'
flat
hide-header
hide-bottom
:rows-per-page-options='[0]'
:loading='loading > 0'
)
template(v-slot:body-cell-id='props')
q-td(:props='props')
q-icon(name='las la-user', color='primary', size='sm')
template(v-slot:body-cell-name='props')
q-td(:props='props')
.flex.items-center
strong {{props.value}}
q-icon.q-ml-sm(
v-if='props.row.isSystem'
name='las la-lock'
color='pink'
)
q-icon.q-ml-sm(
v-if='!props.row.isActive'
name='las la-ban'
color='pink'
)
template(v-slot:body-cell-email='props')
q-td(:props='props')
em {{ props.value }}
template(v-slot:body-cell-date='props')
q-td(:props='props')
i18n-t.text-caption(keypath='admin.users.createdAt', tag='div')
template(#date)
strong {{ humanizeDate(props.value) }}
i18n-t.text-caption(
v-if='props.row.lastLoginAt'
keypath='admin.users.lastLoginAt'
tag='div'
)
template(#date)
strong {{ humanizeDate(props.row.lastLoginAt) }}
template(v-slot:body-cell-edit='props')
q-td(:props='props')
q-btn.acrylic-btn.q-mr-sm(
v-if='!props.row.isSystem'
flat
:to='`/_admin/users/` + props.row.id'
icon='las la-pen'
color='indigo'
:label='$t(`common.actions.edit`)'
no-caps
)
q-btn.acrylic-btn(
v-if='!props.row.isSystem'
flat
icon='las la-trash'
color='accent'
@click='deleteGroup(props.row)'
)
</template>
<script>
import gql from 'graphql-tag'
import cloneDeep from 'lodash/cloneDeep'
import { DateTime } from 'luxon'
import { sync } from 'vuex-pathify'
import { createMetaMixin } from 'quasar'
import UserCreateDialog from '../components/UserCreateDialog.vue'
export default {
mixins: [
createMetaMixin(function () {
return {
title: this.$t('admin.users.title')
}
})
],
data () {
return {
users: [],
loading: 0,
search: ''
}
},
computed: {
overlay: sync('admin/overlay', false),
headers () {
return [
{
align: 'center',
field: 'id',
name: 'id',
sortable: false,
style: 'width: 20px'
},
{
label: this.$t('common.field.name'),
align: 'left',
field: 'name',
name: 'name',
sortable: true
},
{
label: this.$t('admin.users.email'),
align: 'left',
field: 'email',
name: 'email',
sortable: false
},
{
align: 'left',
field: 'createdAt',
name: 'date',
sortable: false
},
{
label: '',
align: 'right',
field: 'edit',
name: 'edit',
sortable: false,
style: 'width: 250px'
}
]
}
},
watch: {
overlay (newValue, oldValue) {
if (newValue === '' && oldValue === 'UserEditOverlay') {
this.$router.push('/_admin/users')
this.load()
}
},
$route: 'checkOverlay'
},
mounted () {
this.checkOverlay()
this.load()
},
beforeUnmount () {
this.overlay = ''
},
methods: {
async load () {
this.loading++
this.$q.loading.show()
const resp = await this.$apollo.query({
query: gql`
query getUsers {
users {
id
name
email
isSystem
isActive
createdAt
lastLoginAt
}
}
`,
fetchPolicy: 'network-only'
})
this.users = cloneDeep(resp?.data?.users)
this.$q.loading.hide()
this.loading--
},
humanizeDate (val) {
return DateTime.fromISO(val).toRelative()
},
checkOverlay () {
if (this.$route.params && this.$route.params.id) {
this.$store.set('admin/overlayOpts', { id: this.$route.params.id })
this.$store.set('admin/overlay', 'UserEditOverlay')
} else {
this.$store.set('admin/overlay', '')
}
},
createUser () {
this.$q.dialog({
component: UserCreateDialog
}).onOk(() => {
this.load()
})
},
deleteUser (gr) {
this.$q.dialog({
// component: UserDeleteDialog,
componentProps: {
group: gr
}
}).onOk(() => {
this.load()
})
}
}
}
</script>
<style lang='scss'>
</style>
<template lang='pug'>
q-page.admin-utilities
.row.q-pa-md.items-center
.col-auto
img.admin-icon.animated.fadeInLeft(src='/_assets/icons/fluent-swiss-army-knife.svg')
.col.q-pl-md
.text-h5.text-primary.animated.fadeInLeft {{ $t('admin.utilities.title') }}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s {{ $t('admin.utilities.subtitle') }}
.col-auto
q-btn.q-mr-sm.acrylic-btn(
icon='las la-question-circle'
flat
color='grey'
href='https://docs.requarks.io/admin/utilities'
target='_blank'
type='a'
)
q-separator(inset)
.q-pa-md.q-gutter-md
q-card.shadow-1
q-list(separator)
q-item
blueprint-icon(icon='matches', :hue-rotate='45')
q-item-section
q-item-label {{$t(`admin.utilities.invalidAuthCertificates`)}}
q-item-label(caption) {{$t(`admin.utilities.invalidAuthCertificatesHint`)}}
q-item-section(side)
q-btn.acrylic-btn(
flat
icon='las la-arrow-circle-right'
color='primary'
@click=''
:label='$t(`common.actions.proceed`)'
)
q-item
blueprint-icon(icon='historical', :hue-rotate='45')
q-item-section
q-item-label {{$t(`admin.utilities.purgeHistory`)}}
q-item-label(caption) {{$t(`admin.utilities.purgeHistoryHint`)}}
q-item-section(side)
q-select(
outlined
:label='$t(`admin.utilities.purgeHistoryTimeframe`)'
v-model='purgeHistoryTimeframe'
style='min-width: 175px;'
emit-value
map-options
dense
:options=`[
{ value: '24h', label: $t('admin.utitilies.purgeHistoryToday') },
{ value: '1m', label: $tc('admin.utitilies.purgeHistoryMonth', 1, { count: 1 }) },
{ value: '3m', label: $tc('admin.utitilies.purgeHistoryMonth', 3, { count: 3 }) },
{ value: '6m', label: $tc('admin.utitilies.purgeHistoryMonth', 6, { count: 6 }) },
{ value: '1y', label: $tc('admin.utitilies.purgeHistoryYear', 1, { count: 1 }) },
{ value: '2y', label: $tc('admin.utitilies.purgeHistoryYear', 2, { count: 2 }) }
]`
)
q-separator.q-ml-sm(vertical)
q-item-section(side)
q-btn.acrylic-btn(
flat
icon='las la-arrow-circle-right'
color='primary'
@click=''
:label='$t(`common.actions.proceed`)'
)
</template>
<script>
export default {
data () {
return {
purgeHistoryTimeframe: '1y'
}
}
}
</script>
<style lang='scss'>
</style>
<template lang='pug'>
q-page.admin-webhooks
.row.q-pa-md.items-center
.col-auto
img.admin-icon.animated.fadeInLeft(src='/_assets/icons/fluent-lightning-bolt.svg')
.col.q-pl-md
.text-h5.text-primary.animated.fadeInLeft {{ $t('admin.webhooks.title') }}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s {{ $t('admin.webhooks.subtitle') }}
.col-auto
q-spinner-tail.q-mr-md(
v-show='loading'
color='accent'
size='sm'
)
q-btn.q-mr-sm.acrylic-btn(
icon='las la-question-circle'
flat
color='grey'
href='https://docs.js.wiki/admin/webhooks'
target='_blank'
type='a'
)
q-btn.acrylic-btn.q-mr-sm(
icon='las la-redo-alt'
flat
color='secondary'
:loading='loading > 0'
@click='load'
)
q-btn(
unelevated
icon='las la-plus'
:label='$t(`admin.webhooks.new`)'
color='primary'
@click='createHook'
)
q-separator(inset)
.row.q-pa-md.q-col-gutter-md
.col-12(v-if='hooks.length < 1')
q-card.rounded-borders(
flat
:class='$q.dark.isActive ? `bg-dark-5 text-white` : `bg-grey-3 text-dark`'
)
q-card-section.items-center(horizontal)
q-card-section.col-auto.q-pr-none
q-icon(name='las la-info-circle', size='sm')
q-card-section.text-caption {{ $t('admin.webhooks.none') }}
.col-12(v-else)
q-card
q-list(separator)
q-item(v-for='hook of hooks', :key='hook.id')
q-item-section(side)
q-icon(name='las la-bolt', color='primary')
q-item-section
q-item-label {{hook.name}}
q-item-label(caption) {{hook.url}}
q-item-section(side, style='flex-direction: row; align-items: center;')
template(v-if='hook.state === `pending`')
q-spinner-clock.q-mr-sm(
color='indigo'
size='xs'
)
.text-caption.text-indigo {{$t('admin.webhooks.statePending')}}
q-tooltip(anchor='center left', self='center right') {{$t('admin.webhooks.statePendingHint')}}
template(v-else-if='hook.state === `success`')
q-spinner-infinity.q-mr-sm(
color='positive'
size='xs'
)
.text-caption.text-positive {{$t('admin.webhooks.stateSuccess')}}
q-tooltip(anchor='center left', self='center right') {{$t('admin.webhooks.stateSuccessHint')}}
template(v-else-if='hook.state === `error`')
q-icon.q-mr-sm(
color='negative'
size='xs'
name='las la-exclamation-triangle'
)
.text-caption.text-negative {{$t('admin.webhooks.stateError')}}
q-tooltip(anchor='center left', self='center right') {{$t('admin.webhooks.stateErrorHint')}}
q-separator.q-ml-md(vertical)
q-item-section(side, style='flex-direction: row; align-items: center;')
q-btn.acrylic-btn.q-mr-sm(
color='indigo'
icon='las la-pen'
label='Edit'
flat
no-caps
@click='editHook(hook.id)'
)
q-btn.acrylic-btn(
color='red'
icon='las la-trash'
flat
@click='deleteHook(hook)'
)
</template>
<script>
import cloneDeep from 'lodash/cloneDeep'
import gql from 'graphql-tag'
import { createMetaMixin, QSpinnerClock, QSpinnerInfinity } from 'quasar'
import WebhookDeleteDialog from '../components/WebhookDeleteDialog.vue'
import WebhookEditDialog from '../components/WebhookEditDialog.vue'
export default {
components: {
QSpinnerClock,
QSpinnerInfinity
},
mixins: [
createMetaMixin(function () {
return {
title: this.$t('admin.webhooks.title')
}
})
],
data () {
return {
hooks: [],
loading: 0
}
},
mounted () {
this.load()
},
methods: {
async load () {
this.loading++
this.$q.loading.show()
const resp = await this.$apollo.query({
query: gql`
query getHooks {
hooks {
id
name
url
state
}
}
`,
fetchPolicy: 'network-only'
})
this.config = cloneDeep(resp?.data?.hooks) ?? []
this.$q.loading.hide()
this.loading--
},
createHook () {
this.$q.dialog({
component: WebhookEditDialog,
componentProps: {
hookId: null
}
}).onOk(() => {
this.load()
})
},
editHook (id) {
this.$q.dialog({
component: WebhookEditDialog,
componentProps: {
hookId: id
}
}).onOk(() => {
this.load()
})
},
deleteHook (hook) {
this.$q.dialog({
component: WebhookDeleteDialog,
componentProps: {
hook
}
}).onOk(() => {
this.load()
})
}
}
}
</script>
<style lang='scss'>
</style>
<template>
<div class="fullscreen bg-blue text-white text-center q-pa-md flex flex-center">
<div>
<div style="font-size: 30vh">
404
</div>
<div class="text-h2" style="opacity:.4">
Oops. Nothing here...
</div>
<q-btn
class="q-mt-xl"
color="white"
text-color="blue"
unelevated
to="/"
label="Go Home"
no-caps
/>
</div>
</div>
</template>
<script>
export default {
name: 'Error404'
}
</script>
<template>
<div class="fullscreen bg-blue text-white text-center q-pa-md flex flex-center">
<div>
<div style="font-size: 30vh">
404
</div>
<div class="text-h2" style="opacity:.4">
Oops. Nothing here...
</div>
<q-btn
class="q-mt-xl"
color="white"
text-color="blue"
unelevated
to="/"
label="Go Home"
no-caps
/>
</div>
</div>
</template>
<script>
import { defineComponent } from 'vue'
export default defineComponent({
name: 'ErrorNotFound'
})
</script>
<template lang='pug'>
q-page.column
.page-breadcrumbs.q-py-sm.q-px-md.row
.col
q-breadcrumbs(
active-color='grey-7'
separator-color='grey'
)
template(v-slot:separator)
q-icon(
name='las la-angle-right'
)
q-breadcrumbs-el(icon='las la-home', to='/', aria-label='Home')
q-tooltip Home
q-breadcrumbs-el(
v-for='brd of breadcrumbs'
:key='brd.id'
:icon='brd.icon'
:label='brd.title'
:aria-label='brd.title'
:to='$pageHelpers.getFullPath(brd)'
)
q-breadcrumbs-el(
v-if='editCreateMode'
:icon='pageIcon'
:label='title || `Untitled Page`'
:aria-label='title || `Untitled Page`'
)
.col-auto.flex.items-center.justify-end
template(v-if='!isPublished')
.text-caption.text-accent: strong Unpublished
q-separator.q-mx-sm(vertical)
.text-caption.text-grey-6(v-if='editCreateMode') New Page
.text-caption.text-grey-6(v-if='!editCreateMode') Last modified on #[strong September 5th, 2020]
.page-header.row
//- PAGE ICON
.col-auto.q-pl-md.flex.items-center(v-if='editMode')
q-btn.rounded-borders(
padding='none'
size='37px'
:icon='pageIcon'
color='primary'
flat
)
q-menu(content-class='shadow-7')
icon-picker-dialog(v-model='pageIcon')
.col-auto.q-pl-md.flex.items-center(v-else)
q-icon.rounded-borders(
:name='pageIcon'
size='64px'
color='primary'
)
//- PAGE HEADER
.col.q-pa-md(v-if='editMode')
q-input.no-height(
borderless
v-model='title'
input-class='font-poppins text-h4 text-grey-9'
input-style='padding: 0;'
placeholder='Untitled Page'
hide-hint
)
q-input.no-height(
borderless
v-model='description'
input-class='font-poppins text-subtitle2 text-grey-7'
input-style='padding: 0;'
placeholder='Enter a short description'
hide-hint
)
.col.q-pa-md.font-poppins(v-else)
.text-h4.page-header-title {{title}}
.text-subtitle2.page-header-subtitle {{description}}
//- PAGE ACTIONS
.col-auto.q-pa-md.flex.items-center.justify-end(v-if='editMode')
q-btn.q-mr-sm.acrylic-btn(
flat
icon='las la-times'
color='grey-7'
label='Discard'
aria-label='Discard'
no-caps
@click='mode = `view`'
)
q-btn(
v-if='editorMode === `edit`'
unelevated
icon='las la-check'
color='secondary'
label='Save'
aria-label='Save'
no-caps
@click='mode = `view`'
)
q-btn(
v-else
unelevated
icon='las la-check'
color='secondary'
label='Create'
aria-label='Create'
no-caps
@click='mode = `view`'
)
.col-auto.q-pa-md.flex.items-center.justify-end(v-else)
q-btn.q-mr-md(
flat
dense
icon='las la-bell'
color='grey'
aria-label='Watch Page'
)
q-tooltip Watch Page
q-btn.q-mr-md(
flat
dense
icon='las la-bookmark'
color='grey'
aria-label='Bookmark Page'
)
q-tooltip Bookmark Page
q-btn.q-mr-md(
flat
dense
icon='las la-share-alt'
color='grey'
aria-label='Share'
)
q-tooltip Share
social-sharing-menu
q-btn.q-mr-md(
flat
dense
icon='las la-print'
color='grey'
aria-label='Print'
)
q-tooltip Print
q-btn.acrylic-btn(
flat
icon='las la-edit'
color='deep-orange-9'
label='Edit'
aria-label='Edit'
no-caps
@click='mode = `edit`'
)
.page-container.row.no-wrap.items-stretch(style='flex: 1 1 100%;')
.col(style='order: 1;')
q-no-ssr(v-if='editMode')
component(:is='editorComponent')
//- editor-wysiwyg
//- editor-markdown
q-scroll-area(
:thumb-style='thumbStyle'
:bar-style='barStyle'
style='height: 100%;'
v-else
)
.q-pa-md
div(v-html='render')
template(v-if='relations && relations.length > 0')
q-separator.q-my-lg
.row.align-center
.col.text-left(v-if='relationsLeft.length > 0')
q-btn.q-mr-sm.q-mb-sm(
padding='sm md'
outline
:icon='rel.icon'
no-caps
color='primary'
v-for='rel of relationsLeft'
:key='`rel-id-` + rel.id'
)
.column.text-left.q-pl-md
.text-body2: strong {{rel.label}}
.text-caption {{rel.caption}}
.col.text-center(v-if='relationsCenter.length > 0')
.column
q-btn(
:label='rel.label'
color='primary'
flat
no-caps
:icon='rel.icon'
v-for='rel of relationsCenter'
:key='`rel-id-` + rel.id'
)
.col.text-right(v-if='relationsRight.length > 0')
q-btn.q-ml-sm.q-mb-sm(
padding='sm md'
outline
:icon-right='rel.icon'
no-caps
color='primary'
v-for='rel of relationsRight'
:key='`rel-id-` + rel.id'
)
.column.text-left.q-pr-md
.text-body2: strong {{rel.label}}
.text-caption {{rel.caption}}
.page-sidebar(
v-if='showSidebar'
style='order: 2;'
)
template(v-if='showToc')
//- TOC
.q-pa-md.flex.items-center
q-icon.q-mr-sm(name='las la-stream', color='grey')
.text-caption.text-grey-7 Contents
.q-px-md.q-pb-sm
q-tree(
:nodes='toc'
node-key='key'
v-model:expanded='tocExpanded'
v-model:selected='tocSelected'
)
//- Tags
template(v-if='showTags')
q-separator(v-if='showToc')
.q-pa-md(
@mouseover='showTagsEditBtn = true'
@mouseleave='showTagsEditBtn = false'
)
.flex.items-center
q-icon.q-mr-sm(name='las la-tags', color='grey')
.text-caption.text-grey-7 Tags
q-space
transition(name='fade')
q-btn(
v-show='showTagsEditBtn'
size='sm'
padding='none xs'
icon='las la-pen'
color='deep-orange-9'
flat
label='Edit'
no-caps
@click='tagEditMode = !tagEditMode'
)
page-tags.q-mt-sm(:edit='tagEditMode')
template(v-if='allowRatings && ratingsMode !== `off`')
q-separator(v-if='showToc || showTags')
//- Rating
.q-pa-md.flex.items-center
q-icon.q-mr-sm(name='las la-star-half-alt', color='grey')
.text-caption.text-grey-7 Rate this page
.q-px-md
q-rating(
v-if='ratingsMode === `stars`'
v-model='currentRating'
icon='las la-star'
color='secondary'
size='sm'
)
.flex.items-center(v-else-if='ratingsMode === `thumbs`')
q-btn.acrylic-btn(
flat
icon='las la-thumbs-down'
color='secondary'
)
q-btn.acrylic-btn.q-ml-sm(
flat
icon='las la-thumbs-up'
color='secondary'
)
.page-actions.column.items-stretch.order-last
q-btn.q-py-md(
flat
icon='las la-pen-nib'
color='deep-orange-9'
aria-label='Page Properties'
@click='togglePageProperties'
)
q-tooltip(anchor='center left' self='center right') Page Properties
q-btn.q-py-md(
flat
icon='las la-project-diagram'
color='deep-orange-9'
aria-label='Page Data'
@click='togglePageData'
)
q-tooltip(anchor='center left' self='center right') Page Data
q-separator.q-my-sm(inset)
q-btn.q-py-sm(
flat
icon='las la-history'
color='grey'
aria-label='Page History'
)
q-tooltip(anchor='center left' self='center right') Page History
q-btn.q-py-sm(
flat
icon='las la-code'
color='grey'
aria-label='Page Source'
)
q-tooltip(anchor='center left' self='center right') Page Source
q-btn.q-py-sm(
flat
icon='las la-ellipsis-h'
color='grey'
aria-label='Page Actions'
)
q-menu(
anchor='top left'
self='top right'
auto-close
transition-show='jump-left'
)
q-list(padding, style='min-width: 225px;')
q-item(clickable)
q-item-section.items-center(avatar)
q-icon(color='deep-orange-9', name='las la-atom', size='sm')
q-item-section
q-item-label Convert Page
q-item(clickable)
q-item-section.items-center(avatar)
q-icon(color='deep-orange-9', name='las la-magic', size='sm')
q-item-section
q-item-label Re-render Page
q-item(clickable)
q-item-section.items-center(avatar)
q-icon(color='deep-orange-9', name='las la-sun', size='sm')
q-item-section
q-item-label View Backlinks
q-space
q-btn.q-py-sm(
flat
icon='las la-copy'
color='grey'
aria-label='Duplicate Page'
)
q-tooltip(anchor='center left' self='center right') Duplicate Page
q-btn.q-py-sm(
flat
icon='las la-share'
color='grey'
aria-label='Rename / Move Page'
)
q-tooltip(anchor='center left' self='center right') Rename / Move Page
q-btn.q-py-sm(
flat
icon='las la-trash'
color='grey'
aria-label='Delete Page'
@click='savePage'
)
q-tooltip(anchor='center left' self='center right') Delete Page
q-dialog(
v-model='showSideDialog'
position='right'
full-height
transition-show='jump-left'
transition-hide='jump-right'
class='floating-sidepanel'
)
component(:is='sideDialogComponent')
q-dialog(
v-model='showGlobalDialog'
transition-show='jump-up'
transition-hide='jump-down'
)
component(:is='globalDialogComponent')
</template>
<script>
import { get, sync } from 'vuex-pathify'
import IconPickerDialog from '../components/IconPickerDialog.vue'
import SocialSharingMenu from '../components/SocialSharingMenu.vue'
import PageDataDialog from '../components/PageDataDialog.vue'
import PageTags from '../components/PageTags.vue'
import PagePropertiesDialog from '../components/PagePropertiesDialog.vue'
import PageSaveDialog from '../components/PageSaveDialog.vue'
import EditorWysiwyg from '../components/EditorWysiwyg.vue'
export default {
name: 'PageIndex',
components: {
EditorWysiwyg,
IconPickerDialog,
PageDataDialog,
PagePropertiesDialog,
PageSaveDialog,
PageTags,
SocialSharingMenu
},
data () {
return {
showSideDialog: false,
sideDialogComponent: null,
showGlobalDialog: false,
globalDialogComponent: null,
showTagsEditBtn: false,
tagEditMode: false,
toc: [
{
key: 'h1-0',
label: 'Introduction'
},
{
key: 'h1-1',
label: 'Planets',
children: [
{
key: 'h2-0',
label: 'Earth',
children: [
{
key: 'h3-0',
label: 'Countries',
children: [
{
key: 'h4-0',
label: 'Cities',
children: [
{
key: 'h5-0',
label: 'Montreal',
children: [
{
key: 'h6-0',
label: 'Districts'
}
]
}
]
}
]
}
]
},
{
key: 'h2-1',
label: 'Mars'
},
{
key: 'h2-2',
label: 'Jupiter'
}
]
}
],
tocExpanded: ['h1-0', 'h1-1'],
tocSelected: [],
currentRating: 3,
thumbStyle: {
right: '2px',
borderRadius: '5px',
backgroundColor: '#000',
width: '5px',
opacity: 0.15
},
barStyle: {
backgroundColor: '#FAFAFA',
width: '9px',
opacity: 1
}
}
},
computed: {
mode: sync('page/mode', false),
editorMode: get('page/editorMode', false),
breadcrumbs: get('page/breadcrumbs', false),
title: sync('page/title', false),
description: sync('page/description', false),
relations: get('page/relations', false),
tags: sync('page/tags', false),
ratingsMode: get('site/ratingsMode', false),
allowComments: get('page/allowComments', false),
allowContributions: get('page/allowContributions', false),
allowRatings: get('page/allowRatings', false),
showSidebar () {
return this.$store.get('page/showSidebar') && this.$store.get('site/showSidebar')
},
showTags: get('page/showTags', false),
showToc: get('page/showToc', false),
tocDepth: get('page/tocDepth', false),
isPublished: get('page/isPublished', false),
pageIcon: sync('page/icon', false),
render: get('page/render', false),
editorComponent () {
return this.$store.get('page/editor') ? `editor-${this.$store.get('page/editor')}` : null
},
relationsLeft () {
return this.relations ? this.relations.filter(r => r.position === 'left') : []
},
relationsCenter () {
return this.relations ? this.relations.filter(r => r.position === 'center') : []
},
relationsRight () {
return this.relations ? this.relations.filter(r => r.position === 'right') : []
},
editMode () {
return this.mode === 'edit'
},
editCreateMode () {
return this.mode === 'edit' && this.editorMode === 'create'
}
},
watch: {
toc () {
this.refreshTocExpanded()
},
tocDepth () {
this.refreshTocExpanded()
}
},
mounted () {
this.refreshTocExpanded()
},
methods: {
togglePageProperties () {
this.sideDialogComponent = 'PagePropertiesDialog'
this.showSideDialog = true
},
togglePageData () {
this.sideDialogComponent = 'PageDataDialog'
this.showSideDialog = true
},
savePage () {
this.globalDialogComponent = 'PageSaveDialog'
this.showGlobalDialog = true
},
refreshTocExpanded (baseToc) {
const toExpand = []
let isRootNode = false
if (!baseToc) {
baseToc = this.toc
isRootNode = true
}
if (baseToc.length > 0) {
for (const node of baseToc) {
if (node.key >= `h${this.tocDepth.min}` && node.key <= `h${this.tocDepth.max}`) {
toExpand.push(node.key)
}
if (node.children?.length && node.key < `h${this.tocDepth.max}`) {
toExpand.push(...this.refreshTocExpanded(node.children))
}
}
}
if (isRootNode) {
this.tocExpanded = toExpand
} else {
return toExpand
}
}
}
}
</script>
<style lang="scss">
.page-breadcrumbs {
@at-root .body--light & {
background: linear-gradient(to bottom, $grey-1 0%, $grey-3 100%);
border-bottom: 1px solid $grey-4;
}
@at-root .body--dark & {
background: linear-gradient(to bottom, $dark-3 0%, $dark-4 100%);
border-bottom: 1px solid $dark-3;
}
}
.page-header {
@at-root .body--light & {
background: linear-gradient(to bottom, $grey-2 0%, $grey-1 100%);
border-bottom: 1px solid $grey-4;
border-top: 1px solid #FFF;
}
@at-root .body--dark & {
background: linear-gradient(to bottom, $dark-4 0%, $dark-3 100%);
// border-bottom: 1px solid $dark-5;
border-top: 1px solid $dark-6;
}
.no-height .q-field__control {
height: auto;
}
&-title {
@at-root .body--light & {
color: $grey-9;
}
@at-root .body--dark & {
color: #FFF;
}
}
&-subtitle {
@at-root .body--light & {
color: $grey-7;
}
@at-root .body--dark & {
color: rgba(255,255,255,.6);
}
}
}
.page-container {
@at-root .body--light & {
border-top: 1px solid #FFF;
}
// @at-root .body--dark & {
// border-top: 1px solid $dark-6;
// }
}
.page-sidebar {
flex: 0 0 300px;
@at-root .body--light & {
background-color: $grey-2;
}
@at-root .body--dark & {
background-color: $dark-5;
}
.q-separator {
background-color: rgba(0,0,0,.05);
border-bottom: 1px solid;
@at-root .body--light & {
background-color: rgba(0,0,0,.05);
border-bottom-color: #FFF;
}
@at-root .body--dark & {
background-color: rgba(255,255,255,.04);
border-bottom-color: #070a0d;
}
}
}
.page-actions {
flex: 0 0 56px;
@at-root .body--light & {
background-color: $grey-3;
}
@at-root .body--dark & {
background-color: $dark-4;
}
}
.floating-syncpanel {
.q-dialog__inner {
margin-top: 14px;
right: 140px;
left: auto;
.q-card {
border-radius: 17px;
}
}
&-msg {
padding-top: 1px;
font-weight: 500;
font-size: .75rem;
padding-right: 16px;
display: flex;
align-items: center;
}
}
.floating-sidepanel {
.q-dialog__inner {
right: 24px;
.q-card {
border-radius: 4px !important;
min-width: 450px;
.q-card__section {
border-radius: 0;
}
}
}
.alt-card {
@at-root .body--light & {
background-color: $grey-2;
border-top: 1px solid $grey-4;
box-shadow: inset 0 1px 0 0 #FFF, inset 0 -1px 0 0 #FFF;
border-bottom: 1px solid $grey-4;
}
@at-root .body--dark & {
background-color: $dark-4;
border-top: 1px solid lighten($dark-3, 8%);
box-shadow: inset 0 1px 0 0 $dark-6, inset 0 -1px 0 0 $dark-6;
border-bottom: 1px solid lighten($dark-3, 8%);
}
}
&-quickaccess {
width: 40px;
border-radius: 4px !important;
background-color: rgba(0,0,0,.75);
color: #FFF;
position: fixed;
right: 486px;
top: 74px;
z-index: -1;
display: flex;
flex-direction: column;
box-shadow: 0 0 5px 0 rgba(0,0,0,.5) !important;
@at-root .q-transition--jump-left-enter-active & {
display: none !important;
}
@at-root .q-transition--jump-right-leave-active & {
display: none !important;
}
}
}
.q-card {
@at-root .body--light & {
background-color: #FFF;
}
@at-root .body--dark & {
background-color: $dark-3;
}
}
</style>
<template lang='pug'>
.auth(:style='`background-image: url(` + bgUrl + `);`')
.auth-box
.flex.mb-5
.auth-login-logo
q-avatar(square, size='34px')
q-img(:src='logoUrl')
.auth-login-title
.text-h6.text-grey-9 {{ siteTitle }}
q-banner.bg-red-7.text-white.q-mt-md(
v-if='errorShown'
transition='slide-y-reverse-transition'
dense
)
template(v-slot:avatar)
q-icon.q-pl-sm(name='las la-exclamation-triangle', size='sm')
span {{errorMessage}}
//-------------------------------------------------
//- PROVIDERS LIST
//-------------------------------------------------
template(v-if='screen === `login` && strategies.length > 1')
.auth-login-subtitle
.text-subtitle1 {{$t('auth.selectAuthProvider')}}
.auth-login-list
q-list.bg-white.shadow-2.rounded-borders.q-pa-sm(separator)
q-item.rounded-borders(
clickable
v-ripple
v-for='(stg, idx) of filteredStrategies'
:key='stg.key'
@click='selectedStrategyKey = stg.key'
:class='stg.key === selectedStrategyKey ? `bg-primary text-white` : ``'
)
q-item-section(avatar)
q-avatar.mr-3(:color='stg.strategy.color', rounded, size='32px')
div(v-html='stg.strategy.icon')
q-item-section
span.text-none {{stg.displayName}}
//-------------------------------------------------
//- LOGIN FORM
//-------------------------------------------------
template(v-if='screen === `login` && selectedStrategy.strategy.useForm')
.auth-login-subtitle
.text-subtitle1 {{$t('auth.enterCredentials')}}
.auth-login-form
q-input.text-black(
outlined
bg-color='white'
ref='iptEmail'
v-model='username'
:label='isUsernameEmail ? $t(`auth.fields.email`) : $t(`auth.fields.username`)'
:type='isUsernameEmail ? `email` : `text`'
:autocomplete='isUsernameEmail ? `email` : `username`'
)
template(v-slot:prepend)
q-icon(name='las la-user-circle', color='primary')
q-input.q-mt-sm(
outlined
bg-color='white'
ref='iptPassword'
v-model='password'
:type='hidePassword ? "password" : "text"'
:label='$t("auth:fields.password")'
autocomplete='current-password'
@keyup.enter='login'
)
template(v-slot:prepend)
q-icon(name='las la-key', color='primary')
template(v-slot:append)
q-icon.cursor-pointer(
:name='hidePassword ? "las la-eye-slash" : "las la-eye"'
@click='() => (hidePassword = !hidePassword)'
)
q-btn.q-mt-sm.q-py-xs.full-width(
no-caps
color='blue-7'
push
@click='login'
:loading='isLoading'
:label='$t(`auth.actions.login`)'
icon='las la-arrow-right'
)
.text-center.q-mt-lg
q-btn(
flat
no-caps
rounded
color='grey-8'
@click.stop.prevent='forgotPassword'
href='#forgot'
): .text-caption {{ $t('auth.forgotPasswordLink') }}
q-btn(
v-if='selectedStrategyKey === `local` && selectedStrategy.selfRegistration'
color='indigo darken-2'
flat
no-caps
rounded
href='/register'
): .text-caption {{ $t('auth.switchToRegister.link') }}
</template>
<script>
import { get } from 'vuex-pathify'
import gql from 'graphql-tag'
import find from 'lodash/find'
import _get from 'lodash/get'
import has from 'lodash/has'
import head from 'lodash/head'
import reject from 'lodash/reject'
import sortBy from 'lodash/sortBy'
import Cookies from 'js-cookie'
export default {
name: 'PageLogin',
i18nOptions: { namespaces: 'auth' },
data () {
return {
error: false,
strategies: [],
selectedStrategyKey: 'unselected',
selectedStrategy: { key: 'unselected', strategy: { useForm: false, usernameType: 'email' } },
screen: 'login',
username: '',
password: '',
hidePassword: true,
securityCode: '',
continuationToken: '',
isLoading: false,
loaderColor: 'grey darken-4',
loaderTitle: 'Working...',
isShown: false,
newPassword: '',
newPasswordVerify: '',
isTFAShown: false,
isTFASetupShown: false,
tfaQRImage: '',
errorShown: false,
errorMessage: '',
bgUrl: '_assets/bg/login-v3.jpg'
}
},
computed: {
logoUrl: get('site/logoUrl', false),
siteTitle: get('site/title', false),
isSocialShown () {
return this.strategies.length > 1
},
filteredStrategies () {
const qParams = new URLSearchParams(!import.meta.env.SSR ? window.location.search : '')
if (this.hideLocal && !qParams.has('all')) {
return reject(this.strategies, ['key', 'local'])
} else {
return this.strategies
}
},
isUsernameEmail () {
return this.selectedStrategy.strategy.usernameType === 'email'
}
},
watch: {
filteredStrategies (newValue, oldValue) {
if (head(newValue).strategy.useForm) {
this.selectedStrategyKey = head(newValue).key
}
},
selectedStrategyKey (newValue, oldValue) {
this.selectedStrategy = find(this.strategies, ['key', newValue])
if (this.screen === 'changePwd') {
return
}
this.screen = 'login'
if (!this.selectedStrategy.strategy.useForm) {
this.isLoading = true
window.location.assign('/login/' + newValue)
} else {
this.$nextTick(() => {
this.$refs.iptEmail.focus()
})
}
}
},
mounted () {
this.isShown = true
if (this.changePwdContinuationToken) {
this.screen = 'changePwd'
this.continuationToken = this.changePwdContinuationToken
}
},
methods: {
/**
* LOGIN
*/
async login () {
this.errorShown = false
if (this.username.length < 2) {
this.errorMessage = this.$t('auth.invalidEmailUsername')
this.errorShown = true
this.$refs.iptEmail.focus()
} else if (this.password.length < 2) {
this.errorMessage = this.$t('auth.invalidPassword')
this.errorShown = true
this.$refs.iptPassword.focus()
} else {
this.loaderColor = 'grey darken-4'
this.loaderTitle = this.$t('auth.signingIn')
this.isLoading = true
try {
const resp = await this.$apollo.mutate({
mutation: gql`
mutation($username: String!, $password: String!, $strategy: String!) {
authentication {
login(username: $username, password: $password, strategy: $strategy) {
responseResult {
succeeded
errorCode
slug
message
}
jwt
mustChangePwd
mustProvideTFA
mustSetupTFA
continuationToken
redirect
tfaQRImage
}
}
}
`,
variables: {
username: this.username,
password: this.password,
strategy: this.selectedStrategy.key
}
})
if (has(resp, 'data.authentication.login')) {
const respObj = _get(resp, 'data.authentication.login', {})
if (respObj.responseResult.succeeded === true) {
this.handleLoginResponse(respObj)
} else {
throw new Error(respObj.responseResult.message)
}
} else {
throw new Error(this.$t('auth.genericError'))
}
} catch (err) {
console.error(err)
this.$q.notify({
type: 'negative',
message: err.message
})
this.isLoading = false
}
}
},
/**
* VERIFY TFA CODE
*/
async verifySecurityCode (setup = false) {
if (this.securityCode.length !== 6) {
this.$store.commit('showNotification', {
style: 'red',
message: 'Enter a valid security code.',
icon: 'alert'
})
if (setup) {
this.$refs.iptTFASetup.focus()
} else {
this.$refs.iptTFA.focus()
}
} else {
this.loaderColor = 'grey darken-4'
this.loaderTitle = this.$t('auth.signingIn')
this.isLoading = true
try {
const resp = await this.$apollo.mutate({
mutation: gql`
mutation(
$continuationToken: String!
$securityCode: String!
$setup: Boolean
) {
authentication {
loginTFA(
continuationToken: $continuationToken
securityCode: $securityCode
setup: $setup
) {
responseResult {
succeeded
errorCode
slug
message
}
jwt
mustChangePwd
continuationToken
redirect
}
}
}
`,
variables: {
continuationToken: this.continuationToken,
securityCode: this.securityCode,
setup
}
})
if (has(resp, 'data.authentication.loginTFA')) {
const respObj = _get(resp, 'data.authentication.loginTFA', {})
if (respObj.responseResult.succeeded === true) {
this.handleLoginResponse(respObj)
} else {
if (!setup) {
this.isTFAShown = false
}
throw new Error(respObj.responseResult.message)
}
} else {
throw new Error(this.$t('auth.genericError'))
}
} catch (err) {
console.error(err)
this.$q.notify({
type: 'negative',
message: err.message
})
this.isLoading = false
}
}
},
/**
* CHANGE PASSWORD
*/
async changePassword () {
this.loaderColor = 'grey darken-4'
this.loaderTitle = this.$t('auth.changePwd.loading')
this.isLoading = true
try {
const resp = await this.$apollo.mutate({
mutation: gql`
mutation (
$continuationToken: String!
$newPassword: String!
) {
authentication {
loginChangePassword (
continuationToken: $continuationToken
newPassword: $newPassword
) {
responseResult {
succeeded
errorCode
slug
message
}
jwt
continuationToken
redirect
}
}
}
`,
variables: {
continuationToken: this.continuationToken,
newPassword: this.newPassword
}
})
if (has(resp, 'data.authentication.loginChangePassword')) {
const respObj = _get(resp, 'data.authentication.loginChangePassword', {})
if (respObj.responseResult.succeeded === true) {
this.handleLoginResponse(respObj)
} else {
throw new Error(respObj.responseResult.message)
}
} else {
throw new Error(this.$t('auth.genericError'))
}
} catch (err) {
console.error(err)
this.$store.commit('showNotification', {
style: 'red',
message: err.message,
icon: 'alert'
})
this.isLoading = false
}
},
/**
* SWITCH TO FORGOT PASSWORD SCREEN
*/
forgotPassword () {
this.screen = 'forgot'
this.$nextTick(() => {
this.$refs.iptForgotPwdEmail.focus()
})
},
/**
* FORGOT PASSWORD SUBMIT
*/
async forgotPasswordSubmit () {
this.loaderColor = 'grey darken-4'
this.loaderTitle = this.$t('auth.forgotPasswordLoading')
this.isLoading = true
try {
const resp = await this.$apollo.mutate({
mutation: gql`
mutation (
$email: String!
) {
authentication {
forgotPassword (
email: $email
) {
responseResult {
succeeded
errorCode
slug
message
}
}
}
}
`,
variables: {
email: this.username
}
})
if (has(resp, 'data.authentication.forgotPassword.responseResult')) {
const respObj = _get(resp, 'data.authentication.forgotPassword.responseResult', {})
if (respObj.succeeded === true) {
this.$store.commit('showNotification', {
style: 'success',
message: this.$t('auth.forgotPasswordSuccess'),
icon: 'email'
})
this.screen = 'login'
} else {
throw new Error(respObj.message)
}
} else {
throw new Error(this.$t('auth.genericError'))
}
} catch (err) {
console.error(err)
this.$store.commit('showNotification', {
style: 'red',
message: err.message,
icon: 'alert'
})
}
this.isLoading = false
},
handleLoginResponse (respObj) {
this.continuationToken = respObj.continuationToken
if (respObj.mustChangePwd === true) {
this.screen = 'changePwd'
this.$nextTick(() => {
this.$refs.iptNewPassword.focus()
})
this.isLoading = false
} else if (respObj.mustProvideTFA === true) {
this.securityCode = ''
this.isTFAShown = true
setTimeout(() => {
this.$refs.iptTFA.focus()
}, 500)
this.isLoading = false
} else if (respObj.mustSetupTFA === true) {
this.securityCode = ''
this.isTFASetupShown = true
this.tfaQRImage = respObj.tfaQRImage
setTimeout(() => {
this.$refs.iptTFASetup.focus()
}, 500)
this.isLoading = false
} else {
this.loaderColor = 'green darken-1'
this.loaderTitle = this.$t('auth.loginSuccess')
Cookies.set('jwt', respObj.jwt, { expires: 365 })
setTimeout(() => {
const loginRedirect = Cookies.get('loginRedirect')
if (loginRedirect === '/' && respObj.redirect) {
Cookies.remove('loginRedirect')
window.location.replace(respObj.redirect)
} else if (loginRedirect) {
Cookies.remove('loginRedirect')
window.location.replace(loginRedirect)
} else if (respObj.redirect) {
window.location.replace(respObj.redirect)
} else {
window.location.replace('/')
}
}, 1000)
}
}
},
apollo: {
strategies: {
prefetch: false,
query: gql`
{
authentication {
activeStrategies(enabledOnly: true) {
key
strategy {
key
logo
color
icon
useForm
usernameType
}
displayName
order
selfRegistration
}
}
}
`,
update: (data) => sortBy(data.authentication.activeStrategies, ['order']),
watchLoading (isLoading) {
this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'login-strategies-refresh')
}
}
}
}
</script>
<style lang="scss">
.auth-login {
&-logo {
padding: 12px 0 0 12px;
width: 58px;
height: 58px;
background-color: #000;
margin-left: 12px;
border-radius: 7px;
}
&-title {
height: 58px;
padding-left: 12px;
display: flex;
align-items: center;
text-shadow: .5px .5px #FFF;
}
&-subtitle {
padding: 24px 12px 12px 12px;
color: #111;
font-weight: 500;
text-shadow: 1px 1px rgba(255,255,255,.5);
background-image: linear-gradient(to bottom, rgba(0,0,0,0), rgba(0,0,0,.15));
text-align: center;
border-bottom: 1px solid rgba(0,0,0,.3);
}
&-info {
border-top: 1px solid rgba(255,255,255,.85);
background-color: rgba(255,255,255,.15);
border-bottom: 1px solid rgba(0,0,0,.15);
padding: 12px;
font-size: 13px;
text-align: center;
color: mc('grey', '900');
}
&-list {
border-top: 1px solid rgba(255,255,255,.85);
padding: 12px;
}
&-form {
padding: 12px;
border-top: 1px solid rgba(255,255,255,.85);
}
&-main {
flex: 1 0 100vw;
height: 100vh;
}
&-tfa {
background-color: #EEE;
border: 7px solid #FFF;
&-field input {
text-align: center;
}
&-qr {
background-color: #FFF;
padding: 5px;
border-radius: 5px;
width: 200px;
height: 200px;
margin: 0 auto;
}
}
}
</style>
<template lang="pug">
q-page.q-py-md(:style-fn='pageStyle')
.text-header {{$t('profile.myInfo')}}
q-item
blueprint-icon(icon='contact')
q-item-section
q-item-label {{$t(`profile.displayName`)}}
q-item-label(caption) {{$t(`profile.displayNameHint`)}}
q-item-section
q-input(
outlined
v-model='config.name'
dense
hide-bottom-space
:aria-label='$t(`profile.displayName`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='envelope')
q-item-section
q-item-label {{$t(`profile.email`)}}
q-item-label(caption) {{$t(`profile.emailHint`)}}
q-item-section
q-input(
outlined
v-model='config.email'
dense
:aria-label='$t(`profile.email`)'
readonly
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='address')
q-item-section
q-item-label {{$t(`profile.location`)}}
q-item-label(caption) {{$t(`profile.locationHint`)}}
q-item-section
q-input(
outlined
v-model='config.location'
dense
hide-bottom-space
:aria-label='$t(`profile.location`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='new-job')
q-item-section
q-item-label {{$t(`profile.jobTitle`)}}
q-item-label(caption) {{$t(`profile.jobTitleHint`)}}
q-item-section
q-input(
outlined
v-model='config.jobTitle'
dense
hide-bottom-space
:aria-label='$t(`profile.jobTitle`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='gender')
q-item-section
q-item-label {{$t(`profile.pronouns`)}}
q-item-label(caption) {{$t(`profile.pronounsHint`)}}
q-item-section
q-input(
outlined
v-model='config.pronouns'
dense
hide-bottom-space
:aria-label='$t(`profile.pronouns`)'
)
.text-header.q-mt-lg {{$t('profile.preferences')}}
q-item
blueprint-icon(icon='timezone')
q-item-section
q-item-label {{$t(`profile.timezone`)}}
q-item-label(caption) {{$t(`profile.timezoneHint`)}}
q-item-section
q-select(
outlined
v-model='config.timezone'
:options='timezones'
option-value='value'
option-label='text'
emit-value
map-options
dense
options-dense
:aria-label='$t(`admin.general.defaultTimezone`)'
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='calendar')
q-item-section
q-item-label {{$t(`profile.dateFormat`)}}
q-item-label(caption) {{$t(`profile.dateFormatHint`)}}
q-item-section
q-select(
outlined
v-model='config.dateFormat'
emit-value
map-options
dense
:aria-label='$t(`admin.general.defaultDateFormat`)'
:options=`[
{ label: $t('profile.localeDefault'), value: '' },
{ label: 'DD/MM/YYYY', value: 'DD/MM/YYYY' },
{ label: 'DD.MM.YYYY', value: 'DD.MM.YYYY' },
{ label: 'MM/DD/YYYY', value: 'MM/DD/YYYY' },
{ label: 'YYYY-MM-DD', value: 'YYYY-MM-DD' },
{ label: 'YYYY/MM/DD', value: 'YYYY/MM/DD' }
]`
)
q-separator.q-my-sm(inset)
q-item
blueprint-icon(icon='clock')
q-item-section
q-item-label {{$t(`profile.timeFormat`)}}
q-item-label(caption) {{$t(`profile.timeFormatHint`)}}
q-item-section.col-auto
q-btn-toggle(
v-model='config.timeFormat'
push
glossy
no-caps
toggle-color='primary'
:options=`[
{ label: $t('admin.general.defaultTimeFormat12h'), value: '12h' },
{ label: $t('admin.general.defaultTimeFormat24h'), value: '24h' }
]`
)
q-separator.q-my-sm(inset)
q-item(tag='label', v-ripple)
blueprint-icon(icon='light-on')
q-item-section
q-item-label {{$t(`profile.darkMode`)}}
q-item-label(caption) {{$t(`profile.darkModeHint`)}}
q-item-section(avatar)
q-toggle(
v-model='config.darkMode'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='$t(`profile.darkMode`)'
)
.actions-bar.q-mt-lg
q-btn(
icon='mdi-check'
unelevated
label='Save Changes'
color='secondary'
)
</template>
<script>
import { get } from 'vuex-pathify'
export default {
data () {
return {
config: {
name: 'John Doe',
email: 'john.doe@company.com',
location: '',
jobTitle: '',
pronouns: '',
dateFormat: '',
timeFormat: '12h',
darkMode: false
}
}
},
computed: {
timezones: get('data/timezones', false)
},
watch: {
'config.darkMode' (newValue) {
this.$q.dark.set(newValue)
}
},
methods: {
pageStyle (offset, height) {
return {
'min-height': `${height - 100 - offset}px`
}
}
}
}
</script>
<template lang='pug'>
.fullscreen.bg-blue.text-white.text-center.q-pa-md.flex.flex-center
div
.text-h1 Unknown Site
.text-h2(style="opacity:.4") Oops. Nothing here...
q-btn(
class="q-mt-xl"
color="white"
text-color="blue"
unelevated
to="/"
label="Go Home"
no-caps
)
</template>
<script>
export default {
name: 'UnknownSite'
}
</script>
import { route } from 'quasar/wrappers'
import { createRouter, createMemoryHistory, createWebHistory, createWebHashHistory } from 'vue-router'
import routes from './routes'
/*
* If not building with SSR mode, you can
* directly export the Router instantiation;
*
* The function below can be async too; either use
* async/await or return a Promise which resolves
* with the Router instance.
*/
export default route(function (/* { store, ssrContext } */) {
const createHistory = process.env.SERVER
? createMemoryHistory
: (process.env.VUE_ROUTER_MODE === 'history' ? createWebHistory : createWebHashHistory)
const Router = createRouter({
scrollBehavior: () => ({ left: 0, top: 0 }),
routes,
// Leave this as is and make changes in quasar.conf.js instead!
// quasar.conf.js -> build -> vueRouterMode
// quasar.conf.js -> build -> publicPath
history: createHistory(process.env.VUE_ROUTER_BASE)
})
return Router
})
const routes = [
// {
// path: '/',
// component: () => import('../layouts/MainLayout.vue'),
// children: [
// { path: '', component: () => import('../pages/Index.vue') },
// { path: 'n/:editor?', component: () => import('../pages/Index.vue') }
// ]
// },
// {
// path: '/login',
// component: () => import('../layouts/AuthLayout.vue'),
// children: [
// { path: '', component: () => import('../pages/Login.vue') }
// ]
// },
// {
// path: '/p',
// component: () => import('../layouts/ProfileLayout.vue'),
// children: [
// { path: '', redirect: '/p/profile' },
// { path: 'profile', component: () => import('../pages/Profile.vue') }
// ]
// },
{
path: '/_admin',
component: () => import('../layouts/AdminLayout.vue'),
children: [
{ path: '', redirect: '/_admin/dashboard' },
{ path: 'dashboard', component: () => import('../pages/AdminDashboard.vue') }
// { path: 'sites', component: () => import('../pages/AdminSites.vue') },
// // -> Site
// { path: ':siteid/general', component: () => import('../pages/AdminGeneral.vue') },
// { path: ':siteid/editors', component: () => import('../pages/AdminEditors.vue') },
// { path: ':siteid/locale', component: () => import('../pages/AdminLocale.vue') },
// { path: ':siteid/login', component: () => import('../pages/AdminLogin.vue') },
// { path: ':siteid/navigation', component: () => import('../pages/AdminNavigation.vue') },
// { path: ':siteid/storage/:id?', component: () => import('../pages/AdminStorage.vue') },
// { path: ':siteid/rendering', component: () => import('../pages/AdminRendering.vue') },
// { path: ':siteid/theme', component: () => import('../pages/AdminTheme.vue') },
// // -> Users
// { path: 'auth', component: () => import('../pages/AdminAuth.vue') },
// { path: 'groups/:id?/:section?', component: () => import('../pages/AdminGroups.vue') },
// { path: 'users/:id?/:section?', component: () => import('../pages/AdminUsers.vue') },
// // -> System
// { path: 'api', component: () => import('../pages/AdminApi.vue') },
// { path: 'extensions', component: () => import('../pages/AdminExtensions.vue') },
// { path: 'mail', component: () => import('../pages/AdminMail.vue') },
// { path: 'security', component: () => import('../pages/AdminSecurity.vue') },
// { path: 'system', component: () => import('../pages/AdminSystem.vue') },
// { path: 'utilities', component: () => import('../pages/AdminUtilities.vue') },
// { path: 'webhooks', component: () => import('../pages/AdminWebhooks.vue') },
// { path: 'flags', component: () => import('../pages/AdminFlags.vue') }
]
},
// {
// path: '/_unknown-site',
// component: () => import('../pages/UnknownSite.vue')
// },
// Always leave this as last one,
// but you can also remove it
{
path: '/:catchAll(.*)*',
component: () => import('pages/ErrorNotFound.vue')
}
]
export default routes
import { defineStore } from 'pinia'
import gql from 'graphql-tag'
import cloneDeep from 'lodash/cloneDeep'
/* global APOLLO_CLIENT */
export const useAdminStore = defineStore('admin', {
state: () => ({
currentSiteId: null,
info: {
currentVersion: 'n/a',
latestVersion: 'n/a',
groupsTotal: 0,
pagesTotal: 0,
usersTotal: 0
},
overlay: null,
overlayOpts: {},
sites: [],
locales: [
{ code: 'en', name: 'English' }
]
}),
getters: {},
actions: {
async fetchSites () {
const resp = await APOLLO_CLIENT.query({
query: gql`
query getSites {
sites {
id
hostname
isEnabled
title
}
}
`,
fetchPolicy: 'network-only'
})
this.sites = cloneDeep(resp?.data?.sites ?? [])
}
}
})
import { defineStore } from 'pinia'
export const useDataStore = defineStore('data', {
state: () => ({
timezones: [
{ text: '(GMT-11:00) Niue', value: 'Pacific/Niue' },
{ text: '(GMT-11:00) Pago Pago', value: 'Pacific/Pago_Pago' },
{ text: '(GMT-10:00) Hawaii Time', value: 'Pacific/Honolulu' },
{ text: '(GMT-10:00) Rarotonga', value: 'Pacific/Rarotonga' },
{ text: '(GMT-10:00) Tahiti', value: 'Pacific/Tahiti' },
{ text: '(GMT-09:30) Marquesas', value: 'Pacific/Marquesas' },
{ text: '(GMT-09:00) Alaska Time', value: 'America/Anchorage' },
{ text: '(GMT-09:00) Gambier', value: 'Pacific/Gambier' },
{ text: '(GMT-08:00) Pacific Time', value: 'America/Los_Angeles' },
{ text: '(GMT-08:00) Pacific Time - Tijuana', value: 'America/Tijuana' },
{ text: '(GMT-08:00) Pacific Time - Vancouver', value: 'America/Vancouver' },
{ text: '(GMT-08:00) Pacific Time - Whitehorse', value: 'America/Whitehorse' },
{ text: '(GMT-08:00) Pitcairn', value: 'Pacific/Pitcairn' },
{ text: '(GMT-07:00) Mountain Time', value: 'America/Denver' },
{ text: '(GMT-07:00) Mountain Time - Arizona', value: 'America/Phoenix' },
{ text: '(GMT-07:00) Mountain Time - Chihuahua, Mazatlan', value: 'America/Mazatlan' },
{ text: '(GMT-07:00) Mountain Time - Dawson Creek', value: 'America/Dawson_Creek' },
{ text: '(GMT-07:00) Mountain Time - Edmonton', value: 'America/Edmonton' },
{ text: '(GMT-07:00) Mountain Time - Hermosillo', value: 'America/Hermosillo' },
{ text: '(GMT-07:00) Mountain Time - Yellowknife', value: 'America/Yellowknife' },
{ text: '(GMT-06:00) Belize', value: 'America/Belize' },
{ text: '(GMT-06:00) Central Time', value: 'America/Chicago' },
{ text: '(GMT-06:00) Central Time - Mexico City', value: 'America/Mexico_City' },
{ text: '(GMT-06:00) Central Time - Regina', value: 'America/Regina' },
{ text: '(GMT-06:00) Central Time - Tegucigalpa', value: 'America/Tegucigalpa' },
{ text: '(GMT-06:00) Central Time - Winnipeg', value: 'America/Winnipeg' },
{ text: '(GMT-06:00) Costa Rica', value: 'America/Costa_Rica' },
{ text: '(GMT-06:00) El Salvador', value: 'America/El_Salvador' },
{ text: '(GMT-06:00) Galapagos', value: 'Pacific/Galapagos' },
{ text: '(GMT-06:00) Guatemala', value: 'America/Guatemala' },
{ text: '(GMT-06:00) Managua', value: 'America/Managua' },
{ text: '(GMT-05:00) America Cancun', value: 'America/Cancun' },
{ text: '(GMT-05:00) Bogota', value: 'America/Bogota' },
{ text: '(GMT-05:00) Easter Island', value: 'Pacific/Easter' },
{ text: '(GMT-05:00) Eastern Time', value: 'America/New_York' },
{ text: '(GMT-05:00) Eastern Time - Iqaluit', value: 'America/Iqaluit' },
{ text: '(GMT-05:00) Eastern Time - Toronto', value: 'America/Toronto' },
{ text: '(GMT-05:00) Guayaquil', value: 'America/Guayaquil' },
{ text: '(GMT-05:00) Havana', value: 'America/Havana' },
{ text: '(GMT-05:00) Jamaica', value: 'America/Jamaica' },
{ text: '(GMT-05:00) Lima', value: 'America/Lima' },
{ text: '(GMT-05:00) Nassau', value: 'America/Nassau' },
{ text: '(GMT-05:00) Panama', value: 'America/Panama' },
{ text: '(GMT-05:00) Port-au-Prince', value: 'America/Port-au-Prince' },
{ text: '(GMT-05:00) Rio Branco', value: 'America/Rio_Branco' },
{ text: '(GMT-04:00) Atlantic Time - Halifax', value: 'America/Halifax' },
{ text: '(GMT-04:00) Barbados', value: 'America/Barbados' },
{ text: '(GMT-04:00) Bermuda', value: 'Atlantic/Bermuda' },
{ text: '(GMT-04:00) Boa Vista', value: 'America/Boa_Vista' },
{ text: '(GMT-04:00) Caracas', value: 'America/Caracas' },
{ text: '(GMT-04:00) Curacao', value: 'America/Curacao' },
{ text: '(GMT-04:00) Grand Turk', value: 'America/Grand_Turk' },
{ text: '(GMT-04:00) Guyana', value: 'America/Guyana' },
{ text: '(GMT-04:00) La Paz', value: 'America/La_Paz' },
{ text: '(GMT-04:00) Manaus', value: 'America/Manaus' },
{ text: '(GMT-04:00) Martinique', value: 'America/Martinique' },
{ text: '(GMT-04:00) Port of Spain', value: 'America/Port_of_Spain' },
{ text: '(GMT-04:00) Porto Velho', value: 'America/Porto_Velho' },
{ text: '(GMT-04:00) Puerto Rico', value: 'America/Puerto_Rico' },
{ text: '(GMT-04:00) Santo Domingo', value: 'America/Santo_Domingo' },
{ text: '(GMT-04:00) Thule', value: 'America/Thule' },
{ text: '(GMT-03:30) Newfoundland Time - St. Johns', value: 'America/St_Johns' },
{ text: '(GMT-03:00) Araguaina', value: 'America/Araguaina' },
{ text: '(GMT-03:00) Asuncion', value: 'America/Asuncion' },
{ text: '(GMT-03:00) Belem', value: 'America/Belem' },
{ text: '(GMT-03:00) Buenos Aires', value: 'America/Argentina/Buenos_Aires' },
{ text: '(GMT-03:00) Campo Grande', value: 'America/Campo_Grande' },
{ text: '(GMT-03:00) Cayenne', value: 'America/Cayenne' },
{ text: '(GMT-03:00) Cuiaba', value: 'America/Cuiaba' },
{ text: '(GMT-03:00) Fortaleza', value: 'America/Fortaleza' },
{ text: '(GMT-03:00) Godthab', value: 'America/Godthab' },
{ text: '(GMT-03:00) Maceio', value: 'America/Maceio' },
{ text: '(GMT-03:00) Miquelon', value: 'America/Miquelon' },
{ text: '(GMT-03:00) Montevideo', value: 'America/Montevideo' },
{ text: '(GMT-03:00) Palmer', value: 'Antarctica/Palmer' },
{ text: '(GMT-03:00) Paramaribo', value: 'America/Paramaribo' },
{ text: '(GMT-03:00) Punta Arenas', value: 'America/Punta_Arenas' },
{ text: '(GMT-03:00) Recife', value: 'America/Recife' },
{ text: '(GMT-03:00) Rothera', value: 'Antarctica/Rothera' },
{ text: '(GMT-03:00) Salvador', value: 'America/Bahia' },
{ text: '(GMT-03:00) Santiago', value: 'America/Santiago' },
{ text: '(GMT-03:00) Stanley', value: 'Atlantic/Stanley' },
{ text: '(GMT-02:00) Noronha', value: 'America/Noronha' },
{ text: '(GMT-02:00) Sao Paulo', value: 'America/Sao_Paulo' },
{ text: '(GMT-02:00) South Georgia', value: 'Atlantic/South_Georgia' },
{ text: '(GMT-01:00) Azores', value: 'Atlantic/Azores' },
{ text: '(GMT-01:00) Cape Verde', value: 'Atlantic/Cape_Verde' },
{ text: '(GMT-01:00) Scoresbysund', value: 'America/Scoresbysund' },
{ text: '(GMT+00:00) Abidjan', value: 'Africa/Abidjan' },
{ text: '(GMT+00:00) Accra', value: 'Africa/Accra' },
{ text: '(GMT+00:00) Bissau', value: 'Africa/Bissau' },
{ text: '(GMT+00:00) Canary Islands', value: 'Atlantic/Canary' },
{ text: '(GMT+00:00) Casablanca', value: 'Africa/Casablanca' },
{ text: '(GMT+00:00) Danmarkshavn', value: 'America/Danmarkshavn' },
{ text: '(GMT+00:00) Dublin', value: 'Europe/Dublin' },
{ text: '(GMT+00:00) El Aaiun', value: 'Africa/El_Aaiun' },
{ text: '(GMT+00:00) Faeroe', value: 'Atlantic/Faroe' },
{ text: '(GMT+00:00) GMT (no daylight saving)', value: 'Etc/GMT' },
{ text: '(GMT+00:00) Lisbon', value: 'Europe/Lisbon' },
{ text: '(GMT+00:00) London', value: 'Europe/London' },
{ text: '(GMT+00:00) Monrovia', value: 'Africa/Monrovia' },
{ text: '(GMT+00:00) Reykjavik', value: 'Atlantic/Reykjavik' },
{ text: '(GMT+01:00) Algiers', value: 'Africa/Algiers' },
{ text: '(GMT+01:00) Amsterdam', value: 'Europe/Amsterdam' },
{ text: '(GMT+01:00) Andorra', value: 'Europe/Andorra' },
{ text: '(GMT+01:00) Berlin', value: 'Europe/Berlin' },
{ text: '(GMT+01:00) Brussels', value: 'Europe/Brussels' },
{ text: '(GMT+01:00) Budapest', value: 'Europe/Budapest' },
{ text: '(GMT+01:00) Central European Time - Belgrade', value: 'Europe/Belgrade' },
{ text: '(GMT+01:00) Central European Time - Prague', value: 'Europe/Prague' },
{ text: '(GMT+01:00) Ceuta', value: 'Africa/Ceuta' },
{ text: '(GMT+01:00) Copenhagen', value: 'Europe/Copenhagen' },
{ text: '(GMT+01:00) Gibraltar', value: 'Europe/Gibraltar' },
{ text: '(GMT+01:00) Lagos', value: 'Africa/Lagos' },
{ text: '(GMT+01:00) Luxembourg', value: 'Europe/Luxembourg' },
{ text: '(GMT+01:00) Madrid', value: 'Europe/Madrid' },
{ text: '(GMT+01:00) Malta', value: 'Europe/Malta' },
{ text: '(GMT+01:00) Monaco', value: 'Europe/Monaco' },
{ text: '(GMT+01:00) Ndjamena', value: 'Africa/Ndjamena' },
{ text: '(GMT+01:00) Oslo', value: 'Europe/Oslo' },
{ text: '(GMT+01:00) Paris', value: 'Europe/Paris' },
{ text: '(GMT+01:00) Rome', value: 'Europe/Rome' },
{ text: '(GMT+01:00) Stockholm', value: 'Europe/Stockholm' },
{ text: '(GMT+01:00) Tirane', value: 'Europe/Tirane' },
{ text: '(GMT+01:00) Tunis', value: 'Africa/Tunis' },
{ text: '(GMT+01:00) Vienna', value: 'Europe/Vienna' },
{ text: '(GMT+01:00) Warsaw', value: 'Europe/Warsaw' },
{ text: '(GMT+01:00) Zurich', value: 'Europe/Zurich' },
{ text: '(GMT+02:00) Amman', value: 'Asia/Amman' },
{ text: '(GMT+02:00) Athens', value: 'Europe/Athens' },
{ text: '(GMT+02:00) Beirut', value: 'Asia/Beirut' },
{ text: '(GMT+02:00) Bucharest', value: 'Europe/Bucharest' },
{ text: '(GMT+02:00) Cairo', value: 'Africa/Cairo' },
{ text: '(GMT+02:00) Chisinau', value: 'Europe/Chisinau' },
{ text: '(GMT+02:00) Damascus', value: 'Asia/Damascus' },
{ text: '(GMT+02:00) Gaza', value: 'Asia/Gaza' },
{ text: '(GMT+02:00) Helsinki', value: 'Europe/Helsinki' },
{ text: '(GMT+02:00) Jerusalem', value: 'Asia/Jerusalem' },
{ text: '(GMT+02:00) Johannesburg', value: 'Africa/Johannesburg' },
{ text: '(GMT+02:00) Khartoum', value: 'Africa/Khartoum' },
{ text: '(GMT+02:00) Kiev', value: 'Europe/Kiev' },
{ text: '(GMT+02:00) Maputo', value: 'Africa/Maputo' },
{ text: '(GMT+02:00) Moscow-01 - Kaliningrad', value: 'Europe/Kaliningrad' },
{ text: '(GMT+02:00) Nicosia', value: 'Asia/Nicosia' },
{ text: '(GMT+02:00) Riga', value: 'Europe/Riga' },
{ text: '(GMT+02:00) Sofia', value: 'Europe/Sofia' },
{ text: '(GMT+02:00) Tallinn', value: 'Europe/Tallinn' },
{ text: '(GMT+02:00) Tripoli', value: 'Africa/Tripoli' },
{ text: '(GMT+02:00) Vilnius', value: 'Europe/Vilnius' },
{ text: '(GMT+02:00) Windhoek', value: 'Africa/Windhoek' },
{ text: '(GMT+03:00) Baghdad', value: 'Asia/Baghdad' },
{ text: '(GMT+03:00) Istanbul', value: 'Europe/Istanbul' },
{ text: '(GMT+03:00) Minsk', value: 'Europe/Minsk' },
{ text: '(GMT+03:00) Moscow+00 - Moscow', value: 'Europe/Moscow' },
{ text: '(GMT+03:00) Nairobi', value: 'Africa/Nairobi' },
{ text: '(GMT+03:00) Qatar', value: 'Asia/Qatar' },
{ text: '(GMT+03:00) Riyadh', value: 'Asia/Riyadh' },
{ text: '(GMT+03:00) Syowa', value: 'Antarctica/Syowa' },
{ text: '(GMT+03:30) Tehran', value: 'Asia/Tehran' },
{ text: '(GMT+04:00) Baku', value: 'Asia/Baku' },
{ text: '(GMT+04:00) Dubai', value: 'Asia/Dubai' },
{ text: '(GMT+04:00) Mahe', value: 'Indian/Mahe' },
{ text: '(GMT+04:00) Mauritius', value: 'Indian/Mauritius' },
{ text: '(GMT+04:00) Moscow+01 - Samara', value: 'Europe/Samara' },
{ text: '(GMT+04:00) Reunion', value: 'Indian/Reunion' },
{ text: '(GMT+04:00) Tbilisi', value: 'Asia/Tbilisi' },
{ text: '(GMT+04:00) Yerevan', value: 'Asia/Yerevan' },
{ text: '(GMT+04:30) Kabul', value: 'Asia/Kabul' },
{ text: '(GMT+05:00) Aqtau', value: 'Asia/Aqtau' },
{ text: '(GMT+05:00) Aqtobe', value: 'Asia/Aqtobe' },
{ text: '(GMT+05:00) Ashgabat', value: 'Asia/Ashgabat' },
{ text: '(GMT+05:00) Dushanbe', value: 'Asia/Dushanbe' },
{ text: '(GMT+05:00) Karachi', value: 'Asia/Karachi' },
{ text: '(GMT+05:00) Kerguelen', value: 'Indian/Kerguelen' },
{ text: '(GMT+05:00) Maldives', value: 'Indian/Maldives' },
{ text: '(GMT+05:00) Mawson', value: 'Antarctica/Mawson' },
{ text: '(GMT+05:00) Moscow+02 - Yekaterinburg', value: 'Asia/Yekaterinburg' },
{ text: '(GMT+05:00) Tashkent', value: 'Asia/Tashkent' },
{ text: '(GMT+05:30) Colombo', value: 'Asia/Colombo' },
{ text: '(GMT+05:30) India Standard Time', value: 'Asia/Kolkata' },
{ text: '(GMT+05:45) Kathmandu', value: 'Asia/Kathmandu' },
{ text: '(GMT+06:00) Almaty', value: 'Asia/Almaty' },
{ text: '(GMT+06:00) Bishkek', value: 'Asia/Bishkek' },
{ text: '(GMT+06:00) Chagos', value: 'Indian/Chagos' },
{ text: '(GMT+06:00) Dhaka', value: 'Asia/Dhaka' },
{ text: '(GMT+06:00) Moscow+03 - Omsk', value: 'Asia/Omsk' },
{ text: '(GMT+06:00) Thimphu', value: 'Asia/Thimphu' },
{ text: '(GMT+06:00) Vostok', value: 'Antarctica/Vostok' },
{ text: '(GMT+06:30) Cocos', value: 'Indian/Cocos' },
{ text: '(GMT+06:30) Rangoon', value: 'Asia/Yangon' },
{ text: '(GMT+07:00) Bangkok', value: 'Asia/Bangkok' },
{ text: '(GMT+07:00) Christmas', value: 'Indian/Christmas' },
{ text: '(GMT+07:00) Davis', value: 'Antarctica/Davis' },
{ text: '(GMT+07:00) Hanoi', value: 'Asia/Saigon' },
{ text: '(GMT+07:00) Hovd', value: 'Asia/Hovd' },
{ text: '(GMT+07:00) Jakarta', value: 'Asia/Jakarta' },
{ text: '(GMT+07:00) Moscow+04 - Krasnoyarsk', value: 'Asia/Krasnoyarsk' },
{ text: '(GMT+08:00) Brunei', value: 'Asia/Brunei' },
{ text: '(GMT+08:00) China Time - Beijing', value: 'Asia/Shanghai' },
{ text: '(GMT+08:00) Choibalsan', value: 'Asia/Choibalsan' },
{ text: '(GMT+08:00) Hong Kong', value: 'Asia/Hong_Kong' },
{ text: '(GMT+08:00) Kuala Lumpur', value: 'Asia/Kuala_Lumpur' },
{ text: '(GMT+08:00) Macau', value: 'Asia/Macau' },
{ text: '(GMT+08:00) Makassar', value: 'Asia/Makassar' },
{ text: '(GMT+08:00) Manila', value: 'Asia/Manila' },
{ text: '(GMT+08:00) Moscow+05 - Irkutsk', value: 'Asia/Irkutsk' },
{ text: '(GMT+08:00) Singapore', value: 'Asia/Singapore' },
{ text: '(GMT+08:00) Taipei', value: 'Asia/Taipei' },
{ text: '(GMT+08:00) Ulaanbaatar', value: 'Asia/Ulaanbaatar' },
{ text: '(GMT+08:00) Western Time - Perth', value: 'Australia/Perth' },
{ text: '(GMT+08:30) Pyongyang', value: 'Asia/Pyongyang' },
{ text: '(GMT+09:00) Dili', value: 'Asia/Dili' },
{ text: '(GMT+09:00) Jayapura', value: 'Asia/Jayapura' },
{ text: '(GMT+09:00) Moscow+06 - Yakutsk', value: 'Asia/Yakutsk' },
{ text: '(GMT+09:00) Palau', value: 'Pacific/Palau' },
{ text: '(GMT+09:00) Seoul', value: 'Asia/Seoul' },
{ text: '(GMT+09:00) Tokyo', value: 'Asia/Tokyo' },
{ text: '(GMT+09:30) Central Time - Darwin', value: 'Australia/Darwin' },
{ text: '(GMT+10:00) Dumont D\'Urville', value: 'Antarctica/DumontDUrville' },
{ text: '(GMT+10:00) Eastern Time - Brisbane', value: 'Australia/Brisbane' },
{ text: '(GMT+10:00) Guam', value: 'Pacific/Guam' },
{ text: '(GMT+10:00) Moscow+07 - Vladivostok', value: 'Asia/Vladivostok' },
{ text: '(GMT+10:00) Port Moresby', value: 'Pacific/Port_Moresby' },
{ text: '(GMT+10:00) Truk', value: 'Pacific/Chuuk' },
{ text: '(GMT+10:30) Central Time - Adelaide', value: 'Australia/Adelaide' },
{ text: '(GMT+11:00) Casey', value: 'Antarctica/Casey' },
{ text: '(GMT+11:00) Eastern Time - Hobart', value: 'Australia/Hobart' },
{ text: '(GMT+11:00) Eastern Time - Melbourne, Sydney', value: 'Australia/Sydney' },
{ text: '(GMT+11:00) Efate', value: 'Pacific/Efate' },
{ text: '(GMT+11:00) Guadalcanal', value: 'Pacific/Guadalcanal' },
{ text: '(GMT+11:00) Kosrae', value: 'Pacific/Kosrae' },
{ text: '(GMT+11:00) Moscow+08 - Magadan', value: 'Asia/Magadan' },
{ text: '(GMT+11:00) Norfolk', value: 'Pacific/Norfolk' },
{ text: '(GMT+11:00) Noumea', value: 'Pacific/Noumea' },
{ text: '(GMT+11:00) Ponape', value: 'Pacific/Pohnpei' },
{ text: '(GMT+12:00) Funafuti', value: 'Pacific/Funafuti' },
{ text: '(GMT+12:00) Kwajalein', value: 'Pacific/Kwajalein' },
{ text: '(GMT+12:00) Majuro', value: 'Pacific/Majuro' },
{ text: '(GMT+12:00) Moscow+09 - Petropavlovsk-Kamchatskiy', value: 'Asia/Kamchatka' },
{ text: '(GMT+12:00) Nauru', value: 'Pacific/Nauru' },
{ text: '(GMT+12:00) Tarawa', value: 'Pacific/Tarawa' },
{ text: '(GMT+12:00) Wake', value: 'Pacific/Wake' },
{ text: '(GMT+12:00) Wallis', value: 'Pacific/Wallis' },
{ text: '(GMT+13:00) Auckland', value: 'Pacific/Auckland' },
{ text: '(GMT+13:00) Enderbury', value: 'Pacific/Enderbury' },
{ text: '(GMT+13:00) Fakaofo', value: 'Pacific/Fakaofo' },
{ text: '(GMT+13:00) Fiji', value: 'Pacific/Fiji' },
{ text: '(GMT+13:00) Tongatapu', value: 'Pacific/Tongatapu' },
{ text: '(GMT+14:00) Apia', value: 'Pacific/Apia' },
{ text: '(GMT+14:00) Kiritimati', value: 'Pacific/Kiritimati' }
]
}),
getters: {},
actions: {}
})
import { defineStore } from 'pinia'
export const useEditorStore = defineStore('editor', {
state: () => ({
editor: '',
content: '',
mode: 'create',
activeModal: '',
activeModalData: null,
media: {
folderTree: [],
currentFolderId: 0,
currentFileId: null
},
checkoutDateActive: '',
editors: {}
}),
getters: {},
actions: {}
})
import { store } from 'quasar/wrappers'
import { createPinia } from 'pinia'
/*
* If not building with SSR mode, you can
* directly export the Store instantiation;
*
* The function below can be async too; either use
* async/await or return a Promise which resolves
* with the Store instance.
*/
export default store((/* { ssrContext } */) => {
const pinia = createPinia()
// You can add Pinia plugins here
// pinia.use(SomePiniaPlugin)
return pinia
})
import { defineStore } from 'pinia'
export const usePageStore = defineStore('page', {
state: () => ({
mode: 'view',
editor: 'wysiwyg',
editorMode: 'edit',
id: 0,
authorId: 0,
authorName: 'Unknown',
createdAt: '',
description: 'How to install Wiki.js on Ubuntu 18.04 / 20.04',
isPublished: true,
showInTree: true,
locale: 'en',
path: '',
publishEndDate: '',
publishStartDate: '',
tags: ['cities', 'canada'],
title: 'Ubuntu',
icon: 'lab la-empire',
updatedAt: '',
relations: [],
scriptJsLoad: '',
scriptJsUnload: '',
scriptStyles: '',
allowComments: false,
allowContributions: true,
allowRatings: true,
showSidebar: true,
showToc: true,
showTags: true,
tocDepth: {
min: 1,
max: 2
},
breadcrumbs: [
{
id: 1,
title: 'Installation',
icon: 'las la-file-alt',
locale: 'en',
path: 'installation'
},
{
id: 2,
title: 'Ubuntu',
icon: 'lab la-ubuntu',
locale: 'en',
path: 'installation/ubuntu'
}
],
effectivePermissions: {
comments: {
read: false,
write: false,
manage: false
},
history: {
read: false
},
source: {
read: false
},
pages: {
write: false,
manage: false,
delete: false,
script: false,
style: false
},
system: {
manage: false
}
},
commentsCount: 0,
content: '',
render: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'
}),
getters: {},
actions: {
/**
* PAGE - CREATE
*/
pageCreate ({ editor, locale, path }) {
// -> Editor View
this.editor = editor
this.editorMode = 'create'
// if (['markdown', 'api'].includes(editor)) {
// commit('site/SET_SHOW_SIDE_NAV', false, { root: true })
// } else {
// commit('site/SET_SHOW_SIDE_NAV', true, { root: true })
// }
// if (['markdown', 'channel', 'api'].includes(editor)) {
// commit('site/SET_SHOW_SIDEBAR', false, { root: true })
// } else {
// commit('site/SET_SHOW_SIDEBAR', true, { root: true })
// }
// -> Page Data
this.id = 0
this.locale = locale || this.locale
if (path) {
this.path = path
} else {
this.path = this.path.length < 2 ? 'new-page' : `${this.path}/new-page`
}
this.title = ''
this.description = ''
this.icon = 'las la-file-alt'
this.isPublished = false
this.relations = []
this.tags = []
this.breadcrumbs = []
this.content = ''
this.render = ''
// -> View Mode
this.mode = 'edit'
},
generateToc () {
}
}
})
import { defineStore } from 'pinia'
import gql from 'graphql-tag'
import clone from 'lodash/clone'
export const useSiteStore = defineStore('site', {
state: () => ({
routerLoading: false,
id: null,
useLocales: false,
hostname: '',
company: '',
contentLicense: '',
dark: false,
title: '',
description: '',
logoUrl: '',
search: '',
searchIsFocused: false,
searchIsLoading: false,
searchRestrictLocale: false,
searchRestrictPath: false,
printView: false,
ratingsMode: 'thumbs',
pageDataTemplates: [],
showSideNav: true,
showSidebar: true,
theme: {
dark: false,
injectCSS: '',
injectHead: '',
injectBody: '',
colorPrimary: '#1976D2',
colorSecondary: '#02C39A',
colorAccent: '#f03a47',
colorHeader: '#000',
colorSidebar: '#1976D2',
sidebarPosition: 'left',
tocPosition: 'right',
showSharingMenu: true,
showPrintBtn: true
},
thumbStyle: {
right: '2px',
borderRadius: '5px',
backgroundColor: '#000',
width: '5px',
opacity: 0.15
},
barStyle: {
backgroundColor: '#FAFAFA',
width: '9px',
opacity: 1
}
}),
getters: {},
actions: {
async loadSite (hostname) {
try {
const resp = await APOLLO_CLIENT.query({
query: gql`
query getSiteInfo ($hostname: String!) {
siteByHostname (
hostname: $hostname
exact: false
) {
id
hostname
title
description
logoText
company
contentLicense
}
}
`,
variables: {
hostname
}
})
const siteInfo = resp.data.siteByHostname
if (siteInfo) {
this.id = clone(siteInfo.id)
this.hostname = clone(siteInfo.hostname)
this.title = clone(siteInfo.title)
this.description = clone(siteInfo.description)
this.logoUrl = clone(siteInfo.logoUrl)
this.company = clone(siteInfo.company)
this.contentLicense = clone(siteInfo.contentLicense)
} else {
throw new Error('Invalid Site')
}
} catch (err) {
console.warn(err.networkError?.result ?? err.message)
throw err
}
}
}
})
/* eslint-disable */
// THIS FEATURE-FLAG FILE IS AUTOGENERATED,
// REMOVAL OR CHANGES WILL CAUSE RELATED TYPES TO STOP WORKING
import "quasar/dist/types/feature-flag";
declare module "quasar/dist/types/feature-flag" {
interface QuasarFeatureFlags {
store: true;
}
}
import { defineStore } from 'pinia'
import jwtDecode from 'jwt-decode'
import Cookies from 'js-cookie'
export const useUserStore = defineStore('user', {
state: () => ({
id: 0,
email: '',
name: '',
pictureUrl: '',
localeCode: '',
defaultEditor: '',
timezone: '',
dateFormat: '',
appearance: '',
permissions: [],
iat: 0,
exp: 0,
authenticated: false
}),
getters: {},
actions: {
refreshAuth () {
const jwtCookie = Cookies.get('jwt')
if (jwtCookie) {
try {
const jwtData = jwtDecode(jwtCookie)
this.id = jwtData.id
this.email = jwtData.email
this.name = jwtData.name
this.pictureUrl = jwtData.av
this.localeCode = jwtData.lc
this.timezone = jwtData.tz || Intl.DateTimeFormat().resolvedOptions().timeZone || ''
this.dateFormat = jwtData.df || ''
this.appearance = jwtData.ap || ''
// this.defaultEditor = jwtData.defaultEditor
this.permissions = jwtData.permissions
this.iat = jwtData.iat
this.exp = jwtData.exp
this.authenticated = true
} catch (err) {
console.debug('Invalid JWT. Silent authentication skipped.')
}
}
}
}
})
This diff was suppressed by a .gitattributes entry.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment