Estrutura de Dados com JavaScript: Deque (Fila duplamente encadeada)

A fila duplamente encadeada é basicamente como uma fila, exceto que você pode adicionar ou remover de qualquer lado. Agora que você está um pouco mais acostumado a como isso funciona, eu gostaria de tornar as coisas um pouco mais difíceis.

function Deque() {
    let contador = 0;
    let head = null;
    let tail = null;

    // Permite visualizar o valor armazenado na cabeça
    this.getHead = function() {
        if (head) {
            return head.dado;
        }

        return null;
    }

    // Permite visualizar o valor armazenado no final
    this.getTaill = function() {
        if (tail) {
            return tail.dado;
        }
        return null;
    }

    // Retorna o número de itens na fila
    this.Getcontador = function() {
        return contador;
    }

    // Permite definir a estrutura do nó fora de cada método.
    // Dessa forma, será necessário fazer apenas uma vez
    let Node = function(dado) {
        this.dado = dado;
        this.proximo = null;
    }

}

 

A fila duplamente encadeada terá muito mais métodos que o outro, com um total de 10, os que você já viu e:

DisplayHeadToTail(), DisplayTailToHead() AddHead(data), AddTail(data),RemoveHead() e RemoveTail().

DisplayHeadToTail():

Descrição:

Retorna um array com os dados ou, se vazio, retorna null.

this.DisplayHeadToTail = function() {
    if (head != null) {
        let arr = new Array();
        let atual = head;

        // enquanto houver um atual
        while (atual) {

            // ATENÇÃO: Para quem é novo no javascript, dê uma olhada. Você consegue adivinhar o que esse método faz?
            arr.push(atual.dado);
            atual = atual.proximo;
        }

        return arr;
    } else {
        return null;
    }
}

DisplayTailToHead():

Descrição:

Retorna os dados da fila duplamente encadeada do início ao fim (oposto ao anterior).

this.DisplayTailToHead = function() {
    if (head != null) {

        // Chama DisplayHeadToTail() e inverte ela.
        let arr = this.DisplayHeadToTail();

        // Este é um dos grandes métodos do JavaScript.
        return arr.reverse();
    } else {
        return null;
    }
}

AddHead():

Descrição:

Adiciona ao início (head) da fila duplamente encadeada.

this.AddHead = function(dado) {

    // Como você pode ver, agora nós precisamos declarar um novo nó
    let node = new Node(dado);

    node.proximo = head;
    head = node;

    // Se a lista está vazia:
    if (!tail) {
        tail = head;
    }

    contador++;
}

AddTail():

Descrição:

Adiciona ao final (tail) da fila duplamente encadeada.

this.AddTail = function(dado) {
    let node = new Node(dado);

    // Se a lista está vazia
    if (!head) {
        head = node;
    } else {
        tail.proximo = node;
    }

    tail = node;
    contador++;
}

RemoveHead():

Descrição:

Remove o início(head) da fila duplamente encadeada.

this.RemoveHead = function() {
    if (head) {
        // Se é o item final
        if (contador === 1) {
            head = null;
            tail = null;
        } else {
            head = head.proximo;
        }

        contador--;
    }
}

RemoveTail():

Descrição:

Remove o elemento final (tail) da fila duplamente encadeada:

this.RemoveTail = function() {
    if (head) {
        // Se não é o último item
        if (contador === 1) {
            head = null;
            tail = null;
        } else {
            let atual = head;

            // precisamos ir tão longe quanto os dois antes da última
            while (atual.proximo.proximo) {
                atual = atual.proximo;
            }

            tail = atual;
            tail.proximo = null;
        }

        contador--;
    }
}
  • DisplayHeadToTail():
  • DisplayTailToHead():
  • AddHead(dado):
  • AddTail(dado):
  • RemoveHead():
  • RemoveHead():

Gostou deste artigo? Comente abaixo!

Richard Feldman e o futuro da web.

Richard Feldman, na ReactiveConf em Praga, fez algumas previsões sobre o futuro da Web até 2025. Ele afirma que aposta em prever as evoluções de tecnologias atuais, como TypeScript e WebAssembly.

Apesar de o TypeScript estar evoluindo gradativamente, ainda há muitas reclamações em relação à sua verbosidade, que afeta a legibilidade do código-fonte. Mas Feldman afirma que o TypeScript será a escolha mais comum entre os desenvolvedores de projetos comerciais.

