├── Renomear arquivos ├── arquivos_para_verificacao │ ├── exemplo.txt │ ├── exemplo02.docx │ ├── sum1.png │ └── codigo.png └── renomear_arquivos.ipynb ├── Unificar Arquivos ├── arquivos │ ├── exemplo01.xlsx │ ├── exemplo02.xlsx │ └── exemplo03.xlsx └── unificar.ipynb ├── README.md ├── Criar pasta e subpastas └── script_criar_pastas.ipynb ├── Inserir_data_no_nome_do_arquivo.ipynb └── Automatizando_Planilhas.ipynb /Renomear arquivos/arquivos_para_verificacao/exemplo.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Renomear arquivos/arquivos_para_verificacao/exemplo02.docx: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Unificar Arquivos/arquivos/exemplo01.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jessycalais/Scripts_Python/HEAD/Unificar Arquivos/arquivos/exemplo01.xlsx -------------------------------------------------------------------------------- /Unificar Arquivos/arquivos/exemplo02.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jessycalais/Scripts_Python/HEAD/Unificar Arquivos/arquivos/exemplo02.xlsx -------------------------------------------------------------------------------- /Unificar Arquivos/arquivos/exemplo03.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jessycalais/Scripts_Python/HEAD/Unificar Arquivos/arquivos/exemplo03.xlsx -------------------------------------------------------------------------------- /Renomear arquivos/arquivos_para_verificacao/sum1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jessycalais/Scripts_Python/HEAD/Renomear arquivos/arquivos_para_verificacao/sum1.png -------------------------------------------------------------------------------- /Renomear arquivos/arquivos_para_verificacao/codigo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jessycalais/Scripts_Python/HEAD/Renomear arquivos/arquivos_para_verificacao/codigo.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### :dart: Objetivo: 2 | Este repositório tem como objetivo demonstrar minhas habilidades técnicas de automação de tarefas utilizando Python. 3 | 4 | ### :hammer: Ferramentas utilizadas: 5 | * Python 6 | 7 | ### :books: Conteúdo dos arquivos do repositório: 8 | **1) Criar pastas e subpastas** 9 | * Criação de pastas e subpastas utilizando o método `mkdir()` da biblioteca `os`. A data foi inserida com a biblioteca `datetime`. 10 | 11 | --- 12 | **2) Renomear arquivos** 13 | * Verifica qual o último arquivo de uma pasta e renomeia via Python. As biliotecas utilizadas foram `os` e `glob`. 14 | > Isso é útil caso você precise realizar downloads e renomear os arquivos. 15 | 16 | --- 17 | **3) Unificar Arquivos** 18 | * Unificar uma quantidade qualquer de planilhas com a mesma estrutura e no formato `.xlsx`. As bibliotecas utilizadas são: `pandas`, `glob` e `datetime`. 19 | 20 | > Se necessário, você pode modificar o código para renomear colunas, excluir as que não precisa e unificar o arquivo já tratado. 21 | --- 22 | 23 | **4) Automatizando Planilhas** 24 | * Este notebook contém dois códigos: 25 | 1. Escrever em arquivos do Excel já existentes; 26 | 2. Unificar abas com mesma estrutura disponíveis em um único arquivo do Excel. 27 | 28 | As bibliotecas utilizadas são: `pandas`, `datetime`, `os` e `pathlib`. 29 | 30 | > Se necessário, você pode modificar o código para renomear colunas, excluir as que não precisa, etc. 31 | --- 32 | 33 | **5) Inserir data no nome do arquivo** 34 | * Salvar arquivos `xlsx` com o nome contendo a data do dia. As bibliotecas utilizadas são: `pandas` e `datetime`. 35 | 36 | > Se necessário, você pode modificar o código para exibir a data em outro formato, ou até mesmo para renomear outros arquivos. 37 | --- 38 | 39 | -------------------------------------------------------------------------------- /Criar pasta e subpastas/script_criar_pastas.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "#### **Criação de pastas no computador de forma automatizada utilizando Python**" 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": 1, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "# imports\n", 17 | "import os\n", 18 | "import datetime" 19 | ] 20 | }, 21 | { 22 | "cell_type": "code", 23 | "execution_count": 2, 24 | "metadata": {}, 25 | "outputs": [], 26 | "source": [ 27 | "# Data do dia\n", 28 | "DATA = datetime.datetime.today().strftime('%d-%m-%Y')" 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": 3, 34 | "metadata": {}, 35 | "outputs": [], 36 | "source": [ 37 | "# Criação das pastas\n", 38 | "for i in range(4):\n", 39 | " os.mkdir(f'exemplo0{i+1}_{DATA}')" 40 | ] 41 | }, 42 | { 43 | "cell_type": "code", 44 | "execution_count": 4, 45 | "metadata": {}, 46 | "outputs": [], 47 | "source": [ 48 | "# Criação de pastas e subpastas simultaneamente\n", 49 | "for i in range(4):\n", 50 | " os.mkdir(f'exemplo0{i+1}_{DATA}')\n", 51 | " for j in range(3):\n", 52 | " os.mkdir(f'exemplo0{i+1}_{DATA}/subpasta0{j+1}_{DATA}')" 53 | ] 54 | } 55 | ], 56 | "metadata": { 57 | "kernelspec": { 58 | "display_name": "base", 59 | "language": "python", 60 | "name": "python3" 61 | }, 62 | "language_info": { 63 | "codemirror_mode": { 64 | "name": "ipython", 65 | "version": 3 66 | }, 67 | "file_extension": ".py", 68 | "mimetype": "text/x-python", 69 | "name": "python", 70 | "nbconvert_exporter": "python", 71 | "pygments_lexer": "ipython3", 72 | "version": "3.11.5" 73 | } 74 | }, 75 | "nbformat": 4, 76 | "nbformat_minor": 2 77 | } 78 | -------------------------------------------------------------------------------- /Unificar Arquivos/unificar.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "# Imports\n", 10 | "import pandas as pd\n", 11 | "from glob import glob \n", 12 | "import datetime" 13 | ] 14 | }, 15 | { 16 | "cell_type": "code", 17 | "execution_count": 2, 18 | "metadata": {}, 19 | "outputs": [], 20 | "source": [ 21 | "# Percorrer os arquivos xlsx\n", 22 | "listar_endereco = glob(r'arquivos/*xlsx')\n", 23 | "\n", 24 | "# Lista para receber as tabelas que usarei no \"concat\"\n", 25 | "lista_unificada = [] \n", 26 | "\n", 27 | "# Loop para salvar arquivos como tabela no Pandas\n", 28 | "for arquivo in listar_endereco:\n", 29 | " try: \n", 30 | " # Ler arquivo \n", 31 | " tabela_df = pd.read_excel(arquivo) \n", 32 | "\n", 33 | " # Identificar arquivo de origem - excluindo as substrings \"arquivos/\" e \".xlsx\"\n", 34 | " n = len(tabela_df.index)\n", 35 | " tabela_df.index = [arquivo[9:-5] for i in range(n)] \n", 36 | "\n", 37 | " # Criando a lista de DataFrames para usar no concat \n", 38 | " lista_unificada.append(tabela_df)\n", 39 | " \n", 40 | " except Exception as erro:\n", 41 | " print(f'Erro {erro} encontrado no arquivo {arquivo}. Verifique!')\n", 42 | "\n", 43 | "# Data e Nome do arquivo compilado\n", 44 | "HOJE = datetime.date.today().strftime(\"%d-%m-%Y\")\n", 45 | "NOME_ARQUIVO = f'PlanilhasUnificadas_{HOJE}.xlsx'\n", 46 | "\n", 47 | "# Gerar tabela unificada com o concat da biblioteca Pandas e exportar para o excel no formato xlsx\n", 48 | "tabela_unificada = pd.concat(lista_unificada)\n", 49 | "tabela_unificada.to_excel(NOME_ARQUIVO)" 50 | ] 51 | } 52 | ], 53 | "metadata": { 54 | "kernelspec": { 55 | "display_name": "Python 3", 56 | "language": "python", 57 | "name": "python3" 58 | }, 59 | "language_info": { 60 | "codemirror_mode": { 61 | "name": "ipython", 62 | "version": 3 63 | }, 64 | "file_extension": ".py", 65 | "mimetype": "text/x-python", 66 | "name": "python", 67 | "nbconvert_exporter": "python", 68 | "pygments_lexer": "ipython3", 69 | "version": "3.11.5" 70 | }, 71 | "orig_nbformat": 4 72 | }, 73 | "nbformat": 4, 74 | "nbformat_minor": 2 75 | } 76 | -------------------------------------------------------------------------------- /Inserir_data_no_nome_do_arquivo.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "provenance": [], 7 | "authorship_tag": "ABX9TyPy78Bd6Hz/ixMzjW17bzjj", 8 | "include_colab_link": true 9 | }, 10 | "kernelspec": { 11 | "name": "python3", 12 | "display_name": "Python 3" 13 | }, 14 | "language_info": { 15 | "name": "python" 16 | } 17 | }, 18 | "cells": [ 19 | { 20 | "cell_type": "markdown", 21 | "metadata": { 22 | "id": "view-in-github", 23 | "colab_type": "text" 24 | }, 25 | "source": [ 26 | "\"Open" 27 | ] 28 | }, 29 | { 30 | "cell_type": "markdown", 31 | "source": [ 32 | "Já precisou exportar seu DataFrame para um arquivo \".xlsx\", por exemplo, mas gostaria que o nome tivesse a data?\n", 33 | "\n", 34 | "Que tal fazer isso de forma automatizada, sem precisar editar o código para colocar a data toda vez que rodar o script que exporta o DataFrame?\n", 35 | "\n", 36 | "Inclusive esse caminho serve para qualquer script que você use e precise nomear o arquivo com a \"data do dia\".\n", 37 | "\n", 38 | "Curti a opção - e vocês?" 39 | ], 40 | "metadata": { 41 | "id": "jpDVk5DNffun" 42 | } 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": null, 47 | "metadata": { 48 | "id": "prdoAXIKfJbP" 49 | }, 50 | "outputs": [], 51 | "source": [ 52 | "# Imports de pacotes built-in\n", 53 | "import datetime\n", 54 | "\n", 55 | "# Imports de pacotes de terceiros\n", 56 | "import pandas as pd\n", 57 | "\n", 58 | "# Ler arquivo\n", 59 | "df = pd.read_excel('exemplo01.xlsx')\n", 60 | "\n", 61 | "# Faça sua análise/tratamento, etc\n", 62 | "# ...\n", 63 | "\n", 64 | "# DATA - Exemplo: 20-03-2024\n", 65 | "HOJE = datetime.date.today().strftime(\"%d-%m-%Y\")\n", 66 | "\n", 67 | "# Nome do arquivo exportado\n", 68 | "NOME_ARQUIVO = f'exemplo02_{DATA}.xlsx'\n", 69 | "\n", 70 | "# Exportar\n", 71 | "df.to_excel(NOME_ARQUIVO, index=False)" 72 | ] 73 | } 74 | ] 75 | } -------------------------------------------------------------------------------- /Renomear arquivos/renomear_arquivos.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "fa266d35", 6 | "metadata": {}, 7 | "source": [ 8 | "#### **Introdução**\n", 9 | "\n", 10 | "Neste exemplo, a pasta que contém o código contém uma subpasta com os arquivos que queremos verificar.\n", 11 | "\n", 12 | "A subpasta está nomeada como `arquivos_para_verificacao`.\n", 13 | "\n", 14 | "O *primeiro passo* é fazer os imports das bibliotecas:\n" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": 1, 20 | "id": "d027d57e", 21 | "metadata": {}, 22 | "outputs": [], 23 | "source": [ 24 | "import os\n", 25 | "from glob import glob" 26 | ] 27 | }, 28 | { 29 | "cell_type": "markdown", 30 | "id": "e8fc7777", 31 | "metadata": {}, 32 | "source": [ 33 | "Agora vamos aos próximos passos.\n", 34 | "\n", 35 | "Para percorrer todos os arquivos da pasta a ser verificada, independentemente do formato, podemos utilizar o \"*\" no método `glob()`da biblioteca **glob**:\n" 36 | ] 37 | }, 38 | { 39 | "cell_type": "code", 40 | "execution_count": 2, 41 | "id": "c1ca6d0e", 42 | "metadata": {}, 43 | "outputs": [], 44 | "source": [ 45 | "pasta = 'arquivos_para_verificacao'\n", 46 | "arquivos = glob(f'{pasta}/*') # o * pega todos os formatos de arquivo" 47 | ] 48 | }, 49 | { 50 | "cell_type": "markdown", 51 | "id": "f74ba68b", 52 | "metadata": {}, 53 | "source": [ 54 | "Agora, iremos determinar as datas de modificação de cada arquivo e verificar qual a maior delas:\n" 55 | ] 56 | }, 57 | { 58 | "cell_type": "code", 59 | "execution_count": 3, 60 | "id": "b575aae1", 61 | "metadata": {}, 62 | "outputs": [ 63 | { 64 | "name": "stdout", 65 | "output_type": "stream", 66 | "text": [ 67 | "O último arquivo modificado foi: exemplo02.docx\n" 68 | ] 69 | } 70 | ], 71 | "source": [ 72 | "# O método getmtime retorna a data de modificação de um arquivo\n", 73 | "datas_de_modificacao = [os.path.getmtime(arquivo) for arquivo in arquivos] \n", 74 | "\n", 75 | "# O método max() retorna a maior data da lista 'datas_de_modificação'\n", 76 | "maximo = max(datas_de_modificacao) \n", 77 | "\n", 78 | "# retorna o índice do último arquivo alterado na lista 'datas_de_modificacao'\n", 79 | "indice = datas_de_modificacao.index(maximo) \n", 80 | "\n", 81 | "# Nome do último arquivo modificado antes de renomearmos\n", 82 | "print(f'O último arquivo modificado foi: {os.path.basename(arquivos[indice])}')" 83 | ] 84 | }, 85 | { 86 | "cell_type": "markdown", 87 | "id": "4bf2479e", 88 | "metadata": {}, 89 | "source": [ 90 | "A seguir, utilizaremos o método `os.path.splitext()` para determinar a ***extensão do arquivo*** a ser renomeado (.pdf, .txt,. xlsx, etc).\n", 91 | "\n", 92 | "Já o método `os.rename()` será utilizado para renomear o arquivo. Ele recebe o nome original e o novo nome.\n", 93 | "\n", 94 | "Veja:\n" 95 | ] 96 | }, 97 | { 98 | "cell_type": "code", 99 | "execution_count": 4, 100 | "id": "7d1f9fa5", 101 | "metadata": {}, 102 | "outputs": [ 103 | { 104 | "name": "stdout", 105 | "output_type": "stream", 106 | "text": [ 107 | "A extensão do arquivo a ser renomeado é: .docx\n" 108 | ] 109 | } 110 | ], 111 | "source": [ 112 | "# Formato do último arquivo modificado\n", 113 | "formato = os.path.splitext(arquivos[indice])[1]\n", 114 | "print(f'A extensão do arquivo a ser renomeado é: {formato}')\n", 115 | "\n", 116 | "# Troca o nome inicial do arquivo de última modificacao\n", 117 | "os.rename(arquivos[indice], ('').join([pasta, '\\\\', 'novo_nome', formato]))" 118 | ] 119 | }, 120 | { 121 | "cell_type": "markdown", 122 | "id": "6029478c", 123 | "metadata": {}, 124 | "source": [ 125 | "Feito!\n", 126 | "\n", 127 | "Vamos verificar o novo nome do arquivo de última data de modificação?\n" 128 | ] 129 | }, 130 | { 131 | "cell_type": "code", 132 | "execution_count": 5, 133 | "id": "caea8992", 134 | "metadata": {}, 135 | "outputs": [ 136 | { 137 | "name": "stdout", 138 | "output_type": "stream", 139 | "text": [ 140 | "novo_nome.docx\n" 141 | ] 142 | } 143 | ], 144 | "source": [ 145 | "arquivos = glob(f'{pasta}/*')\n", 146 | "print(os.path.basename(arquivos[indice]))" 147 | ] 148 | } 149 | ], 150 | "metadata": { 151 | "kernelspec": { 152 | "display_name": "Python 3 (ipykernel)", 153 | "language": "python", 154 | "name": "python3" 155 | }, 156 | "language_info": { 157 | "codemirror_mode": { 158 | "name": "ipython", 159 | "version": 3 160 | }, 161 | "file_extension": ".py", 162 | "mimetype": "text/x-python", 163 | "name": "python", 164 | "nbconvert_exporter": "python", 165 | "pygments_lexer": "ipython3", 166 | "version": "3.11.5" 167 | } 168 | }, 169 | "nbformat": 4, 170 | "nbformat_minor": 5 171 | } 172 | -------------------------------------------------------------------------------- /Automatizando_Planilhas.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "provenance": [], 7 | "authorship_tag": "ABX9TyPZO3XeEUGiAbCwu1mJnouT", 8 | "include_colab_link": true 9 | }, 10 | "kernelspec": { 11 | "name": "python3", 12 | "display_name": "Python 3" 13 | }, 14 | "language_info": { 15 | "name": "python" 16 | } 17 | }, 18 | "cells": [ 19 | { 20 | "cell_type": "markdown", 21 | "metadata": { 22 | "id": "view-in-github", 23 | "colab_type": "text" 24 | }, 25 | "source": [ 26 | "\"Open" 27 | ] 28 | }, 29 | { 30 | "cell_type": "markdown", 31 | "source": [ 32 | "**1. Escrevendo em arquivos do Excel já existentes**\n", 33 | "\n", 34 | "Quando a gente começa a estudar Pandas no Python é um tal de \"df.to_excel()\" para cá, \"df.to_excel()\" para lá\n", 35 | "\n", 36 | "E assim nosso computador fica cheio de arquivos 😂\n", 37 | "\n", 38 | "Pior ainda é quando a gente exporta para o Excel para copiar e colar em outra planilha porque nosso relatório, tabelas dinâmicas ou dashboard estão lá\n", 39 | "\n", 40 | "Você sabia que o Pandas tem um classe específica para \"escrever\" em arquivos já existentes?\n", 41 | "\n", 42 | "__________\n", 43 | "\n", 44 | "Recentemente trabalhei em automatizar um relatório no Excel, mas não queria gerar um arquivo novo toda vez.\n", 45 | "\n", 46 | "A classe ExcelWriter resolveu meu problema 😀\n", 47 | "__________\n", 48 | "\n", 49 | "Veja abaixo um exemplo de aplicação.\n", 50 | "\n", 51 | "Você pode aumentar ou refazer o conteúdo de uma aba existente, ou ainda, criar a aba" 52 | ], 53 | "metadata": { 54 | "id": "bv2EcKp7YeRY" 55 | } 56 | }, 57 | { 58 | "cell_type": "code", 59 | "source": [ 60 | "# Imports de pacotes built-in\n", 61 | "from os import path\n", 62 | "from pathlib import Path\n", 63 | "\n", 64 | "# Imports de pacotes de terceiros\n", 65 | "import pandas as pd\n", 66 | "\n", 67 | "# Endereço do Relatório\n", 68 | "PASTA = Path('__file__').resolve().parent\n", 69 | "ENDERECO_RELATORIO = path.join(PASTA, 'app', 'Relatorio.xlsx')\n", 70 | "\n", 71 | "# Gerar o conteúdo a ser inserido no Relatório\n", 72 | "df = ...\n", 73 | "\n", 74 | "# Apagar o conteúdo anterior e inserir um novo\n", 75 | "with pd.ExcelWriter(\n", 76 | " ENDERECO_RELATORIO,\n", 77 | " mode='a',\n", 78 | " if_sheet_exists='replace',\n", 79 | " engine='openpyxl'\n", 80 | " ) as writer:\n", 81 | " df.to_excel(writer, sheet_name='BaseNotas', index=False)" 82 | ], 83 | "metadata": { 84 | "id": "4C8nl17gh8Jb" 85 | }, 86 | "execution_count": null, 87 | "outputs": [] 88 | }, 89 | { 90 | "cell_type": "markdown", 91 | "source": [ 92 | "**2. Unificar abas idênticas (mesma estrutura) de um mesmo arquivo Excel**\n", 93 | "\n", 94 | "**Exemplo:** Cada aba poderia conter os dados de venda de cada funcionário\n", 95 | "\n", 96 | "---\n", 97 | "\n", 98 | "**Problema:** Como unificar várias abas de um mesmo arquivo Excel?\n", 99 | "\n", 100 | "**Solucão:** Usar a classe ExcelFile do Pandas e o atributo \"sheet_names\"\n", 101 | "____________\n", 102 | "\n", 103 | "Veja abaixo um código que você pode modificar para escolher as abas/colunas, etc, se precisar" 104 | ], 105 | "metadata": { 106 | "id": "j-JdDACJcp42" 107 | } 108 | }, 109 | { 110 | "cell_type": "code", 111 | "source": [ 112 | "# Imports de pacote built-in\n", 113 | "import datetime\n", 114 | "\n", 115 | "# Imports de pacotes de terceiros\n", 116 | "import pandas as pd\n", 117 | "\n", 118 | "# Endereco - coloque entre ''\n", 119 | "ENDERECO = 'teste.xlsx'\n", 120 | "\n", 121 | "# Acessar arquivo\n", 122 | "arquivo = pd.ExcelFile(ENDERECO)" 123 | ], 124 | "metadata": { 125 | "id": "jOz3XRbKh-pP" 126 | }, 127 | "execution_count": null, 128 | "outputs": [] 129 | }, 130 | { 131 | "cell_type": "code", 132 | "source": [ 133 | "# Loop para conferir quais abas serão unificadas\n", 134 | "for i, aba in enumerate(arquivo.sheet_names):\n", 135 | " print(f'Aba {i+1}: {aba}')" 136 | ], 137 | "metadata": { 138 | "id": "6dbitJ_Ic6zD" 139 | }, 140 | "execution_count": null, 141 | "outputs": [] 142 | }, 143 | { 144 | "cell_type": "code", 145 | "source": [ 146 | "# Lista para receber tabelas\n", 147 | "tabelas = []\n", 148 | "\n", 149 | "# Loop para ler abas\n", 150 | "for aba in arquivo.sheet_names:\n", 151 | " df = pd.read_excel(ENDERECO, sheet_name=aba)\n", 152 | " tabelas.append(df)\n", 153 | "\n", 154 | "# Unificar\n", 155 | "unificada = pd.concat(tabelas)\n", 156 | "\n", 157 | "# Data\n", 158 | "DATA = datetime.date.today().strftime(\"%d-%m-%Y\")\n", 159 | "\n", 160 | "# Exportar para excel\n", 161 | "unificada.to_excel(f'ArquivoUnificado_{DATA}.xlsx', index=False)" 162 | ], 163 | "metadata": { 164 | "id": "uXKL_Ulsc66n" 165 | }, 166 | "execution_count": null, 167 | "outputs": [] 168 | } 169 | ] 170 | } --------------------------------------------------------------------------------