diff --git a/.idea/TheGuideForYou.iml b/.idea/TheGuideForYou.iml new file mode 100644 index 0000000..24643cc --- /dev/null +++ b/.idea/TheGuideForYou.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..4a69e81 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/prettier.xml b/.idea/prettier.xml new file mode 100644 index 0000000..0c83ac4 --- /dev/null +++ b/.idea/prettier.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..715d38a --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + { + "lastFilter": { + "state": "OPEN", + "assignee": "LMS5413" + } +} + { + "selectedUrlAndAccountId": { + "url": "https://github.com/theguideforyou/theguideforyou.github.io", + "accountId": "6add92e2-5f0b-4c0a-90a6-e7ca3329aed2" + } +} + { + "associatedIndex": 7 +} + + + + { + "keyToString": { + "RunOnceActivity.ShowReadmeOnStart": "true", + "git-widget-placeholder": "main", + "last_opened_file_path": "/mnt/ntfs2/Codes/TheGuideForYou/docs/linguagens/java/assets", + "node.js.detected.package.eslint": "true", + "node.js.detected.package.stylelint": "true", + "node.js.detected.package.tslint": "true", + "node.js.selected.package.eslint": "(autodetect)", + "node.js.selected.package.stylelint": "", + "node.js.selected.package.tslint": "(autodetect)", + "nodejs_interpreter_path": "/home/lms5413/.local/share/nvm/v21.6.2/bin/node", + "nodejs_package_manager_path": "npm", + "settings.editor.selected.configurable": "configurable.group.editor", + "ts.external.directory.path": "/mnt/ntfs2/Codes/TheGuideForYou/node_modules/typescript/lib", + "vue.rearranger.settings.migration": "true" + } +} + + + + + + + + + + + + + + + + + + 1713443947724 + + + + + + \ No newline at end of file diff --git a/docs/linguagens/java/assets/discordbot-test.png b/docs/linguagens/java/assets/discordbot-test.png new file mode 100644 index 0000000..c0359c6 Binary files /dev/null and b/docs/linguagens/java/assets/discordbot-test.png differ diff --git a/docs/linguagens/java/assets/intellji-gradle-setup-success.png b/docs/linguagens/java/assets/intellji-gradle-setup-success.png new file mode 100644 index 0000000..5e5bbe3 Binary files /dev/null and b/docs/linguagens/java/assets/intellji-gradle-setup-success.png differ diff --git a/docs/linguagens/java/assets/intellji-gradle-setup.png b/docs/linguagens/java/assets/intellji-gradle-setup.png new file mode 100644 index 0000000..f4c1717 Binary files /dev/null and b/docs/linguagens/java/assets/intellji-gradle-setup.png differ diff --git a/docs/linguagens/java/assets/intellji-setup.png b/docs/linguagens/java/assets/intellji-setup.png new file mode 100644 index 0000000..44f1f0c Binary files /dev/null and b/docs/linguagens/java/assets/intellji-setup.png differ diff --git a/docs/linguagens/java/configuracoes-iniciais.mdx b/docs/linguagens/java/configuracoes-iniciais.mdx new file mode 100644 index 0000000..d2c8c5b --- /dev/null +++ b/docs/linguagens/java/configuracoes-iniciais.mdx @@ -0,0 +1,148 @@ +--- +title: "Configurações Iniciais" +displayed_sidebar: javaSidebar +--- + +import {Directory} from "../../../src/components/Directory/Directory"; + +Para acessar o token do seu bot, veja o [guia de como criar uma aplicação no Discord Developer Portal](#) + +### Definindo variáveis de ambiente +Vamos usar o arquivo `.env` para criar as variáveis de ambiente, são pares de chave-valor que ficam salvos no sistema operacional. Geralmente são usadas pra armazenar informações sensíveis, como chaves de API, senhas ou configurações específicas do projeto. +Nesse caso podemos salvar o token do bot, dessa forma: + +```ini title=".env" +BOT_TOKEN=SEU_TOKEN +``` + +### Iniciando o projeto + +Antes de tudo, precisamos entender que o Java possui gerenciadores de dependências, o Gradle e o Maven. Nesse guia, vamos usar o Gradle, pois é mais moderno e mais fácil de usar. +E iremos utilizar uma IDE (Integrated Development Environment) para facilitar o desenvolvimento, nesse caso, vamos usar o IntelliJ IDEA. A versão Community é gratuita e atende perfeitamente para o desenvolvimento de bots. + +Para criar um projeto Gradle, abra o IntelliJ IDEA e clique em `New Project`. Depois, digite o nome do projeto, depois, selecione o diretório do projeto, selecione a linguagem `Java`, em seguida, selecione o `Build System` em `Gradle`. +Depois disso, na opção `JDK`, selecione a versão 21 do Java, caso não encontre, clique na opção `Download JDK` e baixe a versão 21. +Agora, expanda a opção `Configurações Avançadas` ou `Advanced Settings` altere os campos `GroupId` e `ArtifactId` para o nome do seu projeto. +O que seria cada campos? +- `GroupId`: É o nome do pacote do seu projeto, geralmente é o nome do seu domínio ao contrário. (Exemplo: `com.example`) +- `ArtifactId`: É o nome do seu projeto. (Exemplo: `discordbot`) + +A configuração deve ficar assim +[![image](./assets/intellji-setup.png)](./assets/intellji-setup.png) + +Após isso, iremos se deparar com essa seguinte estrutura. + + + + + + + + + + + + + + + + + + + + + + + + + +Explicando a estrutura: +- `src/main/java`: É onde ficam os códigos fontes do projeto. +- `src/main/resources`: É onde ficam os recursos do projeto, como arquivos de configuração. +- `src/test/java`: É onde ficam os testes do projeto. +- `src/test/resources`: É onde ficam os recursos dos testes. +- `build.gradle`: É o arquivo de configuração do Gradle, onde ficam as dependências e configurações do projeto. +- `.gitignore`: É o arquivo que diz ao Git quais arquivos e pastas ignorar. +- `gradlew` e `gradlew.bat`: São scripts que permitem rodar o Gradle sem precisar instalar ele na máquina. +- `settings.gradle`: É o arquivo de configuração do Gradle, onde ficam as configurações do projeto. + + +Agora que possuímos a estrutura do projeto, vamos adicionar as dependências necessárias para o bot funcionar. +Iremos adicionar as dependências do JDA, que é a biblioteca que usaremos para criar o bot. +Ao abrir o arquivo `build.gradle`, iremos se deparar com o seguinte conteúdo: +```gradle title="build.gradle" +plugins { + id 'java' +} + +group = 'org.example' +version = '1.0-SNAPSHOT' + +repositories { + mavenCentral() +} + +dependencies { + testImplementation platform('org.junit:junit-bom:5.9.1') + testImplementation 'org.junit.jupiter:junit-jupiter' +} + +test { + useJUnitPlatform() +} +``` + +Para adicionar as dependências do JDA, iremos adicionar o seguinte código no arquivo `build.gradle` dentro do bloco `dependencies`: +```gradle title="build.gradle" +dependencies { + implementation 'net.dv8tion:JDA:5.0.0-beta.22' +} +``` + +A interpreção de um arquivo `.env` é feita através da biblioteca `dotenv`, que não é nativa do Java, então precisamos adicionar ela ao nosso projeto. +Para isso, vamos adicionar a dependência no arquivo `build.gradle` dentro do bloco `dependencies`: +```gradle title="build.gradle" +dependencies { + implementation 'io.github.cdimascio:java-dotenv:3.0.0' +} +``` + +Para garantir que o bot esteja funcionando corretamente, vamos adicionar uma biblioteca de Logging, que é uma prática comum para debugar o bot. +Para isso, vamos adicionar a dependência no arquivo `build.gradle` dentro do bloco `dependencies`: +```gradle title="build.gradle" +dependencies { + implementation 'ch.qos.logback:logback-classic:1.4.14' +} +``` + +O arquivo `build.gradle` deve ficar assim: +```gradle title="build.gradle" +plugins { + id 'java' +} + +group = 'org.example' +version = '1.0-SNAPSHOT' + +repositories { + mavenCentral() +} + +dependencies { + testImplementation platform('org.junit:junit-bom:5.9.1') + testImplementation 'org.junit.jupiter:junit-jupiter' + implementation 'net.dv8tion:JDA:5.0.0-beta.22' + implementation 'io.github.cdimascio:java-dotenv:3.0.0' + implementation 'ch.qos.logback:logback-classic:1.4.14' +} + +test { + useJUnitPlatform() +} +``` + +Ao alterar, iremos ver que irá aparecer um símbolo de sincronização, clique nele para sincronizar as dependências. +[![image](./assets/intellji-gradle-setup.png)](./assets/intellji-gradle-setup.png) + +É possivel acompanhar o progresso da sincronização no canto inferior direito. Onde existe um ícone de um martelo. Caso esteja marcado sucesso, significa que a sincronização foi bem sucedida. +[![image](./assets/intellji-gradle-setup-success.png)](./assets/intellji-gradle-setup-success.png) \ No newline at end of file diff --git a/docs/linguagens/java/definindo-o-bot.mdx b/docs/linguagens/java/definindo-o-bot.mdx new file mode 100644 index 0000000..bfe070c --- /dev/null +++ b/docs/linguagens/java/definindo-o-bot.mdx @@ -0,0 +1,75 @@ +--- +title: "Definindo o bot" +sidebar_position: 3 +displayed_sidebar: javaSidebar +--- + +# Definindo o bot + +Agora que as bibliotecas estão instaladas e o token já está armazenado no .env, precisamos definir a classe do `bot`. +Antes de tudo, precisamos apagar o conteúdo do arquivo `Main.java`, pois vamos reescrever o código. Iremos apenas manter isso: + +```java title="src/main/java/org/example/Main.java" +public class Main { + public static void main(String[] args) { + } +} +``` + +Agora, vamos criar a classe do bot. Crie um novo arquivo chamado `Bot.java` dentro do pacote `org.example`. +Depois disso, precisamos configurar o dotenv, para que possamos acessar o token do bot. Para isso, adicione o seguinte código no início da classe: +```java title="src/main/java/org/example/Bot.java" +package org.example; + +import io.github.cdimascio.dotenv.Dotenv; + +public class Bot { + private final Dotenv dotenv = Dotenv.load(); + private final String token = dotenv.get("BOT_TOKEN"); + + public Bot() { + } +} +``` +Lembra que falamos sobre o dotenv? Aqui estamos carregando o arquivo `.env` e pegando o token do bot com nome `BOT_TOKEN`. Agora, vamos criar o codigo para que o nosso bot seja carregado e inicie. + +```java title="src/main/java/org/example/Bot.java" +package org.example; + +import io.github.cdimascio.dotenv.Dotenv; +import net.dv8tion.jda.api.JDABuilder; +import net.dv8tion.jda.api.requests.GatewayIntent; + +public class Bot { + private final Dotenv dotenv = Dotenv.configure().directory("./.env").load(); + private final String token = dotenv.get("BOT_TOKEN"); + + public Bot() { + JDABuilder builder = JDABuilder.createDefault(token); + builder.enableIntents(GatewayIntent.MESSAGE_CONTENT, GatewayIntent.GUILD_MESSAGES); + builder.build(); + } +} +``` + +Entendendo o código: +- `JDABuilder.createDefault(token)` - Cria um novo `JDABuilder` com o token do bot. +- `builder.enableIntents(GatewayIntent.MESSAGE_CONTENT, GatewayIntent.GUILD_MESSAGES)` - Habilita as intents necessárias para o bot funcionar. +- `builder.build()` - Inicia o bot. + +O que são intents? Intents são uma forma de o Discord saber o que o bot pretende fazer. Por exemplo, se o bot pretende receber mensagens de texto, ele precisa da intent `MESSAGE_CONTENT`. Se o bot pretende receber mensagens de um servidor, ele precisa da intent `GUILD_MESSAGES`. No nosso caso, estamos habilitando as intents `MESSAGE_CONTENT` e `GUILD_MESSAGES`. + +Agora, na classe `Main`, vamos instanciar a classe `Bot` para que o bot seja iniciado. + +```java title="src/main/java/org/example/Main.java" +package org.example; + +public class Main { + public static void main(String[] args) { + new Bot(); + } +} +``` +:::warning[Aviso] +Caso não tenha habilitado as intents no painel do Discord Developer Portal, você receberá um erro na hora de iniciar o bot. Qualquer dúvida consulte o [guia de intents do Discord](#). +::: \ No newline at end of file diff --git a/docs/linguagens/java/index.mdx b/docs/linguagens/java/index.mdx new file mode 100644 index 0000000..fb21d7f --- /dev/null +++ b/docs/linguagens/java/index.mdx @@ -0,0 +1,18 @@ +--- +sidebar_position: 1 +displayed_sidebar: javaSidebar +pagination_prev: linguagens/index +--- + +# Instalação + +:::info +Veja nosso [guia de como instalar o java em sua máquina](#), antes de iniciar a criação do bot +::: + +### Requisitos +- OpenJDK 21 +- [IntelliJ IDEA Community Edition](https://www.jetbrains.com/idea/download/other.html) + +### Instalação do Java +Para instalar o Java, basta entrar no site da [Oracle](https://www.oracle.com/java/technologies/downloads/) e baixar a versão 21 do Java. diff --git a/docs/linguagens/java/utilizando-eventos.mdx b/docs/linguagens/java/utilizando-eventos.mdx new file mode 100644 index 0000000..e3bd82b --- /dev/null +++ b/docs/linguagens/java/utilizando-eventos.mdx @@ -0,0 +1,102 @@ +--- +title: "Utilizando eventos" +sidebar_position: 4 +displayed_sidebar: javaSidebar +--- + +# Utilizando eventos + +:::info +Recomendamos que veja [o que são eventos](#) antes de continuar esse tópico +::: + +### Criando estrutura de eventos + +Para criar eventos no JDA, deveremos criar uma classe onde iremos armazenar os eventos que iremos utilizar. +Nosso objetivo é criar um simples evento onde recebemos mensagens de um servidor e imprimimos no console. +Primeiro, para organizar, vamos criar um pacote chamado `events` e dentro dele uma classe chamada `Events`. +Para criar um pacote, clique com o botão direito no seu projeto, vá em `New` > `Package` e coloque o nome do pacote como `events`. +Dentro do pacote `events`, clique com o botão direito e vá em `New` > `Java Class` e coloque o nome da classe como `Events`. +Agora, iremos extender a classe `ListenerAdapter` do JDA para podermos utilizar os eventos, ficando assim. + +```java title="src/main/java/org/example/events/Events.java" +package org.example.events; + +import net.dv8tion.jda.api.hooks.ListenerAdapter; + +public class Events extends ListenerAdapter { +} +``` + +### Adicionando eventos + +Agora, iremos adicionar o evento que queremos, que é o `onMessageReceived`. +Para adicionar um evento, basta criar um método com o nome do evento que queremos, e passar o parâmetro que o evento pede. +No caso do `onMessageReceived`, ele pede um `MessageReceivedEvent`. +Vamos adicionar o evento `onMessageReceived` na nossa classe `Events`. + +```java title="src/main/java/org/example/events/Events.java" +package org.example.events; + +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; + +public class Events extends ListenerAdapter { + + @Override + public void onMessageReceived(MessageReceivedEvent event) { + System.out.println("Mensagem recebida: " + event.getMessage().getContentDisplay()); + } +} +``` + +Agora que criamos a classe de eventos, iremos voltar para a nossa classe principal e dizer ao JDA que queremos utilizar esses eventos. +Para isso, iremos utilizar nosso `JDABuilder` e chamar o método .addEventListeners, ficando assim. + +```java title="src/main/java/org/example/Bot.java" +package org.example; + +import io.github.cdimascio.dotenv.Dotenv; +import net.dv8tion.jda.api.JDABuilder; +import net.dv8tion.jda.api.requests.GatewayIntent; +import org.example.events.Events; + +public class Bot { + private final Dotenv dotenv = Dotenv.configure().directory("./.env").load(); + private final String token = dotenv.get("BOT_TOKEN"); + + public Bot() { + JDABuilder builder = JDABuilder.createDefault(token); + builder.enableIntents(GatewayIntent.MESSAGE_CONTENT, GatewayIntent.GUILD_MESSAGES); + builder.addEventListeners(new Events()); + builder.build(); + } +} +``` + +E se você rodar o bot, ele irá imprimir no console todas as mensagens que ele receber. + +[![image](./assets/discordbot-test.png)](./assets/discordbot-test.png) + +Você pode adicionar outros eventos na classe `Events` usando esse mesmo formato. Utilizando a anotação `@override` e seguindo o padrão. Imagine que encontrei um evento chamado `ReadyEvent` que foi feito para ser emitido caso o bot seja ligado, poderia usar da seguinte forma. + +```java title="src/main/java/org/example/events/Events.java" +package org.example.events; + +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; + +public class Events extends ListenerAdapter { + + // Para montar o nome da função, basta adicionar "on" no início e remover o "event" no final + // Exemplo: MessageReceivedEvent -> onMessageReceived + // E depois utilizar a anotação @override + + @Override + public void onReady(ReadyEvent event) { + System.out.println("Logged in as " + event.getJDA().getSelfUser().getAsTag()); + } +} +``` + +Lembrando que os eventos recebem resultados diferentes, você pode verificar a lista de todos esses eventos [clicando aqui](https://jda.wiki/introduction/events-list/). diff --git a/docusaurus.config.ts b/docusaurus.config.ts index 8cfe2be..9192158 100644 --- a/docusaurus.config.ts +++ b/docusaurus.config.ts @@ -1,69 +1,78 @@ import type * as Preset from '@docusaurus/preset-classic'; -import type { Config } from '@docusaurus/types'; -import { catppuccinLatteTheme, catppuccinMochaTheme } from './src/theme/prism-catppuccin'; +import type {Config} from '@docusaurus/types'; +import {catppuccinLatteTheme, catppuccinMochaTheme} from './src/theme/prism-catppuccin'; + const config: Config = { - title: 'TheGuideForYou', - tagline: 'Prático, didático e multi-linguagem', - favicon: 'img/favicon.ico', + title: 'TheGuideForYou', + tagline: 'Prático, didático e multi-linguagem', + favicon: 'img/favicon.ico', - // Set the production url of your site here - url: 'https://theguideforyou.github.io/', - // Set the // pathname under which your site is served - // For GitHub pages deployment, it is often '//' - baseUrl: '/', + // Set the production url of your site here + url: 'https://theguideforyou.github.io/', + // Set the // pathname under which your site is served + // For GitHub pages deployment, it is often '//' + baseUrl: '/', - // GitHub pages deployment config. - // If you aren't using GitHub pages, you don't need these. - organizationName: 'theguideforyou', // Usually your GitHub org/user name. - projectName: 'theguideforyou.github.io', // Usually your repo name. + // GitHub pages deployment config. + // If you aren't using GitHub pages, you don't need these. + organizationName: 'theguideforyou', // Usually your GitHub org/user name. + projectName: 'theguideforyou.github.io', // Usually your repo name. - onBrokenLinks: 'ignore', //throw - onBrokenMarkdownLinks: 'warn', - trailingSlash: true, + onBrokenLinks: 'ignore', //throw + onBrokenMarkdownLinks: 'warn', + trailingSlash: true, - // Even if you don't use internationalization, you can use this field to set - // useful metadata like html lang. For example, if your site is Chinese, you - // may want to replace "en" with "zh-Hans". - i18n: { - defaultLocale: 'en', - locales: ['en', 'pt'], - }, + // Even if you don't use internationalization, you can use this field to set + // useful metadata like html lang. For example, if your site is Chinese, you + // may want to replace "en" with "zh-Hans". + i18n: { + defaultLocale: 'en', + locales: ['en', 'pt'], + }, - presets: [ - [ - 'classic', - { - docs: { - sidebarPath: './sidebars/index.ts', - // Please change this to your repo. - // Remove this to remove the "edit this page" links. - editUrl: - 'https://github.com/theguideforyou/theguideforyou.github.io/tree/main', - }, - theme: { - customCss: './src/css/custom.css', - }, - } satisfies Preset.Options, + presets: [ + [ + 'classic', + { + docs: { + sidebarPath: './sidebars/index.ts', + // Please change this to your repo. + // Remove this to remove the "edit this page" links. + editUrl: + 'https://github.com/theguideforyou/theguideforyou.github.io/tree/main', + }, + theme: { + customCss: './src/css/custom.css', + }, + } satisfies Preset.Options, + ], ], - ], - themeConfig: { - // Replace with your project's social card - image: 'img/docusaurus-social-card.jpg', - navbar: { - title: 'TheGuideForYou', - logo: { - alt: 'My Site Logo', - src: 'img/readme/TheGuideLogo.png', - }, - items: [ - { - type: 'docSidebar', - sidebarId: 'tutorialSidebar', - position: 'left', - label: 'Documentação', + themeConfig: { + // Replace with your project's social card + image: 'img/docusaurus-social-card.jpg', + navbar: { + title: 'TheGuideForYou', + logo: { + alt: 'My Site Logo', + src: 'img/readme/TheGuideLogo.png', + }, + items: [ + { + type: 'docSidebar', + sidebarId: 'tutorialSidebar', + position: 'left', + label: 'Documentação', + }, + { + href: 'https://github.com/theguideforyou', + label: 'GitHub', + position: 'right', + }, + ], }, +<<<<<<< Updated upstream { href: 'https://github.com/theguideforyou', label: 'GitHub', @@ -87,10 +96,28 @@ const config: Config = { postcssOptions.plugins.push(require("tailwindcss")); postcssOptions.plugins.push(require("autoprefixer")); return postcssOptions; +======= + prism: { + theme: catppuccinLatteTheme, + darkTheme: catppuccinMochaTheme, + additionalLanguages: ['java', 'gradle'] +>>>>>>> Stashed changes }, - }; - } - ] + } satisfies Preset.ThemeConfig, + plugins: [ + async function myPlugin() { + return { + name: "docusaurus-tailwindcss", + configurePostCss(postcssOptions) { + // Appends TailwindCSS and AutoPrefixer. + postcssOptions.plugins.push(require("tailwindcss/nesting")); + postcssOptions.plugins.push(require("tailwindcss")); + postcssOptions.plugins.push(require("autoprefixer")); + return postcssOptions; + }, + }; + } + ] }; export default config; diff --git a/sidebars/index.ts b/sidebars/index.ts index 483776a..ac3e565 100644 --- a/sidebars/index.ts +++ b/sidebars/index.ts @@ -1,5 +1,6 @@ import type { PropSidebarItemLink, SidebarsConfig } from "@docusaurus/plugin-content-docs"; import { pythonSidebarItems } from './python'; +import {javaSidebarItems} from "./java"; /** * Creating a sidebar enables you to: @@ -22,6 +23,7 @@ const sidebars: SidebarsConfig = { // By default, Docusaurus generates a sidebar from the docs folder structure tutorialSidebar: [ languagesLink, { type: "autogenerated", dirName: "." } ], pythonSidebar: [ languagesLink, ...pythonSidebarItems], + javaSidebar: [ languagesLink, ...javaSidebarItems] // But you can create a sidebar manually /* diff --git a/sidebars/java.ts b/sidebars/java.ts new file mode 100644 index 0000000..6b3e9b5 --- /dev/null +++ b/sidebars/java.ts @@ -0,0 +1,22 @@ +import type { SidebarItemConfig } from '@docusaurus/plugin-content-docs'; + +export const javaSidebarItems: SidebarItemConfig[] = [ + { + type: 'category', + collapsed: true, + label: 'Primeiros passos', + items: [ + 'linguagens/java/index', + 'linguagens/java/configuracoes-iniciais' + ] + }, + { + type: 'category', + collapsed: true, + label: 'Construindo o bot', + items: [ + 'linguagens/java/definindo-o-bot', + 'linguagens/java/utilizando-eventos', + ] + }, +] \ No newline at end of file