Com relação ao WebAssembly, Feldman sustenta que o futuro não seja guiado pelo WebAssembly por conta de seu desempenho aprimorado. Ele acredita que o WebAssembly permitirá a concorrência com as lojas e instaladores de apps.

Com relação ao gerenciamento de pacotes, Feldman afirma que o npm continuará relevante, mas que até o final de 2025, ocorrerá algum incidente de segurança, infectando pelo menos um pacote malicioso e afetando muitos desenvolvedores.

Feldman acredita que as linguagens de compilação para o JavaScript estarão crescendo, mas nenhuma de modo tão rápido quanto o TypeScript.

Fonte: https://www.infoq.com/news/2019/11/reactiveconf-2019-web-prediction/

Gostou desta notícia? Comente abaixo!

Stealthy Tool detecta Malware em JavaScript

Uma nova ferramenta de código aberto chamada VisibleV8 permite que os usuários rastreiem e registrem o comportamento dos programas JavaScript sem alertar os sites que os executam.

A ferramenta é executada no navegador Chrome e foi projetada para detectar programas maliciosos capazes de escapar dos sistemas de detecção de Malware existentes.

“Quando você acessa a maioria dos sites, seu navegador começa a executar os programas JavaScript do site imediatamente – e você tem pouca ou nenhuma ideia do que esse JavaScript está fazendo”, diz o co-autor Alexandros Kapravelos, professor assistente de ciência da computação na Universidade Estadual da Carolina do Norte.

“Os sistemas de detecção de Malware avançados de última geração dependem de fazer alterações no código JavaScript para ver como o código está sendo executado. Mas essa abordagem é facilmente detectada, permitindo que programas de Malware alterem seu comportamento, a fim de evitar serem identificados como maliciosos ”, diz ele.

“O VisibleV8 é executado no próprio navegador, registrando como o JavaScript é executado; não interage com o código e, como resultado, é muito mais difícil de detectar. “

O VisibleV8 salva todos os dados sobre como um site está usando JavaScript, criando um “perfil de comportamento” para o site. Os pesquisadores podem usar esse perfil e todos os dados de suporte para identificar sites mal-intencionados e as várias maneiras pelas quais o JavaScript pode comprometer navegadores da web e informações do usuário. Como o VisibleV8 consiste em apenas 600 linhas de código, dentre os milhões de linhas de código no Chrome, a ferramenta de software é relativamente fácil de manter atualizada. Essa é uma consideração importante, pois o Google atualiza o código do Chrome aproximadamente a cada seis semanas. O VisibleV8 também pode direcionar os comportamentos maliciosos mais prováveis ​​sem prejudicar o desempenho do navegador.

TypeScript: Adicionando description em um Enum

Dando continuidade ao meu artigo anterior: TypeScript: Enums, hoje eu irei demonstrar como criar uma descrição para cada um dos elementos de um enum, e como recuperar essa descrição a partir de suas chaves. Para isso, eu irei utilizar o enum criado no artigo anterior de dias da Semana.

Caso você não tenha lido o artigo anterior, segue o enum mencionando abaixo:

export enum DiaDaSemana {
    Segunda = 1,
    Terca = 2,
    Quarta = 3,
    Quinta = 4,
    Sexta = 5,
    Sabado = 6,
    Domingo = 7,
}

Conforme demonstrei no artigo anterior, nós podemos pegar os valores de um enum pela sua chave ou pelo seu valor.

Agora pensando em um cenário mais próximo do nosso dia dia e focando no enum acima, não seria mais interessante retornar : “Segunda-feira” ou “Terça-feira” … etc ?

Em outras linguagens como C# nós podemos utilizar as descriptions dos enums, mas e no TS como fazer isso?

Existem algumas formas, uma delas é com a utilização de um map. A seguir você tem um exemplo de criação de um map para retornar os dias da semana conforme mencionado acima.

export enum DiaDaSemana {
    Segunda = 1,
    Terca = 2,
    Quarta = 3,
    Quinta = 4,
    Sexta = 5,
    Sabado = 6,
    Domingo = 7,
}

