<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Juntos Somos Mais - Medium]]></title>
        <description><![CDATA[Somos a maior rede de relacionamento do mercado de construção civil e trabalhamos duro para unir empresas líderes do setor e conectá-las aos varejistas e profissionais de obra. A rede cresce a cada dia e hoje conta com mais de 20 empresas, 150 mil lojistas e 300 mil profissionais - Medium]]></description>
        <link>https://medium.com/juntos-somos-mais?source=rss----7d848878115---4</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>Juntos Somos Mais - Medium</title>
            <link>https://medium.com/juntos-somos-mais?source=rss----7d848878115---4</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Fri, 22 May 2026 13:56:05 GMT</lastBuildDate>
        <atom:link href="https://medium.com/feed/juntos-somos-mais" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Treinamento e Implantação de um Modelo de Aprendizado Não Supervisionado com K-means e Flask]]></title>
            <link>https://medium.com/juntos-somos-mais/treinamento-e-implanta%C3%A7%C3%A3o-de-um-modelo-de-aprendizado-n%C3%A3o-supervisionado-com-k-means-e-flask-3715b4f3948?source=rss----7d848878115---4</link>
            <guid isPermaLink="false">https://medium.com/p/3715b4f3948</guid>
            <category><![CDATA[flask]]></category>
            <category><![CDATA[k-means]]></category>
            <category><![CDATA[machine-learning]]></category>
            <dc:creator><![CDATA[Ricardo Baltazar]]></dc:creator>
            <pubDate>Sun, 02 Apr 2023 12:50:21 GMT</pubDate>
            <atom:updated>2023-04-02T12:50:21.799Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*8UXimUQkHb_lOVvx" /><figcaption>Photo by <a href="https://unsplash.com/@possessedphotography?utm_source=medium&amp;utm_medium=referral">Possessed Photography</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>Neste artigo, vamos explorar o treinamento de um modelo de aprendizado de máquina não supervisionado usando o algoritmo K-means e, em seguida, expor esse modelo através de uma API Flask. O foco deste artigo é o público que já trabalha com tecnologia, mas não é especialista em aprendizado de máquina.</p><h3>Aprendizado Não Supervisionado</h3><p>O aprendizado não supervisionado é um conjunto de técnicas de aprendizado de máquina que analisam e agrupam dados sem um “gabarito” pré-definido. Os algoritmos não supervisionados buscam padrões e estruturas nos dados sem usar rótulos de saída prévios. O objetivo é encontrar agrupamentos naturais, relações ou padrões nos dados.</p><h3>Algoritmo K-means</h3><p>O algoritmo K-means é uma técnica popular de aprendizado não supervisionado que se baseia em agrupar os dados em K grupos distintos, onde K é um número pré-definido de clusters. O algoritmo tenta minimizar a soma das distâncias entre os pontos de dados e os centroides dos clusters, ajustando iterativamente a posição dos centroides até que os clusters se estabilizem.</p><h3>Conjunto de Dados Iris</h3><p>O conjunto de dados Iris é um conjunto de dados popular que consiste em 150 amostras de flores de íris de três espécies diferentes: Iris setosa, Iris versicolor e Iris virginica. Cada amostra contém quatro características (comprimento e largura das sépalas e pétalas). Nosso objetivo é usar o algoritmo K-means para agrupar as amostras em três clusters, correspondendo às três espécies de íris.</p><h3>Treinamento do Modelo K-means</h3><p>Vamos começar treinando nosso modelo K-means no conjunto de dados Iris. Usaremos a biblioteca scikit-learn em Python para treinar o modelo. Primeiro, carregamos o conjunto de dados Iris, criamos um DataFrame e treinamos o modelo K-means com K=3.</p><pre># Importar bibliotecas necessárias<br>import numpy as np<br>import pandas as pd<br>import matplotlib.pyplot as plt<br>from sklearn.cluster import KMeans<br>from sklearn.datasets import load_iris<br><br># Carregar o conjunto de dados Iris<br>iris = load_iris()<br>data = iris.data<br>target = iris.target<br><br># Criar um DataFrame com os dados e as colunas<br>iris_df = pd.DataFrame(data, columns=iris.feature_names)<br><br># Treinar o modelo K-means com K=3<br>kmeans = KMeans(n_clusters=3, random_state=42)<br>kmeans.fit(iris_df)</pre><h3>Exportando o Modelo Treinado</h3><p>Para salvar e carregar o modelo treinado, usaremos a biblioteca joblib. Primeiro, salvamos o modelo treinado em um arquivo.</p><pre>import joblib<br><br># Salvar o modelo treinado em um arquivo<br>joblib.dump(kmeans, &#39;kmeans_model.joblib&#39;)</pre><h3>Criando uma API Flask</h3><p>Agora que treinamos e salvamos nosso modelo, podemos criar uma API Flask para expor o modelo e fazer previsões.</p><pre>from flask import Flask, request, jsonify<br>import numpy as np<br>import joblib<br><br>app = Flask(__name__)<br><br># Carregar o modelo treinado<br>kmeans = joblib.load(&#39;kmeans_model.joblib&#39;)<br><br>@app.route(&#39;/predict&#39;, methods=[&#39;POST&#39;])<br>def predict():<br>  input_data = request.json<br>  features = [input_data[&#39;sepal_length&#39;], input_data[&#39;sepal_width&#39;], input_data[&#39;petal_length&#39;], input_data[&#39;petal_width&#39;]]<br>  features = np.array(features).reshape(1, -1)<br>  cluster = kmeans.predict(features)<br>  return jsonify({&#39;cluster&#39;: int(cluster[0])})<br>  <br>if name == &#39;main&#39;:<br>  app.run(debug=True)</pre><p>Em seguida, iniciamos o servidor Flask executando o arquivo app.py.</p><pre>python app.py</pre><p>Agora, a API está disponível em `<a href="http://localhost:5000/predict`">http://localhost:5000/predict`</a>. Podemos fazer solicitações POST para essa URL com um JSON contendo os valores das características do Iris (comprimento e largura das sépalas e pétalas) e obter o cluster previsto como resposta.</p><p>Exemplo de requisição POST usando o curl no Linux</p><p>Aqui está um exemplo de como fazer uma solicitação POST para a API usando o comando curl.</p><pre>curl -X POST -H &quot;Content-Type: application/json&quot; -d &#39;{&quot;sepal_length&quot;: 5.1, &quot;sepal_width&quot;: 3.5, &quot;petal_length&quot;: 1.4, &quot;petal_width&quot;: 0.2}&#39; http://localhost:5000/predict</pre><p>Este comando envia uma solicitação POST para a API com o cabeçalho Content-Type: application/json e os dados no formato JSON.</p><h3>Conclusão</h3><p>Neste artigo, exploramos o treinamento e a implantação de um modelo de aprendizado não supervisionado usando o algoritmo K-means e o conjunto de dados Iris. Demonstramos como treinar o modelo, exportá-lo e criar uma API Flask para expor o modelo e fazer previsões.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3715b4f3948" width="1" height="1" alt=""><hr><p><a href="https://medium.com/juntos-somos-mais/treinamento-e-implanta%C3%A7%C3%A3o-de-um-modelo-de-aprendizado-n%C3%A3o-supervisionado-com-k-means-e-flask-3715b4f3948">Treinamento e Implantação de um Modelo de Aprendizado Não Supervisionado com K-means e Flask</a> was originally published in <a href="https://medium.com/juntos-somos-mais">Juntos Somos Mais</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Configurando o KEDA para autoescalar com base nas mensagens em uma fila do RabbitMQ]]></title>
            <link>https://medium.com/juntos-somos-mais/configurando-o-keda-para-autoescalar-com-base-nas-mensagens-em-uma-fila-do-rabbitmq-e224f233e219?source=rss----7d848878115---4</link>
            <guid isPermaLink="false">https://medium.com/p/e224f233e219</guid>
            <category><![CDATA[keda]]></category>
            <category><![CDATA[autoscaling]]></category>
            <category><![CDATA[rabbitmq]]></category>
            <category><![CDATA[kubernetes]]></category>
            <dc:creator><![CDATA[Ricardo Baltazar]]></dc:creator>
            <pubDate>Sun, 26 Mar 2023 19:05:43 GMT</pubDate>
            <atom:updated>2023-03-26T19:05:43.236Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*ftwSRNRLegH6mRU_" /><figcaption>Photo by <a href="https://unsplash.com/@growtika?utm_source=medium&amp;utm_medium=referral">Growtika</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>O KEDA (Kubernetes Event-driven Autoscaling) é um projeto de código aberto que oferece escalabilidade baseada em eventos para aplicativos Kubernetes. Neste post, mostraremos como configurar o KEDA para autoescalar um consumidor com base no número de mensagens em uma fila do RabbitMQ. O objetivo é ter um consumidor em espera (sem instâncias) até que uma mensagem seja enfileirada.</p><p>Pré-requisitos:</p><ol><li>Kubernetes cluster configurado.</li><li>kubectl instalado e configurado.</li><li>Helm instalado e configurado.</li><li>Acesso ao RabbitMQ (local ou remoto).</li></ol><h4>Passo 1: Instalar o KEDA usando Helm</h4><p>Para instalar o KEDA usando o Helm, execute o seguinte comando:</p><pre>helm repo add kedacore https://kedacore.github.io/charts<br>helm repo update<br>helm install keda kedacore/keda --namespace keda --create-namespace</pre><h4>Passo 2: Criar um consumidor</h4><p>Crie um arquivo chamado consumer.yaml com o seguinte conteúdo:</p><pre>apiVersion: apps/v1<br>kind: Deployment<br>metadata:<br>  name: rabbitmq-consumer<br>spec:<br>  replicas: 0<br>  selector:<br>    matchLabels:<br>      app: rabbitmq-consumer<br>  template:<br>    metadata:<br>      labels:<br>        app: rabbitmq-consumer<br>    spec:<br>      containers:<br>      - name: consumer<br>        image: &lt;SUA_IMAGEM_DO_CONSUMIDOR&gt;<br>        env:<br>        - name: RABBITMQ_CONNECTIONSTRING<br>          valueFrom:<br>            secretKeyRef:<br>              name: rabbitmq-secret<br>              key: connectionString<br>---<br>apiVersion: v1<br>kind: Secret<br>metadata:<br>  name: rabbitmq-secret<br>type: Opaque<br>stringData:<br>  connectionString: &lt;SUA_STRING_DE_CONEXÃO_DO_RABBITMQ&gt;</pre><p>Substitua &lt;SUA_IMAGEM_DO_CONSUMIDOR&gt; pela imagem do seu consumidor e &lt;SUA_STRING_DE_CONEXÃO_DO_RABBITMQ&gt; pela string de conexão do RabbitMQ.</p><h4>Passo 3: Configurar o ScaledObject</h4><p>Crie um arquivo chamado scaledobject.yaml com o seguinte conteúdo:</p><pre>apiVersion: keda.sh/v1alpha1<br>kind: ScaledObject<br>metadata:<br>  name: rabbitmq-scaledobject<br>spec:<br>  scaleTargetRef:<br>    name: rabbitmq-consumer<br>  minReplicaCount: 0<br>  maxReplicaCount: 10<br>  triggers:<br>  - type: rabbitmq<br>    metadata:<br>      queueName: &lt;NOME_DA_FILA&gt;<br>      queueLength: &#39;1&#39;<br>      hostFromEnv: RABBITMQ_CONNECTIONSTRING</pre><p>Substitua &lt;NOME_DA_FILA&gt; pelo nome da fila do RabbitMQ que você deseja monitorar.</p><h4>Passo 4: Aplicar as configurações</h4><p>Execute os seguintes comandos para aplicar as configurações:</p><pre>kubectl apply -f consumer.yaml<br>kubectl apply -f scaledobject.yaml</pre><p>Agora, o KEDA monitorará a fila do RabbitMQ e ajustará o número de réplicas do consumidor com base no número de mensagens na fila. Quando a fila estiver vazia, não haverá instâncias do consumidor em execução. Quando uma mensagem chegar à fila, o KEDA escalará o consumidor</p><p>Para monitorar os logs do KEDA e verificar se o autoescalonamento está funcionando corretamente, você pode verificar os logs do pod do operador KEDA. Siga os passos abaixo:</p><h4>Passo 1: Liste os pods no namespace do KEDA</h4><p>Execute o seguinte comando para listar todos os pods no namespace do KEDA:</p><pre>kubectl get pods -n keda</pre><p>Você verá uma saída semelhante a esta:</p><pre>NAME                                      READY   STATUS    RESTARTS   AGE<br>keda-6d869d66bd-5ht5j                      1/1     Running   0          1d<br>keda-operator-7c87884b75-4vwmn             1/1     Running   0          1d</pre><h4>Passo 2: Verifique os logs do operador KEDA</h4><p>Para verificar os logs do operador KEDA, execute o seguinte comando substituindo &lt;KEDA_OPERATOR_POD&gt; pelo nome do pod do operador KEDA obtido no passo anterior:</p><pre>kubectl logs -f &lt;KEDA_OPERATOR_POD&gt; -n keda</pre><p>Por exemplo:</p><pre>kubectl logs -f keda-operator-7c87884b75-4vwmn -n keda</pre><p>Você verá logs semelhantes a estes ao monitorar o autoescalonamento:</p><pre>{&quot;level&quot;:&quot;info&quot;,&quot;ts&quot;:...,&quot;logger&quot;:&quot;scalehandler&quot;,&quot;msg&quot;:&quot;Scaling&quot;,&quot;ScaledObject.Namespace&quot;:&quot;default&quot;,&quot;ScaledObject.Name&quot;:&quot;rabbitmq-scaledobject&quot;,&quot;ScaledObject.ScaleType&quot;:&quot;deployment&quot;,&quot;ScaledObject.Scaler&quot;:{},&quot;ScaledObject.MinReplicas&quot;:0,&quot;ScaledObject.MaxReplicas&quot;:10,&quot;ScaledObject.Replicas&quot;:0}<br>{&quot;level&quot;:&quot;info&quot;,&quot;ts&quot;:...,&quot;logger&quot;:&quot;controllers.ScaledObject&quot;,&quot;msg&quot;:&quot;Successfully updated status&quot;,&quot;ScaledObject.Namespace&quot;:&quot;default&quot;,&quot;ScaledObject.Name&quot;:&quot;rabbitmq-scaledobject&quot;}<br>{&quot;level&quot;:&quot;info&quot;,&quot;ts&quot;:...,&quot;logger&quot;:&quot;scalehandler&quot;,&quot;msg&quot;:&quot;Scaling&quot;,&quot;ScaledObject.Namespace&quot;:&quot;default&quot;,&quot;ScaledObject.Name&quot;:&quot;rabbitmq-scaledobject&quot;,&quot;ScaledObject.ScaleType&quot;:&quot;deployment&quot;,&quot;ScaledObject.Scaler&quot;:{},&quot;ScaledObject.MinReplicas&quot;:0,&quot;ScaledObject.MaxReplicas&quot;:10,&quot;ScaledObject.Replicas&quot;:1}</pre><p>Agora você pode monitorar os logs do KEDA e ver o autoescalonamento em ação. Verifique se o número de réplicas aumenta e diminui com base no número de mensagens na fila do RabbitMQ.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e224f233e219" width="1" height="1" alt=""><hr><p><a href="https://medium.com/juntos-somos-mais/configurando-o-keda-para-autoescalar-com-base-nas-mensagens-em-uma-fila-do-rabbitmq-e224f233e219">Configurando o KEDA para autoescalar com base nas mensagens em uma fila do RabbitMQ</a> was originally published in <a href="https://medium.com/juntos-somos-mais">Juntos Somos Mais</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Como modificar a inicialização do serviço do Docker no Ubuntu]]></title>
            <link>https://medium.com/juntos-somos-mais/como-modificar-a-inicializa%C3%A7%C3%A3o-do-servi%C3%A7o-do-docker-no-ubuntu-f1c4c9bfaba4?source=rss----7d848878115---4</link>
            <guid isPermaLink="false">https://medium.com/p/f1c4c9bfaba4</guid>
            <category><![CDATA[docker]]></category>
            <category><![CDATA[ubuntu]]></category>
            <dc:creator><![CDATA[Ricardo Baltazar]]></dc:creator>
            <pubDate>Thu, 09 Mar 2023 11:43:27 GMT</pubDate>
            <atom:updated>2023-03-09T11:43:27.017Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*-3PY8hzoLac_NbOF" /><figcaption>Photo by <a href="https://unsplash.com/@6heinz3r?utm_source=medium&amp;utm_medium=referral">Gabriel Heinzer</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>Eu tive um problema com a montagem de um volume no meu ubunto e quando isso aconteceu o meu serviço docker subiu com erro porque os dados do Docker estavam nesse volume.</p><p>Para isso eu mudei a configuração do Docker para ele esperar a montagem do volume antes de iniciar o serviço. Fui atrás para entender qual a maneira correta de se fazer isso.</p><p>A primeira coisa para entender é que o arquivo que é responsável por inicializar o Docker no Ubuntu é o arquivo /lib/systemd/system/docker.service e ele é gerenciado pelo Docker, por isso não devemos altera-lo.</p><p>Para conseguir mudar o comportamento desse arquivo vamos criar o diretório /etc/systemd/system/docker.service.d/ e dentro dele o arquivo mount.conf e o conteúdo dele será esse:</p><pre>[Unit]<br>RequiresMountsFor=/mnt/disk1</pre><p>Essa configuração vai adicionar ou alterar a configuração RequiresMountsFor do arquivo /lib/systemd/system/docker.service usando o valor /mnt/disk1 que é o nome do volume que eu preciso que ele espere estar montado.</p><p>Após criar um arquivo personalizado em /etc/systemd/system/docker.service.d/, você deve recarregar o daemon do systemd para que as alterações tenham efeito usando o comando:</p><pre>sudo systemctl daemon-reload</pre><p>Em seguida, você pode reiniciar o serviço do Docker para que as alterações sejam aplicadas usando o comando:</p><pre>sudo systemctl restart docker</pre><p>Agora toda vez que o serviço docker for iniciado ele vai verificar se o volume está montando antes.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f1c4c9bfaba4" width="1" height="1" alt=""><hr><p><a href="https://medium.com/juntos-somos-mais/como-modificar-a-inicializa%C3%A7%C3%A3o-do-servi%C3%A7o-do-docker-no-ubuntu-f1c4c9bfaba4">Como modificar a inicialização do serviço do Docker no Ubuntu</a> was originally published in <a href="https://medium.com/juntos-somos-mais">Juntos Somos Mais</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Criando um serviço no Ubuntu para rodar uma imagem Docker]]></title>
            <link>https://medium.com/juntos-somos-mais/criando-um-servi%C3%A7o-no-ubuntu-para-rodar-uma-imagem-docker-ee2707268402?source=rss----7d848878115---4</link>
            <guid isPermaLink="false">https://medium.com/p/ee2707268402</guid>
            <category><![CDATA[linux]]></category>
            <category><![CDATA[systemd]]></category>
            <category><![CDATA[ubuntu]]></category>
            <dc:creator><![CDATA[Ricardo Baltazar]]></dc:creator>
            <pubDate>Sun, 19 Feb 2023 21:35:31 GMT</pubDate>
            <atom:updated>2023-02-19T21:35:31.557Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*QzajugBZFsxWxTxx" /><figcaption>Photo by <a href="https://unsplash.com/@6heinz3r?utm_source=medium&amp;utm_medium=referral">Gabriel Heinzer</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>Primeiro precisamos entender o que é o systemd .</p><p>O Systemd é um sistema de inicialização usado por muitas distribuições Linux. Ele é responsável por iniciar e gerenciar os serviços do sistema. Para configurar um serviço no Systemd, é necessário criar um arquivo de unidade no diretório /etc/systemd/system/. Neste artigo, vamos explicar cada um dos parâmetros que podem ser usados no arquivo de unidade.</p><p>Crie um arquivo no diretório /etc/systemd/system</p><pre>[Unit]<br>Description=Onion Share<br>Wants=network-online.target<br>After=network-online.target<br>Wants=docker.service<br>After=docker.service<br><br>StartLimitInterval=0<br><br>[Service]<br>Type=forking<br>TimeoutStartSec=infinity<br>TimeoutStopSec=16min<br>ExecStart=/mnt/disk1/onion-farm/scripts/start<br>ExecStop=/mnt/disk1/umbrel/scripts/stop<br>User=root<br>Group=root<br>StandardOutput=syslog<br>StandardError=syslog<br>SyslogIdentifier=onion-service-startup<br>RemainAfterExit=yes<br>Restart=always<br>RestartSec=10  <br><br>[Install]<br>WantedBy=multi-user.target</pre><p>Segue um resumo sobre os campos que podem ser usados nesse arquivo.</p><p>Seção [Unit]</p><p>A seção [Unit] é usada para definir informações gerais sobre o serviço.</p><ul><li>Description: Uma descrição curta do serviço.</li><li>Documentation: Uma URL ou caminho para a documentação do serviço.</li><li>Requires: Uma lista de unidades que devem ser iniciadas antes deste serviço.</li><li>After: Uma lista de unidades que devem ser iniciadas antes deste serviço.</li></ul><p>Seção [Service]</p><p>A seção [Service] é usada para definir informações específicas do serviço.</p><ul><li>ExecStart: O comando ou script que deve ser executado para iniciar o serviço.</li><li>Type: O tipo do serviço, pode ser simple, forking, oneshot, dbus, notify, idle.</li><li>User: O usuário que deve ser usado para executar o serviço.</li><li>Group: O grupo que deve ser usado para executar o serviço.</li><li>WorkingDirectory: O diretório de trabalho para o serviço.</li><li>Environment: Uma lista de variáveis de ambiente a serem definidas para o serviço.</li><li>StandardOutput: Onde enviar a saída padrão do serviço, pode ser inherit, null, tty, journal, syslog, kmsg, journal+console, syslog+console, kmsg+console.</li><li>StandardError: Onde enviar a saída de erro do serviço, pode ser inherit, null, tty, journal, syslog, kmsg, journal+console, syslog+console, kmsg+console.</li><li>Restart: Quando o serviço deve ser reiniciado, pode ser no, on-success, on-failure, on-abnormal, on-abort, on-watchdog, always.</li><li>RestartSec: O tempo a esperar antes de reiniciar o serviço.</li><li>TimeoutStartSec: Quanto tempo esperar pelo início do serviço antes de considerá-lo falhado.</li><li>TimeoutStopSec: Quanto tempo esperar pelo término do serviço antes de considerá-lo falhado.</li><li>SyslogIdentifier: A identificação a ser usada ao registrar o serviço no syslog.</li></ul><p>Seção [Install]</p><p>A seção [Install] é usada para definir como o serviço deve ser instalado.</p><ul><li>WantedBy: A unidade ou alvo que deve ser iniciado quando este serviço é iniciado.</li></ul><p>Agora precisamos criar os arquivos que vão iniciar e para o serviço docker.</p><p>Crie a pasta onde os arquivos serão adicionados. No meu caso eu criei no diretório mnt/disk1/onion-farm/scripts/start</p><pre>#!/bin/bash<br><br>docker run \<br>    -p 3000:5000 \<br>    -v $(pwd)/html/:/var/www/html/ \<br>    -v $(pwd)/http.d/:/etc/nginx/http.d/ \<br>    -v $(pwd)/torrc.d/:/etc/torrc.d/ \<br>    -v $(pwd)/tor/:/var/lib/tor/ \<br>    -d \<br>    --name onion-farm \<br>    ricardobchaves6/onion-farm:v1.0.0</pre><p>Vamos criar o arquivo que vai parar o container.</p><pre>#!/bin/bash<br><br>docker stop -t 30 onion-farm<br>docker rm onion-farm</pre><p>Vamos adicionar as permissões para os arquivos: sudo chmod 775 start stop .</p><p>Execute o comando abaixo para que o seu serviço seja iniciado ao reiniciar o sistema operacional:</p><pre>sudo systemctl enable onion-farm-startup.service</pre><p>Teste seu serviço com:</p><pre>  systemctl start onion-farm-startup.service<br>  systemctl stop onion-farm-startup.service</pre><p>Sobre o start e stop, não vou explicar porque é simples de mais :)</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ee2707268402" width="1" height="1" alt=""><hr><p><a href="https://medium.com/juntos-somos-mais/criando-um-servi%C3%A7o-no-ubuntu-para-rodar-uma-imagem-docker-ee2707268402">Criando um serviço no Ubuntu para rodar uma imagem Docker</a> was originally published in <a href="https://medium.com/juntos-somos-mais">Juntos Somos Mais</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Verificando e corrigindo problemas de segurança no Orange Pi 5]]></title>
            <link>https://medium.com/juntos-somos-mais/verificando-e-corrigindo-problemas-de-seguran%C3%A7a-no-orange-pi-5-5180c77a8cd4?source=rss----7d848878115---4</link>
            <guid isPermaLink="false">https://medium.com/p/5180c77a8cd4</guid>
            <category><![CDATA[security]]></category>
            <category><![CDATA[ubuntu]]></category>
            <category><![CDATA[orange-pi-5]]></category>
            <dc:creator><![CDATA[Ricardo Baltazar]]></dc:creator>
            <pubDate>Thu, 26 Jan 2023 11:18:40 GMT</pubDate>
            <atom:updated>2023-01-26T11:18:40.309Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*M6fsaoDj3qWQmFD4" /><figcaption>Photo by <a href="https://unsplash.com/de/@markusspiske?utm_source=medium&amp;utm_medium=referral">Markus Spiske</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>Eu uso o sistema operacional do Ubunto Desktop. Eu explico o porque nesse posto onde detalho minha primeira experiencia com ele.</p><p>Depois de uma primeira configuração e tento já o Umbrel rodando eu parei para dar uma olhada no SO para ver o que temos.</p><p>Veja bem, eu não sou nenhum profissional de segurança e meu conhecimento na área é muito pequeno, por isso tome esse texto apenas como um guia inicial para projetos pessoais, se quiser segurança profissional procure um profissional. Eu vou Back End, sou bom em abrir brechas de segurança, não de fecha-las. :D</p><p>No final, eu não fiz praticamente nada, esto postando aqui para manter um ristro inclusive do que eu não fiz. Caso você veja alguma coisa errada, por favor, me avise.</p><p>Primeiro eu peguei meu IP publico e tentei rodar um ssh nele, conectado no ssh dele:</p><pre>&gt;curl ifconfig.me<br>111.111.111.11</pre><p>Depois em qualquer computador:</p><pre>&gt;ssh 111.111.111.11                                                                                                                                   ricardochaves@Ricardos-MacBook-Pro<br>ssh: connect to host 111.111.111.11 port 22: Connection refused</pre><p>Aqui eu já fiquei mais tranquilo porque não tinha mudado a senha do ssh ainda.</p><p>Agora eu queria alguma ferramenta que me ajudasse a verificar possíveis vulnerabilidades existentes na minha configuração de Linux. Procurando no Google eu achei algumas e comecei pela <a href="https://cisofy.com/lynis/#installation">Lynis</a>.</p><p>Para inslar e rodar é apenas isso:</p><pre>git clone https://github.com/CISOfy/lynis<br>cd lynis<br>./lynis audit system</pre><p>Ao final do estenso relatório ele me deu 47 Suggestions :</p><pre>  * This release is more than 4 months old. Check the website or GitHub to see if there is an update available. [LYNIS]<br>      https://cisofy.com/lynis/controls/LYNIS/</pre><p>Essa eu não tenho o que fazer. Estou com a versão mais nova.</p><pre>  * Consider hardening system services [BOOT-5264]<br>    - Details  : Run &#39;/usr/bin/systemd-analyze security SERVICE&#39; for each service<br>      https://cisofy.com/lynis/controls/BOOT-5264/</pre><p>Quando eu fiz com o Docker ele ficou todo vermelho… São muitos serviços e eu vou precisar de tempo para fazer um a um… Se é que eu vou fazer.</p><pre>  * Determine why /vmlinuz or /boot/vmlinuz is missing on this Debian/Ubuntu system. [KRNL-5788]<br>    - Details  : /vmlinuz or /boot/vmlinuz<br>      https://cisofy.com/lynis/controls/KRNL-5788/</pre><p>Esse eu não entendi… eu tenho o arquivo /boot/vmlinuz-**** , não sei porque ele quesitonou isso, proximo:</p><pre>  * If not required, consider explicit disabling of core dump in /etc/security/limits.conf file [KRNL-5820]<br>      https://cisofy.com/lynis/controls/KRNL-5820/</pre><p>Aqui eu editei o arquivo /etc/sysctl.conf e adicionei fs.suid_dumpable = 0 no final do arquivo. Depois fiz um reload do sysctl com o comando sudo sysctl -p .</p><pre>  * Check process listing for processes waiting for IO requests [PROC-3614]<br>      https://cisofy.com/lynis/controls/PROC-3614/</pre><p>Realmente eu estou usando muito o disco e vou deixar isso para ver depois que reduzir o uso.</p><pre>  * Install a PAM module for password strength testing like pam_cracklib or pam_passwdqc [AUTH-9262]<br>      https://cisofy.com/lynis/controls/AUTH-9262/</pre><p>Aqui é instalar o cracklib e editar o arquivo /etc/pam.d/common-password</p><pre>sudo apt-get install -y libpam-cracklib<br>sudo nano /etc/pam.d/common-password</pre><p>Ache a primeira linha e altere pela segunda:</p><pre>password        requisite                       pam_cracklib.so retry=3 minlen=8 difok=3<br>password        requisite                       pam_cracklib.so retry=3 minlen=16 difok=3 ucredit=-1 lcredit=-2 dcredit=-2 ocredit=-2</pre><p>Proximo:</p><pre>  * When possible set expire dates for all password protected accounts [AUTH-9282]<br>      https://cisofy.com/lynis/controls/AUTH-9282/</pre><p>Eu no nomento não vou configurar nada para expirar, se começar com isso logo vou estar fazendo rotação de chave e tudo mais, avançado de mais para mim.</p><pre>  * Configure minimum password age in /etc/login.defs [AUTH-9286]<br>      https://cisofy.com/lynis/controls/AUTH-9286/</pre><p>Novamente tem a ver com tempo do password, não quero mudar nada disso.</p><pre>  * Configure maximum password age in /etc/login.defs [AUTH-9286]<br>      https://cisofy.com/lynis/controls/AUTH-9286/</pre><p>Mesmo do de cima…</p><pre>  * Default umask in /etc/login.defs could be more strict like 027 [AUTH-9328]<br>      https://cisofy.com/lynis/controls/AUTH-9328/</pre><p>Esse cara é mais problema quando você tem vários usuários, no meu caso, sou apenas eu e tudo bem que a permissão de acesso ao que eu criar fique no padrão mesmo.</p><pre>  * To decrease the impact of a full /home file system, place /home on a separate partition [FILE-6310]<br>      https://cisofy.com/lynis/controls/FILE-6310/</pre><p>Pelo que entendi esse cara também seria problema se tivesse mais gente usando meu linux. O que não é o meu caso também.</p><pre>  * To decrease the impact of a full /var file system, place /var on a separate partition [FILE-6310]<br>      https://cisofy.com/lynis/controls/FILE-6310/</pre><p>Mesmo caso do de cima, só que com outro diretório.</p><pre>  * Disable drivers like USB storage when not used, to prevent unauthorized storage or data theft [USB-1000]<br>      https://cisofy.com/lynis/controls/USB-1000/</pre><p>Esse é um falso positivo, eu preciso do USB ligado direto. Expliquei no post anterior linkado no inicio do artigo.</p><pre>  * Check DNS configuration for the dns domain name [NAME-4028]<br>      https://cisofy.com/lynis/controls/NAME-4028/</pre><p>Esse eu não entendi… A documentação deles é bem ruim na vdd…</p><pre>  * Split resolving between localhost and the hostname of the system [NAME-4406]<br>      https://cisofy.com/lynis/controls/NAME-4406/</pre><p>Esse eu quero que realmente tenha esse comportamento, não vou alterar.</p><pre>  * Install debsums utility for the verification of packages with known good database. [PKGS-7370]<br>      https://cisofy.com/lynis/controls/PKGS-7370/</pre><p>Instalei o debsums executei debsums | grep FAILED e tive esse resultado, depois vou analisar caso a caso. Mas fica para um post futuro.</p><pre>/usr/bin/rkaiq_3A_server                                                  FAILED<br>debsums: missing file /usr/lib/NetworkManager/conf.d/10-globally-managed-devices.conf (from network-manager package)<br>debsums: missing file /etc/default/orangepi-motd.dpkg-dist (from orangepi-bsp-cli-orangepi5 package)<br>debsums: missing file /etc/default/orangepi-ramlog.dpkg-dist (from orangepi-bsp-cli-orangepi5 package)<br>debsums: missing file /etc/default/orangepi-zram-config.dpkg-dist (from orangepi-bsp-cli-orangepi5 package)<br>debsums: missing file /etc/profile.d/orangepi-ssh-title.sh (from orangepi-bsp-cli-orangepi5 package)<br>/etc/orangepi-release                                                     FAILED<br>/etc/skel/.config/htop/htoprc                                             FAILED<br>/etc/skel/.config/xfce4/xfconf/xfce-perchannel-xml/xfwm4.xml              FAILED</pre><pre>  * Install package apt-show-versions for patch management purposes [PKGS-7394]<br>      https://cisofy.com/lynis/controls/PKGS-7394/</pre><p>Esse eu até instalei o pacote para brincar, mas nem sei se vou lembrar de usa constantemete: sudo apt-get install apt-show-versions . Da uma olhada na doc deles para entender o que ele faz e usa aí que é legal.</p><pre>  * Determine if protocol &#39;dccp&#39; is really needed on this system [NETW-3200]<br>      https://cisofy.com/lynis/controls/NETW-3200/</pre><p>Agora começou a ficar complicado de verdade… Eu comecei a conversar com o ChatGPT para entender o que é o protocolo e como verificar se ele está sendo usado ou não. Cheguei a seguinte conclusão, digite os dois comandos abaixo e verifique se ele está em uso:</p><pre>netstat -an | grep dccp<br>ss -p | grep dccp</pre><p>Como não teve nada de resposta estou assumindo que ele não está em uso e vou executar o comando para adiciona-lo ao blacklist e depois reiniciar o Orange Pi:</p><pre>sudo echo &quot;blacklist dccp&quot; &gt;&gt; /etc/modprobe.d/blacklist.conf</pre><pre>  * Determine if protocol &#39;sctp&#39; is really needed on this system [NETW-3200]<br>      https://cisofy.com/lynis/controls/NETW-3200/</pre><p>Igual ao de cima, muda apenas o nome do protocolo, resolvei desabilitar também</p><pre>  * Determine if protocol &#39;rds&#39; is really needed on this system [NETW-3200]<br>      https://cisofy.com/lynis/controls/NETW-3200/</pre><p>Também desabilitado como os outros.</p><pre>  * Determine if protocol &#39;tipc&#39; is really needed on this system [NETW-3200]<br>      https://cisofy.com/lynis/controls/NETW-3200/</pre><p>Desabilitado.</p><pre>  * Access to CUPS configuration could be more strict. [PRNT-2307]<br>      https://cisofy.com/lynis/controls/PRNT-2307/</pre><p>Eu não tenho impressora, por isso nem pensei muito e já restringi o acesso:</p><pre>sudo chown root:lpadmin /etc/cups/cupsd.conf<br>sudo chmod 640 /etc/cups/cupsd.conf</pre><pre>  * Check iptables rules to see which rules are currently not used [FIRE-4513]<br>      https://cisofy.com/lynis/controls/FIRE-4513/</pre><p>Esse eu não tenho capacidade de ver… Vou precisar estudar mais para verificar o que realmente está em uso ou não.</p><pre><br>  * Consider hardening SSH configuration [SSH-7408]<br>    - Details  : AllowTcpForwarding (set YES to NO)<br>      https://cisofy.com/lynis/controls/SSH-7408/<br><br>  * Consider hardening SSH configuration [SSH-7408]<br>    - Details  : ClientAliveCountMax (set 3 to 2)<br>      https://cisofy.com/lynis/controls/SSH-7408/<br><br>  * Consider hardening SSH configuration [SSH-7408]<br>    - Details  : LogLevel (set INFO to VERBOSE)<br>      https://cisofy.com/lynis/controls/SSH-7408/<br><br>  * Consider hardening SSH configuration [SSH-7408]<br>    - Details  : MaxAuthTries (set 6 to 3)<br>      https://cisofy.com/lynis/controls/SSH-7408/<br><br>  * Consider hardening SSH configuration [SSH-7408]<br>    - Details  : MaxSessions (set 10 to 2)<br>      https://cisofy.com/lynis/controls/SSH-7408/<br><br>  * Consider hardening SSH configuration [SSH-7408]<br>    - Details  : PermitRootLogin (set YES to (FORCED-COMMANDS-ONLY|NO|PROHIBIT-PASSWORD|WITHOUT-PASSWORD))<br>      https://cisofy.com/lynis/controls/SSH-7408/<br><br>  * Consider hardening SSH configuration [SSH-7408]<br>    - Details  : Port (set 22 to )<br>      https://cisofy.com/lynis/controls/SSH-7408/<br><br>  * Consider hardening SSH configuration [SSH-7408]<br>    - Details  : TCPKeepAlive (set YES to NO)<br>      https://cisofy.com/lynis/controls/SSH-7408/<br><br>  * Consider hardening SSH configuration [SSH-7408]<br>    - Details  : X11Forwarding (set YES to NO)<br>      https://cisofy.com/lynis/controls/SSH-7408/<br><br>  * Consider hardening SSH configuration [SSH-7408]<br>    - Details  : AllowAgentForwarding (set YES to NO)<br>      https://cisofy.com/lynis/controls/SSH-7408/</pre><p>Aqui ele fala para forçar a barra na configuração do SSH, eu não vou fazer isso agora, uso muito e coisas como manter a conexão aberta são uteis para mim.</p><pre>  * Enable logging to an external logging host for archiving purposes and additional protection [LOGG-2154]<br>      https://cisofy.com/lynis/controls/LOGG-2154/</pre><p>Não vou mandar meus logs para outro lugar, para meu cenário é um overkill.</p><pre>  * Check what deleted files are still in use and why. [LOGG-2190]<br>      https://cisofy.com/lynis/controls/LOGG-2190/</pre><p>O arquivo mais antigo na minha pasta /tmp tinha 3 dias, sei lá se fiz alguma coisa errada, mas acredito que estou bem nesse ponto.</p><pre>  * Add legal banner to /etc/issue.net, to warn unauthorized users [BANN-7130]<br>      https://cisofy.com/lynis/controls/BANN-7130/</pre><p>Esse eu achei bem legal. Editei o arquivo /etc/issue.net e coloquei esse texto:</p><pre>Go away<br>This is your last warning<br>If you try again you will get cancer.</pre><pre>  * Enable process accounting [ACCT-9622]<br>      https://cisofy.com/lynis/controls/ACCT-9622/</pre><p>Não entendi o que fazer com esse…</p><pre>  * Enable sysstat to collect accounting (disabled) [ACCT-9626]<br>      https://cisofy.com/lynis/controls/ACCT-9626/</pre><p>Vou deixar para instalar as ferramentas sugeridas e estudar uma a uma futuramente.</p><pre>  * Enable auditd to collect audit information [ACCT-9628]<br>      https://cisofy.com/lynis/controls/ACCT-9628/</pre><p>Instalei oauditd e usei o comando aureport aparece um report legal. Fica a nota para estudar melhor o report</p><pre>  * Check output of aa-status [MACF-6208]<br>    - Details  : /sys/kernel/security/apparmor/profiles<br>    - Solution : Run aa-status<br>      https://cisofy.com/lynis/controls/MACF-6208/</pre><p>Primeiro eu verifiquei o statudo do serviço dessa forma com esse resultado:</p><pre>&gt;sudo systemctl status apparmor<br>○ apparmor.service - Load AppArmor profiles<br>     Loaded: loaded (/lib/systemd/system/apparmor.service; enabled; vendor preset: enabled)<br>     Active: inactive (dead)<br>  Condition: start condition failed at Mon 2023-01-16 21:11:08 -03; 3 days ago<br>       Docs: man:apparmor(7)<br>             https://gitlab.com/apparmor/apparmor/wikis/home/</pre><p>Tentei um start e continuou igual, depois reinstalei e nada… Fiz de tudo, nada funcionou… Vou deixar para ver isso depois.</p><pre>  * Install a file integrity tool to monitor changes to critical and sensitive files [FINT-4350]<br>      https://cisofy.com/lynis/controls/FINT-4350/</pre><p>Esse aqui pede para instalar outro sistema de segurança, eu vou ver isso depois também.</p><pre>  * Determine if automation tools are present for system management [TOOL-5002]<br>      https://cisofy.com/lynis/controls/TOOL-5002/</pre><p>Ele ta pedindo para instalar ferramentas de automação, não tenho interesse nisso</p><pre>  * Consider restricting file permissions [FILE-7524]<br>    - Details  : See screen output or log file<br>    - Solution : Use chmod to change file permissions<br>      https://cisofy.com/lynis/controls/FILE-7524/</pre><p>Totalmente vago isso aqui… não entendi o que preciso fazer exatamente.</p><pre>  * One or more sysctl values differ from the scan profile and could be tweaked [KRNL-6000]<br>    - Solution : Change sysctl value or disable test (skip-test=KRNL-6000:&lt;sysctl-key&gt;)<br>      https://cisofy.com/lynis/controls/KRNL-6000/</pre><p>Também não entendi esse. No meu caso eu vou deixar tudo como está.</p><pre>  * Harden compilers like restricting access to root user only [HRDN-7222]<br>      https://cisofy.com/lynis/controls/HRDN-7222/</pre><p>Esse é legal, ele fala para remover os compiladores ou registringir o acesso. Eu não vou remover, mas vou estudar para restrigir o acesso, só não vou fazer no meu Orange Pi agora para evitar que eu estrague alguma coisa, isso é novo pra mim.</p><pre>  * Harden the system by installing at least one malware scanner, to perform periodic file system scans [HRDN-7230]<br>    - Solution : Install a tool like rkhunter, chkrootkit, OSSEC<br>      https://cisofy.com/lynis/controls/HRDN-7230/</pre><p>Por ultimo ele pede para instalar uma ferramenta de malware scanner, o que faz sentido pra mim. Vou fazer.</p><h4>Resultado</h4><p>Aprendi muito lendo sobre cada item e vou deixar esse post como nota para executar o que ficou faltando.</p><p>Sugiro você fazer o mesmo para entender melhor como o sistema funciona.</p><p>Vou tentar executar isso constantemente.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5180c77a8cd4" width="1" height="1" alt=""><hr><p><a href="https://medium.com/juntos-somos-mais/verificando-e-corrigindo-problemas-de-seguran%C3%A7a-no-orange-pi-5-5180c77a8cd4">Verificando e corrigindo problemas de segurança no Orange Pi 5</a> was originally published in <a href="https://medium.com/juntos-somos-mais">Juntos Somos Mais</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Bitcoin Node no Orange Pi 5 com Umbrel]]></title>
            <link>https://medium.com/juntos-somos-mais/bitcoin-node-no-orange-pi-5-com-umbrel-9b48ee127b41?source=rss----7d848878115---4</link>
            <guid isPermaLink="false">https://medium.com/p/9b48ee127b41</guid>
            <category><![CDATA[orange-pi]]></category>
            <category><![CDATA[bitcoin]]></category>
            <category><![CDATA[umbrel]]></category>
            <dc:creator><![CDATA[Ricardo Baltazar]]></dc:creator>
            <pubDate>Wed, 18 Jan 2023 20:46:03 GMT</pubDate>
            <atom:updated>2023-01-18T20:46:03.835Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*e3Jy-cOr_Cslc3sY" /><figcaption>Photo by <a href="https://unsplash.com/@alexkixa?utm_source=medium&amp;utm_medium=referral">Alexandre Debiève</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>Essa é minha primeira experiencia com Orange Pi 5 e eu tive que fazer algumas coisas um pouco diferentes para conseguir colocar tudo para funcionar.</p><p>Os equipamentos:</p><ul><li><a href="https://www.amazon.com.br/s?k=MicroSD+card+A2+64g&amp;rh=n%3A16209062011%2Cp_89%3ASanDisk&amp;dc=&amp;ds=v1%3Afncp0Pq7aOZMhH9VAWXr%2BEFApeO1B4kl3THqqrzsfk0&amp;__mk_pt_BR=%C3%85M%C3%85%C5%BD%C3%95%C3%91&amp;crid=INVP33LSSDC4&amp;qid=1674047327&amp;rnid=18120432011&amp;sprefix=microsd+card+a2+64g%2Caps%2C170&amp;linkCode=ll2&amp;tag=ricardochaves-20&amp;linkId=f07828e56a26db9a27996421dadb2772&amp;ref_=as_li_ss_tl">MicroSd card A2 64g</a></li><li><a href="https://amzn.to/3ISkrfr">Orange Pi 5</a></li></ul><p>A ideia é começar a conversar a partir do momento que você já tem o seu sistema operacional rodando no Oragen Pi 5. Existem alguns guias para isso na internet e por isso não acho que vale a pena perder tempo com isso. Eu usei esse vídeo para aprender e ele é fenomenal.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FcBqV4QWj0lE%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DcBqV4QWj0lE&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FcBqV4QWj0lE%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/deed0be7dc22073d727d461b6a26e396/href">https://medium.com/media/deed0be7dc22073d727d461b6a26e396/href</a></iframe><p>Eu escolhi a imagem Orangepi5_1.1.0_ubuntu_jammy_desktop_xfce_linux5.10.110.7z, então se você escolheu outra imagem, pode ser que algumas coisas aqui não se aplique a você.</p><p>Para ver as opções de imagem entre no site deles, nesse <a href="http://www.orangepi.org/html/serviceAndSupport/index.html">link</a>.</p><p>Eu peguei a versão descktop porque o <a href="https://umbrel.com/">Umbrel</a> precisa de uma interface grafica. Outro requisito é que precisa ser 64 bits.</p><p>O CPU do Orange Pi 5 tem suporte para 64 bits, mas eu não sei proque eles não adicionaram isso na imagem que eu falei acima, por isso precisamos executar o seguinte comando:</p><pre>sudo dpkg --add-architecture amd64 ## adding 64-bits architecture package</pre><p>Agora já podemos instalar o Umbrel.</p><p>Aqui eu tive outro problema, eu tenho apenas um MicroSD Card de 64gb. Eu achei que poderia ficar sem HD rapidamente (quero adicionar mais cosas no PC) e por isso optei por botar um HD externo de 2T que eu tenho na porta USB 3 do Orange Pi.</p><p>Para fazer isso direito, pelo menos é o que eu consegui fazer com meu pobre conhecimento de Linux, se existe solução melhor, por favor, deixe no comentário um direcionamento para eu poder estudar.</p><p>Eu aprendi muita coisa com esse vídeo:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2F2Z6ouBYfZr8%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D2Z6ouBYfZr8&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2F2Z6ouBYfZr8%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/df9577493dfb5c24f17f3e4cf5bb9631/href">https://medium.com/media/df9577493dfb5c24f17f3e4cf5bb9631/href</a></iframe><p>Eu precisei montar o HD externo na pasta mnt porque quero ele como parte do meu sistema todo o tempo.</p><p>Para isso, insira o HD externo na USB, depois use o comando lsblk :</p><pre>&gt; lsblk<br>NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS<br>sda           8:0    0  1.8T  0 disk<br>└─sda1        8:1    0  1.8T  0 part<br>mtdblock0    31:0    0   16M  0 disk<br>mmcblk1     179:0    0 59.5G  0 disk<br>├─mmcblk1p1 179:1    0  256M  0 part /boot<br>└─mmcblk1p2 179:2    0 58.6G  0 part /var/log.hdd<br>                                     /<br>zram0       254:0    0  7.7G  0 disk [SWAP]<br>zram1       254:1    0  200M  0 disk /var/log<br></pre><p>Você deve ver alguma coisa com o nome sda ou parecido… Esse é o nome que o Linux da quando você tem alguma coisa no USB.</p><p>Com esse nome em mãos, vamos fazer o seguinte:</p><pre>cd /mnt<br>mkdir disk1<br>sudo mount /dev/sda1 /mnt/disk1/</pre><p>O /dev/ é padrão e você devi adicionar na frente do sda1 ou o nome similar que você tem aí. O próximo parametro é o /mnt/disk1/ que é onde ele vai montar.</p><p>Quando você roda o mount ele funciona apenas para a sessão atual, para fazer ele montar isso quando existir um boot você precisa alterar o arquivo /etc/fstab e adicionar essa linha no final dele /dev/sda1 mnt/disk1 ext4 default 0 0 , o meu ficou assim:</p><pre>&gt; cat /etc/fstab<br>UUID=bc3a0620-7f52-4f69-9d48-be19c533ab12 / ext4 defaults,noatime,commit=600,errors=remount-ro 0 1<br>UUID=E429-E94B /boot vfat defaults 0 2<br>tmpfs /tmp tmpfs defaults,nosuid 0 0<br>/dev/sda1 /mnt/disk1 ext4 defaults 0 0</pre><p>Isso feito, o próximo passo é instalar e configurar o docker. Eu não tive problemas com a instalação, então você também não deve ter, basta seguir com qualquer uma <a href="https://docs.docker.com/engine/install/ubuntu/">dessas opções</a>.</p><p>Uma vez instalado, eu queria mudar onde o docker vai salvar os dados. O docker sempre grava tudo em um único diretório, o valor default é /var/lib/docker . No meu caso eu quero que ele grave no meu HD externo. Para isso vamos criar uma uma pasta nele e configurar o docker:</p><p>Estou considerando duas coisas no script, uma é que o arquivo daemon.json não existe, ele não é criado na instalação do docker. O segundo ponto é que eu uso nano para editar o arquivo, faça como você acha melhor.</p><pre>cd /mnt/disk1<br>mkdir docker-data<br>cd /etc/docker<br>touch daemon.json<br>nano daemon.json</pre><p>O arquivo deve ficar da seguinte forma:</p><pre>{<br>  &quot;data-root&quot; : &quot;/mnt/disk1/docker-data&quot;<br>}</pre><p>Agora basta reiniciar o docker:</p><pre>service docker restart</pre><p>Se você fizer um ls /mnt/disk1/docker-data verá vários itens criados.</p><p>Vamos instalar o Umbrel agora. Eu também quero instalar ele no meu HD externo. Por padrão ele vai guardar os dados das aplicações na pasta app-data que é criada onde ele foi instalado.</p><p>Para instalar eu usei o comando abaixo com três parametros, um para mudar o diretório e dois para ele não instalar o docker porque a gente já instalou.</p><pre>cd /mnt/disk1<br>mkdir umbrel<br>curl -L https://umbrel.sh | bash -s -- --install-path /mnt/disk1/umbrel/ --no-install-docker --no-install-compose</pre><p>O log final do comando será alguma coisa assim:</p><pre>Creating manager   ... done<br>Creating auth      ... done<br>Creating tor_proxy ... done<br>Creating dashboard ... done<br>Creating nginx     ... done<br><br>Removing status server iptables entry...<br>Exiting iptables setup when not on Umbrel OS<br><br>Starting installed apps...<br><br><br>Umbrel is now accessible at<br>  http://orangepi5.local<br>  http://10.0.0.147<br>Skipping status update when not on Umbrel OS<br><br>Umbrel has been sucessfully installed!</pre><p>Quando você abrir essa URL no browser já terá o Umbrel pronto. Basta instalar as apps que você quiser e aproveitar.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9b48ee127b41" width="1" height="1" alt=""><hr><p><a href="https://medium.com/juntos-somos-mais/bitcoin-node-no-orange-pi-5-com-umbrel-9b48ee127b41">Bitcoin Node no Orange Pi 5 com Umbrel</a> was originally published in <a href="https://medium.com/juntos-somos-mais">Juntos Somos Mais</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Como hospedar seu site gatsby na rede Onion para ser acessível via Tor.]]></title>
            <link>https://medium.com/juntos-somos-mais/como-hospedar-seu-site-gatsby-na-rede-onion-para-ser-acess%C3%ADvel-via-tor-8f8e310a97d6?source=rss----7d848878115---4</link>
            <guid isPermaLink="false">https://medium.com/p/8f8e310a97d6</guid>
            <category><![CDATA[gatsbyjs]]></category>
            <category><![CDATA[tor]]></category>
            <category><![CDATA[onion]]></category>
            <category><![CDATA[gatsby]]></category>
            <dc:creator><![CDATA[Ricardo Baltazar]]></dc:creator>
            <pubDate>Thu, 12 Jan 2023 22:49:29 GMT</pubDate>
            <atom:updated>2023-01-12T22:49:29.262Z</atom:updated>
            <content:encoded><![CDATA[<p>A primeira coisa que você precisa fazer é aprender a hospedar qualquer site na rede Tor. Vamos começar criando um site simples.</p><p>Crie um index.html em uma diretório qualquer:</p><pre>&lt;h1&gt;Hi&lt;/h1&gt;</pre><p>Vamos usar o <a href="https://onionshare.org/">OnionShare</a> para hospedar um site na rede Tor. Eu estou usando um MAC M1 para esse projeto e para instalar o OnionShare basta executar brew install --cask onionshare</p><p>Abre o programa e vá em Host a Website.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*pqo6CzA6pxwTG-Ke5U3JtA.png" /></figure><p>Adicione o diretório que você criou com o index.html dentro, marque a opção This is a public OnionShare service (disabeles private key) e click em Start sharing você recebera um endereço como esse: <a href="http://6nvrcuddztfiokksb7phvnv6k4xfu64xpcm55joj5znije22rdsob7id.onion">http://6nvrcuddztfiokksb7phvnv6k4xfu64xpcm55joj5znije22rdsob7id.onion</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MMC1H0zL69h2Om1sSBxtjw.png" /></figure><p>Abra o endereço em um browser com acesso a rede Onion e veja o seu HTML.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*pJ96IicE8tFd-5j62Zleqw.png" /></figure><p>Agora no seu projeto Gatsby, se você como eu, não mudou nada no projeto basta executar npm run build . Ele vai criar a pasta public .</p><p>Adicione a pasta public no OnionShare e agora marque a opção Don&#39;t send default Content Security Policy header (allows your website to use third-party resources) e Start novamente.</p><p>Abra o link e pronto, está tudo funcionando… Bem quase tudo, você não tem HTTPS e coisas como o ServiceWorker não vão funcionar. Mas para quem está querendo usar a rede Onion, já será um ótimo resultado.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*blCtCrQb28LE4T4sfl6taQ.png" /></figure><p>Eu esotu esperando o meu Oragen Pi 5 chegar, eu pretendo colocar meu node Bitcoin nele e também hospedar meu blog na rede Onion. Quando eu fizer isso atualizo esse post com o link do meu blog.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8f8e310a97d6" width="1" height="1" alt=""><hr><p><a href="https://medium.com/juntos-somos-mais/como-hospedar-seu-site-gatsby-na-rede-onion-para-ser-acess%C3%ADvel-via-tor-8f8e310a97d6">Como hospedar seu site gatsby na rede Onion para ser acessível via Tor.</a> was originally published in <a href="https://medium.com/juntos-somos-mais">Juntos Somos Mais</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[SCSS como você nunca viu!]]></title>
            <link>https://medium.com/juntos-somos-mais/scss-como-voc%C3%AA-nunca-viu-b0afec417386?source=rss----7d848878115---4</link>
            <guid isPermaLink="false">https://medium.com/p/b0afec417386</guid>
            <category><![CDATA[front-end-development]]></category>
            <category><![CDATA[css]]></category>
            <category><![CDATA[architecture]]></category>
            <category><![CDATA[scss]]></category>
            <category><![CDATA[patterns]]></category>
            <dc:creator><![CDATA[Lucas Souza]]></dc:creator>
            <pubDate>Thu, 12 Jan 2023 14:39:22 GMT</pubDate>
            <atom:updated>2023-01-12T15:40:47.075Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*KSxuJeYgo1AS0C2TjnvtnQ.png" /><figcaption>imagem mostrando a logo do scss</figcaption></figure><p>Olá, mundo! Tudo bem com ocês ? Hoje quero falar um pouco sobre SCSS e algumas novidades.</p><p>Caso queira ver o funcionamento de todas as novas features e/ou modificar algumas coisas, basta acessar meu repo <a href="https://github.com/deverebor/scss-like-you-never-seen">scss-like-you-never-seen</a> e seguir o passo-a-passo para visualizar. <em>Deixa uma starzinha também ❤️</em></p><p><strong>Importante saber antes de tudo!</strong></p><p>Algumas das funcionalidades que vou mostrar ainda não possuem suporte em todos os navegadores, mas é possível testá-las habilitando as respectivas flags em seu navegador.</p><p>EX: chrome://flags</p><p>Basta, agora, procurar a flag desejada, habilitar e reiniciar o navegador.</p><p>Para ter uma leitura mais agradável e ver cada uma das features, aconselho a clonar o meu repo <a href="https://github.com/deverebor/scss-like-you-never-seen">scss-like-you-never-seen</a> e rodar ele localmente. Dentro de cada pasta do repo existe um <strong><em>README.md</em></strong> explicando a feature.</p><p><strong>Eu posso utilizar essas features?</strong></p><p><a href="https://sass-lang.com/documentation/at-rules/use">A documentação do SASS</a> recomenda utilizar o sass ou dart-sass como compilador do projeto, conseguindo, assim, usar todas essas features sem problema. Caso você esteja utilizando ruby-sass ou lib-sass, por exemplo, acredito que não será capaz, visto que está <em>deprecated</em>.</p><p><strong>Sass module mode</strong></p><p>Há um tempo foi lançado um feature no scss que é chamado de scss modules. Basicamente, ela permite que o seu estilo funcione como um modulo da aplicação, assim liberando alguns recursos interessantes.</p><p>Existem duas formas de se utilizar o sass module:</p><p><strong><em>nome.module.scss</em></strong> ou<strong> <em>_nome.scss</em></strong></p><p>Nas duas formas você poderá usufruir de todos os recursos do sass module.</p><p>As novidades que vieram foram justamente os:</p><p><strong>@use</strong>, que permite importar um arquivo de estilo dentro de outro para ser utilizado naquele contexto.</p><p><strong>@foward </strong>que permite importar um arquivo de estilo dentro de outro e que ele seja passado para frente na importação.</p><p><strong>Porque o <em>@import</em> é um problema ?</strong></p><p>Usando o <strong>@import</strong> no scss encontramos um problema, um arquivo que possui, por exemplo, <strong>margin: 5rem; </strong>no final pode ficar com <strong>margin: 10rem;</strong> caso tenha alguma variável com o mesmo nome da qual alimenta aquela propriedade, visto que o <strong>@import</strong> na hora da compilação leva em consideração a ordem.</p><p>EXEMPLO:</p><pre>@import &quot;spacings&quot;; // margin: 10rem;<br>@import &quot;variables&quot;;// margin: 5rem;<br>@import &quot;mixins&quot;;<br>@import &quot;colors&quot;;<br><br><br>.container {<br>  margin: var(--margin); // essa margin vem do variables<br>}s</pre><p>Caso a gente altere a ordem de importação, na hora que ocorrer a compilação será alterado o valor.</p><pre>@import &quot;variables&quot;;// margin: 5rem;<br>@import &quot;spacings&quot;; // margin: 10rem;<br>@import &quot;mixins&quot;;<br>@import &quot;colors&quot;;<br><br><br>.container {<br>  margin: var(--margin); // essa margin vem do spacings<br>}</pre><p>O sass compila de forma procedural, ou seja, o valor da propriedade vai ser alterado de acordo com a última variável encontrada.</p><h3>O problema que o @use e @foward resolve</h3><h4>@foward</h4><p>Ele é similar ao <strong>@import</strong>, você passará para frente o que estiver em um contexto, não haverá sobre escrita.</p><h4>@use</h4><p>É utilizado no contexto e recebe um namespace, então se o meu arquivo se chama util tudo que eu utilizar ali será necessário passar o util como prefixo.</p><p>EX:</p><pre>@use &quot;_util&quot;;<br><br>.container {<br>  margin: util.$margin;<br>}</pre><p>Caso não queria usar o namespace, esteja em processo de migração ou deseja utilizar outro nome porque o atual é grande, basta utilizar as e colocar um alias.</p><pre>@use &quot;_util&quot; as u; // o prefixo agora é `u`<br>@use &quot;_animations&quot; as *; // não será necessário passar o namespace</pre><h3>7–1 pattern scss</h3><p><em>“One file to RULE them all.</em></p><p><em>One file to FIND them.</em></p><p><em>One file to BRING them all.</em></p><p><em>And in the sass way MERGE them”.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ucmyz294nBbdtbLzJLTzAQ.png" /></figure><p><a href="https://sass-guidelin.es/pt/#o-padro-7-1">Esse é o pattern mais utilizado</a> para desfrutar do scss modules, ou seja, o scss modules é um modo de modularizar, cada arquivo é um componente e, cada componente, é um modulo. A sua estrutura é a seguinte:<br> abstracts, vendors, base, layout, components, pages e themes</p><p>Existem vários patterns 4–1, 5–1 etc. Tudo vai depender da sua necessidade.</p><p>Particularmente utilizo bastante esse para meus projetos:</p><pre>styles/<br>|<br>|– base/<br>|   |– _reset.scss       # Reset/normalize<br>|   |– _color.scss       # Paleta de cores da aplicação<br>|   |– _typography.scss  # Typography rules<br>|   |– _index.scss       # File used to import all base<br>|<br>|– layout/<br>|   |– _navigation.scss   # Navigation<br>|   |– _grid.scss         # Grid system<br>|   |– _header.scss       # Header<br>|   |– _footer.scss       # Footer<br>|   |– _sidebar.scss      # Sidebar<br>|   |– _forms.scss        # Forms<br>|<br>|– pages/                # Base views -&gt; HOME, ABOUT, CONTACT etc.<br>|   |– _home.scss        # Home specific styles<br>|   |– _contact.scss     # Contact specific styles<br>|<br>|– themes/<br>|   |– _theme.scss       # Default theme<br>|<br>|– abstract/<br>|   |– _variables.scss   # Sass Variables<br>|   |– _functions.scss   # Sass Functions<br>|   |– _mixins.scss      # Sass Mixins<br>|   |– _index.scss       # File used to import all abstracts<br>|<br>`– _index.scss           # Main Sass file</pre><h3>Container Queries</h3><p>Para utilizar o @container é necessário definir um query para o componente, fazemos isso da seguinte forma:</p><pre>.nosso-wrapper {<br>  container-name: wrapper;<br>  container-type: inline-size;<br>}</pre><p>O que fizemos acima foi definir o tipo do container e o nome dele.</p><p>Note que o @container tem o mesmo funcionamento do @media, entretanto, o que diferencia os dois é que o container vai ter o adicional de poder utilizar operadores lógicos para definir o tamanho do container.</p><p>O que também diferencia o @container do @media é que ele ajusta o tamanho dos elementos baseado na classe pai e não pelo tamanho do viewport.</p><p>EX:</p><pre>@container wrapper (inline &gt; 50px) {<br>  .nossa-classe {<br>    display: grid;<br>    align-items: center;<br>    justify-content: center;<br>  }<br>}</pre><blockquote>Compatibilidade: Chrome(🚧Beta), Firefox(🚧Beta), Chromium(🚧Beta) &amp; Safari(✅Suportado)</blockquote><h3>Extend Rule</h3><p>O extend é um recurso em que você replica o mesmo estilo de uma classe em outra.</p><p>Mas qual a diferença entre o @mixin e o @extend?</p><p>O mixin vai gerar uma cópia daquele estilo em outro componente na hora da compilação.<br> Já o extends, gera uma referência para a classe original.</p><p>EXEMPLO:</p><pre>@mixin placeHolder {<br>    display: -webkit-box;<br>    display: -ms-flexbox;<br>    display: -webkit-flex;<br>    display: flex;<br>}<br>.classe1 {<br>    @include placeholder;<br>}<br>.classe2 {<br>    @include placeholder;<br>}<br><br>/// Mixin output<br>.classe1 {<br>    display: -webkit-box;<br>    display: -ms-flexbox;<br>    display: -webkit-flex;<br>    display: flex;<br>}<br>.classe2 {<br>    display: -webkit-box;<br>    display: -ms-flexbox;<br>    display: -webkit-flex;<br>    display: flex;<br>}</pre><pre>/// Extend input<br>.placeHolder {<br>    display: -webkit-box;<br>    display: -ms-flexbox;<br>    display: -webkit-flex;<br>    display: flex;<br>}<br>.classe1 {<br>    @extend %placeHolder;<br>}<br>.classe2 {<br>    @extend %placeHolder;<br>}<br><br>/// Extend output<br>.classe1,<br>.classe2 {<br>    display: -webkit-box;<br>    display: -ms-flexbox;<br>    display: -webkit-flex;<br>    display: flex;<br>}</pre><p>Apesar do @extend ser mais simples, ele é tão poderoso quanto @mixin. Mas isso pode causar alguns problemas.</p><ul><li>Como a classe .placeHolder é copiada para duas classes, elas são independentes e não se comportam como se fossem uma única classe.</li><li>Dependendo do comportamento da classe, a classe pai pode não ser a classe original.</li></ul><h3>Quando usar ou não o @extend?</h3><ul><li>Mixin: utilize para gerar seu código de modo dinâmico através de variáveis.</li><li>Extend: utilize para elementos comuns mas que haverá pouca repetição.</li></ul><p>Quando for necessário criar algum tipo de automatização, utilize o @mixin, caso contrário utilize o @extend, ou até mesmo os dois juntos.</p><blockquote>Compatibilidade: Chrome(✅Suportado), Firefox(✅Suportado), Chromium(✅Suportado) &amp; Safari(✅Suportado)</blockquote><h3>Has Selector</h3><p>É uma pseudo classe que permite ao usuário selecionar um elemento do DOM e manipular caso o mesmo exista. Ele não pode ser utilizado dentro de classes css, somente selecionando seletores para seletores.</p><pre>section:has(div) {<br>  color: red;<br>}</pre><pre>&lt;section&gt;<br>    &lt;h1&gt;Has Selector&lt;/h1&gt;<br>    &lt;div&gt;<br>      &lt;p&gt;Message&lt;/p&gt;<br>    &lt;/div&gt;<br>  &lt;/section&gt;</pre><blockquote>Compatibilidade: Chrome(🚧Beta), Firefox(🚧Beta), Chromium(🚧Beta) &amp; Safari(✅Suportado)</blockquote><h3>Layer Rule</h3><p>Define uma camada de cascata para ser trabalhada, as regas farão parte daquele contexto, não do escopo global da view.</p><p>EXEMPLO:</p><pre>@layer base, component;<br><br>@layer base {<br>  .button {<br>    background: #eee;<br>    border: 1px solid #ccc;<br>    border-radius: 3px;<br>    color: #333;<br>    padding: 10px;<br>    margin: 10px;<br>  }<br>}<br><br>@layer component {<br>  .button {<br>    &amp;__title {<br>      font-size: 1.5rem;<br>      font-weight: bold;<br>    }<br>    &amp;__icon {<br>      margin-right: 0.5rem;<br>    }<br>  }<br>}</pre><p>A ordem de declaração de camadas é importante, pois a camada mais acima será a camada mais próxima do contexto. Caso você altere a ordem, a prioridade do estilo também mudará.</p><p>A propriedade layer pode ser útil para resolver problemas de prioridade, não sendo mais necessário usar o atributo important.</p><blockquote>Compatibilidade: Chrome(✅Suportado), Firefox(✅Suportado), Chromium(✅Suportado) &amp; Safari(✅Suportado)</blockquote><h3>Conclusão</h3><p>Ufa! Foram muitas coisas que conseguimos ver hoje, mas algumas ainda estão em estado de desenvolvimento e será necessário ativar flags do seu navegador para testar.</p><p>Caso queria ver o código funcional de cada funcionalidade apresentada aqui, basta acessar o meu repo <a href="https://github.com/deverebor/scss-like-you-never-seen">scss-like-you-never-seen</a> deixa uma star!</p><p>Até a próxima!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b0afec417386" width="1" height="1" alt=""><hr><p><a href="https://medium.com/juntos-somos-mais/scss-como-voc%C3%AA-nunca-viu-b0afec417386">SCSS como você nunca viu!</a> was originally published in <a href="https://medium.com/juntos-somos-mais">Juntos Somos Mais</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Como usar gatsbyImageData no corpo do MDX]]></title>
            <link>https://medium.com/juntos-somos-mais/como-usar-gatsbyimagedata-no-corpo-do-mdx-6f5b11252668?source=rss----7d848878115---4</link>
            <guid isPermaLink="false">https://medium.com/p/6f5b11252668</guid>
            <category><![CDATA[gatsbyjs]]></category>
            <category><![CDATA[gatsby]]></category>
            <dc:creator><![CDATA[Ricardo Baltazar]]></dc:creator>
            <pubDate>Sat, 07 Jan 2023 21:03:25 GMT</pubDate>
            <atom:updated>2023-01-07T21:03:25.348Z</atom:updated>
            <content:encoded><![CDATA[<p>Eu tive uma certa dificuldade para conseguir utilizar tudo o que o gatsby-plugin-sharp tem a oferecer quando se trata de imagens dentro do corpo dos meus posts.</p><p>A ideia aqui é mostrar a solução que eu consegui. Não consigo afirmar que é a melhor solução, mas funciona.</p><p>O código desse post pode ser visto<a href="https://github.com/ricardochaves/how-to-use-gatsbyimagedata-in-mdx-body"> nesse repositório</a>.</p><p>Estou começando um projeto do zero para criar um exemplo funcional, como sempre, usando interpretador remoto. Falei sobre isso no meu blog em outro post: <a href="https://ricardobaltazar.com/blog/remote-interpreter-a-new-word-for-develops/">Remote interpreter. A new word for develops</a>.</p><p>Uma vez o projeto inicial pronto, vamos instalar os plugins:</p><pre>docker compose run --rm app npm --prefix ./image-mdxbody install --save gatsby-plugin-image gatsby-plugin-sharp gatsby-source-filesystem gatsby-transformer-sharp<br>docker compose run --rm app npm --prefix ./image-mdxbody install --save gatsby-plugin-mdx gatsby-source-filesystem @mdx-js/react<br>docker compose run --rm app npm --prefix ./image-mdxbody install --save gatsby-remark-images</pre><p>Nosso package.json fica da seguinte forma:</p><pre>  &quot;dependencies&quot;: {<br>    &quot;@mdx-js/react&quot;: &quot;^2.2.1&quot;,<br>    &quot;gatsby&quot;: &quot;^5.3.3&quot;,<br>    &quot;gatsby-plugin-image&quot;: &quot;^3.3.2&quot;,<br>    &quot;gatsby-plugin-mdx&quot;: &quot;^5.3.1&quot;,<br>    &quot;gatsby-plugin-sharp&quot;: &quot;^5.3.2&quot;,<br>    &quot;gatsby-remark-images&quot;: &quot;^7.3.1&quot;,<br>    &quot;gatsby-source-filesystem&quot;: &quot;^5.3.1&quot;,<br>    &quot;gatsby-transformer-sharp&quot;: &quot;^5.3.1&quot;,<br>    &quot;react&quot;: &quot;^18.2.0&quot;,<br>    &quot;react-dom&quot;: &quot;^18.2.0&quot;<br>  }</pre><p>Precisamos configurar os plugins, vai ficar assim:</p><pre>  plugins: [<br>    &quot;gatsby-transformer-sharp&quot;,<br>    &quot;gatsby-plugin-image&quot;,<br>    &quot;gatsby-plugin-sharp&quot;,<br>    {<br>      resolve: `gatsby-plugin-mdx`,<br>      options: {<br>        gatsbyRemarkPlugins: [<br>          {<br>            resolve: `gatsby-remark-images`,<br>            options: {<br>              maxWidth: 1200,<br>            },<br>          },<br>        ],<br>      },<br>    },<br>  ],</pre><p>O post não tem como objetivo configuar o MDX, então vou pular a parte de renderizar o MDX na tela.</p><p>Uma vez renderizando o MDX você pode usar direto o &lt;img&gt; no body, mas com isso você não tem o benefício do processamento de imagens.</p><p>Para conseguir utilizar o maximo possível que o Gatsby pode dar vamos precisar criar o seguinte componente:</p><pre>import React from &#39;react&#39;;<br>import { GatsbyImage } from &quot;gatsby-plugin-image&quot;;<br><br>const MDXImageBody = (props) =&gt; {<br>    console.log(props);<br>    const image = props.img.mdx.frontmatter.embeddedImagesLocal[props.index].childImageSharp.gatsbyImageData;<br>    return &lt;GatsbyImage image={image} alt={props.alt}/&gt;<br><br>}<br>export default MDXImageBody;</pre><p>No body do MDX vamos usar assim:</p><pre>---<br>title: Render image in Body<br>slug: render-image-in-body<br>embeddedImagesLocal:<br>  - typeface.jpg<br>---<br><br>import MDXImageBody from &quot;../src/components/MDXImageBody&quot;;<br><br># {props.pageContext.frontmatter.title}<br>My processed image: {props.pageContext.frontmatter.embeddedImagesLocal}<br><br>&lt;MDXImageBody img={props.data} index={0} alt={&quot;A new project windows of WebStorm&quot;}/&gt;</pre><p>A imagem typeface.jpg está no mesmo diretório que o mdx.</p><p>Quando você abrir o seu post, a imagem mostrada é uma webp :</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/770/1*gj1HWIWbGkmMVqHDPm57Sw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Qmq-wrWJY661cwyodf8oiQ.png" /></figure><p>Espero conseguir ajudar mais alguém que tenha a mesma dificuldade… Essa é a vida do BackEnd se aventurando em um FrontEnd</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6f5b11252668" width="1" height="1" alt=""><hr><p><a href="https://medium.com/juntos-somos-mais/como-usar-gatsbyimagedata-no-corpo-do-mdx-6f5b11252668">Como usar gatsbyImageData no corpo do MDX</a> was originally published in <a href="https://medium.com/juntos-somos-mais">Juntos Somos Mais</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Interpretador Remoto — Um novo mundo para o desenvolvedor]]></title>
            <link>https://medium.com/juntos-somos-mais/interpretador-remoto-um-novo-mundo-para-o-desenvolvedor-e18b34294026?source=rss----7d848878115---4</link>
            <guid isPermaLink="false">https://medium.com/p/e18b34294026</guid>
            <category><![CDATA[monitoring]]></category>
            <category><![CDATA[databricks]]></category>
            <category><![CDATA[grafana]]></category>
            <category><![CDATA[grafana-plugin]]></category>
            <dc:creator><![CDATA[Ricardo Baltazar]]></dc:creator>
            <pubDate>Mon, 02 Jan 2023 15:23:03 GMT</pubDate>
            <atom:updated>2023-01-02T15:23:03.006Z</atom:updated>
            <content:encoded><![CDATA[<h3>Interpretador Remoto — Um novo mundo para o desenvolvedor</h3><p>Um desenvolvedor, antes de tudo é um profissional. Eu gosto de definir o profissional como alguém que consegue vender uma habilidade para outra pessoa.</p><p>Quando você começa a trabalhar, um dos primeiros pensamentos que vem na sua cabeça é: &quot;Como posso ganhar mais?&quot;. A resposta é simples, melhores as suas habilidades.</p><p>Somos uma categoria privilegiada em muitos sentidos, e ferramentas é o que não falta para um desenvolvedor hoje em dia.</p><p>Nesse artigo vamos aprender como se configura um interpretador remoto no WebStorm. Uma IDEs da JetBrains.</p><h3>Interpretador Remoto</h3><p>Uma IDE não existe sozinha no seu sistema, o Visual Studio ou Rider precisa do C# na maquina, o Pycharm do Python, WebStorm do npm e assim vai, muitos já instalam junto o que precisam juntos, olha essa imagem onde o WebStorm já diz que vai fazer o download o npm quando eu peço para criar um novo projeto:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MfI-3mViQiWDUuYnuwd0nQ.png" /></figure><p>O ponto aqui é, quando você vai trabalhar para uma empresa e precisa alterar muitos projetos ao mesmo tempo você começa a ter várias versões de python, npm, c# e coisas como <a href="https://github.com/pyenv/pyenv">pyenv</a> e <a href="https://github.com/nvm-sh/nvm">nvm</a> começam a aparecer para ajudar. Também começamso a criar ambiente virtuais para instalar versões dos pacotes que preisamos somente para aquele projeto.</p><p>E bem, tudo isso funciona… O problema é que em determinado momento você vai precisar de tantas versões que muitas vezes podem nem ser suportadas mais pelo seu SO ou até mesmo encher de tanta coisa a sua máquina que torna ela inutilizável. Quem nunca instalou um pacote sem ---dev ou deu um pip install no lugar errado colocando coisas em lugares onde não deveriam, duvido que você vai lá e remove isso.</p><p>O interpretador remoto nada mais é que você ter o ambiente para aquele projeto específico rodar em outro computador, deixando sua máquina local sem absolutamente nenhuma instalação além do necessário para rodar sua IDE.</p><p>A maioria das IDEs já dão suporte para isso, o VSCode também tem esse opção. O que vai mudar é a maneira de fazer.</p><p>Como computador remoto vamos utilizar o docker, a ideia aqui é ter alguma coisa como esse. docker-compose.ymlna raiz do seu projeto:</p><pre>version: &quot;3.7&quot;<br>services:<br>  db:<br>    image: postgres:10.1-alpine<br>  web:<br>    build: .<br>    depends_on:<br>      - db<br>    command: [&quot;./start.sh&quot;]</pre><p>Uma uma vez que você fizer o clone do seu projeto e apontar o interpretador remoto para o container web ele será capaz de rodar testes de integração apontando para um banco de dados real que é o container db , consegue ver a mágica? Você consegue ter um ambiente com banco de dados rodando tudo localmente sem instalar nada na sua máquina.</p><p>Agora vamos a prática. Lembrando que estou escrevendo isso em 12/2022, e futuramente os prints podem ficar desatualizados, por isso é importante você entender o conceito e não apenas sair fazendo o que está escrito aqui.</p><h3>Configurando o WebStorm</h3><p>Se você quiser um exemplo funcional, basta olhar <a href="https://github.com/ricardochaves/ricardobaltazar.com">o repositório</a> do meu blog, ele é feito com Gatsby e para construi-lo eu nem mesmo instalei o npm no meu MAC.</p><p>Vamos usar como exemplo a criação de um projeto usando Gatsby.</p><p>A primeira coisa que você precisa são dois arquivos no diretório que você vai criar o seu projeto:</p><p>Dockerfile:</p><pre>FROM node:19-alpine3.16<br><br>RUN npm install -g gatsby-cli@5.2.0<br><br>RUN apk update<br>RUN apk add --update --repository https://dl-3.alpinelinux.org/alpine/edge/testing vips-tools vips-dev fftw-dev gcc g++ make libc6-compat<br>RUN apk add git<br>RUN apk add --update --no-cache python3<br>RUN rm -rf /var/cache/apk/*<br><br>WORKDIR /app<br><br>COPY . .</pre><p>docker-compose.yml:</p><pre>version: &quot;3.8&quot;<br>services:<br>  app:<br>    build: .<br>    volumes:<br>      - .:/app<br>    ports:<br>      - &quot;8000:8000&quot;<br>    command:<br>      [<br>        &quot;npm&quot;, &quot;run&quot;, &quot;develop&quot;<br>      ]</pre><p>Agora, basta executar . Ele vai fazer o build da imagem e pedir as informações para criar o seu projeto. O resultado final é alguma coisa assim:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/528/1*8L5sijT__ihrl2TirlhULA.png" /></figure><p>Somente com Docker você conseguiu criar um projeto sem instalar absolutamente nada na sua máquina.</p><p>Agora você abre o projeto com o WebStorm, vá em settings e procure pela configuração Node.js, a opção Node interpreter estará com um alerta:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6nHB5oeG0TcdFJZIefkowQ.png" /></figure><p>Isso, logicamente é porque você não tem o node no seu computador. Vamos criar um interpretar remoto agora.</p><p>Abra a combo do interpretador, mande adicionar um novo e escolha remoto. Na janela que for aberta, escolha Docker Compose e na combo Service escolha app que é o nome do serviço que usamos no docker.compose.yml :</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mR4jtqh1FUuIn1-jRrt0xA.png" /></figure><p>Seleciona Ok e Ok de novo.</p><p>Agora vamos rodar o projeto, click em Current File:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/550/1*x6_hr26YWTVLW01bc4E-Og.png" /></figure><p>Edit Configuration, add new e escolha npm:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*uyp1o8TbqdEuVIy6VbODPA.png" /></figure><p>Configure o necessário para rodar um projeto Gatsby como se fosse localmente:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*z-hyo8jJ-KW43meoY9J3kg.png" /></figure><p>Selecione OK e aperte Play:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/666/1*GZyINnnkH0xfxOaMUWx_lQ.png" /></figure><p>E agora você tem o projeto rodando:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mKzowwIRXV_FCidQ_fmQqA.png" /></figure><p>Tente abrir http://localhost:8000/ e você vai tomar um erro: localhost didn&#39;t send any data . E agora sim, essa é a pegadinha do interpretador remoto no caso do npm, você precisa explicitar que ele está respondendo no host 0.0.0.0 , basta configurar dessa forma o package.json :</p><pre>  &quot;scripts&quot;: {<br>    &quot;develop&quot;: &quot;gatsby develop -H 0.0.0.0&quot;,<br>    &quot;start&quot;: &quot;gatsby develop&quot;,<br>    &quot;build&quot;: &quot;gatsby build&quot;,<br>    &quot;serve&quot;: &quot;gatsby serve&quot;,<br>    &quot;clean&quot;: &quot;gatsby clean&quot;<br>  },</pre><p>Agora aperte play novamente e acesse o mesmo endereço:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FDJ_yTYSsYM3ERiST2_QkQ.png" /></figure><p>Pronto, você tem seu projeto rodando localmente. Você pode fazer debug, rodar testes, tudo dentro do container.</p><p>Uma vez isso no git, basta outro desenvolvedor fazer o git clone , configurar o interpretador remoto e trabalhar, sem precisar instalar absolutamente nada localmente.</p><p><a href="https://github.com/ricardochaves/remote-interpreter-webstorm">Link para o repositório desse post.</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e18b34294026" width="1" height="1" alt=""><hr><p><a href="https://medium.com/juntos-somos-mais/interpretador-remoto-um-novo-mundo-para-o-desenvolvedor-e18b34294026">Interpretador Remoto — Um novo mundo para o desenvolvedor</a> was originally published in <a href="https://medium.com/juntos-somos-mais">Juntos Somos Mais</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>