Escrevo hoje para (orgulhosamente) apresentar meu software [GitHub] para percorrer grafos 3D. O faço quase que pedindo desculpas, porque sei do tédio que este tipo de conversa provoca nas pessoas.
Ilustração de um grafo esférico. Imagem: Grok. Prompt: generate a hyper-realistic image of a spherical graph suspended in space, with nodes at the intersection of lines. highlight several brightened edges crisscrossing the graph sphere linking several nodes
Mas o fato é que este blog é totalmente dedicado ao lado nerd/geek das pessoas, e não pode haver nada mais nerdy-geeky do que isto.
Além disso, este trabalho representa a culminação de um esforço pessoal muito grande e eu preciso registrar a efeméride. Se você gosta de tudo o que é 3D, robótica, games, VR/AR isto pode te interessar.
Introdução
Estruturas de dados espaciais (isto é, em três dimensões) estão por toda parte — de motores de jogos à robótica e simulações científicas. Mas estruturas tradicionais de manipulação do espaço 3D como quadtrees e octrees funcionam melhor quando lidamos com posições. Quando o que importa é a orientação, essas estruturas perdem eficiência.
Como navegar por uma hierarquia rotacionando a visão, em vez de apenas seguir direções cartesianas?
Essa é a proposta do SpinStep.
O que é SpinStep?
SpinStep é um framework de travessia de árvores baseado em quatérnios[link], números especiais usados para representar rotações no espaço 3D. Em vez de seguir os ramos de uma árvore com base na distância entre eles, SpinStep seleciona caminhos com base na proximidade angular em relação à orientação atual.
Isso cria uma nova metáfora de navegação: não caminhamos do ponto A ao B, mas sim giramos em direção ao próximo nó do grafo.
À esq. uma árvore clássica, 2D e posicional. À dir. uma árvore 3D, orientacional, como nossa proposta. Imagem VL/GitHub
Por que quatérnios? E por que agora?
Quatérnios são mais estáveis que ângulos de Euler e mais compactos que matrizes de rotação, classicamente usados para indexação de nós em 3D. São comuns em animação 3D, realidade virtual, engenharia aeroespacial e robótica. Mas seu uso em travesia de dados ainda é pouco explorado.
SpinStep propõe que, quando os dados são orientacionais por natureza, estruturas baseadas em rotação são mais naturais e precisas do que estruturas posicionais.
Desafios e Limitações
Essa abordagem traz desafios técnicos:
Cálculo de distâncias angulares é mais pesado que comparações vetoriais simples.
Pequenos erros de ponto flutuante afetam estabilidade da travessia.
Faltam heurísticas padrão para definição de “distância” em espaços de rotação.
Mesmo assim, em muitos casos, o ganho em expressividade compensa a perda de desempenho.
Quando Vale a Pena?
SpinStep se destaca em nichos onde a orientação tem mais valor que a posição. Exemplos:
Planejamento de juntas em robôs articulados.
Travessia de cenas em VR baseada no ponto de vista do usuário.
Inteligência artificial com campo de visão dinâmico.
Simulações astrofísicas com caminhos orbitais.
Geração procedural em superfícies esféricas ou planetas.
Mesmo em cenários sensíveis a desempenho, SpinStep pode atuar como um filtro inicial para reduzir o espaço de busca.
Melhorias Futuras
Como projeto em crescimento, o SpinStep pode evoluir em várias frentes:
Aceleração com Numba ou Cython.
Ferramentas visuais para debug e visualização da travessia.
Integração com motores físicos ou bibliotecas de robótica.
Estratégias alternativas de travessia com pesos e heurísticas.
Considerações Finais
O futuro da computação espacial depende de como organizamos e percorremos dados. SpinStep propõe uma nova lente: pensar menos em “eixos” e mais em rotações.
É um convite para explorar, adaptar, e, quem sabe, transformar como lidamos com orientação em estruturas complexas.
A eleição recente do Papa Leão XIV, um padre pertencente à Ordem de Santo Agostinho, reacendeu o interesse pelo legado e pelas ideias de Santo Agostinho de Hipona, um dos pensadores mais influentes da história do cristianismo.
Antes de mais nada, devo dizer que por nenhuma medida eu posso ser considerado religioso. Sou, de fato, um racionalista empedernido, mas também um amante da história e da filosofia. A eleição do novo papa agostiniano me levou a revisitar algumas reflexões de Agostinho, especialmente sobre temas que ele considerava centrais: o direcionamento da alma ao Divino, os perigos do orgulho e o papel do humor na vida humana.
O Humor na Visão de Agostinho
Agostinho não era exatamente contrário ao riso, mas tratava o humor com bastante cautela. Em obras como Confissões e A Cidade de Deus, ele expressava dúvidas sobre o valor de certos prazeres humanos, incluindo o humor, quando estes pareciam desviar a alma da verdade divina. O riso, por si só, não era visto como algo mau, mas se tornava problemático quando se aproximava da irreverência ou do exagero. Ele se preocupava particularmente com piadas que zombassem do que é sagrado ou que levassem as pessoas a um comportamento frívolo. Em seus sermões, frequentemente alertava contra a chamada “fala indecorosa”, discursos excessivamente brincalhões que poderiam enfraquecer a seriedade espiritual e alimentar o orgulho.
Redes Sociais: Um Novo Palco para a “Fala Indecorosa”
Diante do cenário atual das redes sociais, dominado por memes, sarcasmo e comentários rasos, é interessante imaginar o que Agostinho pensaria. É provável que não ficasse indiferente.
Plataformas como X (antigo Twitter), Instagram, TikTok e outras estão repletas justamente do tipo de humor que ele criticava. Zombarias sobre o sagrado? Presentes. Piadas de gosto duvidoso, insinuações? Também. Ironia constante, indignação performática, escárnio de valores morais? Em abundância. Na comunicação digital de hoje, o riso muitas vezes vem acompanhado de desprezo, vaidade ou falta de reflexão. Difícil imaginar Agostinho navegando nessas plataformas sem sentir um certo incômodo teológico. Ele talvez enxergasse tudo isso como uma versão contemporânea da “fala indecorosa” que tanto condenava.
Orgulho, Distração e a Busca pelo Eterno
Para Agostinho, o problema maior do humor era o que ele poderia causar: orgulho, vaidade, ou um entorpecimento da alma — que deixaria de perceber a presença de Deus. Na sua visão, o bem maior é a união com o divino, e qualquer coisa que distraia desse objetivo — principalmente se mascarada por inteligência ou comédia — representa um risco espiritual significativo.
O Equilíbrio Agostiniano
Ainda assim, Agostinho não era alguém incapaz de reconhecer o valor da leveza. Ele sabia que o humor, quando usado com moderação e humildade, podia ter um papel positivo na vida humana. Ele não rejeitava toda forma de riso, apenas aquela que humilha, que exagera, ou que alimenta o ego. Para ele, o contexto sempre importava. Uma piada contada com respeito, afeto e simplicidade podia muito bem fazer parte da convivência entre pessoas de fé. Já um conteúdo sarcástico feito para ridicularizar as crenças alheias em troca de curtidas, esse, provavelmente, ele veria com preocupação.
Curiosamente, ele talvez reconhecesse que, mesmo com todos os seus excessos, as redes sociais também podem ser espaços para o bem. Quando promovem sabedoria, estimulam o senso de comunidade ou inspiram reflexão, elas podem se alinhar à ideia de amor bem ordenado que ele tanto valorizava. Mas, na prática, o que se vê com mais frequência são postagens carregadas de sarcasmo, ironia e desejo por atenção. Para Agostinho, isso não seria apenas um problema de gosto, seria uma ameaça real ao cultivo do espírito.
Um Convite à Reflexão na Era do Papa Leão XIV
Num mundo profundamente moldado pela mídia digital e pelo humor instantâneo, os alertas de Agostinho soam menos como moralismo antiquado e mais como uma reflexão que continua atual. Ele nos convida a pensar no que fazemos com o riso, e no que o riso faz com a gente. A forma como nos expressamos, especialmente em ambientes públicos e online, influencia tanto a cultura quanto aquilo que somos interiormente.
Talvez, com um papa de raízes agostinianas no Vaticano, essas reflexões ganhem novo espaço. Em uma época de rolagens infinitas e piadas descartáveis, vale a pena perguntar: o que nosso humor revela sobre nossas prioridades? Ele nos aproxima do que é profundo e verdadeiro, ou nos afasta ainda mais?
Na primeira parte deste guia prático exploramos os fundamentos da blockchain. A segunda parte tem um foco claro e objetivo: mostrar na prática a estrutura dos contratos inteligentes e como você pode implementá-los em sua própria blockchain.
Se no primeiro volume vimos a estrutura básica do bloco e da blockchain, aqui começamos a plantar os mecanismos que darão vida às aplicações descentralizadas (dApps). Seja para transferências automatizadas, registros imutáveis ou lógica condicional entre partes, os contratos inteligentes são a chave para desbloquear o verdadeiro potencial da Web3.
🚀 Integrando Contratos Inteligentes à Sua Blockchain
Contratos inteligentes permitem acordos automatizados e autoexecutáveis sem a necessidade de uma autoridade central. Você pode implementá-los diretamente na sua blockchain para viabilizar funcionalidades como transferência de ativos, validação de transações ou execução de aplicativos descentralizados (dApps).
🌐 Visão Geral dos Contratos Inteligentes
Contratos inteligentes são programas que rodam na blockchain. Eles podem ser escritos em linguagens como Solidity (comumente usada no Ethereum) ou Vyper, e têm como objetivo automatizar acordos ou transações entre partes.
Em sua blockchain baseada em Go, você essencialmente precisará de:
Uma forma de armazenar contratos inteligentes na blockchain.
Um mecanismo para executar o código do contrato inteligente quando certas condições forem atendidas.
Vamos simular isso de forma simples para começar, utilizando as capacidades nativas do Go. Isso não será tão complexo quanto o Ethereum, mas ilustrará os conceitos. Se você quiser avançar para contratos inteligentes compatíveis com o Ethereum, precisará de Solidity e de um cliente Ethereum como Geth ou Parity.
Abordagem Básica para Integrar Contratos Inteligentes
1️⃣ Representar Contratos Inteligentes
Em Go, você pode representar um contrato inteligente criando uma estrutura (struct) para o código do contrato e seu estado. Vamos começar definindo um contrato inteligente simples que pode atualizar seu estado quando chamado.
type SmartContract struct {
ID int
Code string // Este pode ser o código do contrato (por exemplo, código Solidity ou pseudo-código)
State string // Armazena o estado do contrato (por exemplo, "ativo", "concluído", etc.)
}
2️⃣ Adicionar Contratos Inteligentes aos Blocos
Você pode modificar a estrutura do bloco para incluir um contrato inteligente em cada bloco.
type Block struct {
Index int
Timestamp string
Data string // Dados da transação ou do contrato inteligente
PrevHash string
Hash string
SmartContract *SmartContract // Adiciona um ponteiro para o contrato inteligente (se houver)
}
Ao adicionar um novo bloco, você pode verificar se o bloco deve conter um contrato inteligente e configurá-lo.
Uma maneira básica de simular a execução de um contrato é chamando uma função no SmartContract quando certas condições forem atendidas.
Vamos supor que você tenha um contrato que permite alguém “ativá-lo” e definir seu estado como “concluído”:
func (sc *SmartContract) execute() {
// Para este exemplo simples, vamos dizer que executar significa mudar o estado
if sc.State == "ativo" {
sc.State = "concluído"
fmt.Println("Contrato executado com sucesso!")
} else {
fmt.Println("Contrato já está concluído!")
}
}
Então, na sua blockchain, você poderia ter uma função que verifica se há contratos que precisam ser executados quando um novo bloco é adicionado:
func (bc *Blockchain) executeContracts() {
for _, block := range bc.Chain {
if block.SmartContract != nil && block.SmartContract.State == "ativo" {
block.SmartContract.execute()
}
}
}
4️⃣ Acionar Contratos Inteligentes
Agora você pode executar a lógica do contrato inteligente ao adicionar blocos à sua blockchain:
func main() {
blockchain := Blockchain{}
blockchain.Chain = append(blockchain.Chain, createGenesisBlock())
// Cria um novo contrato inteligente
contract := &SmartContract{
ID: 1,
Code: "transferir(100 tokens)",
State: "ativo", // Inicialmente ativo, pode ser executado
}
// Adiciona o contrato a um novo bloco
blockchain.addBlockWithContract("Dados da Transação", contract)
// Executa quaisquer contratos ativos
blockchain.executeContracts()
// Imprime a blockchain para verificar o estado do contrato
for _, block := range blockchain.Chain {
fmt.Printf("Bloco %d: %s - Estado do Contrato: %s\n", block.Index, block.Timestamp, block.SmartContract.State)
}
}
5️⃣ Expandir os Contratos Inteligentes
Para tornar este sistema mais semelhante ao que você veria com contratos inteligentes baseados no Ethereum, você poderia:
Adicionar uma linguagem (como Solidity) para escrever contratos mais complexos.
Usar uma máquina virtual para executar a lógica do contrato (semelhante à EVM do Ethereum).
Adicionar mecanismos de gás para limitar quanto de recursos cada execução de contrato consome.
Implementar um algoritmo de consenso para execução descentralizada (Proof of Work, Proof of Stake, etc.).
Considerações do Mundo Real
Para integrar completamente contratos inteligentes em uma blockchain:
Armazenamento de dados: Armazene o código e os estados do contrato de forma descentralizada (por exemplo, IPFS ou em seus blocos).
Ambiente de execução: Você precisará implementar um sistema para interpretar e executar o código do contrato de forma segura. Isso poderia ser semelhante à Máquina Virtual Ethereum (EVM), mas poderia ser muito mais simples na sua blockchain baseada em Go.
Segurança: Contratos inteligentes podem ser vulneráveis a ataques como reentrância ou bugs de estouro. Lidar com isso de forma segura é crucial (por exemplo, testando contratos minuciosamente).
Conectar a um Contrato Inteligente baseado em Ethereum (Avançado)
Se você está procurando conectar sua blockchain Go ao Ethereum ou a uma blockchain semelhante ao Ethereum para executar contratos inteligentes Solidity, aqui está a abordagem geral:
Instalar o Web3 para Go: Esta é uma biblioteca Go que permite interagir com contratos inteligentes do Ethereum. go get github.com/ethereum/go-ethereum
Conectar-se ao Ethereum: Você precisará configurar um nó Ethereum (por exemplo, usando Infura ou executando seu próprio nó) e usar o Web3 em Go para implantar e interagir com contratos inteligentes.
Aqui está um exemplo:
package main
import (
"fmt"
"log"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
)
func main() {
client, err := ethclient.Dial("https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID")
if err != nil {
log.Fatalf("Falha ao conectar ao cliente Ethereum: %v", err)
}
address := common.HexToAddress("0xYourContractAddress")
fmt.Println("Conectado ao Ethereum!")
fmt.Println("Endereço do Contrato:", address.Hex())
}
Nesta segunda parte, exploramos na prática como os contratos inteligentes funcionam dentro de uma blockchain. Em breve vamos aprofundar ainda mais: analisando padrões de contratos inteligentes, interações entre múltiplos contratos e desafios reais como segurança, escalabilidade e integração com redes como Ethereum.
O futuro é descentralizado — e ele começa com nossas linhas de código.
Sempre estabeleci como condição para um tutorial que o assunto tratado fosse realmente relevante e original. Agora, finalmente, surge a oportunidade de desenvolver um tutorial original sobre esse sistema importante, ainda pouco compreendido, mas cada vez mais presente na realidade do mundo moderno.
A mídia fala constantemente sobre blockchain e seus derivados — como as criptomoedas e os contratos inteligentes mas, para muitos, incluindo colegas de profissão, esses conceitos ainda são envoltos em uma névoa de imprecisão, quando não de total confusão. Este guia tem como objetivo destacar o aspecto concreto dessas tecnologias, trazendo à tona sua implementação real por meio de código, e mostrando, na prática, como interagir com elas dentro do ambiente computacional.
Neste tutorial uso a linguagem Go, tanto pela simplicidade como por seu uso crescente nos projetos voltados à Blockchain. Qualquer LLM poderá refatorar o código facilmente para qualquer outra linguagem, como Python.
O que é uma Blockchain?
O termo “blockchain” vem da junção das palavras em inglês block (bloco) e chain (cadeia), e descreve exatamente o que ela é: uma cadeia de blocos ligados entre si, onde cada bloco contém um conjunto de dados, um carimbo de data/hora (timestamp), e um hash que o conecta ao bloco anterior. Essa estrutura torna os dados praticamente imutáveis, sendo largamente usada para garantir transparência e segurança em ambientes descentralizados.
Um Pouco de História
A ideia de encadear blocos usando hashes não surgiu com o Bitcoin. Já em 1991, Stuart Haber e W. Scott Stornetta propuseram um sistema computacional para armazenar documentos com carimbos de tempo de forma segura — sem possibilidade de adulteração. Esse trabalho é considerado uma das raízes da blockchain moderna. Foi somente em 2008 que Satoshi Nakamoto uniu essa ideia com o conceito de dinheiro digital, criando o Bitcoin e, com ele, a blockchain como a conhecemos hoje.
Conceitos-chave para Entender
🧩 Bloco
Cada bloco é como uma página em um livro-razão digital. Ele possui:
Carimbo de data/hora (T1, T2, T3…): Indica quando o bloco foi criado.
Hash do bloco anterior (PreHash): Uma “impressão digital” do bloco anterior, que o conecta à cadeia.
Hash atual (Root Hash): Calculado com base no conteúdo do bloco e serve para garantir sua integridade.
Dados: Pode conter qualquer informação — transações financeiras, contratos, documentos, etc.
Fig 1 – Ilustração da estrutura de um bloco.
Como se vê, o hash do bloco anterior se liga ao hash atual, conectando a cadeia. Se qualquer informação em um bloco for alterada, seu hash muda. Isso quebra a cadeia, tornando evidente que houve uma tentativa de adulteração.
🔐 Hashing
Hashing é o processo de aplicar uma função criptográfica sobre um dado para obter uma sequência de caracteres (o hash). Um dos algoritmos mais usados é o SHA-256, criado pela NSA e adotado amplamente desde os anos 2000. Ele transforma qualquer entrada (como um texto ou número) em uma sequência hexadecimal de 64 caracteres. Pequenas mudanças no dado original geram hashes completamente diferentes — um princípio chamado efeito avalanche.
⛏️ Prova de Trabalho (Proof of Work)
A Prova de Trabalho surgiu para resolver o problema da confiança em redes descentralizadas, como no Bitcoin. Ela exige que os participantes gastem poder computacional para adicionar novos blocos, tornando ataques muito caros e, portanto, inviáveis. A ideia foi inspirada em sistemas anti-spam dos anos 90 (como o Hashcash de Adam Back), onde uma tarefa computacional dificultava o envio de emails em massa.
🛠️ Construindo uma Blockchain Simples em Go
Agora que (provavelmente) entendemos os conceitos, vamos ver como isso se traduz em código.
Etapa 1: Definir a Estrutura do Bloco
package main
import (
"crypto/sha256"
"fmt"
"time"
)
type Block struct {
Index int
Timestamp string
Data string
PrevHash string
Hash string
}
🧱 Aqui definimos os principais componentes do bloco. Veja que a estrutura lógica do bloco define todos os ítens (atributos) do bloco, como ilustrado na Fig 1. Ele é uma estrutura básica, mas com tudo o que precisamos para construir a cadeia.
📜 O bloco gênesis é o primeiro bloco da blockchain. Ele é especial porque não possui um antecessor. No Bitcoin, ele foi minerado por Satoshi Nakamoto em 3 de janeiro de 2009. Uma curiosidade: sua mensagem de dados incluía o título de uma manchete de jornal daquele dia, uma crítica à crise bancária da época.
🔍 Essa função garante a integridade do bloco, produzindo um hash único com base nas suas informações. Isso é o que torna a blockchain resistente a modificações: se qualquer dado mudar, o hash será diferente.
🔗 Aqui a cadeia começa a tomar forma. Cada novo bloco contém o hash do anterior, criando a estrutura de “cadeia”.
Etapa 5: Iniciar e Usar a Blockchain
func main() {
blockchain := Blockchain{}
blockchain.Chain = append(blockchain.Chain, createGenesisBlock())
blockchain.addBlock("Primeiro bloco depois do genesis")
blockchain.addBlock("Segundo bloco depois do genesis")
for _, block := range blockchain.Chain {
fmt.Printf("Index: %d, Timestamp: %s, Data: %s, PrevHash: %s, Hash: %s\n",
block.Index, block.Timestamp, block.Data, block.PrevHash, block.Hash)
}
}
📤 A execução do código imprime cada bloco da cadeia, demonstrando como a estrutura vai se formando e se conectando.
Etapa 6: Saída Esperada
Index: 0, Timestamp: ..., Data: Genesis Block, PrevHash: , Hash: 6b3d...
Index: 1, Timestamp: ..., Data: Primeiro bloco depois do genesis, PrevHash: 6b3d..., Hash: 2c6e...
Index: 2, Timestamp: ..., Data: Segundo bloco depois do genesis, PrevHash: 2c6e..., Hash: 9c4a...
📊 Você verá blocos encadeados, com cada PrevHash correspondendo ao Hash do bloco anterior.
🧠 O que mais?
A blockchain construída acima é funcional, mas ainda simples. Você pode expandir com:
✅ Validação da Blockchain
func (bc *Blockchain) isValid() bool {
for i := 1; i < len(bc.Chain); i++ {
prevBlock := bc.Chain[i-1]
block := bc.Chain[i]
if block.PrevHash != prevBlock.Hash || block.Hash != calculateHash(block.Index, block.PrevHash, block.Data) {
return false
}
}
return true
}
🔎 Esta função verifica se a cadeia é válida. É um conceito essencial para detectar fraudes ou inconsistências em sistemas descentralizados.
🔨 Prova de Trabalho (Opcional)
Você pode implementar um campo nonce no bloco e ajustar o algoritmo de hash para que o resultado comece com, por exemplo, “0000”. Isso simula a mineração usada no Bitcoin, onde é preciso tentar milhões de combinações até encontrar um hash com a “dificuldade” exigida.
🌐 Descentralização
Até agora, nossa blockchain é local e centralizada. Em um projeto mais complexo, você pode usar:
Go-Ethereum: Implementação oficial do Ethereum em Go.
Gorilla Websocket: Para comunicação P2P entre nós (nodes).
Go-Swagger: Para criar APIs REST que expõem a blockchain.
🎓 Conclusão da primeira parte
Construir uma blockchain do zero é uma excelente forma de aprender estruturas de dados, criptografia, segurança da informação e sistemas distribuídos. Começando com algo simples, você pode continuar a adicionar camadas de complexidade: provas de consenso, contratos inteligentes, persistência em disco, interfaces gráficas e muito mais.
Se você chegou até aqui você está mais perto de entender não só como a blockchain funciona, mas por que ela é revolucionária. Na segunda parte deste pequeno guia, vou mostrar a lógica estrutural de um contrato inteligente e como adicioná-lo à Blockchain.
Estou desenvolvendo um tutorial completo (e executável!) sobre o tema, que abrigarei em meu Github. Você pode acompanhar — e contribuir.
[EDITADO – VER NOTA] Em uma era onde a informação flui livremente — e instantaneamente, é fácil assumir que a batalha pela verdade é a luta definidora do nosso tempo. Frequentemente ouvimos falar em “fake news”, “pós-verdade” e a erosão da realidade objetiva, como se o principal desafio enfrentado pela sociedade fosse simplesmente a distorção dos fatos.
Imagem: pexels.com
Porém, em seu provocativo livro Hipnocracia, Jianwei Xun apresenta uma perspectiva mais sutil e alarmante sobre como o poder opera hoje. Em vez de se concentrar na supressão da verdade, Xun argumenta que vivemos agora sob um sistema onde o controle é alcançado ao nos sobrecarregar com narrativas, a ponto de perdermos a capacidade de distinguir qualquer uma delas como “a verdade”.
NOTA
Este filósofo de Hong Kong não existe, como revela Sabina Minardi, editora-chefe da revista italiana L’Espresso. A teoria é fruto da imaginação do ensaísta e editor Andrea Colamedici, que assina como tradutor, mas que, na verdade, é coautor do livro, auxiliado por duas plataformas de inteligência artificial, sem qualquer menção a esse fato [conforme exigido pela legislação da UE sobre IA]. Ele justifica a obra como um “experimento filosófico e uma performance artística”.
Eu desconhecia essa infeliz estória. Decidi remover o conteúdo da matéria publicada em 5 de Abril que se referia a conteúdo explícito na obra atribuído ao suposto filósofo de Hong Kong, cuja existência foi comprovada como falsa.