export const DiaDaSemanaLabel = new Map<string, string>([
    ['Segunda', 'Segunda-feira'],
    ['Terca', 'Terça-feira'],
    ['Quarta', 'Quarta-feira'],
    ['Quinta', 'Quinta-feira'],
    ['Sexta', 'Sexta'],
    ['Sabado', 'Sábado'],
    ['Domingo', 'Domingo']
]);

Caso você tenha interesse em saber mais sobre o map, eu recomendo a leitura do seguinte artigo: [Dica rápida]TypeScript: map().

Agora para que possamos retornar a descrição do dia da semana, basta executar o trecho de código abaixo:

console.log(DiaDaSemanaLabel.get(DiaDaSemana[1]))

Resultado:

Bem simples né?

Dessa forma nós conseguimos mapear para que os nossos enums retorne um valor mais amigável para o nosso front.

Espero que tenham gostado e até um próximo artigo pessoal 😉

Fonte: https://medium.com/xp-inc/typescript-adicionando-description-em-um-enum

Gostou deste artigo? Comente abaixo as suas dúvidas!

Angular decode payload JWT

Veja nesse artigo como decodificar o seu token JWT e ler o seu payload.

Dando continuidade aos meus artigos sobre Angular e JWT, hoje eu irei demonstrar como decodificar os dados de um token no lado do seu front.

Caso tenha interesse em ler os meus artigos anteriores sobre esse assunto, segue o link de cada um deles abaixo:

O objetivo desse artigo não sera demonstrar como configurar o JWT em um projeto angular, ele será rápido e objetivo demonstrado através de alguns trechos de código.

O primeiro passo será importar o pacote jwt-decode. Para isso, abra um terminal no seu computador, navegue até o seu projeto e execute o comando abaixo:

npm i jwt-decode --save

Agora execute o comando abaixo para criar serviço no seu projeto para ser responsável por decodificar o token:

ng g s shared/authToken

Em seguida atualize ele com o seguinte trecho de código:

import { Injectable } from '@angular/core';
import * as jwt_decode from 'jwt-decode';


@Injectable({
  providedIn: 'root'
})
export class AuthTokenService {
  public getToken(): string {
    return localStorage.getItem('token');
  }

  public decodePayloadJWT(): any {
    try {
      return jwt_decode(this.getToken());
    } catch (Error) {
      return null;
    }
  }
}

Analisando o trecho de código anterior, note que nós temos um método chamado getToken(), responsável por pegar o token do seu localStorage e um outro método chamado decodePayloadJWT() retornando any, esse método irá decodificar o token e retornar os seus dados de payload.

Obs.: Esse método está retornando any porque o payload pode variar de projeto para projeto, caso você já tenha um contrato definido de retorno o ideal será criar um class ou interface com os dados de retorno no lugar de any.

Bem simples né?

Agora você pode injetar o seu código nos seus componentes e receber os dados do seu token 😉

Espero que tenham gostado e até um próximo artigo pessoal 😉

Fonte: https://medium.com/xp-inc/angular-decode-payload-jwt

Gostou deste artigo? Comente abaixo!

Estrutura de Dados com JavaScript: Lista Encadeada

Listas encadeadas são estruturas de dados feitas de grupos de nós que juntos representam uma sequência. Você notará que a Fila e a Pilha foram criadas usando a ideia básica de uma lista encadeada. No entanto, eles têm regras especiais que os tornam diferentes em funcionalidade.

function ListaEncadeada() {
    let contador = 0;
    let head = null;

    this.GetCount = function(){
        return countador;
    }

} 

Nossa lista encadeada terá 6 métodos adicionais: DisplayAll (), DisplayAt (índice), AddFirst (dados), Add (dados, índice), RemoveFirst (), RemoveAt() .

DisplayAll():

Descrição:

O nome já diz tudo. Retorna um array com os dados ou, se vazio, retorna nulo.

this.DisplayAll = function() {
    // se está vazio
    if (head === null) {
        return null;
    } else {
        //senão, percorre a lista e a coloca em um array.
        let arr = new Array();
        let atual = head;

        for (let i = 0; i < contador; i++) {
            arr[i] = atual.dado;
            atual = atual.próximo;
        }
        return arr;
    }
}

DisplayAt():

Descrição:

Como o método PeekAt (indice) anterior da Fila, é exibido em um índice específico ou, fora dos limites, ele retorna null.

