Escolar Documentos
Profissional Documentos
Cultura Documentos
Motivação
Estrutura de um pacote
DESCRIPTION: Caracterização do pacote
R/: Funções
man/: Documentação
NAMESPACE: Organização
Exportando funções
Importando funções
Construindo o pacote
Work ow
Referências
Pacotes R Code
Motivação
Como já dizia John M. Chambers (http://statweb.stanford.edu/~jmc4/) quando criou a
linguagem S (predecessora do R), o objetivo da linguagem é
Se você já explorou um pouco mais do que o potencial básico do R, certamente já criou sua
própria função (ou várias funções) para fazer alguma tarefa especí ca. A ideia é que se você
tiver que realizar uma tarefa muitas vezes, então deve criar uma função para fazer isso.
Agrupar e manter uma série de funções criadas por você e que são basicamente de uso
próprio ou rotineiro.
Compartilhar funções de novos métodos e/ou implementações que você tenha criado e
queira disponibilizar para outras pessoas usarem.
Não raramente, um pacote de uso pessoal acaba se tornando útil para outras pessoas e o autor
disponibiliza para uso geral. O importante é então saber como transformar suas funções em um
pacote. E mais importante ainda é saber como fazer isso se preocupando apenas com as
funções, ao invés de se preocupar com todo o processo de criação do pacote.
cursos.leg.ufpr.br/prr/capPacR.html 1/21
25/04/2020 Pacotes R
A maneira tradicional de criar pacotes no R é um pouco mais trabalhosa, pois cada vez que você
quiser checar se seu pacote está funcionando, é necessário ir para um terminal e rodar os
comandos por fora do R. Além disso, se você quiser testar seu pacote após a instalação, será
necessário instalar de fato o pacote e carregá-lo com library() . O grande problema é que
durante o desenvolvimento de um pacote, esses passos geralmente são repetidos muitas vezes,
o que torna todo o processo muito demorado.
O pacote devtools facilita todo esse processo, pois você pode construir, checar, documentar
(e conferir a documentação) de dentro da própria sessão do R que você está desenvolvendo o
pacote. Além disso esse pacote também permite que, com uma função, você simule a instalação
do seu pacote na mesma sessão R, evitando ter que instalar e desinstalar para testes todas as
vezes.
Estrutura de um pacote
Basicamente um pacote do R é uma convenção para organizar e padronizar a distribuição de
funções extras do R. Todo pacote é composto obrigatoriamente por apenas dois diretórios e dois
arquivos de meta dados:
Outros componentes que não são obrigatórios, mas podem estar presentes no pacote são:
tests/ : um diretório contendo scripts com testes unitários, rodados durante a criação
do pacote, para testar se existe algum resultado não esperado sendo retornado por
cursos.leg.ufpr.br/prr/capPacR.html 2/21
25/04/2020 Pacotes R
Caso você queira começar um pacote do início, as opções são: 1) criar todos os componentes
(diretórios e arquivos) manualmente e ir alimentando com conteúdo, ou 2) usar a função
create() do pacote devtools para criar um “esqueleto” inicial com os arquivos e diretórios
fundamentais de um pacote. Portanto:
Hide
library(devtools)
create("prrpac", rstudio = FALSE)
Package: prrpac
Title: What the Package Does (one line, title case)
Version: 0.0.0.9000
Authors@R: person("First", "Last", email = "first.last@example.com", role = c
("aut", "cre"))
Description: What the package does (one paragraph).
Depends: R (>= 3.3.0)
License: What license is it under?
Encoding: UTF-8
LazyData: true
Como pode ser observado na saída acima, esse comando cria um diretório chamado
meupacote , contendo dois arquivos: DESCRIPTION e NAMESPACE , e um diretório: R/
.
├── DESCRIPTION
├── NAMESPACE
└── R
1 directory, 2 files
Note que na mensagem de criação acima, o arquivo DESCRIPTION já é preenchido com alguns
campos padrão, sendo necessário apenas alterá-los com as informações do seu pacote.
Abaixo serão especi cados os detalhes para a criação de cada um dos componentes
obrigatórios criados acima.
O arquivo DESCRIPTION é quem caracteriza o seu pacote: que é (são) o(s) autor(es), uma breve
descrição do que ele faz, qual o tipo de licença, quais pacotes são necessários para que o seu
funcione, e mais alguns detalhes.
Package: prrpac
Uma breve descrição (de uma linha) sobre o que o seu pacote faz.
Version: 0.0.0.9000
A versão inicia (ou atual do pacote). O versionamento de qualquer pedaço de software é uma
coisa muito importante e não há um consenso de que exista um padrão para todos os casos. No
entanto, nos pacotes do R, recomenda-se que as versões sejam do tipo x.y-z ou x.y.z onde
x seria a versão “maior”, y a versão “menor”, e z os “patches” (alterações menores no código,
como correção de bugs por exemplo).
O autor, ou os autores e contribuidores do pacote. Este campo pode ser preenchido com a
função person() do R, no formato que está apresentada. Se tiver mais de um autor, eles
podem ser concatenados com a função c() , por exemplo, c(person(...), person(...)) . O
argumento role é importante pois é ele que identi ca o papel de cada autor no
desenvolvimento do pacote. Por padrão, é necessário ter um (e somente um) autor "aut" e um
mantenedor "cre" , que pode ou não ser a mesma pessoa. Outros papéis, como por exemplo o
de um contribuidor ( "ctb" ), e outros detalhes dessa função estão em ?person .
Uma descrição um pouco mais detalhada sobre o que o seu pacote faz. É preciso ter pelo menos
duas frases completas (sim, o R confere isso), mas não muito maior do que um parágrafo.
Qual a versão do R que o seu pacote depende. É sempre prudente colocar uma versão que seja
maior ou igual a versão que você está desevolvendo o pacote.
A licença é fundamental se você pretende compartilhar o seu pacote. Algumas opções comuns
são: CC0 (nenhum tipo de restrição), MIT (prevê atribuição mas é bastante permissiva), e
GPL-3 (a mais utilizada, requer que qualquer trabalho derivado do seu seja distribuido com a
cursos.leg.ufpr.br/prr/capPacR.html 4/21
25/04/2020 Pacotes R
mesma licença). Para mais opções e detalhes sobre licenças de software livre, consulte
choosealicense.com (http://choosealicense.com).
LazyData: true
Essa opção somente é importante se você pretende distribuir algum conjunto de dados com o
seu pacote (arquivos .rda no diretório data/ ). Com a opção acima, os dados só serão
carregados se realmente forem chamados (com a função data() ), e não carregados na
inicialização do pacote. Isso garante mais agilidade para carregar o pacote e economiza
memória caso os dados não sejam utilizados (especialmente se as bases de dadpos forem
gandes).
Outros campos do arquivo DESCRIPTION que serão necessários caso seu pacote possua
dependências:
Imports: uma lista, separada por vígulas, dos pacotes dos quais o seu pacote precisa
para funcionar. Estes são os pacotes que o seu depende, portanto eles também serão
instalados (se já não estiverem), quando o seu for instalado. Colocar um pacote nesse
campo garante que o pacote estará instalado, mas não que ele será carregado toda que
vez que o seu pacote for carregado. Para utilizar funções de outros pacotes
corretamente é necessário especi ções da forma pacote::funcao() ou então utilizar o
arquivo NAMESPACE conforme veremos abaixo.
Suggests: os pacotes listados aqui não serão instalados junto com o seu. Eles podem ser
usados, mas não são necessários. Por exemplo, você pode usar um pacote apenas para
usar alguma base de dados ou apenas uma função. Use esse campo apenas se o seu
pacote puder funcionar mesmo sem os pacotes especi cados.
Para podermos utilizar esse arquivo para de fato gerarmos um pacote de exemplo ao nal deste
tutorial, vamos modi car alguns campos e utilizar o seguinte arquivo DESCRIPTION :
Package: prrpac
Title: Pacote Para Pesquisa Reproduzivel
Version: 0.0.1
Authors@R: c(person("Fernando", "Mayer", email = "fernando.mayer@ufpr.br", ro
le = c("aut", "cre")),
person("Walmes", "Zeviani", email = "walmes@ufpr.br", role = "ct
b"))
Description: Pacote de exemplo para pesquisa reproduzivel com R. Para
mais informacoes consulte o material.
Depends: R (>= 3.3.0)
License: GPL-3
Encoding: UTF-8
LazyData: true
R/ : Funções
O diretório R/ irá conter apenas as funções (arquivos .R ) do seu pacote. As funções podem
estar em vários arquivos .R separados (um para cada função) ou em um (ou alguns) arquivo
único. A escolha é mais uma questão de preferência pessoal, mas como veremos mais adiante,
utilizar arquivos separados para as funções torna o processo de documentação um pouco mais
ágil, além de facilitar a manutenção do pacote com o tempo.
cursos.leg.ufpr.br/prr/capPacR.html 5/21
25/04/2020 Pacotes R
Para exempli car, vamos criar uma função simples para fazer a soma de dois números, e colocá-
la dentro do diretório R/ com o nome soma.R
Hide
Com a função pronta, possivelmente iremos testá-la, e para isso vamos utilizar a função
load_all() do pacote devtools . Portanto, de dentro de uma seção do R:
Hide
load_all()
Loading prrpac
irá carregar todas as funções que estiverem dentro do diretório R/ , tornado-as disponíveis
para uso. Note que seria o mesmo resultado se utilizassemos a função source("soma.R") para
carregar a função, no entanto, se tivermos várias funções, e/ou estivermos testando alterações
em muitas delas, a função load_all() é bem mais conveniente. Basta fazer as alterações nas
funções .R , carregá-las com load_all() e testar novamente. Esse processo geralmente se
repete muitas vezes durante o desenvolvimento de um pacote.
man/ : Documentação
Você deve ter notado que o diretório man/ não é criado da mesma forma que os demais
quando utilizamos a função create() acima. Isso porque esse diretório depende das funções
que serão criadas dentro do diretório R/ . No entanto, ele é também é obrigatório para
podermos criar um pacote mínimo.
Existem duas formas de documentar uma função com os arquivos .Rd : uma é da maneira
tradicional, escrevendo manualmente a documentação utilizando a linguagem especí ca e
colocando os campos necessários. Os detalhes de como fazer isso manualmente estão em
Writing R documentation les (http://cran.r-project.org/doc/manuals/r-release/R-
exts.html#Writing-R-documentation- les). Outra forma de escrever a documentação de uma
função é utilizando o pacote roxygen2 , que utiliza algumas tags simples e permite que você
escreva a documentação dentro do próprio arquivo .R . Dessa forma ca muito mais simples
alterar ou atualizar a documentação de uma função, pois tudo se concentra dentro de um único
arquivo.
Neste texto vamos utilizar o pacote roxygen2 para gerar a documentação das funções. O
primeiro passo é escrever a documentação dentro do arquivo .R . A documentação usando o
roxygen2 segue o seguinte formato:
cursos.leg.ufpr.br/prr/capPacR.html 6/21
25/04/2020 Pacotes R
Toda documentação começa com um comentário especial, do tipo #' (note o ' depois
do # ).
Os campos de documentação são criados a parir de tags que iniciam com @ , colocados
logo após um comentário especial #' .
Toda a documentação deve car diretamente acima do início da função.
Usando como exemplo a função soma() criada acima dentro do arquivo soma.R , podemos
documentá-la com o roxygen2 da seguinte forma:
Para gerar a documentação agora basta utilizar a função document() do pacote devtools :
Hide
document()
Loading prrpac
cursos.leg.ufpr.br/prr/capPacR.html 7/21
25/04/2020 Pacotes R
Criar o diretório man/ se ele ainda não existir, ou se for a primeira vez que estiver
criando a documentação com a função document() .
Gerar os arquivos .Rd dentro de man/ (se ainda não existirem) correspondentes às
funções no diretório .R .
Se os arquivos .Rd já existirem, a chamada da função document() irá apenas atualizar
os arquivos que foram modi cados.
Escrever no arquivo NAMESPACE as funções a serem exportadas ou importadas. Veremos
mais detalhes abaixo na seção NAMESPACE.
No nosso exemplo, a chamada da função document() criou o diretório man/ e gerou o arquivo
soma.Rd com o seguinte conteúdo
cursos.leg.ufpr.br/prr/capPacR.html 8/21
25/04/2020 Pacotes R
\item{y}{Outro numero}
}
\value{
A soma dos numeros \code{x} e \code{y}.
}
\description{
Uma (incrivel) funcao que pega dois numeros e faz a
soma. Utilize este campo para descrever melhor o proposito de
sua funcao e o que ela e capaz de fazer.
}
\details{
Utilize este campo para escrever detalhes mais tecnicos da
sua funcao (se necessario), ou para detalhar melhor como
utilizar determinados argumentos.
}
\examples{
soma(2, 2)
x <- 3
y <- 4
soma(x = x, y = y)
}
\author{
Fernando Mayer
}
\seealso{
\code{\link[base]{sum}}, \code{\link[base]{+}}
}
Note que é muito mais simples ecrever com o roxygen2 do que ter que editar esse arquivo
todo a mão. Note também o comentário no início desse arquivo:
O roxygen2 deixa claro que você não deve (e não precisa) modi car esse arquivo soma.Rd
para atualizar a documentação. Sempre que alterar alguma coisa faça no próprio arquivo .R , e
a função document() irá atualizar a documentação no arquivo .Rd .
cursos.leg.ufpr.br/prr/capPacR.html 9/21
25/04/2020 Pacotes R
Para conferir se a documentação está de acordo com o que você espera, você pode conferir a
qualquer momento, por exemplo, com ?soma ou help(soma) , após rodar a função
load_all() para carregar a documentação atualizada depois de document() .
Uma outra forma mais automática de conferir se a documentação está escrita de maneira
correta, é utilizando a função check_man() do pacote devtools :
Hide
check_man()
Loading prrpac
Checking documentation
Se nenhuma mensagem de aviso ou erro apareceu acima, então a documentação está de acordo
com o esperado.
NAMESPACE : Organização
cursos.leg.ufpr.br/prr/capPacR.html 10/21
25/04/2020 Pacotes R
O NAMESPACE é um arquivo que ajuda a organizar as funções exportadas e importadas pelo seu
pacote. Ele ajuda um pacote a ser auto contido, no sentido de que ele não vai interferir no
funcionamento de outros pacotes, e que também os outros pacotes não irão interferir no
funcionamento do seu.
Normalmente, a especi cação do NAMESPACE é a parte mais difícil da criação de um pacote, mas
com o uso do devtools como estamos fazendo, normalmente não será necessário se
preocupar com todos os detalhes que envolvem esse arquivo. O mais importante é saber quais
funções serão exportadas do seu pacote, quais serão importadas, e de que maneira podemos
especi car essas funções.
Exportando funções
O conceito de exportar uma ou mais funções de um pacote, é o de tornar estas funções
disponíveis para o usuário. No desenvolvimento de um pacote, normalmente são criadas
algumas funções internas ou auxiliares, que são utilizadas por uma ou mais funções principais.
Se em nenhum momento estas funções precisarem ser utilizadas pelo usuário do pacote, então
elas não precisam (e não devem) ser exportadas, para minimizar a possibilidade de con ito com
outros pacotes.
Por padrão, quando iniciamos um pacote com a função create() do pacote devtools , é
criado um arquivo NAMESPACE que exporta automaticamente todas as funções que forem
criadas, e que não começem com um ponto . . O arquivo NAMESPACE inicial possui essa
especi cação:
No entanto, se você não quiser exportar todas as funções de dentro do diretório R/ , será
necessário especi car quais funções deseja exportar. Para isso, basta usar a tag @export na
documentação da função com o roxygen2 (assim como usamos na documentação da função
soma.R acima). A função document() é a responsável por veri car as funções que possuem
@export e colocá-las adequadamente no arquivo NAMESPACE . Dessa forma, usando o nosso
exemplo, após escrever a função soma.R com @export e rodar document() , o arquivo
NAMESPACE agora será:
export(soma)
Se houverem mais funções exportadas, elas aparecerão nesse arquivo, uma em cada linha. Caso
existam funções que você não queira exportar, basta não colocar a tag @export na
documentação da função. (Na verdade, as funções não exportadas não precisam nem ser
documentadas, mas é sempre uma boa prática escrever a documentação até mesmo para você
no futuro).
Importando funções
cursos.leg.ufpr.br/prr/capPacR.html 11/21
25/04/2020 Pacotes R
Normalmente as funções que estamos criando para um pacote utilizam funções de outros
pacotes. Todas as funções dos pacotes que são distribuídos e automaticamente carregados
quando você inicia uma sessão do R, são disponíveis para serem utilizadas em qualquer outra
função, sem a necessidade de qualquer especi cação adicional. Estes pacotes básicos do R são:
base , utils , datasets , grDevices , graphics , stats , e methods . Esse conjunto de pacotes
já garante uma grande quantidade de funções, no entanto, algumas vezes podem ser
necessárias funções especí cas de outros pacotes.
Existem três formas básicas de importar, ou seja, utilizar funções de outros pacotes dentro do
seu pacote:
Já vimos anteriromemte na seção DESCRIPTION que existe um campo Imports que serve
para especi car quais pacotes o seu depende. Se você utilizou qualquer um dos três métodos
acima para importar uma ou várias funções, então obrigatoriamente o pacote que contém
estas funções deve ser listado no campo Imports do arquivo DESCRIPTION .
Uma distinção importante é que listar os pacotes no campo Imports do arquivo DESCRIPTION ,
garante que o usuário terá instalado os pacotes necessários para que o seu funcione, mas ele
não é o responsável por carregar e tornar as funções desse pacote disponível. Esse papel é feito
por algum dos três métodos citados acima, que por consequência irão atualizar o arquivo
NAMESPACE , que é o verdadeiro responsável por carregar os pacotes e funções necessárias para
o uso do seu pacote.
Por exemplo, vamos criar uma função personalizada para fazer um grá co de pontos utilizando
a função xyplot() do pacote lattice . Vamos supor que esse grá co personalizado usa um x
no lugar do ponto ( pch = 4 ), e de cor preto ( col = 1 ), já que o padrão do lattice é azul
claro. Vamos chamar essa função de meuxy() e colocá-la no arquivo meuxy.R do diretório R/ .
O conteúdo desse arquivo é:
cursos.leg.ufpr.br/prr/capPacR.html 12/21
25/04/2020 Pacotes R
Agora é necessário rodar a função document() para gerar o arquivo man/meuxy.Rd e atualizar
o arquivo NAMESPACE , com a exportação da função meuxy() , e a importação da função
xyplot() do pacote lattice .
Hide
document()
Loading prrpac
Writing NAMESPACE
Writing meuxy.Rd
Note que, na mensagem acima, além de criar o arquivo meuxy.Rd , houve uma atualização do
arquivo NAMESPACE , que agora irá conter:
cursos.leg.ufpr.br/prr/capPacR.html 13/21
25/04/2020 Pacotes R
export(meuxy)
export(soma)
importFrom(lattice,xyplot)
importFrom(lattice,xyplot)
Hide
Mas poderíamos também ter utilizado o operador :: diretamente na função, por exemplo
Hide
E, nesse caso, não precisariamos usar a tag @importFrom . O resultado no NAMESPACE seria o
mesmo. A tag @import também poderia ter sido utilizada, por exemplo,
Hide
No entanto, nesse caso não há vantagem em importar todo o pacote pois estamos utilizando
apenas uma função.
Hide
use_package("lattice")
Next:
cursos.leg.ufpr.br/prr/capPacR.html 14/21
25/04/2020 Pacotes R
Dessa forma, o arquivo DESCRIPTION caria atualizado com o seguinte conteúdo (repare a
última linha):
Package: prrpac
Title: Pacote Para Pesquisa Reproduzivel
Version: 0.0.1
Authors@R: c(person("Fernando", "Mayer", email = "fernando.mayer@ufpr.br", ro
le = c("aut", "cre")),
person("Walmes", "Zeviani", email = "walmes@ufpr.br", role = "ct
b"))
Description: Pacote de exemplo para pesquisa reproduzivel com R. Para
mais informacoes consulte o material.
Depends:
R (>= 3.3.0)
License: GPL-3
Encoding: UTF-8
LazyData: true
RoxygenNote: 5.0.1
Imports: lattice
Construindo o pacote
A última etapa é nalmente construir o pacote, ou seja, gerar um arquivo fonte (ou binário) que
pode ser distribuído para os usuários instalarem.
Antes de construir o pacote, podemos rodar uma série de checagens para conferir se todos os
componentes do pacote estão funcionando como seria o esperado. Essa checagem é feita com
o comando R CMD check depois de construir o pacote. No entanto, como estamos usando o
devtools , podemos simpli car e utilizar a função check() para realizar a mesma checagem
automaticamente, de dentro de uma sessão do R, e deixar para construir o pacote só no nal
quando tudo estiver funcionando.
Hide
check()
Loading prrpac
cursos.leg.ufpr.br/prr/capPacR.html 15/21
25/04/2020 Pacotes R
_R_CHECK_CRAN_INCOMING_USE_ASPELL_: TRUE
_R_CHECK_CRAN_INCOMING_ : FALSE
_R_CHECK_FORCE_SUGGESTS_ : FALSE
cursos.leg.ufpr.br/prr/capPacR.html 16/21
25/04/2020 Pacotes R
cursos.leg.ufpr.br/prr/capPacR.html 17/21
25/04/2020 Pacotes R
Note que esta checagem é bem completa, e se o status nal for OK , então o pacote está
funcionando e pronto para ser instalado. Se nesta checagem aparecer no nal algum NOTE ,
signi ca que o pacote funciona mas algumas coisas precisam ser arrumadas. Se houverem
ERROR s, o processo de checagem é parado e não é possível instalar o seu pacote até que no seja
arrumado.
Hide
build()
cursos.leg.ufpr.br/prr/capPacR.html 18/21
25/04/2020 Pacotes R
teste.R
playground/
Para gerar um arquivo binário ( .zip ) para instalar no Windows, o processo é mais complicado
(como tudo no Windows). Esse arquivo binário só é possível ser gerado de dentro do Windows,
o que, em muitos casos, ão está disponível para uso. Uma opção então é utilizar o win-builder
(http://win-builder.r-project.org/), um servidor Windows disponibilizado pelos mantenedores
do R para que pessoas sem acesso ao Windows possam gerar arquivos binários de pacotes. O
processo consiste em entrar na página e enviar o código-fonte ( .tar.gz ) por upload. Em
alguns minutos você recebe um email com o link para baixar a versão binária do seu pacote
para Windows.
Como estamos usando o devtools , podemos apenas utilizar a função build_win() , que irá
fazer todo esse processo automaticamente. O link com a versão binária do arquivo será
enviado para o email colocado no campo Maintainer no arquivo DESCRIPTION , por isso é
importante que seja um email válido.
Hide
build_win()
Uma vantagem dessa função é que ela também roda uma checagem para ver se o pacote
funcionará adequadamente no Windows.
Work ow
Um work ow típico para a construção de um pacote utilizando devtools e roxygen2 seria:
Hide
cursos.leg.ufpr.br/prr/capPacR.html 19/21
25/04/2020 Pacotes R
##======================================================================
## Criando pacote com devtools e roxygen2
##======================================================================
##----------------------------------------------------------------------
## Pacotes necessarios
library(devtools)
library(roxygen2)
##----------------------------------------------------------------------
## 1) Criando a estrutura (esqueleto) do pacote
create("prrpac", rstudio = FALSE)
# irá criar o diretório 'meupacote' com man/, R/ e DESCRIPTION
# Edite o arquivo DESCRIPTION com as informações do seu pacote
##----------------------------------------------------------------------
## 2) Crie funções e carregue com
load_all()
# cada vez que criar ou alterar uma função, use esse comando para
# carregá-las no seu workspace e testá-las. Crie funções em arquivos com
# extensão .R dentro do diretório R/
##----------------------------------------------------------------------
## 3) Documente as funções usando as tags do roxygen2 e use a função
document()
# para gerar os arquivos com extensão .Rd correspondentes no diretório
# man/. Use também a função
check_man()
# para conferir a documentação
##----------------------------------------------------------------------
## 4) Certifique-se de que o arquivo NAMESPACE esteja contendo todas as
## funções do seu pacote a serem exportadas, e todas as funções (ou
## pacotes inteiros) a serem importadas para o seu pacote. Use as tags
## @export para exportar e @import ou @importFrom para importar (na
## documentação roxygen2 de cada função). Rode
document()
# sempre que exportar ou importar uma função, para que o arquivo
# NAMESPACE seja atualizado.
##----------------------------------------------------------------------
## 5) Confira o pacote com
check()
# e construa o pacote final com
build()
Referências
Estas notas são altamente baseadas em:
R packages by Hadley Wickham (http://r-pkgs.had.co.nz/)
cursos.leg.ufpr.br/prr/capPacR.html 20/21
25/04/2020 Pacotes R
(https://creativecommons.org/licenses/by-nc-sa/4.0/deed.pt_BR)
Este conteúdo está disponível por meio da Licença Creative Commons 4.0
cursos.leg.ufpr.br/prr/capPacR.html 21/21