Migrating Bukkript IntelliJ plugin to inside of KotlinBukkitAPI Tooling
This commit is contained in:
1 parent
ed6bc67dc1
commit
077e371be6
16 files changed
+180
-17
No files matched your search
@@ -9,10 +9,14 @@ version = "0.0.1-SNAPSHOT"
|
|||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
jcenter()
|
jcenter()
|
||||||
|
maven("http://nexus.devsrsouza.com.br/repository/maven-public/")
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(kotlin("stdlib-jdk8"))
|
implementation(kotlin("stdlib-jdk8"))
|
||||||
|
|
||||||
|
api("br.com.devsrsouza.bukkript:script-definition-embedded:0.1.0-SNAPSHOT")
|
||||||
|
|
||||||
testCompile("junit", "junit", "4.12")
|
testCompile("junit", "junit", "4.12")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package br.com.devsrsouza.kotlinbukkitapi.tooling
|
||||||
|
|
||||||
|
import com.intellij.ui.IconManager
|
||||||
|
import javax.swing.Icon
|
||||||
|
|
||||||
|
object Assets {
|
||||||
|
private fun load(path: String): Icon {
|
||||||
|
return IconManager.getInstance().getIcon(path, Assets::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
private const val assetFolder = "/assets"
|
||||||
|
|
||||||
|
val KotlinBukkitAPIIcon =
|
||||||
|
load("$assetFolder/icons/kotlinbukkitapi-icon.svg")
|
||||||
|
}
|
||||||
+39
@@ -0,0 +1,39 @@
|
|||||||
|
package br.com.devsrsouza.kotlinbukkitapi.tooling.bukkript
|
||||||
|
|
||||||
|
import com.intellij.ide.actions.CreateFileFromTemplateAction
|
||||||
|
import com.intellij.ide.actions.CreateFileFromTemplateDialog
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.psi.PsiDirectory
|
||||||
|
import com.intellij.psi.PsiFile
|
||||||
|
|
||||||
|
class BukkriptCreateNewFileAction : CreateFileFromTemplateAction(
|
||||||
|
BUKKRIPT_SCRIPT,
|
||||||
|
BUKKRIPT_DESCRIPTION,
|
||||||
|
BukkriptFileType.INSTANCE.icon
|
||||||
|
) {
|
||||||
|
override fun getActionName(
|
||||||
|
directory: PsiDirectory?,
|
||||||
|
newName: String,
|
||||||
|
templateName: String?
|
||||||
|
): String = BUKKRIPT_CREATE_SCRIPT_DESCRIPTION
|
||||||
|
|
||||||
|
override fun createFile(
|
||||||
|
name: String,
|
||||||
|
templateName: String,
|
||||||
|
dir: PsiDirectory
|
||||||
|
): PsiFile? = super.createFile("$name.bk", templateName, dir)
|
||||||
|
|
||||||
|
override fun buildDialog(
|
||||||
|
project: Project,
|
||||||
|
directory: PsiDirectory,
|
||||||
|
builder: CreateFileFromTemplateDialog.Builder
|
||||||
|
) {
|
||||||
|
builder.setTitle(BUKKRIPT_SCRIPT)
|
||||||
|
.addKind(
|
||||||
|
BUKKRIPT_FILE,
|
||||||
|
BukkriptFileType.INSTANCE.icon,
|
||||||
|
BUKKRIPT_SCRIPT
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
package br.com.devsrsouza.kotlinbukkitapi.tooling.bukkript
|
||||||
|
|
||||||
|
import br.com.devsrsouza.kotlinbukkitapi.tooling.Assets
|
||||||
|
import com.intellij.openapi.fileTypes.LanguageFileType
|
||||||
|
import com.intellij.openapi.fileTypes.ex.FileTypeIdentifiableByVirtualFile
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||||
|
import javax.swing.Icon
|
||||||
|
|
||||||
|
class BukkriptFileType : LanguageFileType(KotlinLanguage.INSTANCE), FileTypeIdentifiableByVirtualFile {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmField
|
||||||
|
val INSTANCE = BukkriptFileType()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getIcon(): Icon? = Assets.KotlinBukkitAPIIcon
|
||||||
|
|
||||||
|
override fun getName(): String = BUKKRIPT_FILE
|
||||||
|
|
||||||
|
override fun getDefaultExtension(): String = BUKKRIPT_EXTENSION
|
||||||
|
|
||||||
|
override fun getDescription(): String = BUKKRIPT_DESCRIPTION
|
||||||
|
|
||||||
|
override fun isMyFileType(file: VirtualFile): Boolean = file.name.isBukkriptScript()
|
||||||
|
}
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
package br.com.devsrsouza.kotlinbukkitapi.tooling.bukkript
|
||||||
|
|
||||||
|
import com.intellij.ide.IconProvider
|
||||||
|
import com.intellij.openapi.project.DumbAware
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiFile
|
||||||
|
import javax.swing.Icon
|
||||||
|
|
||||||
|
class BukkriptIconProvider : IconProvider(), DumbAware {
|
||||||
|
override fun getIcon(element: PsiElement, flags: Int): Icon? {
|
||||||
|
if(element is PsiFile && element.name.isBukkriptScript()) {
|
||||||
|
return BukkriptFileType.INSTANCE.icon
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
package br.com.devsrsouza.kotlinbukkitapi.tooling.bukkript
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.utils.PathUtil
|
||||||
|
import java.io.File
|
||||||
|
import kotlin.script.experimental.intellij.ScriptDefinitionsProvider
|
||||||
|
import br.com.devsrsouza.bukkript.script.definition.BukkriptScript
|
||||||
|
|
||||||
|
class BukkriptScriptDefinitionProvider : ScriptDefinitionsProvider {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val ID = "BukkriptScriptDefinition"
|
||||||
|
}
|
||||||
|
|
||||||
|
override val id: String
|
||||||
|
get() = ID
|
||||||
|
|
||||||
|
override fun getDefinitionClasses(): Iterable<String> {
|
||||||
|
return listOf("br.com.devsrsouza.bukkript.script.definition.BukkriptScript")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getDefinitionsClassPath(): Iterable<File> {
|
||||||
|
val jarFile = PathUtil.getResourcePathForClass(BukkriptScript::class.java)
|
||||||
|
|
||||||
|
return listOf(jarFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun useDiscovery(): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package br.com.devsrsouza.kotlinbukkitapi.tooling.bukkript
|
||||||
|
|
||||||
|
const val BUKKRIPT_EXTENSION = "bk.kts"
|
||||||
|
|
||||||
|
const val BUKKRIPT_SCRIPT = "Bukkript Script"
|
||||||
|
const val BUKKRIPT_FILE = "Bukkript File"
|
||||||
|
const val BUKKRIPT_DESCRIPTION = "Bukkript Script File for Bukkit"
|
||||||
|
const val BUKKRIPT_CREATE_SCRIPT_DESCRIPTION = "Create Bukkript Script"
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package br.com.devsrsouza.kotlinbukkitapi.tooling.bukkript
|
||||||
|
|
||||||
|
fun String.isBukkriptScript() = endsWith(".$BUKKRIPT_EXTENSION", true)
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package br.com.devsrsouza.kotlinbukkitapi.tooling
|
package br.com.devsrsouza.kotlinbukkitapi.tooling.menu
|
||||||
|
|
||||||
data class MenuDeclaration(
|
data class MenuDeclaration(
|
||||||
val displayname: String,
|
val displayname: String,
|
||||||
+1
-2
@@ -1,11 +1,10 @@
|
|||||||
package br.com.devsrsouza.kotlinbukkitapi.tooling
|
package br.com.devsrsouza.kotlinbukkitapi.tooling.menu
|
||||||
|
|
||||||
import com.intellij.util.ImageLoader
|
import com.intellij.util.ImageLoader
|
||||||
import org.jetbrains.kotlin.utils.keysToMap
|
import org.jetbrains.kotlin.utils.keysToMap
|
||||||
import java.awt.*
|
import java.awt.*
|
||||||
import javax.swing.JPanel
|
import javax.swing.JPanel
|
||||||
|
|
||||||
|
|
||||||
class InventoryComponent(
|
class InventoryComponent(
|
||||||
val declaration: MenuDeclaration
|
val declaration: MenuDeclaration
|
||||||
) : JPanel() {
|
) : JPanel() {
|
||||||
+3
-2
@@ -1,4 +1,4 @@
|
|||||||
package br.com.devsrsouza.kotlinbukkitapi.tooling
|
package br.com.devsrsouza.kotlinbukkitapi.tooling.menu
|
||||||
|
|
||||||
import com.intellij.openapi.editor.event.CaretEvent
|
import com.intellij.openapi.editor.event.CaretEvent
|
||||||
import com.intellij.openapi.editor.event.CaretListener
|
import com.intellij.openapi.editor.event.CaretListener
|
||||||
@@ -73,7 +73,8 @@ class MenuPreviewFileEditor(
|
|||||||
currentScroll = JBScrollPane(
|
currentScroll = JBScrollPane(
|
||||||
panel {
|
panel {
|
||||||
tree.forEachDescendantOfType<KtCallExpression> {
|
tree.forEachDescendantOfType<KtCallExpression> {
|
||||||
val declaration = findMenuDeclaration(
|
val declaration =
|
||||||
|
findMenuDeclaration(
|
||||||
it,
|
it,
|
||||||
currentSelectedLine
|
currentSelectedLine
|
||||||
)
|
)
|
||||||
+5
-3
@@ -1,11 +1,12 @@
|
|||||||
package br.com.devsrsouza.kotlinbukkitapi.tooling
|
package br.com.devsrsouza.kotlinbukkitapi.tooling.menu
|
||||||
|
|
||||||
|
|
||||||
|
import br.com.devsrsouza.kotlinbukkitapi.tooling.bukkript.BukkriptFileType
|
||||||
import com.intellij.openapi.fileEditor.*
|
import com.intellij.openapi.fileEditor.*
|
||||||
import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider
|
import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.vfs.VirtualFile
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||||
|
|
||||||
class MenuPreviewFileEditorProvider : WeighedFileEditorProvider() {
|
class MenuPreviewFileEditorProvider : WeighedFileEditorProvider() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -19,7 +20,7 @@ class MenuPreviewFileEditorProvider : WeighedFileEditorProvider() {
|
|||||||
|
|
||||||
val type = file.fileType
|
val type = file.fileType
|
||||||
|
|
||||||
if(type != KotlinFileType.INSTANCE) return false
|
if(type != KotlinFileType.INSTANCE && type != BukkriptFileType.INSTANCE) return false
|
||||||
|
|
||||||
return true
|
return true
|
||||||
// return PsiManager.getInstance(project).findFile(file)?.findDescendantOfType<KtCallExpression> {
|
// return PsiManager.getInstance(project).findFile(file)?.findDescendantOfType<KtCallExpression> {
|
||||||
@@ -28,6 +29,7 @@ class MenuPreviewFileEditorProvider : WeighedFileEditorProvider() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun createEditor(project: Project, file: VirtualFile): FileEditor {
|
override fun createEditor(project: Project, file: VirtualFile): FileEditor {
|
||||||
|
println(file.canonicalPath)
|
||||||
val editor: TextEditor = TextEditorProvider.getInstance().createEditor(project, file) as TextEditor
|
val editor: TextEditor = TextEditorProvider.getInstance().createEditor(project, file) as TextEditor
|
||||||
val preview =
|
val preview =
|
||||||
MenuPreviewFileEditor(project, file, editor)
|
MenuPreviewFileEditor(project, file, editor)
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package br.com.devsrsouza.kotlinbukkitapi.tooling
|
package br.com.devsrsouza.kotlinbukkitapi.tooling.menu
|
||||||
|
|
||||||
enum class MinecraftItem(val id: Int) {
|
enum class MinecraftItem(val id: Int) {
|
||||||
AIR(0),
|
AIR(0),
|
||||||
+11
-7
@@ -1,4 +1,4 @@
|
|||||||
package br.com.devsrsouza.kotlinbukkitapi.tooling
|
package br.com.devsrsouza.kotlinbukkitapi.tooling.menu
|
||||||
|
|
||||||
import com.intellij.psi.util.collectDescendantsOfType
|
import com.intellij.psi.util.collectDescendantsOfType
|
||||||
import com.intellij.psi.util.findDescendantOfType
|
import com.intellij.psi.util.findDescendantOfType
|
||||||
@@ -14,14 +14,18 @@ import org.jetbrains.kotlin.idea.references.mainReference
|
|||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||||
|
|
||||||
|
private val menuFqSupportedNames = listOf(
|
||||||
|
"br.com.devsrsouza.kotlinbukkitapi.dsl.menu.menu",
|
||||||
|
"br.com.devsrsouza.bukkript.script.definition.api.menu"
|
||||||
|
)
|
||||||
|
|
||||||
fun findMenuDeclaration(
|
fun findMenuDeclaration(
|
||||||
element: KtCallExpression,
|
element: KtCallExpression,
|
||||||
currentSelectedLine: Int? = null
|
currentSelectedLine: Int? = null
|
||||||
): MenuDeclaration? {
|
): MenuDeclaration? {
|
||||||
val menuFqName = "br.com.devsrsouza.kotlinbukkitapi.dsl.menu.menu"
|
|
||||||
val simpleName = "menu"
|
val simpleName = "menu"
|
||||||
|
|
||||||
if (!element.isCallFrom(simpleName, menuFqName)) return null
|
if (!element.isCallFrom(simpleName, menuFqSupportedNames)) return null
|
||||||
|
|
||||||
val menuFunction = element.findDescendantOfType<KtCallExpression> {
|
val menuFunction = element.findDescendantOfType<KtCallExpression> {
|
||||||
isMenuCall(it)
|
isMenuCall(it)
|
||||||
@@ -36,7 +40,7 @@ fun findMenuDeclaration(
|
|||||||
it.isBuilderBlockFor("br.com.devsrsouza.kotlinbukkitapi.dsl.menu.MenuDSL")
|
it.isBuilderBlockFor("br.com.devsrsouza.kotlinbukkitapi.dsl.menu.MenuDSL")
|
||||||
} ?: return null
|
} ?: return null
|
||||||
|
|
||||||
val slotFqName = "br.com.devsrsouza.kotlinbukkitapi.dsl.menu.slot"
|
val slotFqName = listOf("br.com.devsrsouza.kotlinbukkitapi.dsl.menu.slot")
|
||||||
val slotSimpleName = "slot"
|
val slotSimpleName = "slot"
|
||||||
|
|
||||||
val slotCalls = menuLambdaBlock.collectDescendantsOfType<KtCallExpression> {
|
val slotCalls = menuLambdaBlock.collectDescendantsOfType<KtCallExpression> {
|
||||||
@@ -82,7 +86,7 @@ fun findMenuDeclaration(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun isMenuCall(it: KtCallExpression) =
|
fun isMenuCall(it: KtCallExpression) =
|
||||||
it.isCallFrom("menu", "br.com.devsrsouza.kotlinbukkitapi.dsl.menu.menu")
|
it.isCallFrom("menu", menuFqSupportedNames)
|
||||||
|
|
||||||
fun KtLambdaExpression.isBuilderBlockFor(fqName: String): Boolean {
|
fun KtLambdaExpression.isBuilderBlockFor(fqName: String): Boolean {
|
||||||
val type = resolveType()
|
val type = resolveType()
|
||||||
@@ -100,7 +104,7 @@ fun KtLambdaExpression.isBuilderBlockFor(fqName: String): Boolean {
|
|||||||
|
|
||||||
fun KtCallExpression.isCallFrom(
|
fun KtCallExpression.isCallFrom(
|
||||||
simpleName: String,
|
simpleName: String,
|
||||||
fqName: String
|
fqNames: List<String>
|
||||||
): Boolean {
|
): Boolean {
|
||||||
return text.startsWith(simpleName) && isMethodCall(fqName)
|
return text.startsWith(simpleName) && fqNames.any { isMethodCall(it) }
|
||||||
}
|
}
|
||||||
@@ -10,10 +10,22 @@
|
|||||||
|
|
||||||
<extensions defaultExtensionNs="com.intellij">
|
<extensions defaultExtensionNs="com.intellij">
|
||||||
<!-- Add your extensions here -->
|
<!-- Add your extensions here -->
|
||||||
<fileEditorProvider implementation="br.com.devsrsouza.kotlinbukkitapi.tooling.MenuPreviewFileEditorProvider"/>
|
<fileEditorProvider implementation="br.com.devsrsouza.kotlinbukkitapi.tooling.menu.MenuPreviewFileEditorProvider"/>
|
||||||
|
|
||||||
|
<fileType language="kotlin" extensions="bk.kts" name="Bukkript File" fieldName="INSTANCE"
|
||||||
|
implementationClass="br.com.devsrsouza.kotlinbukkitapi.tooling.bukkript.BukkriptFileType" />
|
||||||
|
<internalFileTemplate name="Bukkript Script" />
|
||||||
|
<iconProvider implementation="br.com.devsrsouza.kotlinbukkitapi.tooling.bukkript.BukkriptIconProvider" order="first"/>
|
||||||
|
</extensions>
|
||||||
|
|
||||||
|
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
||||||
|
<scriptDefinitionsProvider implementation="br.com.devsrsouza.kotlinbukkitapi.tooling.bukkript.BukkriptScriptDefinitionProvider" />
|
||||||
</extensions>
|
</extensions>
|
||||||
|
|
||||||
<actions>
|
<actions>
|
||||||
<!-- Add your actions here -->
|
<!-- Add your actions here -->
|
||||||
|
<action id="Bukkript.NewScript" class="br.com.devsrsouza.kotlinbukkitapi.tooling.bukkript.BukkriptCreateNewFileAction">
|
||||||
|
<add-to-group group-id="NewGroup" anchor="before" relative-to-action="NewFromTemplate"/>
|
||||||
|
</action>
|
||||||
</actions>
|
</actions>
|
||||||
</idea-plugin>
|
</idea-plugin>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 354.67 501.96"><defs><style>.cls-1{isolation:isolate;}.cls-2{fill:#797879;}.cls-3{fill:#6d6d6d;}.cls-4{fill:#989999;}.cls-5{fill:#565656;}.cls-6{fill:#525252;}.cls-7{fill:#353535;}.cls-8{opacity:0.65;}.cls-17,.cls-8{mix-blend-mode:multiply;}.cls-9{fill:url(#Gradiente_sem_nome_4);}.cls-10{fill:url(#Gradiente_sem_nome_2);}.cls-11{fill:url(#Gradiente_sem_nome_3);}.cls-12{fill:#979797;}.cls-13{fill:#d8d8d8;}.cls-14{fill:#a8a8a8;}.cls-15{fill:#737373;}.cls-16{fill:#fff;}.cls-17{opacity:0.45;}</style><linearGradient id="Gradiente_sem_nome_4" x1="196.69" y1="389.39" x2="360.57" y2="225.51" gradientUnits="userSpaceOnUse"><stop offset="0.1" stop-color="#0995d3"/><stop offset="0.3" stop-color="#3387c8"/><stop offset="0.62" stop-color="#5876b9"/><stop offset="0.86" stop-color="#6a6eb2"/><stop offset="1" stop-color="#716baf"/></linearGradient><linearGradient id="Gradiente_sem_nome_2" x1="184.43" y1="194.2" x2="266.91" y2="111.72" gradientTransform="matrix(0.98, -0.21, 0.21, 0.98, -180.79, -26.57)" gradientUnits="userSpaceOnUse"><stop offset="0.12" stop-color="#0995d3"/><stop offset="0.42" stop-color="#497fc1"/><stop offset="0.7" stop-color="#676fb3"/><stop offset="0.83" stop-color="#716baf"/></linearGradient><linearGradient id="Gradiente_sem_nome_3" x1="112.74" y1="410.17" x2="392.46" y2="130.45" gradientTransform="matrix(0.98, -0.21, 0.21, 0.98, -180.79, -26.57)" gradientUnits="userSpaceOnUse"><stop offset="0.11" stop-color="#af5ea1"/><stop offset="0.21" stop-color="#d1609b"/><stop offset="0.43" stop-color="#e1725c"/><stop offset="0.6" stop-color="#ef7f30"/><stop offset="0.74" stop-color="#f18519"/><stop offset="0.82" stop-color="#f18816"/></linearGradient></defs><title>kotlinbukkitapi-logo</title><g class="cls-1"><g id="Camada_1" data-name="Camada 1"><rect class="cls-2" x="210.57" y="242.57" width="28.82" height="28.82"/><rect class="cls-2" x="181.75" y="242.57" width="28.82" height="28.82"/><rect class="cls-2" x="152.93" y="242.57" width="28.82" height="28.82"/><rect class="cls-3" x="124.11" y="242.57" width="28.82" height="28.82"/><rect class="cls-4" x="268.21" y="213.75" width="28.82" height="28.82"/><rect class="cls-4" x="239.39" y="213.75" width="28.82" height="28.82"/><rect class="cls-2" x="210.57" y="213.75" width="28.82" height="28.82"/><rect class="cls-2" x="181.75" y="213.75" width="28.82" height="28.82"/><rect class="cls-2" x="152.93" y="213.75" width="28.82" height="28.82"/><rect class="cls-3" x="124.11" y="213.75" width="28.82" height="28.82"/><rect class="cls-3" x="95.29" y="213.75" width="28.82" height="28.82"/><rect class="cls-5" x="66.46" y="213.75" width="28.82" height="28.82"/><rect class="cls-4" x="297.03" y="184.93" width="28.82" height="28.82"/><rect class="cls-4" x="268.21" y="184.93" width="28.82" height="28.82"/><rect class="cls-4" x="239.39" y="184.93" width="28.82" height="28.82"/><rect class="cls-2" x="210.57" y="184.93" width="28.82" height="28.82"/><rect class="cls-2" x="181.75" y="184.93" width="28.82" height="28.82"/><rect class="cls-2" x="152.93" y="184.93" width="28.82" height="28.82"/><rect class="cls-2" x="124.11" y="184.93" width="28.82" height="28.82"/><rect class="cls-3" x="95.29" y="184.93" width="28.82" height="28.82"/><rect class="cls-5" x="66.46" y="184.93" width="28.82" height="28.82"/><rect class="cls-5" x="37.64" y="184.93" width="28.82" height="28.82"/><rect class="cls-6" x="297.03" y="156.11" width="28.82" height="28.82"/><rect class="cls-6" x="268.21" y="156.11" width="28.82" height="28.82"/><rect class="cls-4" x="239.39" y="156.11" width="28.82" height="28.82"/><rect class="cls-2" x="210.57" y="156.11" width="28.82" height="28.82"/><rect class="cls-2" x="181.75" y="156.11" width="28.82" height="28.82"/><rect class="cls-2" x="152.93" y="156.11" width="28.82" height="28.82"/><rect class="cls-2" x="124.11" y="156.11" width="28.82" height="28.82"/><rect class="cls-3" x="95.29" y="156.11" width="28.82" height="28.82"/><rect class="cls-7" x="66.46" y="156.11" width="28.82" height="28.82"/><rect class="cls-7" x="37.64" y="156.11" width="28.82" height="28.82"/><rect class="cls-6" x="239.39" y="127.29" width="28.82" height="28.82"/><rect class="cls-6" x="210.57" y="127.29" width="28.82" height="28.82"/><rect class="cls-6" x="181.75" y="127.29" width="28.82" height="28.82"/><rect class="cls-7" x="152.93" y="127.29" width="28.82" height="28.82"/><rect class="cls-7" x="124.11" y="127.29" width="28.82" height="28.82"/><rect class="cls-7" x="95.29" y="127.29" width="28.82" height="28.82"/></g><g id="Camada_2_cópia_cópia" data-name="Camada 2 cópia cópia"><image class="cls-8" width="1456" height="1563" transform="scale(0.24)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABbEAAAYcCAYAAAA8LMeNAAAACXBIWXMAAC4jAAAuIwF4pT92AAAgAElEQVR4Xuy9244jyQ4ly6yZ///h6ew6D7XjtIvFy2JclCHJDCCcXO6hUgjoF4Mj++v3798GAAAAAAAAAAAAAHBHfnUHAAAAAAAAAAAAAAB+CiQ2AAAAAAAAAAAAANwWJDYAAAAAAAAAAAAA3BYkNgAAALine truncated
|
||||||
|
After Width: | Height: | Size: 304 KiB |
Reference in new issue
Block a user