this.DisplayAt = function(indice) {
    // verifique se há valores fora dos limites
    if (indice > -1 && indice < contador) {
        let atual = head;
        let i = 0;

        // não fui eu, é da nczonline (veja fonte).
        // É uma maneira diferente de implementar o FOR que estamos usando
        // e eu queria que todos tivessem a chance de conhecê-lo.
        while (i++ < indice) {
            atual = atual.proximo;
        }

        return atual.dado;
    } else {
        return null;
    }
}

AddFirst():

Descrição:

Adiciona à frente da lista. Se você está se perguntando, frente é onde o índice é 0 e referenciado pelo cabeçalho.

this.AddFirst = function(dado) {
    // Cria um novo nó
    let node = {
        dado: dado,
        proximo: head
    };

    head = node;
    contador++;
}

Add()

Descrição:

Adiciona um item à lista na posição especificada.

this.Add = function(dado, indice) {
    // se o índice escolhido for 0, faça o método AddFirst (dado).
    if (indice === 0) {
        this.AddFirst(dado);
    }
    // verifique se há valores fora dos limites
    else if (indice > -1 && indice < contador) {
        let node = {
            dado: dado,
            proximo: null
        };

        let anterior;
        let atual = head;
        let i = 0;

        // encontre o local certo
        while (i++ < indice) {
            anterior = atual;
            atual = atual.proximo;
        }

        anterior.proximo = node;
        node.proximo = atual;

        contador++;
    } else {
        alert("fora de alcance");
    }
}

RemoveFirst()

Descrição:

Remove o primeiro item.

this.RemoveFirst = function() {
    // se não há itens na lista, retorna nulo
    if (head === null) {
        return null;
    } else {
        let out = head;
        head = head.proximo;

        if (contador > 0) {
            contador--;
        }

        return out.dado;
    }
}

RemoveAt()

Descrição:

Remove um item de um índice específico.

this.RemoveAt = function(indice) {
    if (indice === 0) {
        return this.RemoveFirst(indice);
    }
    // verifique se há valores fora dos limites
    else if (indice > -1 && indice < contador) {

        let atual = head;
        let anterior;
        let i = 0;

        // encontre a localização correta
        while (i++ < indice) {
            anterior = atual;
            atual = atual.proximo;
        }

        // pule o item para remover
        anterior.proximo = atual.proximo;

        // diminuir o comprimento
        contador--;
    } else {
        return null;
    }

    // retorna o valor
    return atual.dado;
}
  • DISPLAYALL():
  • DISPLAYAT(INDICE):
  • ADDFIRST(DADO):
  • ADD(DADO,INDICE):
  • REMOVEFIRST():
  • REMOVEAT(INDICE):

Gostou deste artigo? Comente abaixo!

Estrutura de Dados com JavaScript: Fila

Filas são coletâneas de dados que mantém os objetos em uma ordem determinada ao aplicar o algoritmo FIFO (First In First Out), ou seja, o primeiro a entrar é o primeiro a sair.

function Fila(){
    let contador = 0;

    // Ambos início e final da fila estão nulos (não possuem nenhum dado)
    let inicio = null;
    let final = null;

    // Retorna a quantidade de itens na fila.
    this.GetContador = function(){
        return contador;
    }
}

A nossa fila terá quatro métodos adicionais: enqueue(dado), dequeue(), peekAt() e displayAll().

Enqueue():

Descrição:

Adiciona um item no início da fila. O processo é o mesmo do método push() utilizado na pilha, mas foi alterado por causa do exercício.

this.Enqueue = function (dado){
    // Cria um nó com o dado
    let node = {
        dado: dado,
        // Os próximos pontos serão para valorizar de maneira linear
        // Se o início está vazio (null), não será um problema
        proximo: inicio
    };

    // Se é o primeiro item a ser inserido na lista
    // o início será o final
    if (inicio === null){
        tail = node;
    }

    // define o nó como o novo início
    inicio = node;

    //incrementa o contador
    contador++;
}

Dequeue()

Descrição:

Remove e retorna o último item inserido e armazenado que seria aquele no lado oposto da fila.

this.Dequeue = function(){
    // Se a fila está vazia, retorna null
    if (contador === 0){
        return;
    }else{
        let atual = inicio;
        let anterior = null;
    }

    // Enquanto houver um próximo, ele avançará a fila
    // A ideia é ter um atual no final e um anterior
    while (atual.proximo){
        anterior = atual;
        atual = atual.proximo;
    }

    // se há mais que 1 item, 
    // remove o final e decrementa o contador em 1
    if (contador > 1){
        // remove a referência ao último nó.
        anterior.proximo = null;

        // torna o nó anterior como final da lista
        final = anterior;
    }

    // Reseta a fila
    else{
        inicio = null;
        final = null;
    }

}

DisplayAll()

Descrição:

O nome já diz tudo. Ele funciona da mesma maneira que o método da pilha().

this.DisplayAll =  function(){
    // Se não há nada no início, nada será retornado
    if (inicio === null){
        return null;
    }else{
        let arr = new Array();
        let atual = inicio;

        for ( let i = 0; i < contador; i++){
            arr[i] = atual.dado;
            atual = atual.proximo;
        }
        return arr;
    }
}

PeekAt()

Descrição:

Segue a mesma ideia do peek(), mas qualquer item da fila pode ser buscado e exibido.

this.PeekAt = function (index){
    // Qualquer coisa menor que 0 e igual ou maior que a contagem não está na fila
    if (index > -1 && index < contador){
        let atual = inicio;

        // Navega pela fila para achar o item
        for (let i = 0; i < index; i++){
            atual = atual.proximo;
        }
        return atual.dado;
    }
    // Um index fora dos limites da fila foi escolhido
    else{
        return null;
    }
}
  • enqueue(dado)
  • dequeue()
  • displayAll()
  • peekAt(index)

Gostou deste artigo? Comente abaixo!

Estrutura de Dados com JavaScript: Pilha

Uma pilha é um tipo particular de dado em que as principais operações são a adição de um item (método push()) e remoção (método pop()). A pilha implementa um algoritmo LIFO (Last In First Out), que é uma estrutura onde o último elemento adicionado deve ser o primeiro a ser removido. Inicialmente, ela terá o seguinte código:

 

function pilha(){
    //cria uma variável que servirá 
     //para criação da pilha
    let topo = null; 
    let contador = 0;

    //Retorna o número de itens da fila
    this.GetContador = function(){
        return contador;
    }

    /* Métodos */
}

A nossa pilha terá quatro métodos adicionais: push(), pop(), peek() e displayAll(). Eles serão definidos dentro da função pilha() abaixo de this.GetContador. Vamos começar:

Push():

Descrição:

O método push() adiciona os dados especificados na pilha e o torna o nó do topo. Ele também aumenta a contagem de pilhas em 1.

this.Push = function (dado) {
    // Cria um nó que contém o dado e a referência para o próximo item
    let node = {
        dado: dado, 
        proximo: null
    };

    // Linka o nó atual para o topo da pilha
    // O próximo nó receberá o valor null como referência.
    node.proximo = topo;
        
    // Faz o nó atual ser o topo da pilha
    topo = node;

    // Incrementa o contador
    contador++;
}

Peek()

Descrição:

Exibe o item do topo da pilha. Retorna null se a pilha estiver vazia.

this.Peek = function(){
    // Se a lista estiver vazia, retornará null
    // senão, retornará o dado que estiver no nó topo.
    if (topo === null){
        return null;
    }else{
        return topo.dado;
    }
}

Pop()

Descrição:

Parece muito com o método peek(), com a diferença que o pop() remove o item que está no topo da pilha e diminui o contador em 1.

this.Pop = function(){
    // Se a lista estiver vazia, retornará null
    if(topo === null){
        return null;
    }else{
        // Atribui o topo a uma variável temporária
        let out = topo;

        // Atribui o topo para o próximo elemento da pilha
        topo = topo.proximo;

        // Se existir itens na pilha, decrementa o contador
        if (contador > 0){
            contador--;
        }

        // Retorna o valor que foi removido da pilha
        return out.dado;
    }
}

displayAll()

Descrição:

Exibe todos os dados da pilha como um vetor. Exibi-lo como um vetor foi minha escolha, pois não tinha certeza sobre como iria exibi-lo (por exemplo: console.log; document.write etc.).

this.DisplayAll = function(){
    // Se a lista estiver vazia, retornará null
    if (topo === null){
        return null;
    }else{
        // Instancia um vetor
        let arr = new Array();
        // Cria um nó que irá percorrer a pilha
        let noAtual = topo;

        // Percorre a pilha até alcançar o item mais abaixo
        for (let i = 0; i < contador; i++){
            // Atribui os dados ao vetor
            arr[i] = noAtual.dado;
            // Avança para a próxima posição da pilha
            noAtual = noAtual.proximo;
        }

        // Retorna o vetor
        return arr;
    }
}

Métodos utilizados na estrutura do tipo PILHA:

  • push(dado)
  • peek()
  • pop()
  • displayAll()

Gostou deste artigo? Comente abaixo!

Novidades Angular 8.3

A alguns dias saiu a release 8.3.12 do Angular. Segundo alguns tweets, o time focou em algumas novidades como: um novo comando no CLI, correção de bugs e ajustes no novo render que deve entrar como default na versão 9, o Ivy.

Caso tenha interesse em saber mais sobre esse compilador, eu recomendo a leitura do seguinte artigo: Angular: Conhecendo Ivy.

Bom, mas quais foram os novidades dessa versão?

Novo layout

Caso você já tenha atualizado o seu CLI e criado um novo projeto , deve ter notado o novo layout dessa versão.

Além do novo layout, note que nessa etapa nos temos algumas sugestões de próximos passos.

Deploy

Nessa versão foi adicionado um novo comando no CLI, o ng deploy. Agora com apenas alguns comandos no terminal, e possível publicar o nosso app no Azure, Firebase, Zeit, Netlify, ou GitHub.

Em um próximo artigo eu irei criar um passo a passo de como publicar o nosso utilizando esse novo comando do CLI.

Espero que tenham gostado e até um próximo artigo pessoal 😉

Fonte: https://medium.com/xp-inc/novidades-angular-8-3

Gostou deste artigo? Deixe seu comentário abaixo!

Angular 8.3: publicando projeto com o Angular CLI em 5 passos

Veja nesse artigo como publicar o seu projeto no GitHub pages em 5 passos

Dando continuidade ao meu artigo anterior: novidades do Angular 8.3, hoje eu irei demonstrar como publicar um projeto no GitHub pages, utilizando o novo comando que foi adicionado na versão 8.3 do CLI, o ng deploy.

Para os próximos passos será necessário estar com a versão 8.3.12 do Angular CLI no seu computador. Caso essa não seja a sua versão, abra um terminal e execute o comando abaixo:

npm install -g @angular/cli

Com a versão do CLI atualizada, vamos aos 5 passos de criação e deploy do projeto.

1- Passo: Criação de um novo projeto

Abra um terminal no seu computador e execute o seguinte comando para criação de um novo projeto:

ng new (nome do seu projeto)

2- Adicionando pacote ghpages

Com o projeto criado, volte no seu terminal, navegue até ele e execute o comando abaixo:

ng add angular-cli-ghpages

3- Criação de um novo repositório no GitHub

Com o projeto criado e o pacote importado, vamos criar um novo repositório no GitHub. Para isso, siga os passos abaixo:

Acesse o link: https://github.com/, vá até o canto superior e clique no icone do lado do simbolo de notificações:

Em seguida clique em new repository:

Agora volte no seu terminal e execute os comandos abaixo para versionar ele no GitHub:

git add *
git commit -m "first commit"
git remote add origin https://github.com/{seu usuario}/{seu repositorio}.git
git push -u origin master

4- Alterando a base url do projeto

Como o projeto será publicado em um subdiretório, será necessário alterar a base url dele. Para isso, vá até o arquivo index.html do seu projeto e altere ele conforme abaixo:

<base href="/nome do seu repositório no git/">

5-Deploy do projeto

Com todos os passos anteriores OK, execute o comando abaixo no seu terminal para publicar o projeto:

ng deploy

Esse comando irá publicar o seu projeto no GitHub Pages no seguinte link: https://github.com/<username>/<repositoryname>.git

  • username: o seu usuário do GitHub
  • nome do seu repositório

Para verificar se o seu projeto foi publicado com sucesso, acesse a url mencionada acima no seu navegador. No meu exemplo ficou a seguinte url: https://programadriano.github.io/angulardeploy/

Bom, a ideia desse artigo era de ser algo rápido demonstrando uma das novidades do Angular 8.3.

Espero que tenham gostado e até um próximo artigo pessoal 😉

Fonte: https://medium.com/xp-inc/angular-8-3-publicando-projeto-com-o-angular-cli-em-5-passos

Gostou deste artigo? Comente abaixo!