Compare commits

..
12 Commits
Author SHA1 Message Date
rodado 60a5584b34 fix: cartão sem trilhas nem assuntos repetidos 2026-10-01 20:34:09 +02:00
rodado 7357d38066 fix: fechar a peça volta direto ao mural em vez de à peça anterior 2026-10-01 19:42:21 +02:00
rodado 09f4568b5c perf: mural só redesenha quando algo muda e para atrás do visor
- render sob demanda: câmera em movimento, peças animando ou entrada recente;
  parado, 0 quadros (antes ~60/s com 13 mil peças)
- nada é desenhado com o visor aberto; abrir uma peça não anima mais o mural
- pré-carrega 1 vizinho de cada lado (medio agora tem ~120 KB)
- relacionados desenhados direto em canvas, sem JPEG em base64
- fechar o visor limpa o estado dos filtros sobrepostos
2026-10-01 12:07:27 +02:00
rodado da105a1a46 feat: liga a derivada grande no visor e registra as derivadas de acesso
- medio/ 1.200 px e grande/ 2.000 px para os 13.059 itens (6,0 GB)
- 9 matrizes com JPEG corrompido viram tarefa; derivadas delas saem da
  imagem do DSpace
- MANIFEST com as contagens novas, reenviado ao bucket
2026-10-01 11:32:52 +02:00
rodado fd37348811 feat: derivadas de acesso com tamanhos pela NARA e CONARQ (medio 1.200, grande 2.000)
- pipeline/deriva-acesso.py gera medio/ e grande/ da matriz no finland, em
  WebP sRGB, sem ampliar, com retomada
- MANIFEST e CONARQ.md documentam matriz, derivada de navegação e de acesso
  (Res. CONARQ 31/2010) e os tamanhos da NARA 2004
- INDEX.md revisto; teste-upload.txt e falhas-500 antigos saem do bucket
2026-10-01 09:48:55 +02:00
rodado ff7dc3cf3f docs: tarefas abertas reunidas em tasks/tasks.md 2026-10-01 09:06:11 +02:00
rodado 2667af317b docs: marca a publicação do mural como feita no plano 2026-09-30 22:35:53 +02:00
rodado dfb6362e30 docs: plano, manifest e textos da descrição conferidos; descrição publicada no bucket
- PLANO §1/§7 com o estado real (ledger e bucket em 2026-09-30) e §9 com o
  visor do mural (7.1–7.2c), 7.3 e 7.4 pendentes
- MANIFEST final com contagens fechadas e seção sobre a descrição NOBRADE
- textos das 15 seções e do nível 1 conferidos na web, com fontes fora da descrição
- rascunho do pedido de CODEARQ ao CONARQ
- descricao/ enviada a s3://brasiliana/descricao/ com manifest-sha256.txt
2026-09-30 22:35:21 +02:00
rodado f05cdc5b9d docs: TODO só com o que está aberto; versão completa arquivada em tasks/done 2026-09-30 22:32:36 +02:00
rodado 5c84619e5d feat: visor da peça com zoom real, ficha NOBRADE e filtros agrupados pela norma
- painel à esquerda (folha no celular) com barra ← mural | filtros, palco com
  roda, pinça, duplo clique, arrastar e modo só a imagem (F)
- ficha arquivística: código, nível, arranjo clicável, data da norma com selo
  de atribuída, produtor ISAAR, suporte, original, reprodução e citação
- filtros em Arranjo, Data, Pontos de acesso e Suporte e uso; autor pela
  autoridade, espécie da 1.5 e condição de reprodução; link pelo código
- datas: ano implausível vira ilegível, atribuição pelo miolo p10–p90 e
  histograma só com datas de até 30 anos de amplitude
2026-09-30 22:30:13 +02:00
rodado 23b56e8c87 feat: descrição arquivística NOBRADE multinível com exportação EAD 3, EAC-CPF e AtoM
- pipeline/nobrade: normalizadores de datas (ISO 8601-2), séries, autoridades,
  espécie/suporte, direitos, lugar e assuntos; montagem dos níveis 0–5 com
  código de referência BR RJXYZ.BF.<seção>.<série>.<handle>.<imagem>
- validador dos elementos obrigatórios: 0 pendências em 26.454 unidades
- EAD 3 e 457 EAC-CPF validados contra os XSD
- mural: cartão com código, data normalizada, série e reprodução; filtro por série
2026-09-30 21:22:00 +02:00
rodado e92df83a78 docs: resumo da NOBRADE em CONARQ.md e plano de descrição arquivística 2026-09-30 21:05:28 +02:00
55 changed files with 22306 additions and 1161 deletions
+11
View File
@@ -20,3 +20,14 @@ pipeline/rejeitados/
web/atlas/*.webp web/atlas/*.webp
pipeline/catalogo.jsonl pipeline/catalogo.jsonl
pipeline/wordpress-posts.jsonl pipeline/wordpress-posts.jsonl
# descrição NOBRADE: saídas pesadas, regeneradas por `python -m nobrade` (vão para o bucket)
descricao/unidades.jsonl
descricao/ead/
descricao/eac/
descricao/atom.csv
__pycache__/
pipeline/deriva-acesso.resultados.jsonl
# restos do FUSE (arquivo apagado enquanto aberto)
.fuse_hidden*
+285
View File
@@ -0,0 +1,285 @@
# NOBRADE — o que a norma pede e como este acervo a cumpre
Fonte: CONSELHO NACIONAL DE ARQUIVOS (Brasil). *NOBRADE: Norma brasileira de
descrição arquivística*. Rio de Janeiro: Arquivo Nacional, 2006. 124 p.
<https://www.gov.br/conarq/pt-br/centrais-de-conteudo/publicacoes/nobrade.pdf>
Este arquivo resume a norma (seções 1–4) e registra as decisões de aplicação
tomadas para a cópia digital da Brasiliana Fotográfica (seção 5). A
implementação está em `pipeline/nobrade/` e a saída em `descricao/`.
```bash
cd pipeline
python3 -m nobrade # descricao/: unidades, autoridades, revisão, pendências, EAD 3, EAC-CPF, AtoM
python3 -m nobrade.mural # leva código, data, série e suporte para web/atlas/atlas-map.json
```
---
## 1. O que é a NOBRADE
- Adaptação brasileira da **ISAD(G)** (descrição) e da **ISAAR(CPF)** (registros
de autoridade: entidades coletivas, pessoas e famílias), feita pela Câmara
Técnica de Normalização da Descrição Arquivística do CONARQ (criada em 2001).
- Pensada para documentos em fase permanente, aplicável a **qualquer suporte ou
gênero** — fotografia inclusive.
- **Não impõe formato** de entrada nem de saída. Exige só que os **elementos
obrigatórios** estejam presentes. Para intercâmbio recomenda um formato
comum, citando o **EAD** (Encoded Archival Description) — nota 13.
- Acrescenta à ISAD(G) dois elementos: **6.1 Notas sobre conservação** e
**8.1 Pontos de acesso e indexação de assuntos**.
- Fundo e coleção equivalem-se para efeito da norma. *Coleção* = "conjunto de
documentos com características comuns, reunidos intencionalmente";
*colecionador* = quem a formou.
## 2. Princípios (herdados da ISAD(G))
1. **Do geral para o particular** — representar o contexto e a estrutura
hierárquica do fundo e das suas partes.
2. **Informação relevante para o nível** — cada nível descreve o que é seu.
3. **Relação entre descrições** — explicitar a posição de cada unidade na
hierarquia.
4. **Não repetição** — o que vale para o nível de cima não se repete embaixo.
### Níveis de descrição
| Nível | Unidade |
|---|---|
| 0 | acervo da entidade custodiadora |
| 0,5 | acervo da subunidade custodiadora |
| 1 | fundo ou coleção |
| 2 | seção |
| 2,5 | subseção |
| 3 | série |
| 3,5 | subsérie |
| 4 | dossiê ou processo |
| 5 | item documental |
Nem todos os níveis precisam existir, mas **o nível 5 exige o nível 4**: um
item documental só é descrito dentro de um dossiê. Um dossiê pode ter um
único documento — "item" é um nível, não um documento.
## 3. Os 28 elementos, em 8 áreas
Em **negrito**, os 7 obrigatórios.
| Área | Elementos |
|---|---|
| 1 Identificação | **1.1 Código de referência** · **1.2 Título** · **1.3 Data(s)** · **1.4 Nível de descrição** · **1.5 Dimensão e suporte** |
| 2 Contextualização | **2.1 Nome(s) do(s) produtor(es)** · 2.2 História administrativa/Biografia · 2.3 História arquivística · 2.4 Procedência |
| 3 Conteúdo e estrutura | 3.1 Âmbito e conteúdo · 3.2 Avaliação, eliminação e temporalidade · 3.3 Incorporações · 3.4 Sistema de arranjo |
| 4 Condições de acesso e uso | **4.1 Condições de acesso** (obrigatório só nos níveis 0 e 1) · 4.2 Condições de reprodução · 4.3 Idioma · 4.4 Características físicas e requisitos técnicos · 4.5 Instrumentos de pesquisa |
| 5 Fontes relacionadas | 5.1 Existência e localização dos originais · 5.2 Existência e localização de cópias · 5.3 Unidades de descrição relacionadas · 5.4 Nota sobre publicação |
| 6 Notas | 6.1 Notas sobre conservação · 6.2 Notas gerais |
| 7 Controle da descrição | 7.1 Nota do arquivista · 7.2 Regras ou convenções · 7.3 Data(s) da(s) descrição(ões) |
| 8 Pontos de acesso | 8.1 Pontos de acesso e indexação de assuntos |
## 4. Regras que mais pesam neste acervo
### 1.1 Código de referência
- Três partes: **código do país (`BR`, ISO 3166)** + **código da entidade
custodiadora** + **código da unidade de descrição**.
- O código da entidade é **solicitado ao CONARQ** (proc. 1.1.1).
- A parte da unidade é convencionada pela entidade. Ela pode ter subpartes por
nível (1.1.2.1) ou reaproveitar uma notação existente (1.1.2.2). Se o código
não expuser os níveis, o elemento 1.4 tem de listar os títulos de todos os
níveis superiores (1.1.4).
- Exemplos da norma: `BR MN`, `BR CPDOC JG`, `BR AN Q6.LEG.COR,TEL`.
- Na prática (código CODEARQ), o código da entidade leva a UF colada à sigla,
e as partes da unidade vão separadas por ponto. Exemplo do Arquivo Geral da
Cidade do Rio de Janeiro: `BR RJAGCRJ.SOP.NL.AVE.03.01` = país · UF+entidade ·
fundo (Secretaria de Obras Públicas) · série (Negrão de Lima) · subsérie
(Avenidas) · dossiê 03 · item 01, a imagem em si.
### 1.2 Título
- Registrar o título original. Na falta dele, atribuir um título formado a
partir da própria unidade. **Título atribuído vai entre colchetes.**
### 1.3 Data(s)
- Obrigatória a **data de produção** (data crônica). Opcionais: data de
acumulação, data-assunto e **data tópica** (local de produção, útil nos
níveis 4 e 5).
- Data crônica: ano obrigatório, algarismos arábicos, **data atribuída entre
colchetes, dúvida com `?`** (`[1860?]`). Só século ou década: completar com
traço (`[18--]`, `[186-]`). Período provável: datas-limite (`1950-1975`).
- **Toda unidade recebe data de produção, mesmo aproximada** (1.3.3.2).
- A data tal como aparece no documento vai para 6.2. Para indexação e
intercâmbio, saída em **ISO 8601** (1.3.2.7).
### 1.5 Dimensão e suporte
- Por **gênero documental** (bibliográfico, cartográfico, eletrônico,
filmográfico, **iconográfico**, micrográfico, sonoro, textual,
tridimensional). Fora os textuais, quantificar **por espécie**.
- Espécies do gênero iconográfico: caricatura, cartaz, cartão-postal, charge,
cópia por contato, desenho, diapositivo, **fotografia**, gravura,
ilustração, **negativo fotográfico**, pintura.
- Registro normalizado para permitir **somatórios** nos níveis superiores.
Exemplo da norma: `fotografia 1 item p&b`.
### 2.1 Produtor
- Forma normalizada do nome (ISAAR(CPF)). Nas coleções, o produtor é o
**colecionador**. Afirma o princípio da proveniência.
### 2.3 História arquivística e 2.4 Procedência
- 2.3: natureza da acumulação, transferências de custódia, **intervenções
técnicas, dispersões e sinistros**.
- 2.4: origem imediata, forma e data de aquisição. Se desconhecida, "dado não
disponível".
### 4.1–4.3 Acesso, reprodução, idioma
- 4.1: dizer se há restrição, com base legal e prazo.
- 4.2: restrições de reprodução e **a quem pedir autorização**.
- 4.3: idiomas em ISO 639. Idioma que não seja o português é sempre
registrado.
### 5.1 e 5.2 Originais e cópias
- 5.1: onde está o original e os números de controle, mesmo que ele esteja em
**outra entidade**.
- 5.2: cópias existentes, com a referência de controle, ou o nome, a cidade e
o site de outra entidade que as tenha.
### 8.1 Pontos de acesso
- Indexação controlada de **nomes, eventos, áreas geográficas, períodos e
assuntos**, com fontes validadoras (ex.: Biblioteca Nacional, Library of
Congress). As regras seguidas vão em 7.2.
- Nomes de pessoas em forma autorizada ISAAR(CPF), com **remissivas para as
variantes**.
---
## 5. Aplicação a este acervo
### 5.1 O que é esta coleção
Esta é uma **coleção de cópias digitais**, reunida intencionalmente em 2026 a
partir da Brasiliana Fotográfica. Os originais continuam nas 16 instituições
de origem. Por isso:
- a entidade custodiadora **das cópias** é quem mantém o bucket `s3://brasiliana`;
- o produtor do nível 1 é o **colecionador** (a mesma entidade);
- cada dossiê aponta o original em **5.1**: instituição, handle do DSpace,
código Sophia e objdigital;
- não descrevemos o acervo alheio: descrevemos a nossa cópia e dizemos onde
está o original.
### 5.2 Hierarquia adotada
| Nível | Unidade | Origem | Código |
|---|---|---|---|
| 0 | Acervo da entidade | — | `BR RJXYZ` |
| 1 | Coleção Brasiliana Fotográfica (cópia digital) | — | `BR RJXYZ.BF` |
| 2 | Seção = instituição de origem | `community` | `BR RJXYZ.BF.IMS` |
| 3 | Série = coleção/fundo de origem | `dc.source` normalizado | `BR RJXYZ.BF.IMS.GF` |
| 4 | Dossiê = item do DSpace (handle) | `handle` | `BR RJXYZ.BF.IMS.GF.12345` |
| 5 | Item documental = cada imagem do dossiê | ledger do bucket | `BR RJXYZ.BF.IMS.GF.12345.01` |
- `RJXYZ` é **provisório** até o CONARQ atribuir um código. A troca é uma
constante em `pipeline/nobrade/config.py`.
- **Toda imagem é um item de nível 5**, mesmo quando o dossiê tem só uma
(`.01`), como no AGCRJ. Os 121 dossiês com várias imagens vão de `.01` a `.08`.
- O código do dossiê termina no número do handle (proc. 1.1.2.2), então
sobrevive a reclassificações de série sem perder a ligação com a origem.
- Itens sem série identificável ficam na série `AV` ("Avulsos") da sua seção.
Notações de caixa e de negativo em `dc.source` (`CX 14`, `NV 2056`) não viram
série: vão para 5.1 como notação na origem.
- O IHGB é a única instituição que publica o próprio código NOBRADE
(`BR RJIHGB 064IG 0278`, em `dc.identifier`). Ele fica em 5.1 como código na
origem.
### 5.3 De onde vem cada elemento
| Elemento | Nível 4 (dossiê) | Níveis 1–3 |
|---|---|---|
| 1.2 Título | `dc.title` | nome da coleção, instituição ou série |
| 1.3 Data | `dc.date` normalizado + ISO 8601. `dc.coverage` → data tópica | datas-limite dos filhos |
| 1.5 Dimensão | `dc.type` → espécie + suporte; cor e medidas que AN e AGCRJ põem em `dc.description`. Cópia digital: arquivos e bytes | soma por espécie |
| 2.1 Produtor | `dc.contributor` (fotógrafo), forma autorizada | colecionador / instituição |
| 2.3 Hist. arquivística | `dc.date.accessioned` (entrada no DSpace), data da coleta | relato da coleta (nível 1) |
| 2.4 Procedência | Brasiliana Fotográfica, handle, data da coleta | idem, agregado |
| 3.1 Âmbito e conteúdo | `dc.description` | resumo gerado (quantidades, datas, fotógrafos) |
| 4.1 Acesso | herdado do nível 1 | texto fixo no nível 1 |
| 4.2 Reprodução | `dc.rights` → categoria + texto original | — |
| 4.3 Idioma | `dc.language` (ISO 639-2) | — |
| 4.4 Requisitos técnicos | formato, resolução | — |
| 5.1 Originais | instituição + handle + Sophia | instituição |
| 5.2 Cópias | preservação, legado objdigital, miniaturas no S3 | — |
| 5.3 Relacionadas | `dc.relation`, `dc.relation.ispartof` | — |
| 5.4 Publicação | posts do blog que citam o handle | — |
| 6.1 Conservação | falha de bitstream na origem (HTTP 500) | — |
| 6.2 Notas | data e direitos como vieram da origem | — |
| 7.x Controle | fonte, regras (NOBRADE/ISAD(G)), data de geração | idem |
| 8.1 Pontos de acesso | assuntos (pt), lugares, nomes, período | — |
### 5.4 Saídas
- `descricao/unidades.jsonl`: uma linha por unidade de descrição, com os
campos nomeados pelo número do elemento.
- `descricao/autoridades.jsonl`: registros ISAAR(CPF) de fotógrafos e
colecionadores.
- `descricao/ead/brasiliana.xml`: EAD 3 do acervo inteiro.
- `descricao/eac/`: um EAC-CPF por autoridade.
- `descricao/pendencias.md`: relatório do validador dos obrigatórios.
- `descricao/revisao/*.tsv`: tabelas dos normalizadores para revisão manual.
- `pipeline/nobrade/ajustes/series.tsv` (colunas `instituicao`, `dc_source`,
`titulo`): correção manual de série, que prevalece sobre a regra na próxima
geração.
- `descricao/atom.csv`: importação no AtoM (modelo ISAD).
Versionados no git: textos, revisão, autoridades e pendências. `unidades.jsonl`,
`ead/`, `eac/` e `atom.csv` são regenerados e vão para o bucket.
### 5.5 Decisões de normalização
- **Datas:** 190 padrões distintos na origem. Saem na forma da norma
(`[ca. 1905]`, `[193-?]`, `8/2/1890-18/4/1890`) e em ISO 8601-2/EDTF
(`1905~`, `193X?`, `1890-02-08/1890-04-18`). `circa` fica como `ca.`,
convenção do AACR2, que a norma cita. Os 167 carimbos de registro do DSpace
gravados em `dc.date` não são tratados como data de produção. Os dossiês sem
data recebem uma data atribuída (proc. 1.3.3.2), `[A-B?]`, a partir do
período de atividade do autor, ou senão das datas-limite da série, ou senão
das da instituição. A base da atribuição fica anotada.
- **Título ausente:** atribuído entre colchetes a partir da descrição ou dos
assuntos (proc. 1.2).
- **Espécie ausente:** presumida fotografia, com nota. O repositório inteiro é
fotográfico.
- **Autoridades:** grafias unidas por chave sem acento e por inversão ("Marc
Ferrez" → "Ferrez, Marc"). A forma autorizada é a variante com datas mais
completas; as outras viram remissivas (8.1.4). Anônimos não viram autoridade.
- **Assuntos:** as traduções inglesas que o DSpace da BN repete ficam separadas
(`assuntos_eng`). Os assuntos seguem o vocabulário da origem, sem controle
adicional.
- **Direitos:** quatro categorias: domínio público, uso cultural liberado,
requer autorização do detentor, e consultar o detentor. O texto da origem
fica em 6.2.
- **Valores corrompidos na origem** (fragmentos de XML ou hash no lugar do
texto): desconsiderados e anotados em 6.2.
### 5.6 Matriz e derivadas (Resolução CONARQ 31/2010)
A NOBRADE não trata de imagem; quem trata é a Resolução 31/2010
(*Recomendações para digitalização de documentos arquivísticos
permanentes*). Ela separa **matriz digital** (alta resolução, TIFF ≥ 300 dpi
em escala 1:1, acesso restrito) de **derivadas**: de acesso (JPEG/PNG,
formato aberto, "em variados tamanhos de acordo com a banda") e de
navegação (thumbnail). Não fixa pixels para as derivadas.
Aqui a matriz é a imagem de preservação de cada instituição (`preservacao/`).
Os tamanhos das derivadas seguem a NARA 2004, citada pela própria
recomendação: `thumb256/` 256 px (navegação), `medio/` 1.200 px (acesso
recomendado) e `grande/` 2.000 px (acesso ampliado), em WebP sRGB, sem
ampliar. Tabela completa em `MANIFEST.md` → "Tamanhos das derivadas".
### 5.7 Pendências fora do código
- [ ] Pedir ao CONARQ o código da entidade custodiadora (proc. 1.1.1). O
rascunho para o formulário CODEARQ está em
`descricao/pedido-codigo-conarq.md`. Com o código, trocar `RJXYZ` e
`ENTIDADE_NOME` em `pipeline/nobrade/config.py`.
- [x] Textos dos níveis 1 e 2 conferidos na web em 2026-09-30, com as fontes
no fim de cada arquivo (em `### Fontes`, fora da descrição).
- [ ] Revisar as datas atribuídas pelo arquivista (`revisao/datas.tsv`,
qualidade "atribuída pelo arquivista").
- [ ] Revisar `revisao/series.tsv`. Correções vão em
`pipeline/nobrade/ajustes/series.tsv`.
- [x] `descricao/` publicada em `s3://brasiliana/descricao/` (2026-09-30),
com `manifest-sha256.txt`. Depois de regenerar, suba de novo.
+1 -1
View File
@@ -1,6 +1,6 @@
# INDEX — Brasiliana Fotográfica → S3 # INDEX — Brasiliana Fotográfica → S3
> Índice do que foi coletado. Ver `MANIFEST.md` pra estrutura/checksums e `tasks/PLANO.md` pro estado ao vivo dos downloads (as imagens continuam sendo baixadas depois deste índice ser gerado — os metadados abaixo já são definitivos). > Índice do que foi coletado (coleta concluída em 2026-09-13; índice revisto em 2026-10-01). Ver `MANIFEST.md` para a estrutura do bucket, checksums, derivadas e a descrição NOBRADE em `descricao/`.
## Acervo DSpace (brasilianafotografica.bn.gov.br/brasiliana) ## Acervo DSpace (brasilianafotografica.bn.gov.br/brasiliana)
+99 -35
View File
@@ -1,16 +1,15 @@
# MANIFEST — Brasiliana Fotográfica → S3 # MANIFEST — Brasiliana Fotográfica → S3
> **Rascunho, gerado em 2026-09-10.** Os pipelines de download ainda estavam > **Versão final, 2026-09-30.** Coleta concluída em 2026-09-13. Números
> em andamento quando este arquivo foi escrito pela última vez — os números > conferidos contra o ledger de envio (`pipeline/subidor.sqlite`) e a listagem
> marcados como "em andamento" precisam de uma passada final antes de > do bucket. Detalhe técnico em `tasks/PLANO.md` e `README.md`.
> publicar. Ver `tasks/PLANO.md` pro detalhe técnico completo.
## O que é ## O que é
Cópia de preservação do acervo da **Brasiliana Fotográfica** Cópia de preservação do acervo da **Brasiliana Fotográfica**
(brasilianafotografica.bn.gov.br), um repositório DSpace mantido pela (brasilianafotografica.bn.gov.br), um repositório DSpace mantido pela
Biblioteca Nacional do Brasil reunindo fotografias de 15 instituições Biblioteca Nacional do Brasil reunindo fotografias de 15 instituições
brasileiras e uma alemã (handles `20.500.12156.1/*`). Depositada em (14 brasileiras e uma alemã) (handles `20.500.12156.1/*`). Depositada em
`s3://brasiliana` como acervo arquivístico — procedência e checksums `s3://brasiliana` como acervo arquivístico — procedência e checksums
preservados por item, não uma cópia solta de imagens. preservados por item, não uma cópia solta de imagens.
@@ -27,7 +26,7 @@ coletor mantidos ao longo de toda a coleta.
## Como foi coletado ## Como foi coletado
**Metadados** (13.058 itens reais — ver nota sobre falso-positivo abaixo): **Metadados** (13.060 itens):
enumerados via `browse?type=title` por comunidade (o sitemap oficial está enumerados via `browse?type=title` por comunidade (o sitemap oficial está
desatualizado desde 2019 e cobre só 41% do acervo), colhidos um a um do desatualizado desde 2019 e cobre só 41% do acervo), colhidos um a um do
DSpace (`?show=full`), executado a partir de um navegador real — o site DSpace (`?show=full`), executado a partir de um navegador real — o site
@@ -36,7 +35,7 @@ navegadores sem sessão real, mesmo pra bitstreams de imagem, não só
páginas HTML. páginas HTML.
**Imagens**: cada item pode ter mais de uma imagem original (achado desta **Imagens**: cada item pode ter mais de uma imagem original (achado desta
coleta — 115 itens tinham 2 a 6 bitstreams reais, não um). Pra cada item coleta — 121 itens tinham de 2 a 8 bitstreams reais, não um). Pra cada item
coletamos: a imagem de preservação (a de maior resolução), a(s) imagem(ns) coletamos: a imagem de preservação (a de maior resolução), a(s) imagem(ns)
adicional(is) quando existem, e a miniatura gerada pelo próprio DSpace. adicional(is) quando existem, e a miniatura gerada pelo próprio DSpace.
Uma cópia legada de menor resolução (`objdigital.bn.br`) também foi Uma cópia legada de menor resolução (`objdigital.bn.br`) também foi
@@ -44,7 +43,7 @@ preservada quando disponível — é a mesma proveniência, resolução inferior
mantida por referência histórica, nunca como substituta da imagem de mantida por referência histórica, nunca como substituta da imagem de
preservação. preservação.
**Posts do blog**: 637 posts únicos identificados (8 categorias do **Posts do blog**: 636 posts únicos coletados (637 identificados, 1 com erro na origem; 8 categorias do
WordPress, com sobreposição substancial entre elas), com título, autor, WordPress, com sobreposição substancial entre elas), com título, autor,
data, categorias e corpo do texto, mais a lista de handles do acervo que data, categorias e corpo do texto, mais a lista de handles do acervo que
cada post referencia. cada post referencia.
@@ -54,8 +53,12 @@ cada post referencia.
``` ```
s3://brasiliana/ s3://brasiliana/
MANIFEST.md este arquivo MANIFEST.md este arquivo
INDEX.md índice legível dos itens
catalogo.jsonl metadados completos, 1 linha por item catalogo.jsonl metadados completos, 1 linha por item
wordpress-posts.jsonl posts do blog, 1 linha por post wordpress-posts.jsonl posts do blog, 1 linha por post
wordpress/ um Markdown por post
falhas-500-2026-09-13.txt itens cuja preservação a origem não serve
descricao/ descrição arquivística NOBRADE (ver abaixo)
itens/{handle-com-underscore}/ itens/{handle-com-underscore}/
metadata.json Dublin Core completo + URL de origem metadata.json Dublin Core completo + URL de origem
+ data/hora UTC de captura + data/hora UTC de captura
@@ -74,6 +77,12 @@ s3://brasiliana/
derivados/thumb256/ derivados/thumb256/
{handle-com-underscore}.webp miniatura DERIVADA por nós (não é {handle-com-underscore}.webp miniatura DERIVADA por nós (não é
material de origem — ver abaixo) material de origem — ver abaixo)
derivados/medio/
{handle-com-underscore}.webp derivada de acesso, 1.200 px, DERIVADA,
aberta no visor do mural
derivados/grande/
{handle-com-underscore}.webp derivada de acesso ampliada, 2.000 px,
carregada no zoom do visor
``` ```
### Sobre `derivados/` ### Sobre `derivados/`
@@ -91,12 +100,42 @@ imagem de preservação quando ela existe e, nos 69 itens sem ela, do
então o conjunto é uniforme. então o conjunto é uniforme.
Cobre **13.059 dos 13.060 handles do catálogo (99,99%)**. O único ausente Cobre **13.059 dos 13.060 handles do catálogo (99,99%)**. O único ausente
é `7523`, cujos bitstreams a origem serve com HTTP 500. é `7523`, cujos bitstreams a origem serve com HTTP 500. `derivados/medio/` e
`derivados/grande/` têm a mesma cobertura (13.059).
Nota sobre a contagem de itens: este manifesto fala em 13.058 itens reais, #### Tamanhos das derivadas (definidos em 2026-10-01)
mas o `catalogo.jsonl` tem 13.060 handles distintos. A diferença de 2 não
foi reconciliada — vale conferir antes de tratar qualquer um dos dois Nos termos do CONARQ (Resolução 31/2010, *Recomendações para digitalização
números como definitivo. de documentos arquivísticos permanentes*), a imagem de preservação faz o
papel de **matriz digital**, e o que está em `derivados/` são **derivadas**:
a de navegação (thumbnail) e as de acesso, que o CONARQ pede em formato
aberto e "em variados tamanhos de acordo com a banda" — sem fixar pixels.
Os pixels seguem a NARA (*Technical Guidelines for Digitizing Archival
Materials for Electronic Access*, 2004, tabela de fotografias), que é a
referência citada pela própria recomendação do CONARQ:
| Pasta | Lado maior | CONARQ | NARA 2004 (fotografias) | Uso no mural |
|---|--:|---|---|---|
| `thumb256/` | 256 px | derivada de navegação | thumbnail (≤ 200 px) | fonte do atlas 3D (blocos de 128 px) |
| `medio/` | 1.200 px | derivada de acesso | *Access – Recommended* (800–1.200 px) | imagem aberta no visor |
| `grande/` | 2.000 px | derivada de acesso | *Larger Alternative* (1.200–2.000 px) | carregada só no zoom |
Regras comuns: WebP (formato aberto; o CONARQ recomenda JPEG/PNG mas admite
outros quando o acesso exige), espaço de cor **sRGB** (pedido pela NARA para
acesso), metadados embutidos removidos, e **nunca ampliar** — a matriz menor
que o alvo fica no próprio tamanho. Também chega ao nível 3–4 do Europeana
Publishing Framework (≥ 0,95 megapixel). Gerado por
`pipeline/deriva-acesso.py` a partir da matriz (ou, nos 68 itens sem ela, da
imagem servida pelo DSpace). Em 9 itens (`6574`, `6969`, `6975`, `6994`,
`7153`, `7161`, `7169`, `7173`, `7203`) a matriz é um JPEG com dados
corrompidos (marcador RST quebrado; o arquivo está inteiro e o SHA-256 confere
com o ledger), e as derivadas saíram da imagem do DSpace. No fim,
134 `medio` e 991 `grande` ficaram abaixo do alvo porque a matriz é menor.
Contagem de itens: o `catalogo.jsonl` final tem **13.060 handles distintos**,
todos itens reais. O falso-positivo `20.500.12156.1/1` (página raiz da
comunidade) não está nele. A cifra de 13.058 de rascunhos anteriores está
superada.
Note que `itens/{handle}/thumbnail/` **não** é uma miniatura no sentido Note que `itens/{handle}/thumbnail/` **não** é uma miniatura no sentido
usual: os arquivos que o DSpace chama de thumbnail têm 721 a 3.709 px no usual: os arquivos que o DSpace chama de thumbnail têm 721 a 3.709 px no
@@ -112,21 +151,48 @@ miniaturas de listagem.
`metadata.json` traz `community` (100% dos itens) e `rights` (quando a `metadata.json` traz `community` (100% dos itens) e `rights` (quando a
instituição de origem o preencheu — ver nota abaixo) instituição de origem o preencheu — ver nota abaixo)
## Contagens (⚠️ conferir antes de publicar — pipelines em andamento) ## Contagens (fechadas em 2026-09-30)
| | Total esperado | Status | | | Arquivos | Itens | Tamanho |
|---|--:|---| |---|--:|--:|--:|
| Itens no catálogo | 13.058 | ✅ fechado | | Itens no catálogo | — | 13.060 | 45,9 MB (`catalogo.jsonl`) |
| Imagem de preservação | **12.991** | ✅ fechado | | Imagem de preservação | 13.194 | 12.991 | 127,4 GB |
| Miniatura (thumbnail do DSpace) | **13.059** | ✅ fechado | | ↳ extras (itens com 2 a 8 imagens) | 203 | 121 | incluídos acima |
| Miniatura derivada (`derivados/thumb256/`) | **13.059** | ✅ fechado | | Miniatura do DSpace (`thumbnail/`) | 13.060 | 13.059 | 1,5 GB |
| Imagens extras (multi-bitstream) | 245 | ✅ completo | | Cópia legada (objdigital) | 2.137 (1.899 JPG, 213 PDF, 25 outros) | 2.137 | 9,6 GB |
| Cópia legada (objdigital) | **2.112** imagens (1.899 JPG + 213 PDF) de 2.702 elegíveis; 565 × HTTP 404; 25 são páginas HTML de visualizador, não imagem | ✅ fechado | | `metadata.json` + `manifest-sha256.txt` | 26.118 | 13.059 | 65 MB |
| Posts do blog | 637 | 🟡 em andamento | | Derivado `thumb256` | 13.059 | 13.059 | 101 MB |
| Derivado `medio` (1.200 px) | 13.059 | 13.059 | 1,61 GB |
| Derivado `grande` (2.000 px) | 13.059 | 13.059 | 4,37 GB |
| Posts do blog (`wordpress/`) | 636 | — | 10 MB |
| **Total no bucket** (sem `descricao/`) | **81.269 objetos** | | **139,2 GB** |
**Antes de publicar**: rodar a verificação final (contagem de pastas no Sem imagem de preservação: **69 itens**, listados em `errors.md` e
bucket vs. catálogo, checksums batendo) e atualizar esta tabela com os `falhas-500-2026-09-13.txt`. A origem responde HTTP 500 ao bitstream, e
números fechados. todos, menos o `7523`, têm a miniatura do DSpace.
## Descrição arquivística (NOBRADE)
`descricao/` descreve esta coleção segundo a NOBRADE (CONARQ, 2006), em seis
níveis: acervo › coleção › 15 seções (instituição de origem) › 115 séries
(coleção ou fundo de origem) › 13.060 dossiês (itens do DSpace) › 13.262
itens documentais (cada imagem). Código de referência
`BR RJXYZ.BF.<seção>.<série>.<handle>.<imagem>`, com a entidade `RJXYZ`
provisória até o CONARQ atribuir um CODEARQ.
| Arquivo | Conteúdo |
|---|---|
| `unidades.jsonl` | 26.454 unidades de descrição, elementos pelo número da norma |
| `autoridades.jsonl`, `eac/` | 457 registros de autoridade (ISAAR(CPF)), também em EAC-CPF |
| `ead/brasiliana.xml` | a coleção inteira em EAD 3, validada contra o XSD oficial |
| `atom.csv` | importação no AtoM (modelo ISAD) |
| `pendencias.md` | validador dos obrigatórios: 0 pendências |
| `revisao/`, `textos/` | tabelas dos normalizadores e textos dos níveis 1–2 |
| `manifest-sha256.txt` | SHA-256 de cada arquivo de `descricao/` |
A descrição é derivada, como `derivados/`: regenera-se com
`python3 -m nobrade` a partir do catálogo e do ledger. Decisões e mapeamentos
estão em `CONARQ.md`, no repositório.
## Exceções conhecidas (não são bugs) ## Exceções conhecidas (não são bugs)
@@ -148,18 +214,16 @@ números fechados.
Aeroespacial) — sem imagem. O servidor da Biblioteca Nacional retorna Aeroespacial) — sem imagem. O servidor da Biblioteca Nacional retorna
`HTTP 500` ao tentar servir os bitstreams desse item especificamente; `HTTP 500` ao tentar servir os bitstreams desse item especificamente;
não é um problema do nosso lado. Metadados preservados normalmente. não é um problema do nosso lado. Metadados preservados normalmente.
- **Handles `20.500.12156.1/6656` e `20.500.12156.1/7939`** — o que foi - **Handles `20.500.12156.1/6656` e `20.500.12156.1/7939`**: a primeira
baixado como imagem de preservação é, na verdade, o bitstream de tentativa baixou o bitstream de LICENÇA do DSpace (777 bytes de texto com
LICENÇA do DSpace (777 bytes de texto UTF-8 com extensão `.jpg`). É a extensão `.jpg`), que a validação de magic bytes barrou. Na rodada de
mesma contaminação do achado 2.8b, desta vez na trilha de preservação e 2026-09-13 os dois foram recuperados, e a imagem de preservação real está
não na de miniatura. A validação de magic bytes do `subidor.py` barra no bucket.
esses arquivos no upload, então eles nunca chegaram ao bucket — mas
significa que esses dois itens ainda não têm imagem coletada.
## Direitos ## Direitos
Majoritariamente domínio público por antiguidade, mas as 16 instituições Majoritariamente domínio público por antiguidade, mas as 15 instituições
de origem (15 brasileiras + 1 alemã) têm políticas distintas. `dc.rights` de origem (14 brasileiras + 1 alemã) têm políticas distintas. `dc.rights`
e a instituição de origem são preservados **por item**: a decisão de e a instituição de origem são preservados **por item**: a decisão de
redistribuir é item a item, não do acervo em bloco. Arquivar para si é redistribuir é item a item, não do acervo em bloco. Arquivar para si é
uma coisa; republicar é outra. uma coisa; republicar é outra.
+5 -14
View File
@@ -244,7 +244,8 @@ brasiliano/
README.md este arquivo README.md este arquivo
tasks/ retomada de sessão e plano de trabalho tasks/ retomada de sessão e plano de trabalho
PLANO.md estado atual, achados, runbook (comece por aqui) PLANO.md estado atual, achados, runbook (comece por aqui)
TODO.md lista de trabalho da sessão corrente tasks.md todas as tarefas abertas, numa lista só
TODO.md notas técnicas para retomar o trabalho
PROMPT_TERMINAL.md runbook original (parcialmente superado, ver PLANO.md) PROMPT_TERMINAL.md runbook original (parcialmente superado, ver PLANO.md)
pipeline/ scripts ativos + estado em disco (catálogo, .sqlite, .log, .tmp/, credenciais) pipeline/ scripts ativos + estado em disco (catálogo, .sqlite, .log, .tmp/, credenciais)
coletor.js Fase 1 — metadados, console do navegador coletor.js Fase 1 — metadados, console do navegador
@@ -293,19 +294,9 @@ brasiliano/
## Pendências ## Pendências
Lista completa e com contexto em [`tasks/TODO.md`](tasks/TODO.md). As principais: Todas as tarefas abertas, organizadas por área (descrição NOBRADE, mural,
acervo no bucket) e por quem destrava cada uma, estão em
1. **69 itens sem preservação** ([`errors.md`](errors.md)) — depende da origem [`tasks/tasks.md`](tasks/tasks.md).
voltar a servir esses bitstreams; retomar com `FALTA3.retomar()` na aba.
2. **30 bitstreams `extra_seqN`** apagados pelo `subidor.py` antigo (que
confundia TIFF com texto de licença) precisam ser enumerados item a item
com `reparo-multibitstream.js` antes de rebaixar.
3. **30 objetos `(N)` com tamanho diferente do gêmeo** — não são duplicata,
são versões distintas; precisam de conferência individual.
4. **Reconciliar 13.058 × 13.060** — o MANIFEST fala em 13.058 itens reais e o
catálogo tem 13.060 handles distintos; a diferença nunca foi explicada.
5. **PDFs de álbum** no objdigital são objetos distintos e precisam de decisão
própria — o de 71,9 MB do item 14582 provavelmente não é caso isolado.
## Direitos ## Direitos
File diff suppressed because one or more lines are too long
+486
View File
@@ -0,0 +1,486 @@
44b0aafc51234f32bdc6a757717d6c32891b052a68e770959ba8bd1ee33a2367 atom.csv
8581b957123b7e283ae3d17eee6d980b0a59c258bfcea57bb2dce4692dc07fff autoridades.jsonl
bc998d1a27a2d8fde1fbf2270d96acad56be939ad540f2a77c82da73f97c3278 eac/A0001.xml
ce2bcd9dea092b9e0d70f6e853d0871d9347faaf42d5c57e3d3aa2a130ca6051 eac/A0002.xml
7b16be6c934bc27677ca63c37ae3355455ebc0971502b3ff25ff4fb0f735d242 eac/A0003.xml
d8ee5a0a4016535a7ed08da30c6408ea8fe5a10b7e0b7b34bee6fbe65e0c09ef eac/A0004.xml
b41b250d5bd5bc18f3f3ea207647fb252d8bf25f310d78fdf5e16e9a3ef529a7 eac/A0005.xml
3fb59d260aec36df4709fb3a4bc7ee127d9236d2fdde5dd0f951493e83622ada eac/A0006.xml
c1956a5457afb3a452bad14f323993571e50ef181779b938cbaf2c2d1eeb33d5 eac/A0007.xml
b0e3cf08ab5bac481444588bd2a79ebe553596adc22d84f4c2d4f16ac0a8c7c6 eac/A0008.xml
c8b89bc8a27510f63d737c24bc6cb07d179829747389fc6aa257f7f161117136 eac/A0009.xml
c5fdb30266eeeba8c3edb1625cbc73308aadb816a6b5ce735ea532f69107f281 eac/A0010.xml
56352e93e27eadbc528debf089f3d6e932f9e58f3108fad20232527f719b6367 eac/A0011.xml
1b3607005e1469247c7be7aa1f357f736817bfdc09c4a3ace584aad7d0eaf976 eac/A0012.xml
48eb4b548de7882132b013572e15d495e213ba6f2af0700a1aefe64eccc2d407 eac/A0013.xml
8eea1653a36d7d229ee9e3bb4632dbd8b75225d986b18c0ff3be00a21313a170 eac/A0014.xml
c96efe15be9c3d32491ae830132d3f38796a1181538adef35011c94178801d01 eac/A0015.xml
afb867613fbe9734c999159d9a208164772ce9a557fb6eca4be474b001d75cc6 eac/A0016.xml
8c479171c2446e31f80aaf45d4eac146c9b48323b370f364b1d965c6748a5a5b eac/A0017.xml
271bebe60472f5e9d996c28a8aaedafde028dd6809b077b074cb27cd9f662b51 eac/A0018.xml
e1921fe5627091ffeb35f84f8d7004aa6b25c6880512528055a23102e7b1a30e eac/A0019.xml
ef528c23dbc683b28f1d7e8df7a261e369c03ef61470b41f3993833a9271ba66 eac/A0020.xml
b128e949563b3315f1ad4d5653fb1cf9f34336c52672c39847c09f40aaecf8ee eac/A0021.xml
d040e02f5acba6f7adf7834a29c55e3c26c63cfe2da14d821fbcb7ac4df15fc9 eac/A0022.xml
33a9485a9d4b089ead7eb4566616e303986e6561eb48bd5b1b8c5ffb57e1e690 eac/A0023.xml
261a01dcebe71d454b783dcdc34b255505f49b450f0a98b1b01f2d5f4df3efd3 eac/A0024.xml
94ea94a143ab54601d26d86fd607e73d998f539e2d68876fee1daa496afe35b3 eac/A0025.xml
f27876c4737c1ac9d38706533f44188ec9d2bcdf4d33cb8a8d5448e52228cc42 eac/A0026.xml
ffffb131872b0730d93426f8e58ed3f6132082ae3d30138cd8ad5f600431fe8b eac/A0027.xml
3cfcc3145493b4723d68afd489c8000a960cf13cea5f10030a2d7e294caae396 eac/A0028.xml
ae8e55a1b175195695800672f18f87dcf6aaa77bd0a82f0ddca7da92658a85ca eac/A0029.xml
0c4f571a16da77ee2004b315d3c6bac46373c334d7ee64c7b5c1307d795a6248 eac/A0030.xml
8fe1b88a61377252bb1567c871d22f57df83e666c445e7cd215f6487aa02837e eac/A0031.xml
90704e4f450ad0986df67930b4ce680f1cf73d63cecf76cebdbaa9277917dc2b eac/A0032.xml
c5a5e5082a328e5e56208a985875834157b199fc07b3930f8ad14907599ccbb2 eac/A0033.xml
6b1a5967ffb2034c5ddf28b2819a3c8c33669d84aec3cc103c6df639d05dc80f eac/A0034.xml
ed5ededae460d84fa2b4322ec6c9263bcc78de53668b2f81fb46e5b9030ce04e eac/A0035.xml
6ea391f5f48be68e452e12236cec0fa6840616a3c477710ce95fbd03a4b7fdae eac/A0036.xml
76271e17d59b44e1760f59d75df446fc5bd1e756bf30fc5446464757f2fb4d55 eac/A0037.xml
c43b7e9ea11a61c24956e18166df52d3961aa38d5da9fc587f5a5442c55de8d8 eac/A0038.xml
7f28cb360ee25d69535e5c53d684d397b7b7c04f86d3fbfd01ad4759510c8a68 eac/A0039.xml
428e973972723638143f4a79826d287023d2141804122d3ef7ba87fb36a0bc00 eac/A0040.xml
12abc00e832f204589e538ebb16d2b8abcdb065e0cdcaf0d4591239536832c3b eac/A0041.xml
849de16fc9c5dd01acef14b846268447a92f6a9634403d6e78a5f751550bb89f eac/A0042.xml
29dce46395ed4e7cabac1cf673935d695a4fee9a91371594feff7c39eba45472 eac/A0043.xml
56f9947fd6e0334e2c8f1cf8be1fb81cf10823293e831a55d24c1210db52d756 eac/A0044.xml
30f6a2691e8c44898d5a85d676f8cebe2fba8c01db6addf8d052f4bc53a52060 eac/A0045.xml
bda713d1733a824b86b2a2f2e2df5f504c7f46b834798fa442ac9ef8f7b11aac eac/A0046.xml
1da36df73bca7c40bfcb59140bd11961a5733bda591044d5284db0c97ead85ff eac/A0047.xml
31e20249a034853b2824faf96da238b5cae4960cd033eac04430c5bf079ae9a4 eac/A0048.xml
b5d9699ee8550f0b7fca02bae66c4bfbcf3fd30d968d1ad31d1a96c883c5e6cd eac/A0049.xml
9d5cdfc370f26a544ae1c3aafef294fef147786c75bbc4e80ba6afdb13da286d eac/A0050.xml
4fdea8786bf23f3effff8486db4cfb4a8f4c2d180f4944a484bec5a6c99dda8e eac/A0051.xml
73ea82aeb53e50bec15cd6ac4e34703c926c19f859d3cc9a6e20dfd446e87c48 eac/A0052.xml
60feb836a3e714586185cc4bfc60e921bfa3d7b3d138ea5dcac476aa2b747104 eac/A0053.xml
6ab6ae236dc021541963604e5b45df55d02cc9f16275e49ba6d994ffb9d8cbab eac/A0054.xml
da4741cc1742924366e3b95c1f8c703d210d5642b941090b0adad03510f67657 eac/A0055.xml
31af196d488afc1de4aa94a6d24fc9853bd27096c5396cfda14fa55b200a314c eac/A0056.xml
87d8721988a62284393eb3a66dde527155c23bf39db974c7739dc4ca7e869710 eac/A0057.xml
899be0083b7613d629eb4302eb391d9190c5c69e2ee8f7d1bf3d71fb43592f7a eac/A0058.xml
0f6d19e174d72a19d609674e9043aa1cc3bcb391ee7378460d03d0b0bcd924eb eac/A0059.xml
5484ea6495762bcbd2a7719aecc0c046bbc67bd515aee135b905e00bf24bde6c eac/A0060.xml
b8756d6004baeab787d917df261348fdf67596ea3bb11540fd4b7438951beda3 eac/A0061.xml
c1d1eba3f574ed9eb4e74d2e8b22fdc12d7dbf7df6a04502322ecf210835eaae eac/A0062.xml
40d0394332bcbca9ab9df459a69786f75f46f38cee5cccc0cda715dee4e06e8e eac/A0063.xml
dc501ee467ff2bed022c5ad51b0227a98ee0c06966980da23b6ea0fac8e253fc eac/A0064.xml
dd4babb2bfef333007697fe269ed03a1f287694688491e5b25847bc00abc56e2 eac/A0065.xml
7c17886bfa48e7f2695e964a0531a2083402045e9c7c7097be4f92faf656cf25 eac/A0066.xml
63ee60e7b1a9377f05d2ccb88e62fc8cc44be32aefad09d09e6242e12904a0a1 eac/A0067.xml
114ae5e4333e3c6de5f5afe6dcf0b62e2819da4aa055d30b73845cdf476db2a2 eac/A0068.xml
0aeb981caedd0effd61e9f8519ce9ad0f1d24f617abdb299d6896ade576254c0 eac/A0069.xml
a9444783682246fde81818bc0da9ac56aac6d089a1dabd28ebeec029c2bf401e eac/A0070.xml
005a5ddda8dafd11faa381a8fad99bf135c0088937f755d1b0f600edd12e2a6b eac/A0071.xml
53e8879c60e027113a4465d9ba1a227cfd7443cc1f1d617ee25e66006be0baf8 eac/A0072.xml
b38dc9dfb7a6b588523a6878a28a35cece4e89055c105e8785b90ffad486e998 eac/A0073.xml
05474384f9f155904e048d49a5213fa6616fec28f0cc59a6bfb0c47a1db3e8ae eac/A0074.xml
b373901b5090a357cd76a132f654a4697ddfce9f27e377070e69d2333a46b9dc eac/A0075.xml
a82a2dd22063c4cc25aa8d3aa931f39ca72c0f8f4e5e900a5ec821982d26f155 eac/A0076.xml
6ea1d44f9e3ac47b6a805952cceaae05a6d1fbd43c125f145e9f7e8083b1e737 eac/A0077.xml
5c1fe172738846c8e46182a7c50fea7a6239edd74f69ccb18f42efbb23083413 eac/A0078.xml
53d390bf6ff860ea3bb1755e652790eaf706670882a2ad64a8e5f42ecdfd2e87 eac/A0079.xml
2304f7b62aee7834b5acf186d51aa94195649c211ff98a3a50c1fa78af579668 eac/A0080.xml
b49da39ccf64af816505326dcfaee9b91328dfbe722f956c07c9883079ffbf6d eac/A0081.xml
d0a0da81975d03f3e6c8aab3922891e0156311f54e551cc820172060951b2968 eac/A0082.xml
05bd416118dde45a75ce0c99c037a2dcff4e044457f47264c9d9ce0848fbe2a9 eac/A0083.xml
baa1d01e3b12db7291ba96dc19a6ef43d2ea3936d67fa2177e862dfc088c873b eac/A0084.xml
4fe3fcbb9fd74f996ef5918bbb5c60600ce0dee79e3d56cd181596cf5dc89f9e eac/A0085.xml
cdc51006c473423c3754817a9e28e26cfa7813f00b19933ec4c934eb9fa8306a eac/A0086.xml
70148b22c8f6f96ce44ff7dc281b635982bbf98e5375a26c4b7e177c7dcd950b eac/A0087.xml
8ba600191fc8aa88b27f078552c9ab013606b163863cacbf2325fb6c35868029 eac/A0088.xml
7f86f570abbc9c8ce4f8b50d65f3565be244289dc173953b99cff33145c40b44 eac/A0089.xml
c598608ab68d1080f67264db37c909a321d904c554b0c5bb03e130b4c6f16cf8 eac/A0090.xml
c4b55578392a481002752d9592490a090f307b77faf9d8824450a0f8a30deafb eac/A0091.xml
69572e9108619665e97bb4882edf1cc800167e9be517fe16dc72bc0fa56375a7 eac/A0092.xml
d2197cf1331a976a89fb430750a98f4d9b40a473e1ddb3ba2a838f68ff095d16 eac/A0093.xml
dae6e563e04522b07a5f946ad49aa027efb67a622848746dc4ddb6b78b7fb1c6 eac/A0094.xml
c8a7aaaa08bf0cc30c59efb2e8868762a70217fdf734e8fa97de692f92ffd95b eac/A0095.xml
129686baf77c03538d9d63b0f0c3de0bfc570be786d81e4208d731675bb535c1 eac/A0096.xml
962b979f8dd72596b70f799ba4534f8b46abf3ac54d2492f6fa49887ccea5c89 eac/A0097.xml
8977239515b2a1290fda6009c6e7f28361b0bbd1153bf0df927d07cdadd71005 eac/A0098.xml
5cdcc545451c4155a5289200906977301e8266b127ee7b06ffe5c57634d5d8b9 eac/A0099.xml
8e49f772ed7870096e9285e6beec589eec35c9d5ff0a7f0ffadbbd9e98ae7768 eac/A0100.xml
7c86c0c0dd45ef86b0c222cab2f0f1157e162315e7408f937324ed99981f986b eac/A0101.xml
1d94c3a41f9a62a75c06e188d0903ab43a9f97d1e4dfb45b9f24638d483cf959 eac/A0102.xml
b2a4dcbcb08ba7f2119329c530e3bf31c1d1a212b3abb8e98bd08d9bc35e1084 eac/A0103.xml
dfcf14fcf1b67f963ebd62458a9a7d3f1ac67858c822026928220d90a1da11da eac/A0104.xml
2dde7dcf4133349ceeb6e2765e67e5944904611540482b0b810e5e404602f207 eac/A0105.xml
659b29e2a205d1a1cd3fc01d97507455eada083e57be88f15123a7ef720e7687 eac/A0106.xml
549dd6be912ddc38af5e1762a3f237a547f2bb6cbafedfcc6cbea6860b0a41ba eac/A0107.xml
a0efe1f160615a35bc4af44800e32cef9cdfbec65254485fe96a006b851b6182 eac/A0108.xml
929b43643490640dcd80cd98b3befb84b645953a4f32ddce7b509939437e28ce eac/A0109.xml
1d359f2c70cf419ee81bf22d665d1df491efa8be522d44c3a0324cc1b0a47e42 eac/A0110.xml
f818d605efd46406369ef1afe5f431c8197a05c7fc5f6733fafaf5798565db3d eac/A0111.xml
f0ff15abe56b37fd0c2033f4d25a67d54a3e6f2b5e58465c2a3c757ae28c71d7 eac/A0112.xml
1c2247fb87f67de4b4e68ef5e7b8468183e24b199b665090e4102de18a16faae eac/A0113.xml
8767c49ce6e92cc338ec7b3e1dbb79e58001c03f86c4f53b2b669a15957dad6d eac/A0114.xml
e5b1bad94d3f1fd8b37b02fae2c63e95eee2307698fe5c2be231ab51dc0d9a02 eac/A0115.xml
9cc16c681e40c5078e433abb450a6a2bc525ac4603795a573e94646ccf420577 eac/A0116.xml
5bb7038e4600da65c8db168b53b93b39809e75687e85d27475ef1fc66b327858 eac/A0117.xml
53dea4273ca9c8d8a27f6653ce7bef6b7af8deb5d4fe7556a61831ef4ec9305e eac/A0118.xml
3a594651841151fa38c0e4549083aef84f71cbca5c90ebe76b44a7a2f7355f25 eac/A0119.xml
6e385d862248dc5a8e0481c23ed0353ee897382f4c50c6837d93646cab98f936 eac/A0120.xml
7ec0bb6d46e062d3b171ad1474440dd8db516c7c5fd4c1b0f98486cb7c6c90e7 eac/A0121.xml
325234742396eb31d87474a911009876cabd0c2395fcda2569ed68402004613c eac/A0122.xml
2474aac2a872e890fbe2191773f50b26a2225b2f3342dc6d95489d0be6d3b7dc eac/A0123.xml
6380c0dd3a10f7aad9ab2af6a0b297a9c84e511eb27c1f41bb776c4eb8352171 eac/A0124.xml
6c382670c4b6a8ab35e93b33a408f864cace165a29a3e74167a1b8cb0f11c9c3 eac/A0125.xml
1b09d526563f6f7a5815c3f8f77c650e976cb8d56536b8db44767a71da30a266 eac/A0126.xml
6bd9673f7563c37cc39216d618b806116ca870b9f839f887b0a6ca7691d5a54f eac/A0127.xml
0071575022e0c05d4d63c501392f215a59b5018e783823526a417133f25eaef8 eac/A0128.xml
0592724135462bfa5db2185624e0faa756eeded9d23b07c64ca36e4f154719fc eac/A0129.xml
0df3fdfc4b09a44dff11c43ea63f10dfdfedff1bf43533fde792883120b6470b eac/A0130.xml
50f251390509076dbab33f54466d1e6b0166a068f1640a6b86c5f86db0e47862 eac/A0131.xml
a4dcfa9e09a17caade8315b74c6191e111ef45d7e8ff5899331cf7d4a8fad712 eac/A0132.xml
ab8c8184abc4db3742bc4b811e28d212e3dd27f850f5b6a68d1749164543f7a8 eac/A0133.xml
5be7cf8e168d0b8bdd2e139dc794160057b4187c3b9cef9241057a1699204303 eac/A0134.xml
f0d661e1f7849071717b4fec97b0de484fe0bf5cb41473c50c8da415edfc7a09 eac/A0135.xml
dd406cd07c7a7e01d441b1068dacc3e671544d221ee57c74fa2e41b1c93cc80e eac/A0136.xml
d8be1958441da041e2ceb848587fe4d81b2cfa06edc28537d91d9cdf0a6968b5 eac/A0137.xml
ab096ac0f87fe5f7e18a3bbc828d94565b726c101d4337cdbafdcc95962da34d eac/A0138.xml
12dd6d325151580b701dafdd2769cc36252e1fa3c26c4e0254d23a3532a68d2f eac/A0139.xml
7f3b8b6867c1432349c733132b811fd75d89fcc8c278d5ce69a8275d7af8f39b eac/A0140.xml
ec270189a28aa906654fada12a928ec535c26b4811a1002cc997aa6331373ce0 eac/A0141.xml
9e646cb508b7eb97e1e3283dde20ab92f62a14175b77cfed547c9642608a4f68 eac/A0142.xml
6f36bb40920ef389e8a9fadca3d90d950d2313d054621df3165d6a2c0d064066 eac/A0143.xml
34ca8a13fca75d07957c2c06fee8d3e124d76637c425dc460ceadb8cb0d1b2f8 eac/A0144.xml
d2d5b66cf5c278cbb46712f51de65278b80aca3bb39f17fc735163fbf7e489bd eac/A0145.xml
13b6c2bdb00e10a6f0d3e32d65602eb174837547cc4d5cd97a60f9bc084709ae eac/A0146.xml
6d18e884e83fac01eeeaae6d698e5f47d669b5797bd95bb8b1ae4a23eb58a823 eac/A0147.xml
9caabf7b18623f98ff604e5149ffab561216c4c9687c829186b38c15fe3fb0fb eac/A0148.xml
1ff5084ee75fbeb2c8765c32a3a5408b2cb332e1342efbddf65b8b137d148fe9 eac/A0149.xml
75400cd71862530b98515a9d84ad4a233ca49f8fbbe441f1e8cd700b78003483 eac/A0150.xml
ad1d463d8b421c89c4e1f79e331e90e52b1d5cdbe0eee41215a2b377d8b0eb19 eac/A0151.xml
d866ff5258e48ab3c686b243bb3e6ad6542100e65f1dc2e278d819fb150e99d5 eac/A0152.xml
9bc61992ce44df2d21222fdefa3e3115a16d557ca35ce3ebd0e29f4aa7f43d00 eac/A0153.xml
5473260688da7fe8ce65ec52435fcde541b6edb42524f5e46a6ae945d1ec7d15 eac/A0154.xml
aa9b2f28b731929e6051b3dbe08efc48af8d885b4b5537fa65b22c28f263cafb eac/A0155.xml
a13f228f626c8584a56690a219bf966d5180e9aa73318270b3ebb3d9ea4d9b9e eac/A0156.xml
7ffcdf0f4d41a778c8ab3d2e60fd3801c20688008eead562f6a9ea2a8b7705a3 eac/A0157.xml
90f69ab6a261687bcc3f57d73ebd5ea7ecfc5841c7fbb41fc6ed631941d6fd34 eac/A0158.xml
eb2ff76b65fd535593bfdd521c8955013ac6f8221333610c261628d1f33ab0d2 eac/A0159.xml
c3917cb18ddd8afddf375929fce6cf909dda88fe63189003292788430483760d eac/A0160.xml
762af8df0b46233c06eb6fc5be03cfa06d61d024e1b8f327107ed4516dbd008e eac/A0161.xml
1f2af2e0ba19aee333bf4cdaae1bd4c8d66989752da066ab69a8306f440d25df eac/A0162.xml
c6559fe478f4eea639cdaed03fce291593d21fcefc67515f54f0c1e4a18a24ac eac/A0163.xml
400a1763276da9d0f2c9ca13e11c78756dc69870ae8edaafcaad9dfff19c484a eac/A0164.xml
a7e06d2bd0bb32dfa9de3868ae011db96eea639e54c29427488e673e946426ab eac/A0165.xml
e34d2f03b69eddcc1ac4b0ccd27d2ebcd40964c38714bbfa8df642d3b92a6882 eac/A0166.xml
6c9c48f08e7ab1aabff43064783a83f7407cb0d8f056758bd8ea9ad548adfbc7 eac/A0167.xml
ee320134bfdb43560fe62a5dfe8a4bf412464c037520c4cc2cec71a50d9ad811 eac/A0168.xml
7d35353d0a6d802be083892cf61ba676e8cbe17411e84aa72c9df614708e0b6d eac/A0169.xml
4d5a053aa71ca809a917735da6e4e1c1ebff8fc65b2b6073ff4705a0729b437a eac/A0170.xml
dbd002fad2fed02cb6db0819fd011058c7cf54a67e3497155b5329a7eb88457a eac/A0171.xml
05ec83c8b46a511da3b65e91387f0b82379ab803aad14fa1d6b8108f62b4ceb6 eac/A0172.xml
f2d0e2258ffc7a657bc6d8f09369bea7611e9070aa1e19534e5ddd6d290df1e2 eac/A0173.xml
9ab81072e2b49aa3dcabb316f98f141b6d52be5bd0e0a0fbecc8bd04916cb897 eac/A0174.xml
a6d86f9b7d271e57699a18d1019611d4d4e11ac7eb42ffca83e0c8feebbcd32e eac/A0175.xml
2ec611caf3e9f2e215ccc7d1e40fec2035bd79fdccbd455c15a588a34c89e7ae eac/A0176.xml
f9368380b7ac38adecb7942e771e72ed7c40839331019fdf9db2e303693e6c95 eac/A0177.xml
bdc661f2adbfbc753a540b577702e6e2e3a15374714ab9d4e103fcf28b62f8ad eac/A0178.xml
e649dae984355dffa3afdca5827a63c65e6693e03a5d36062b195d76b0eece25 eac/A0179.xml
5b060ec077591800273571692fa42957a6514e28f07769ab72374ebc64971d0b eac/A0180.xml
a7e06790bae89f7c6379deffc51b597a23a8650a58e08bfc8803e5c8274c8b5c eac/A0181.xml
1f0d3da1e033803a74abbca03165ee34ec4710452b3a0fbcebc9c00863bf42e8 eac/A0182.xml
585b5c32b9b6bd5e4768532ad816c24afa468e7fa6de1d10019c47bfac3c7399 eac/A0183.xml
ebc6300720db66a997bc5ae4d9093e364cdfbfc465311651b86c1fceb2ee1d8e eac/A0184.xml
c79268eae9e1860cc54a2e75cb196c827fe2e123b39a8508922528060ffd3e1c eac/A0185.xml
93ffaaf43352918acd61fab5948fbc0efbc2883c52b04a727ac0437a7e0d3341 eac/A0186.xml
922518370d7eab9144f0e9349743bd12fb67afd5149691d034285057bc46a69d eac/A0187.xml
f8c3d31b9b8071c282461fd9f3e0ba40b5bf9318e1df7549551728bfcb8f45dd eac/A0188.xml
a32e230c9ce790bbe7fcb6679af76c5ebf4fa8aac20d4dcaf4a6a931c5dcd39f eac/A0189.xml
fe570ee56e8d5a12b73b7a70734f3c235f3352d3b3d8b724f5ac84c258ad96fb eac/A0190.xml
bb04f1e66d0f2ad779a7be36214bf88cf87e340127794226a8cead4170ede41a eac/A0191.xml
e99988a8f6bf045b21bf95cd347b74ce46f1a651d64e05063d7f248066ca394a eac/A0192.xml
7f36a3071a09f74c5c3513a3b10f61ea7dbe08d592d8e06e040597e3b946e50d eac/A0193.xml
b3b22b6b8ccc31b76d9b188073d6c2d5d71b1274c5e3d3f7c968fc9ca673dd3f eac/A0194.xml
ae69f0c7a777de1ae5b3e8757b740b23c3bc638b0dd58d5f8d1a4a3f00ed9303 eac/A0195.xml
4b777f59c9483a6fe074d19e55bf8ed1f0427462fbd2ccfd34df77825daefed9 eac/A0196.xml
f885d92952524265f00aca3d8047ee85cdf11fe9886fc0eb6e969f729f1f745d eac/A0197.xml
ed129c538834409b21a7eed68ad42c186eca95ce45bfed5bf463470b29048586 eac/A0198.xml
99a1a1e677dbb923fc30079fb6dc23b41d0bd480c64457c601aed139645961fc eac/A0199.xml
69b6b9252ae62897546c4ce415e1088b706aac32054400b97a152d1c52ba9b7f eac/A0200.xml
4b2d3945f368427166963dbab9d7c8229d13c120f5ca1cf7779e41ef128aaeaf eac/A0201.xml
8c265ca44cb42cc279b6fa3144dc9284028d52165c933b7335a80ec3fe764696 eac/A0202.xml
326ae0d174d3c138bd31fa6baa1623790f9febe1485cd6db0c55cded7e7fbb2f eac/A0203.xml
0f24fc920994a7fe23a6df1214bbf0e1fbe35d779499588eb5c6be112282ba77 eac/A0204.xml
8b56d433fc83e9f594913fc285fc31ca2521cff84adead5fe7de74e1ac21c5f1 eac/A0205.xml
b2d842fe7e1a015e3b1f5c3d174cc3fe2a2af24ed35710bfe221c43dfd2cd3e6 eac/A0206.xml
e8cbc956fa882726b46f0b4e1575e9568f620c3c04b2a29aaa9ad130ba5279a8 eac/A0207.xml
06c4232991005de187b2ba9bb3d0d9e2922518de39b0170786763e5594b463e8 eac/A0208.xml
4b278efa127e038000f3a43c532ef350b45a1bf53449a6489420da74b485a2c1 eac/A0209.xml
70fefb0640f6507da7b19f146b218a23897c479c2582c7fc420cd86776a071a7 eac/A0210.xml
dab11d28c74948253dc541583fac9c200cf4a7eabecee2e6d02bde0417631a6f eac/A0211.xml
5c9ee4256487cb71ee2b4598fab1db538ca75860ff9276e1633f6e3d02bf8a46 eac/A0212.xml
89c74d183ab3ccd42af797fd71d3d2b4dc23c14556f7f43b9ead617ce1d98a7a eac/A0213.xml
a4f8a3800658f5cf4c8e66d148d4e6dfcdfeb858deb243301e8d4e31d6587143 eac/A0214.xml
df03f715df57464617c949de691b04f008236cf095d83d7a29771cc01ab3df7e eac/A0215.xml
ef5ec66e3f43594ca2f2ce9c3ce8daa7722589bc93c4e130bc32e374bcbec2bd eac/A0216.xml
5c8ea8a64731db20653e3b9bcc5dba3bc6289eeb6df84b10ff440075bc5d9468 eac/A0217.xml
db8630eb559746d3367c6c175d0925369a793f13c56d0f105a12d3528bef8940 eac/A0218.xml
8fe4ae0364de93d1164358efc11f16912d2ab6c69a5e883aff0cbf685d621b41 eac/A0219.xml
a14de1f984328c250613c4510e4d6035e99578d8a770b47cf4adc022558372b7 eac/A0220.xml
87358dfd08b99e4730ce03ddb9ac592f7e1bec611ec251af7429f37154603d10 eac/A0221.xml
dc7b7317040a10991ab0b9bd7e2f98c4397a79615c3e15103c54e2207301ab3d eac/A0222.xml
ba9eeb4021d0461328d65bbc07b9734069a21befd90d1f0207a23136903354cb eac/A0223.xml
b84adfc57c82cef75e83c9ff507c6fe0c2f907d197336bdcd919b2412a9b58c9 eac/A0224.xml
533899727132a2fb83ae19a84d73e21f764f0d54a0cec4ea2e7bed8628d6c203 eac/A0225.xml
46f48a5b334737448e6acc894145701ac9ec0ae8d627aa188cf913475368c44c eac/A0226.xml
61b3ea9522a51a4b6cc435b9596cd884ca53aa56149d35d1fc49ad0d2eaaf345 eac/A0227.xml
7ef9d7e79aab781ea9c47b5e06d96ad4c9bdc41e7fb38c4a6eab0d5c5cd98702 eac/A0228.xml
a14f6d43d6efb72196aba1a31b5cc77b83e811cd105bfea6e42ab507558d96c9 eac/A0229.xml
8594bfcf5047dc5ad6973d5220a53dbace5f412262f6e75d93e0a193eab3a0c5 eac/A0230.xml
39051c392250d95019f79f89696205b9242bddc6ca54776d3c3505fb7053680f eac/A0231.xml
16900adca87c78fd0dd12dc3ec3585541d2d50905df8df1d2a9639742c8a00f6 eac/A0232.xml
001ad187965a7c530903b4615889392e20b30ed1f6a9edacb3275677d2cb13ac eac/A0233.xml
caefc94b181c6998f8bf4bfa91f36b21fbe67396a3f67731c4bc542d60bead1d eac/A0234.xml
3b039daac834511fb0649f7e1b3a97f4d13215522d674b4c5c7ae58eded92b29 eac/A0235.xml
6e3632dcbfcebef5ccd72442ec51eda5583472fd6e76791ad48066b1b184029c eac/A0236.xml
ba7a62fa5f74d5dd8b426d5d33693cbcbd25b814e728f314b76ac5b8ebea079d eac/A0237.xml
c8f40845cab954f9d3b4fdd06236c37b7f8d6253e1df00aa92fb3424fcbef5a9 eac/A0238.xml
87e7cb5b34a1d646acbd824a47c7aadfef14279bc159bb55fefba60d3ce1a73b eac/A0239.xml
bf53c91fa2420c319d35e2864b8e9d6e8f2e6180fdac88a9f176e20c06691095 eac/A0240.xml
fe71bc720a6e6bc2c88c3fd19df7b5248bd4f35f3afb254fb63e93d394c63802 eac/A0241.xml
2e9cddefb67c3c627fc3817784873e0a522e00ae2caf62145b2dd35d6361ef46 eac/A0242.xml
751e569b396969000f04e0a55b1df517b86ccc34007d202bc004c11390e4e080 eac/A0243.xml
9f98dc3577d9a71c870525be9ab3cf776e3e775c7f0238b74d94bc43d6dc7a87 eac/A0244.xml
153859d6a1b1042153bf23905c055478bba9c7cc09f7ffb6b23fb1f3d291d27b eac/A0245.xml
30bfd93d82ac052b0e41504ecfebae3059665ee332e2c975ebf9b060b2bf4b8d eac/A0246.xml
9fc08ab9584e16ec850b94d32f3da5cc59def9d397d279c0d0689352959d0de5 eac/A0247.xml
bfd561f3f51eaa2fa416ce50eb142f3ad385d6bda5aa6b802fdf2d2722faa732 eac/A0248.xml
f4bc3267aa73663badf5d77b69c48e0f66ebfce4c411a51ef6c20f077435b683 eac/A0249.xml
6650738e9f3681d56b0fd710462f03cf01d4aed04a079593e4dbf01fe8a479b9 eac/A0250.xml
6ce47a57c34429f3b9fa668a0d10975094ea39b97a03bfa5efd2d14103a81a1b eac/A0251.xml
35be8563dc86c936935bce42d25c0214f3c683af6f2eb9d1f75e9eeb259dd734 eac/A0252.xml
32b265bf33adae27ed0f0cdbb9674dd755c0e36b00c9ac1a715ce66fc4d51700 eac/A0253.xml
96bb06f21f66aba929c801a1739951a097ca33919387363cca154aa0279d7806 eac/A0254.xml
182e2d380442e1235440acf60213e4479b5e5d2de0cbcb2fefa59462669109e8 eac/A0255.xml
57512e09f4e7e4f2cc5e5ddcd0494c926fa3cba8b76c737a77708603e55ae366 eac/A0256.xml
11bfe51b406d94f71ae80743a44ea46903e5d34e1bcb8eb9c310ebc121593227 eac/A0257.xml
b486cc1b61658f86283de957365eb72e8298bc1142a8738aefeb50503b65db77 eac/A0258.xml
94ae3a4eb81bbb567a0f7c132a58b93f09b0db0e2e46e1de6bb9ca6b0c9af493 eac/A0259.xml
8ce3d11c221887950e558d680f25d3f07975eae8be2c7236b36bfea993d7864c eac/A0260.xml
371ff65ed7aa2aa5ad0e7b7a88d4dc89cc1f0dae218631764f238cf086fcb88a eac/A0261.xml
b726e1b2b63ab221f5992cd47ef1985889325a31297613e9b98e83e2ce37b5f6 eac/A0262.xml
a0bae5b17b1aae991bf5f971249da4c10380e850b9009ce3973ef37f238a61fe eac/A0263.xml
ee0def79c5f1c21cf1f2e0587705c7ae5fb5b055d887461c8bd08b95a420c71e eac/A0264.xml
f6ef14174ad38884c3c9ec5681db1b82f33c8e18b8cb0462735b7ca0bcbfbb07 eac/A0265.xml
8efe0b6ac1ef90eec1483682ab98896144225ed98c411fd731a95a039da9c654 eac/A0266.xml
a0e015c7ad54fd27dbeb653582add426a3e7a2cb1f20d9827f9b711eedbc221b eac/A0267.xml
7e90805f8f2a94f42c40803c241d31c2553c623558ebfc0ec07d82e8ac5b4ca2 eac/A0268.xml
92dd408f2b7bfe95d06763ecb1563e016adc4540206491e2c62fb3637310e41d eac/A0269.xml
69abfcc3f63eb0b55d639b2367e4bb06dc178435c48347d87ac8119cfbf4f6fa eac/A0270.xml
a5b9cf6c7eb0c2b59566fd195cd79d4e2a6c8d9a7295c082444d43de81812973 eac/A0271.xml
9ea646cd49ca4743bba3a875d2a2c1e216b66bd996e0bd6d06cfa1a057847baf eac/A0272.xml
60597b6693a3d7833f8082f221d5b4bc1fd67965c5d5b70a4a7638600261a7d2 eac/A0273.xml
1d413fd73a195197f788d48b6c141fc2a289b0844e52dbc83cc4772856095859 eac/A0274.xml
d5019a0f560ce5b4357673710a01815898a16fe05100ca91e886e5b9f09d5163 eac/A0275.xml
3caedb05b892917fd32ca4031c6be2123b36b4cedb13fdf5e916b74109a79263 eac/A0276.xml
1c75004884c1c4b479ab0d675d954f6f2705b816b515f5de211e91ab0942f4cf eac/A0277.xml
fa87c6fa5729b75f167bd93d7a9835bf9a4e0e1ece314ef40e2f9d22b7a3dfbe eac/A0278.xml
6ead7753f6d47a6fdb082916a04d1029f790b3766f6ae7e81ac09a6b9a0b9b09 eac/A0279.xml
ae996dd3e94ee297c5f0ec185058ea536be2f3bf2e03143466e5807d6d1a68d0 eac/A0280.xml
0c28f602696e060c606b9a3c7e92dc1ae11631d123bc66128676c44cc421ba49 eac/A0281.xml
fe08ec4469a0e1a5aed8848f723d1db7e8116c45c80af38244aaa26c10272dcc eac/A0282.xml
c5af6c6a63aeee9b1bdfcbf384251be0652a99277522b15964a49c5413450359 eac/A0283.xml
fc260d3d6683bdc0fba827a60c2eab8edc6a0976afe4ea3f240217079e737c1c eac/A0284.xml
45ab5dd2a8315e06b30e1cd83155dec566f6869a5b1281e252e896646eab2fe4 eac/A0285.xml
86f0ac6c88d218f11e1e1a4aa61381f51e0af3ae3c4424ee06606d38f6f2998a eac/A0286.xml
0d080727d202d2215292be15ffb4fd1d2fa89a615b130e50a1a2764173ef13bd eac/A0287.xml
57a4938d2903ff7fab7ba0fe3af60fecbdbacd6e92d85c43e42f6b4ed613a7a5 eac/A0288.xml
e2c734f2cdeb346946a00b862c355329839d1de41a8b42b899ed582132982a48 eac/A0289.xml
ec011b7fb6632e7a04a23df246e0d1e5902bae47e58ba5055f43f854e06d773c eac/A0290.xml
56134c7fb994edce3d595a275374f1b9128186d588375aeece7b2fa8acdbf79c eac/A0291.xml
eff30050c6f93d7312be5cad040eb11d1ac571afd9793d80cfd76df16f87dbb3 eac/A0292.xml
23feb5106c7874ec7c8e79b1b0d3f50f67af44c5f004fdb639f6d5eb46ebb6dd eac/A0293.xml
9d03edb2cfb0a8bed8c4dca2f7c85e151dd7eb78526962d88643bd8bf918b043 eac/A0294.xml
f7338a8a81b7aff332b145af2fd953fda92a3aa19c6dc698aa34718c8bc324c5 eac/A0295.xml
3daa8e3553e0e56f7e78a21786d01364234cd1cbfda74aee693e401c439f598f eac/A0296.xml
58129057e117438a6093b3a4000fd7f5c6be73863de80308c9419eeeb01bcd0e eac/A0297.xml
6d6284e999e2d612bd003b08854b6fd72a968ba5d49f77ff584262e7e28dde17 eac/A0298.xml
a18f2f5a5f2d4dc7a808ff61ff242e37b246744c2b626c1c903a0ec069c31df9 eac/A0299.xml
4882d1a5cfc1d5b1e374f270118cf57975f0131fae71be8b7c33cac4b49897d7 eac/A0300.xml
29a03a5fef30c7b8c74d44529bf2f526a0f88b5c40da799bd28d32d8f36d28dc eac/A0301.xml
6c9c2a6e2f2ca97f511cff2440db221a03ae6cddf70c3d91d9ee27fe75164de2 eac/A0302.xml
03c786c1f3d5d9165adafa4a58530ceb391b84966bc1ccbe812b54b6b9bcdbdd eac/A0303.xml
ee33d22b0790d6f51eebbd0b0290a4383e83b7a43aceb79a36a09bc87b0de22a eac/A0304.xml
c0a3b3cfd44dc5d2047a390a6a5bc78230aa9df3691e5376284283761154b351 eac/A0305.xml
afd9e0a171f86fae070e48bac931cac014001c94d22b7986a31227116ac92088 eac/A0306.xml
d90e64ee3111625ef3fd3e792f6d4b7d9f4ad3c4e6037c22a6bd18aca5d5a16b eac/A0307.xml
013b5ee74db7a7a60be9b94f1c34b9d31a0924fdc274a63d3a041c3336ef4810 eac/A0308.xml
93913e303b8ba880233f6d785e127f1424df5c7957dbf2258302ebb3c92ae00e eac/A0309.xml
8f4b6ad8052f8cc4eb625495f86d40b390e5e4b56c802b7b3b2360476166df63 eac/A0310.xml
764822761bc9cb243837e45d3c992dacfeaab40095fd0af970267bd9664cf409 eac/A0311.xml
22ffc394d9e891bb0433cf1879d727c45f651c8c0575250d571f58efba686f0d eac/A0312.xml
eb9eaeb0a66973df05133f9d202b8b7e53adfb2fff775e32b0d01e3b94a6b4df eac/A0313.xml
f30634c531f76a6e32c69024412c5b381f9a27598800cc757a75d99576302276 eac/A0314.xml
43d4a34d6caab504d999225bfa9f598bc84e600aa792e35b51e7d959ab027baa eac/A0315.xml
8f592dec4ecdefcf2f28b58193a71989934d010b9a0e9162998f6fe4ea58281a eac/A0316.xml
237bf855bfeda448efc21d89b6354ef18f07b1f4fea53d97fdd79af13402c498 eac/A0317.xml
1adbf32acf97084d2376fd81514fa3f00a49eb37a506b187f623b3b55eedf651 eac/A0318.xml
7af619468d39e30573f8c3699b2193844a5fc3a0b63956f804a1d997316a34be eac/A0319.xml
a1c6a0df50e35f7cc2c39325b79f48f4846f30dc531a31d4ee66376f5c227e1a eac/A0320.xml
edba2564d8856ffc9997b955c38f989fcae267e5a1e4c9e6ddf02f21714c81a1 eac/A0321.xml
21a8c05ff617d8079296f6fbf1e296cf14cde386182632fe58da941e853dc849 eac/A0322.xml
19896ba8342d4dce7e3292a5748c403fdf293a3a9b176e183682fd8f934408e6 eac/A0323.xml
d308d93493870047b3714edb57f18e05c20e7803f417057f20a44688da143402 eac/A0324.xml
f08f6e7595e5dcc5becd1180a11110b119281631139adfdbfe92e4ab42349d27 eac/A0325.xml
d1661c7b5fadb2beb25ed0aaeb35d32a7c760a0ccc86359b56afea1480864f43 eac/A0326.xml
037656a0e3aa4f0da9a8238b4cbe6cb17b0320a6308f17e24f6189945fa3cd16 eac/A0327.xml
431d0a6aa9c6400e88976e3bc1071343203c9f5efc357883453ed7b8eb5adc74 eac/A0328.xml
86746b12e12597356cb15942e5b9883fd2bcb0f9194d99dcb4f55c1d0b8ebb59 eac/A0329.xml
02eb468273e370520e9e1f86d5dc81bb77073a2d9d05d3b9b26e287ee98daa9c eac/A0330.xml
a8e73e11210eb92f351659df564611815b3d07b3d8c3d7b199fce29c63d8e806 eac/A0331.xml
ce6130aca471a01895f2e3c62bbb517a5f476621143b882a091a446276f7d66d eac/A0332.xml
7411ca2ac55ac04a92d2ad5e37e347cada4fbd9e4f5345b0b993c2680af35065 eac/A0333.xml
91413b7005a2e504cba0fab927fd079eee91df7885c98426c17786eb23b4e392 eac/A0334.xml
c951fe176deb9f7bb5fa0cfb3a74280a6a4160f55c42e8a69f69a712c8e0c062 eac/A0335.xml
afe6369c7a8c235fdf55aad1fbcd37129b34437ec01ebce54408cb876786f56e eac/A0336.xml
0e935f9621cdfb9e50b6aa46919d65a435860ae753c354a5bec3dee3a89385f8 eac/A0337.xml
d4f51337b6eb0ae08519178dc7d49431c780b26c8786a7d198f90fa9fdb834bf eac/A0338.xml
6477d8ea256e2e8b7218eb72345e3b2598dc03132b195519498bd14470515c78 eac/A0339.xml
7b1ae2ae02305001ae07ffe4713742781d4da4455009b58aa6fb695c0f248067 eac/A0340.xml
feb324d3177ed415c18608b06bde826cd12195b1cade4c31b2de04d1bcf71220 eac/A0341.xml
4113be5f0be1c9bb162c007c1df58934ff27f6f6360ec2938723af4fd1578113 eac/A0342.xml
e997d5bf965f848c7f08a8df4994ff621fc478fd6ee8a930e521b1b89ddf4a83 eac/A0343.xml
b90232343acdd716c5e0edb0ec2799d22848cfbf7bb4daadb8568d76ebedaa18 eac/A0344.xml
4ed307daee8213d095e3ce7463e753f931efcc5d462b3daa13268914bc30e253 eac/A0345.xml
17c37c894ca1a21a055bd9e549d527832bcca58f18521c2db4665f9306805b4a eac/A0346.xml
3f4ff50d89e236f6037a44a64b764a4843f81dfc50588d4c2885664045918992 eac/A0347.xml
44352bf566cc4c87260ff8e5fff462bca826924a25ab4538601986f33f82a40b eac/A0348.xml
f632fcfb4d8da879c38818bcb26cd8bc73946bb6234b42e66643c16f605a3c67 eac/A0349.xml
da7ed672359e88d0b0f5f312f8b787fa1e8f48d40d185f118fff10955c4633b4 eac/A0350.xml
4d9c1ca37d96b2d7336a10fba50ac5c9337cd1a3a4d9bc77fb0c4655b7c11a2e eac/A0351.xml
a711bc5dd0238f51e4be5c895a35f7e58f8ba76bbf8545739720d8365267105f eac/A0352.xml
4ba7ad94780ec791a5b593894961e7f81ee03a24f493d94e537c121abf2449a6 eac/A0353.xml
94a1b3772f17527cba09a903122190e41212df4201fcd17a591b49b350ee340c eac/A0354.xml
919fc443bbf4dfc96c87ee6af9998602cb1de5a6cdf6ab943488f024f1561a68 eac/A0355.xml
b9972a482d11230fcd5b4d9f518ca3cda7629491bcce54914ced6d6d9f7ac1f5 eac/A0356.xml
78dc5cf392f8c5b7c9f9364a5397b6888ef43c24de4c686e99e3da76afff5397 eac/A0357.xml
1101dceb29a3f58dec259669bac700b73e37f1b23bf1312642440bdba4ebba61 eac/A0358.xml
959209a6ea0a4621b3380ab08041cf503af3c16b1dc54d804b93602f96f90476 eac/A0359.xml
53bca05e843fc2b4cbe45b430728d0946e1322d7f010cc8b6743953e573e7b1b eac/A0360.xml
007d9968905155584a3d6e878750e64ae243d491957bc5c8dd52663acdd3e97f eac/A0361.xml
d7492363628c296d1a602df17d06b002f3fdd9471e8cd73927d5ae9e9e65be71 eac/A0362.xml
40ef37f13aadffd7343bc5c8408da823902980c13daec8f662da65899c95f9c0 eac/A0363.xml
77f20d3fdb8a378790034954917e39c4c1404f5495c2bd4952a8f9ba8bc35536 eac/A0364.xml
b05bf0921847c6aa12bb37de648b165fa6b8d78454fb046b62e114b84300a870 eac/A0365.xml
40667ded678105c73dc3746cbeb35422f12f8cea4cb510b58821e5b69250cf1a eac/A0366.xml
c53edfe5c922386814a3545cc4abecb153348492a62d7da94f69fe4f4b9d4c8a eac/A0367.xml
d302169330fa7825731d7e4796b3dd2ed536943085fbe72af06266366592cb0e eac/A0368.xml
27218983d35cd5ccc4368c1a63fc5aa10954476122f29a32da802ff6e1b84c21 eac/A0369.xml
ccb60f98df45aebdc89b9b6af9c472cd731ee2a6e4d2147a0de74e808c4ecaac eac/A0370.xml
c8e34a1d0476093cd6aebb836e2be81d7b0653106462922a51b2560d8186f28a eac/A0371.xml
90821027d163c00b55b7ed3d557df0039a4fe5d0131ef035350f6085b16e0802 eac/A0372.xml
03e2dc29a2b32b7c79b72a8bde95fc095595f3f084c2545503b2f29faa278bec eac/A0373.xml
f4f31c9ff9f36aa9246c3f5bb4b7832992f26613baabb8f3a386f204c724ea1c eac/A0374.xml
cc986343e36216d5a7cf29e90ffd7b03c4ae3ae56b5dac4629e8c05123a64f94 eac/A0375.xml
2c41e870c4abe6930e63c9ab44a6f59c079f26287d1f678bef34e01d8f90ccf9 eac/A0376.xml
50efe6d2c042f86d254130dc9c67e96149f28a626dd95d5eddb6badc9aeb7bed eac/A0377.xml
226c98b9297aff87164770dec470052bfd20ef02050bb715bbc61af5e284c291 eac/A0378.xml
434f874229a75ea9a5b2e295397371920fc1fd3bb833da602da6e52af588a753 eac/A0379.xml
a3e03fb4f5ab4ff84693e850732f7832fb7b794df818ef789bbe256693a4d16c eac/A0380.xml
94fbd5ebe1a5162293889e24a54c99324d07904bb44f6aff3dedccac557e516e eac/A0381.xml
834755af56d10bf559eb3ccb38eae8c7f87efaa827e7ddf752ddd16323da2666 eac/A0382.xml
d0be5e85151157636cf511e298d8f019a6b107c05a43e90e88236aea094a8521 eac/A0383.xml
5d45048d91d83fe8b2069841a41983c4a3e30a1229bbf39650fd7d658e247b81 eac/A0384.xml
2c845eb0d9455e17da76aa1525b7d08c958f55836150cb962296c448eaae72ed eac/A0385.xml
2e8bbd4d66299ccc2c07e4f007a2735ffefb7c2dc05afaf8ea1b2f5a14240811 eac/A0386.xml
2c3fbb6972a69f45a239378ca5c052802dc982a6102657adac056c2b49578ea7 eac/A0387.xml
20cbd3d226fea5c7600d383ad4b4f6c9e2fb759b4c4228bf8980ac4e5c6b39a8 eac/A0388.xml
dc30a80d541360d724e70a459bd4095a03b5b4331736e03f85c83f283c403550 eac/A0389.xml
7636614f29f56f65e26db2cd6c438c72d467d9f6d3de047f607db9abc41aa7ca eac/A0390.xml
2209bc4a36c56ab6c30d31d63cf00c36ce68d46bd52a597f9d557e116dd0946b eac/A0391.xml
2ff20ec878a705387c3498f32ba98713f6c50ec8e7d9ede34875ee788ae63b01 eac/A0392.xml
5e3e1bfa3320347cc622c8d986bece872110769cc08ea53c99aa3b159588cc1f eac/A0393.xml
dd930f82663ffe63e5c1288029fdc89010aee46f821c86781bfe85736b211a0c eac/A0394.xml
b4b362f1b5e516f049ed8b6c56d55066e79c88f706892fbd005333407bb0fb1d eac/A0395.xml
b8a6dd7d5f2b1e5074aa4fcb31bcfdc2edc6d0741f4f3b89b121ea576f7a6227 eac/A0396.xml
08c27c797ad1facab3496a2c83f3f162356f1ee23dbb4f380174c1a40844f461 eac/A0397.xml
f68db1fa4198a7bfdf6759856eb42265a32fee88230bd7491815061017221e05 eac/A0398.xml
117ba7921c1667491ac6531904b5e699438395c08c99dc8bb1bf597705d25958 eac/A0399.xml
a2b3bed0b05bc1db7277f8bf65c8a39fdad377c337080edb239fab1efa18e7ab eac/A0400.xml
c2aace9fc9aa8268629394feedd32ec914e62709d53be22d28697f7326dc198c eac/A0401.xml
c1427441bba9983c213f85c4227b1db54b8df087a4062026ba0e1ce525d10a52 eac/A0402.xml
39838c383b2939f819ef4bbc070b0f46e5a78ab7a088278e2f0ba21352abc79f eac/A0403.xml
f2b4e86ceb99abc389701a50a43c9c72de4901fcb54d57dc356bea81cc99aff3 eac/A0404.xml
56db4613cd464d5a1092bb8538ee659924b014734d16d5bafca4a97344754b4b eac/A0405.xml
7a2d20e6a552605485ddf82b4b21509832144c1ee13957e8417654ae58a04b72 eac/A0406.xml
50d0508b238da878f66050c8b91d9aaee2de9beb19e9eb86e89e73002c9ba959 eac/A0407.xml
dadbdb79e0bf5defb5270d363dc095af0c91a7e6a956a70026621ce624022191 eac/A0408.xml
99ad02334d3713e40e75c1d0a5f7c7aed6ebb66ce9a7d8dff703d44c9bf4735b eac/A0409.xml
2137962b3e782b24ea07915223ff7cb2ae643fdfbb6688969a84de54e169cf35 eac/A0410.xml
568734ab02ac824be10aa53ecb32576399c98ec0ae17865056c6f4df5dbe35e9 eac/A0411.xml
2d7d197c18d12fe513b1c31b6d1d430ad3806afd237c371259fadc25645f3c02 eac/A0412.xml
b98f1c592f0b0ad8b2c8a38d09d171e895f078b0df7106a7f5bdd95a208dc3d8 eac/A0413.xml
c460af5e1136dba563209a158e89c0962172c15fd74de6a3045c81a201b450ba eac/A0414.xml
20ef90154406d11b4b187c45da1ee130e085746eb4e3168f17added9f6d7dbb5 eac/A0415.xml
52cf334e53d4152533016ae1e0a6de71c98496cf786e28d368fca574df23dfca eac/A0416.xml
3458d185825af16e2efc29bb49cf0c37b55f6989d3fdd8848d0c1ed60e5aa694 eac/A0417.xml
b7841ea4b9133b02f9556253996e249400dd2bce7b1f047c0d2cd410b08534c7 eac/A0418.xml
beb9afc4d6c9cec06f359aa43b12d9590232c76866af37580caad9ae9ee33efa eac/A0419.xml
e1ce49ce3b25dc970780d3362a866e9c6485f4ccc0148626d2ddf571f8ba6a8c eac/A0420.xml
c67ef8032802113d8a76152357669e1c3ae568c40e3e7c9292f0b94a3a01937a eac/A0421.xml
4b1f29efbb8ba211a6faf9a180fbddb3cb910dfa12b080dc459efd3a3d312c9e eac/A0422.xml
efb30cf8b80c5fc1d133d454e8511f9ef95971bcbb6aa6aaf1fdc05b0ab6ab48 eac/A0423.xml
afa3c910d9ab61458dadaaebf68e5527e7570dd5c7623cd405f2163c1f934534 eac/A0424.xml
ed6aeb93a67059bc9e6cc3106b0fd89ccd6b48daf06e921c7624b7212f076114 eac/A0425.xml
48f30bfc8ac943429c680cf2310e04f88df6322469001029e5a70a74f71cb045 eac/A0426.xml
14ec6f32eef0c7042ece5f98a2e13f50a0f8161419eafd9b3606008783393f2d eac/A0427.xml
d0855de994fd25ccb1108f36b1ff74efa48ec06b0f124231cdd17faa5ece9901 eac/A0428.xml
6b1e29d28f5b6001dda4f888e94c1aba871299d732a1df484c76a6a7d9d698fb eac/A0429.xml
c7bac29b28785f67a089eb954bb41dd31976813473992f51140aad059dfe3d8c eac/A0430.xml
eb3952e28d2437c0aa93809ae6e963b8a8f2955fcfc068a9cfdc53ffd859e89a eac/A0431.xml
2bc50430befc8bb0761aa4263f4e74d8719fded4476ca17e1042d80ad22410f9 eac/A0432.xml
0b5e46abd5c8d5b8257d87151395797accd8e322336b9c5f2a815832ef934cb7 eac/A0433.xml
cb2da8f30162e3af7bc49dfdbb7669b04fe986ae6ee2bd9caaedb7b05001539b eac/A0434.xml
1e74d8778be20067b07a35013f436d85be05f6803873033a3e65aea2426a731e eac/A0435.xml
95ece03f1f9d1b393a9c7e344ac1f6cb88ae981b888879c25756165869bc992e eac/A0436.xml
7df0e7b4e464c771bbad04197878bbfcf4cf96a47595624ef8b8512f3e83533a eac/A0437.xml
b56ae0760f946235bb4037253bf1e18ea4bc1a954c8d7540fcfeab9b5e32958b eac/A0438.xml
d620f76246bd8ac5c26b665ca86e586e41a535805939ef30a10aa75f1a675d12 eac/A0439.xml
e16a170a184f16a449df38517e4a33eec04a9fab9333cdc01bcf03cfd61d0361 eac/A0440.xml
9b97995fdbd6d7d2e2ed0ef617f2cb86b6879ba48f4c6dc414e09805cfa4f8f8 eac/A0441.xml
677973d5809c61cb0c4521bd7eba7c53725796856d3af943c859f9e7a85433e1 eac/A0442.xml
b0007b28de67301c9abe089b3c0dab40f4e63bf88120db18cd1f26e877a1141b eac/A0443.xml
6b14948d4df37799fd37d2daae8eb0a498a25f65a5ae03953187b7e6dbeceae0 eac/A0444.xml
5800c2320943b24736a67d54d061c641a33176470f5f71e5db172162270cb702 eac/A0445.xml
6ce101976a0457f1ff004330af419d3f135f0cd761eddea7af61b26ca9d6942c eac/A0446.xml
012a0e7bddab3005e21bfa4306730912db9b6af249bd943d725cd3e37add545d eac/A0447.xml
a2470062845575e6a142fe97ce6cca5ade4f83fa79b45b52677acad836269309 eac/A0448.xml
6aee58b3091073ad8b5e5bd302b0f583ab4b7f8c92efd71dfdace539c2a3a9d5 eac/A0449.xml
8fc906eaa868911b27a21247e4a024156e70316f464e6fb8a89569e331a72123 eac/A0450.xml
d05e529ade6987a7bb60df5419b099e0619a13a038c9ed05b6b0519e612d6595 eac/A0451.xml
86b51144ab5aa22a3bb709cccb840df525aeed7b9653ff6fbab7ed942baf2687 eac/A0452.xml
1e16c4c726b3f8aab0ae219a9a5164ebd1cb7e93e2d640748a9159e2c9916e82 eac/A0453.xml
6cc6a202ca88768a5946a74b48df3fca7017fe853af86d51e5eeb8b58592f86d eac/A0454.xml
066dd8b48e1612386f93b33183caaa2dd387f8e72ddc84c86d87093cffd085bb eac/A0455.xml
97fe687cbaec1c3987b984ce61fb787169cb9997ea4b597ee6fc4b8e484d8a66 eac/A0456.xml
6482b25f8c2631ed31f827f3f8acd871614cd0fc008d586b28ba95c1798920d9 eac/A0457.xml
e0c8f3f0f7713c1239d183cef778dcde3f96ff48dc370c67513d154a352a4eba ead/brasiliana.xml
5bc0542527635f05919b6f57e472718c2bedb2994498220a1d917c558f7203e4 pendencias.md
c4d30ecdfd127a7b34c247bb57cfb10242da6ffa140eef5013db7ec74efdfca7 revisao/autoridades.tsv
56a8978ab5cc52df68bd4e30a4dab483eac972912dddbe64442fa0d4ca3f350c revisao/datas.tsv
268b2362d57babef293560d61a2e031e15fa9d9202f40044778fcea8a00c57df revisao/direitos.tsv
0093242ac6f547c0ed633b2d2f4d32ec3f3b6ae6e7cca4afa18249a71f71f051 revisao/lugares.tsv
0a978246210a87fc9385c3fa0e2e96bc191487c3c02b4c2231d59bcf93376718 revisao/series.tsv
cda085160c795301cc97a55e381abc9085f4027976aec15ca4400a365f67cd83 revisao/tipos.tsv
2012587acb206b9edb58c647379ad2e3582487897721a479bae520acb62f01ea textos/nivel0.md
d4bdd7d0e90fbf10ef5d11a61e0fad972e5d50268ea3ea97294d6f63cc836852 textos/nivel1.md
82bbd86d09ca69a417324940b4c7265e92996b0a354cccbc206e91539348dbce textos/secoes/AGCRJ.md
6e9cad01f816ff0e507467f7aa9171ee567c77175fc99193818fc20a7319ea35 textos/secoes/AN.md
6973f5a42cc3485fb53394698fed4be222303e5311ef29ca1c413ed32368f7d9 textos/secoes/BN.md
b2ab4ee61c96f3c6abd603fe95e1325fad7f290febfe97e39e26bd2a29f7407d textos/secoes/COC.md
797d5775051788b82c5fb8b4ada1a010749f21685be7f661e43b5fb81a8f0309 textos/secoes/CPDOC.md
0023b53f1ca888aa89662724bf9182fbc806e3cfa9875a4d019f5a1a9dc97171 textos/secoes/DPHDM.md
975efd53ac3e706540e6ae515589fdb073e4a43115188e9152c9474ff55d0d7d textos/secoes/FUNDAJ.md
efcd5661677821588c4c5622325d050e9366907c39acb4e4f6f5a8f6d2d5ad3c textos/secoes/IBGE.md
de58b8673ef680d172e028fcf26c2620dcb1781795c29b2fb50c672158d36901 textos/secoes/IFL.md
378d70a46f3b50e8ca49306b93d7a8ebdf376de6e2f6db200f2f22b720b6f50d textos/secoes/IHGB.md
4255ecaaa03baa127a63e1e46f55996e58f934d27872fefa9e9ec87436649eed textos/secoes/IMS.md
0fcdd6db33d7de7e9e685f121eb2a0af629152acc6c485181055c68bbac2ebf7 textos/secoes/MHN.md
2f11cb16d8ee5dde33bcdadc1fbe5ceb6fa4aad788a56dc0146c91a5628a4e5d textos/secoes/MPEG.md
8853b38627ecd667de1ae7f415cb7aee0b67b23a4fedf9086117bea62c329656 textos/secoes/MR.md
63b8f31662c88350e60f9268eee98742a617034345ba29eecd9852e852d6a6f0 textos/secoes/MUSAL.md
e8d811090e186ecbc41f274ddffff6a16e0e395b895937b2f5bb56b1922ac12e textos/series/README.md
d8592bb9edf515b543be6ec8617330dff8906d5aecfc8fcdaa246cbe2e7da771 unidades.jsonl
+65
View File
@@ -0,0 +1,65 @@
# Pedido de código de entidade custodiadora (CODEARQ) ao CONARQ
> Rascunho para a tarefa 0.2 do `tasks/PLANO.md`. **Nada foi enviado.** O
> envio é feito por quem responde pela entidade, pelo formulário oficial.
> Campos `[[…]]` ficam a preencher.
## Como funciona
- O **CODEARQ** é o código que o CONARQ atribui a cada entidade que guarda
acervo arquivístico no Brasil. É a parte "entidade custodiadora" do código de
referência da NOBRADE (proc. 1.1.1), como em `BR RJAGCRJ` ou `BR RJIHGB`.
- O cadastro foi instituído pela **Resolução CONARQ nº 28, de 17 de fevereiro
de 2009**. A mesma resolução recomenda a adoção da NOBRADE.
- **Quem pode se cadastrar:** entidades que custodiam acervo arquivístico e
dão algum acesso público a ele, mesmo com restrições.
- **Como pedir:** pelo formulário eletrônico
<https://www.gov.br/conarq/pt-br/servicos-1/formulario-para-cadastro-de-entidade-custodiadora>.
Depois de cadastrada, a entidade aparece na consulta pública por UF:
<https://www.gov.br/conarq/pt-br/servicos-1/consulta-as-entidades-custodiadoras-de-acervos-arquivisticos-cadastradas>.
**Ponto de atenção:** esta é uma coleção de *cópias digitais*; os originais
estão nas 15 instituições de origem. O cadastro pede acervo arquivístico
custodiado com acesso ao público. Vale deixar isso explícito na caracterização
do acervo, abaixo, e aceitar que o CONARQ pode entender que o caso não se
enquadra. Se não se enquadrar, o código `BR RJXYZ` continua provisório e a
descrição segue válida internamente.
## Respostas para o formulário
Os rótulos são os do formulário oficial, na mesma ordem.
| Campo | Resposta proposta |
|---|---|
| Sigla da Instituição | `[[sigla, 2–10 letras, ex. XYZ]]`. O código resultante segue o padrão UF+sigla, ex. `BR RJXYZ` |
| Nome da Instituição | `[[nome da entidade]]` |
| Endereço | `[[endereço]]` |
| Cidade | `[[cidade]]` |
| Estado | `[[UF]]` |
| CEP | `[[CEP]]` |
| Telefone | `[[telefone]]` |
| Seu endereço de e-mail | `[[e-mail]]` |
| URL | https://xn--2dk.xyz/brasiliana/ |
| Ano de criação | 2026 |
| Vinculação Administrativa | `[[ex.: entidade privada sem vínculo com a administração pública]]` |
| Missão Institucional | Preservar e dar acesso a cópias digitais íntegras, com procedência e checksums, de acervos fotográficos brasileiros de interesse público, descritas segundo a NOBRADE. |
| Caracterização do Acervo | Coleção de cópias digitais de 13.060 dossiês fotográficos (séculos XIX e XX) reunidos a partir do portal Brasiliana Fotográfica (Biblioteca Nacional e instituições parceiras), com cerca de 13,2 mil imagens de preservação, miniaturas e cópias legadas, cerca de 139 GB. Os originais permanecem nas 15 instituições de origem, indicadas item a item. Descrição multinível conforme a NOBRADE (acervo › coleção › seção por instituição › série › dossiê › item), com exportação em EAD 3 e registros de autoridade em EAC-CPF. |
| Condições de acesso aos documentos | Acesso livre e gratuito à descrição e às imagens pelo mural on-line; cópias de preservação sob consulta. Reprodução condicionada à política do detentor de direitos de cada item (elemento 4.2 de cada dossiê). |
| Dia e horário de atendimento | Acesso on-line permanente; atendimento por e-mail `[[e-mail]]` |
| Serviços de reprodução | Não há serviço de reprodução próprio; os pedidos são encaminhados à instituição detentora do original. |
| Nome e telefone do responsável pelo preenchimento | `[[nome]]`, `[[telefone]]` |
## Depois de receber o código
1. Trocar `ENTIDADE = 'RJXYZ'` e `ENTIDADE_NOME` em `pipeline/nobrade/config.py`.
2. Rodar `cd pipeline && python3 -m nobrade && python3 -m nobrade.mural`: todos
os códigos de referência, o EAD e o EAC-CPF são regenerados.
3. Subir de novo `descricao/` para `s3://brasiliana/descricao/` e republicar o mural.
### Fontes
- CONARQ, Cadastro nacional de entidades custodiadoras de acervos arquivísticos:
<https://www.gov.br/conarq/pt-br/servicos-1/cadastro-nacional-de-entidades-custodiadoras-de-acervos-arquivisticos>
- CONARQ, formulário de cadastro:
<https://www.gov.br/conarq/pt-br/servicos-1/formulario-para-cadastro-de-entidade-custodiadora>
- CONARQ, NOBRADE (2006), proc. 1.1.1.
+29
View File
@@ -0,0 +1,29 @@
# Pendências da descrição NOBRADE
Gerado por `python -m nobrade`. Obrigatórios reprovam; avisos pedem revisão.
| Nível | Unidades |
|---|--:|
| 0 acervo | 1 |
| 1 coleção | 1 |
| 2 seção | 15 |
| 3 série | 115 |
| 4 dossiê | 13.060 |
| 5 item | 13.262 |
## Obrigatórios faltando: 0
Nenhum. Todas as unidades têm os elementos obrigatórios do seu nível.
## Avisos
| Aviso | Dossiês |
|---|--:|
| 4.2 condição de reprodução não informada na origem | 8.036 |
| 1.5 espécie presumida | 5.422 |
| 2.1 autoria não identificada | 3.287 |
| nível 3 em Avulsos — série de origem não identificada | 2.865 |
| 3.1 sem âmbito e conteúdo | 2.775 |
| 1.3 data atribuída pelo arquivista — conferir | 814 |
| valores corrompidos na origem | 105 |
| 6.1 preservação indisponível na origem | 69 |
+458
View File
@@ -0,0 +1,458 @@
id forma_autorizada tipo ocorrencias variantes
A0001 Ferrez, Marc, 1843-1923 pessoa 1960 Ferrez, Marc | Marc Ferrez | Marc Ferrez (Autoria)
A0002 Malta, Augusto, 1864-1957 pessoa 1175 Augusto Malta | MALTA, Augusto | Malta, Augusto | Malta, Augusto,1864-1957
A0003 Escola de Aviação Militar entidade coletiva 596 ""
A0004 Santos, Guilherme pessoa 420 ""
A0005 Gutierrez, Juan, 1859-1897 pessoa 373 Gutierrez, Juan | Gutierrez, Juan, m. 1897
A0006 Kfuri, Jorge, 1893-1965 pessoa 294 Kfuri, Jorge
A0007 Klumb, Revert Henrique, fl. 1855-1880 pessoa 290 Klumb, Revert Henrique
A0008 Leuzinger, Georges pessoa 257 ""
A0009 Escola de Aeronáutica entidade coletiva 174 ""
A0010 Officina de Paulo Robin entidade coletiva 169 ""
A0011 Robin, Paulo, m. 1897 pessoa 158 ""
A0012 Photographia Brazileira entidade coletiva 126 ""
A0013 Wischral, Arthur pessoa 124 ""
A0014 Gaensly, Guilherme, 1843-1928 pessoa 123 Gaensly, Guilherme
A0015 Escola de Aeronáutica Militar entidade coletiva 88 ""
A0016 Merrill, D. B. (Dana B.) pessoa 86 ""
A0017 Pacheco, Joaquim Insley, 1830-1912 pessoa 82 Pacheco, Joaquim Insley | Pacheco, Joaquim Insley, m. 1912
A0018 Azevedo, Militão Augusto de pessoa 75 ""
A0019 Museu Aeroespacial entidade coletiva 74 ""
A0020 Lamberg, Moritz pessoa 73 ""
A0021 Stahl, Augusto pessoa 72 ""
A0022 Barros, Justiniano José de pessoa 72 ""
A0023 Barros, Flávio de pessoa 71 ""
A0024 Holland, S. H pessoa 63 ""
A0025 Photographia Americana entidade coletiva 63 ""
A0026 Marc Ferrez & Cia entidade coletiva 62 ""
A0027 Rondon, Benjamin pessoa 62 Benjamin Rondon | [Rondon, Benjamin]
A0028 Gabinete Fotográfico da Comissão de Obras do Porto (RJ) entidade coletiva 58 ""
A0029 Pastore, Vincenzo pessoa 58 ""
A0030 Henschel, Alberto, 1827-1882 pessoa 57 Alberto Henschel | Henschel, Alberto
A0031 Gorham, Reginald pessoa 56 ""
A0032 Pinto, J., 1884-1951 pessoa 56 J. PInto | J. Pinto | Pinto, J.
A0033 Torres pessoa ou entidade 55 ""
A0034 BOSCAGLI, José pessoa 54 ""
A0035 Mendo, Ignácio F., fl. 1870 pessoa 54 ""
A0036 Krausz, Alfredo pessoa 53 ""
A0037 [s.n.] pessoa ou entidade 52 [S.N] | [s.n]
A0038 Quaas, Otto Rudolf pessoa 51 ""
A0039 Malta, Uriel, 1910-1994 pessoa 51 ""
A0040 Escola de Aeronáutica do Exército entidade coletiva 46 ""
A0041 Robin, Paul Théodore, m. 1897 pessoa 46 ""
A0042 Frisch, Albert pessoa 45 ""
A0043 Riedel, Augusto, 1836-ca.1877 pessoa 45 Riedel, Augusto
A0044 Klumb, Revert Henry, ca. 1826-ca. 1886 pessoa 44 ""
A0045 Fidanza, Felipe Augusto, ca.1847-1904 pessoa 44 Fidanza, Felipe Augusto
A0046 A. Ribeiro pessoa ou entidade 44 Ribeiro, A | Ribeiro, A.
A0047 Frond, Victor, 1821-1881 pessoa 43 Frond, Victor
A0048 Rodrigues & C°. Editores e Proprietários pessoa ou entidade 39 ""
A0049 Justa, O pessoa 38 ""
A0050 Ribeiro, Antônio Caetano da Costa pessoa 38 ""
A0051 Maison Chic pessoa ou entidade 37 ""
A0052 Musso, Luiz pessoa 37 ""
A0053 Musso & Cia entidade coletiva 37 ""
A0054 Paul Erbe pessoa ou entidade 36 ""
A0055 Guimarães, José Ferreira, 1841-1924 pessoa 36 Guimarães, José Ferreira
A0056 Horácio Coelho pessoa ou entidade 35 ""
A0057 Prugner, Gustavo pessoa 35 ""
A0058 Stahl & Cia entidade coletiva 35 ""
A0059 Teixeira, José pessoa 35 José Teixeira | Teixeira, José,
A0060 Phototypia A. Ribeiro pessoa ou entidade 33 ""
A0061 Photo Lindemann &Cª entidade coletiva 31 ""
A0062 Malta, Aristógiton, 1904-1954 pessoa 31 Malta, Aristógiton
A0063 Mulock, Benjamin Robert, 1829-1863 pessoa 31 ""
A0064 Silva, Pedro Gonsalves da pessoa 31 ""
A0065 Christiano Junior pessoa ou entidade 30 ""
A0066 Thomaz Farkas (Autoria) pessoa ou entidade 28 Thomaz Farkas
A0067 Ribeyrolles, Charles, 1812-1860 pessoa 28 ""
A0068 Vianna, José Baptista Barreira pessoa 28 ""
A0069 Christiano Junior, 1830-1902 pessoa 28 ""
A0070 Tondella, Manoel pessoa 28 ""
A0071 Amoretty, Augusto, 1845-1906 pessoa 26 Amoretty, Augusto
A0072 Huebner, George pessoa 26 ""
A0073 Vedani, Camillo pessoa 25 ""
A0074 Manuel, F. (Frédéric) pessoa 25 ""
A0075 Ferreira, Antonio Luiz pessoa 24 ""
A0076 Martins, Henrique pessoa 24 ""
A0077 Huber, Jacques (1867-1914) pessoa 24 Huber, Jacques | Jacques Huber
A0078 Julien Mandel (1893 - 1961) pessoa ou entidade 23 ""
A0079 Menezes, J pessoa 23 ""
A0080 Dietze, Albert Richard, fl. 1869 pessoa 22 ""
A0081 Parente, Nicola Maria pessoa 22 ""
A0082 Abrahão, Benjamin pessoa 22 ""
A0083 Henschel & Benque pessoa ou entidade 21 ""
A0084 Villela, João Ferreira, fl. 1861-1880 pessoa 21 Villela, João Ferreira
A0085 Photo Lopes Rio entidade coletiva 20 ""
A0086 Oswaldo Cruz pessoa ou entidade 20 Cruz, Oswaldo
A0087 Casa Leuzinger entidade coletiva 20 ""
A0088 Alkmim, Chichico pessoa 20 ""
A0089 Queiroz, Anastacio pessoa 20 ""
A0090 Lunara pessoa ou entidade 20 ""
A0091 Hees, Pedro, 1841-1880 pessoa 19 ""
A0092 Ayres, Joaquim pessoa 19 ""
A0093 José Louro pessoa ou entidade 19 ""
A0094 Preising, Theodor pessoa 18 ""
A0095 IBGE pessoa ou entidade 18 ""
A0096 Garbe, Walter pessoa 17 ""
A0097 Provável Uriel Malta pessoa ou entidade 16 ""
A0098 Thiele & Kollien pessoa ou entidade 16 ""
A0099 Pacheco, Bernardo José pessoa 16 ""
A0100 Christiano Junior E Pacheco pessoa ou entidade 16 ""
A0101 Mascarenhas, Therezio pessoa 16 ""
A0102 Photo Mortimer entidade coletiva 15 ""
A0103 Piereck, Louis, 1880-1931 pessoa 15 Piereck, Louis
A0104 Instituto de Expansão Comercial entidade coletiva 15 ""
A0105 Lobo, Antônio Araújo de Souza; Oliveira, Antônio Barbosa pessoa 15 ""
A0106 Trindade, J. S pessoa 14 ""
A0107 Oficina de Paulo Robin entidade coletiva 14 ""
A0108 H&J Tourte Éditeurs entidade coletiva 14 ""
A0109 Corrêa, J. A pessoa 14 ""
A0110 Bippus, Carlos pessoa 13 ""
A0111 Papelaria e Typographia Botelho pessoa ou entidade 13 ""
A0112 [sem autor] pessoa ou entidade 13 ""
A0113 João Stamato pessoa ou entidade 13 ""
A0114 Photographia Allemã entidade coletiva 12 Photographia Allemã (Firma)
A0115 Silva, Pio pessoa 12 ""
A0116 Benoist, Philippe, 1813-1905 pessoa 12 ""
A0117 LTM (Firma) pessoa ou entidade 12 LTM
A0118 Fidanza, Filipe Augusto, fl. 1861-1920 pessoa 12 ""
A0119 Tondella, Manoel, Photografia Tondella pessoa 12 ""
A0120 Garcia, F pessoa 11 ""
A0121 Subcomissão de Estudos dos Portos de Fortaleza e Camocim (CE) pessoa ou entidade 11 ""
A0122 Mulock, Benjamin pessoa 11 ""
A0123 Christiano Jr. & Pacheco pessoa ou entidade 11 ""
A0124 William Notman pessoa ou entidade 11 ""
A0125 Centennial Photographic Co pessoa ou entidade 11 ""
A0126 Boote, Samuel, 1844-1921 pessoa 11 ""
A0127 Costa, Hermina de Carvalho Menna da, 18- -19- pessoa 10 ""
A0128 Terragno, Luiz pessoa 10 ""
A0129 Joaquim Insley Pacheco (Autoria) pessoa ou entidade 10 ""
A0130 Lohse, Ernst (1873-1930) pessoa 10 ""
A0131 Bocage, Francisco du pessoa 10 ""
A0132 Lindemann, Rodolpho pessoa 10 ""
A0133 Jacottet, Louis-Julien, 1806-1880 pessoa 10 ""
A0134 Biblioteca Nacional (Brasil) entidade coletiva 10 ""
A0135 Carneiro & Gaspar pessoa ou entidade 10 ""
A0136 Editores & propriedade de Rodrigues & Co. Rua do Ouvidor, 57 pessoa 10 ""
A0137 Passos, Elysio Pereira dos pessoa 9 ""
A0138 Wessel pessoa ou entidade 9 ""
A0139 Moura, Miguel de, 1883- pessoa 9 Moura, Miguel de, n. 1883
A0140 Florence, Hercule pessoa 9 ""
A0141 Niemeyer, Louis pessoa 9 ""
A0142 The Aircraft Operating Co. Ltd pessoa ou entidade 8 ""
A0143 Hagmann, Gottfried (1874-1946) pessoa 8 ""
A0144 Goston, João pessoa 8 ""
A0145 Sorrieu, Frédéric, n. 1807 pessoa 8 ""
A0146 Champagne pessoa ou entidade 8 ""
A0147 Lima, Eudozio pessoa 8 ""
A0148 Bate E Cia entidade coletiva 8 ""
A0149 Huebner & Amaral pessoa ou entidade 8 ""
A0150 Photo Bippus entidade coletiva 8 ""
A0151 Rosen, Henrique, m. 1892 pessoa 8 ""
A0152 Peixoto, Antonio Carlos de Sampaio, m. 1914 pessoa 8 ""
A0153 King, John pessoa 7 ""
A0154 Angelo Regato (Fotógrafo) pessoa ou entidade 7 ""
A0155 Leuzinger, George, 1813-1892 pessoa 7 ""
A0156 Perez, M pessoa 7 ""
A0157 Martineau, Willian pessoa 7 ""
A0158 Musso, Luís, [? -1908] pessoa 7 ""
A0159 Carvalho, Alfredo Climaco de pessoa 7 ""
A0160 Tondella, Manoel, Photographia Tondella entidade coletiva 7 ""
A0161 Moraites, P pessoa 7 ""
A0162 Scheidemantel, Bernardo, 1834-1908 pessoa 7 ""
A0163 Affonso, José dos Santos pessoa 6 ""
A0164 G. Leuzinger & Filhos pessoa ou entidade 6 ""
A0165 Wanderley, Luiz Lavenère pessoa 6 ""
A0166 Gomes Junior pessoa ou entidade 6 ""
A0167 Destacamento de Aviação de Curitiba entidade coletiva 6 ""
A0168 Photo Bippus Rio entidade coletiva 6 ""
A0169 Photo Rotativo entidade coletiva 5 ""
A0170 Thiele pessoa ou entidade 5 ""
A0171 Silva, Paulo Bracy Gama da pessoa 5 ""
A0172 Photographia Artística de Miguel de Moura entidade coletiva 5 ""
A0173 Stahl & Wahnschaffe pessoa ou entidade 5 ""
A0174 Coutinho, Abilio pessoa 5 ""
A0175 Silva, Ezequiel pessoa 5 ""
A0176 Barza, Constantino pessoa 5 ""
A0177 Bianchi, Luis, 1876-1940 pessoa 5 ""
A0178 Lavenère, L pessoa 5 ""
A0179 J. J Oliveira, Manoel Tondella pessoa 5 ""
A0180 Lombaerts & Comp. Editores pessoa ou entidade 4 ""
A0181 Keller, Franz, 1835-1890 pessoa 4 Keller, Franz
A0182 Van Nyvel, Guimarães & C pessoa 4 ""
A0183 Silva, Arsenio da pessoa 4 ""
A0184 Büsch, Fritz pessoa 4 ""
A0185 Duruy, A. (Alexandre), fl. 1845-1881 pessoa 4 ""
A0186 Charpentier pessoa ou entidade 4 ""
A0187 Ateliers D. A. Longuet Imp. Phot pessoa ou entidade 4 ""
A0188 Ducasble, Alfredo pessoa 4 ""
A0189 Frisch, Christoph Albert, 1840-1918 pessoa 4 ""
A0190 Calcagno, Luiz Bartolomeu pessoa 4 ""
A0191 Cardoso, Antônio Lopes pessoa 4 ""
A0192 Pedro Le Houërou Photographo pessoa ou entidade 4 ""
A0193 Skarke, Fernando pessoa 4 ""
A0194 Livraria Lombaerts & C pessoa ou entidade 3 ""
A0195 Soper, Fred Lowe, 1893-1977 pessoa 3 ""
A0196 Monnerat, Roberto Mario pessoa 3 ""
A0197 Law, Henry, 1824-1900 pessoa 3 ""
A0198 Paranaguá, Francisco Vilela Barbosa, Marquês de, 1769-1846 pessoa 3 ""
A0199 Mora (Fotógrafo) pessoa ou entidade 3 ""
A0200 G. & A. Overbeck pessoa ou entidade 3 G & A Overbeck | G&A Overbeck
A0201 Glaziou, Auguste François Marie, 1833-1897 pessoa 3 ""
A0202 Cesar, Carlos pessoa 3 ""
A0203 Cunha, Silvio pessoa 3 ""
A0204 Archanjo Sobrinho pessoa ou entidade 3 ""
A0205 Lobo, A. de Barros pessoa 2 ""
A0206 Barreiros, A pessoa 2 ""
A0207 Lombaerts & Comp., Editores pessoa 2 ""
A0208 Izabel Jacintha Reeckell pessoa ou entidade 2 ""
A0209 Madame Reeckell pessoa ou entidade 2 ""
A0210 Eduardo de Los Rios pessoa ou entidade 2 ""
A0211 Photo Weiss- Estúdio/Agência entidade coletiva 2 Photo Weiss - Estúdio/Agência
A0212 Museu Aero Espacial entidade coletiva 2 ""
A0213 Soucasaux, Francisco pessoa 2 ""
A0214 Photographia Atayama entidade coletiva 2 ""
A0215 Comissão de desobstrução dos rios da Baixada Fluminense (RJ) entidade coletiva 2 ""
A0216 Dias, Bastos pessoa 2 ""
A0217 Costa, Osvaldo Gilson Fonseca, 1948 pessoa 2 ""
A0218 Campos, Augusto César Malta de, 1864-1957 pessoa 2 ""
A0219 Horacio Coppola pessoa ou entidade 2 ""
A0220 Rossi, Giulio, 1824-1884 pessoa 2 ""
A0221 Marcel Gautherot pessoa ou entidade 2 ""
A0222 Gioconda Rizzo pessoa ou entidade 2 ""
A0223 Braz pessoa ou entidade 2 ""
A0224 Laurens, J pessoa 2 ""
A0225 Laurens, Jules-Joseph-Augustin, 1825-1901 pessoa 2 ""
A0226 Bernieri, J pessoa 2 ""
A0227 Sommer, Giorgio, 1834-1914 pessoa 2 ""
A0228 Pacheco & Filho pessoa ou entidade 2 PACHECO & FILHO
A0229 Schleier J pessoa ou entidade 2 ""
A0230 Lewis, John C. A pessoa 2 ""
A0231 Moreira, Archimedes pessoa 2 ""
A0232 Vannini, N pessoa 2 ""
A0233 Fragoso, Armando pessoa 2 ""
A0234 Huberti (Fotógrafo) pessoa ou entidade 2 Huberti
A0235 Barboza, João de Almeida pessoa 2 ""
A0236 Firpo, João pessoa 2 ""
A0237 Forni, Agostino pessoa 2 ""
A0238 Trebby, Frederico pessoa 2 ""
A0239 Galeria Universal de Carlos Cesar pessoa ou entidade 2 ""
A0240 Trebby y Cia entidade coletiva 2 ""
A0241 Filgueiras, A pessoa 2 ""
A0242 Sá, Gazzi de, 1901-1981 pessoa 2 ""
A0243 Fernandes, Gonçalves, 1909-1986 pessoa 2 ""
A0244 A. Filgueiras Photo Amador entidade coletiva 2 ""
A0245 Agfa Tropex pessoa ou entidade 2 ""
A0246 Aliwu pessoa ou entidade 2 ""
A0247 Ultzmann, Robert, 1842-1889 pessoa 2 ""
A0248 Benque, Francisco e Henschel, Alberto pessoa 2 ""
A0249 Carneiro, Joaquim Feliciano Alves e Tavares pessoa 2 ""
A0250 Lobo, Antônio Araújo de Souza pessoa 2 ""
A0251 Oliveira, Antônio Barbosa pessoa 2 ""
A0252 Pinto. J pessoa ou entidade 2 ""
A0253 Ducasble, Alfredo | Fotografia Parisienne entidade coletiva 2 ""
A0254 Soucasaux, Augusto pessoa 2 ""
A0255 s/nome pessoa ou entidade 2 ""
A0256 Photographia Popular Oliveira & Tondella entidade coletiva 2 ""
A0257 Tondella, Manoel. Photografia Tondella pessoa 2 ""
A0258 Du Bocage, F., F. Du Bocage Photographia entidade coletiva 2 ""
A0259 Mello, Borges de, Photographia modelo Borges de Mello entidade coletiva 2 ""
A0260 1º Comando do Exército entidade coletiva 2 ""
A0261 Silveira, J pessoa 2 ""
A0262 Guimarães, Antonio de Oliveira pessoa 2 ""
A0263 Furne fils et H. Tournier pessoa ou entidade 2 ""
A0264 Carneiro & Smith pessoa ou entidade 2 ""
A0265 Sabino pessoa ou entidade 2 ""
A0266 Arthur e J. J. Wischral pessoa ou entidade 2 ""
A0267 A. C. da Costa Ribeiro pessoa ou entidade 2 ""
A0268 Pittigliani, Armando pessoa 2 ""
A0269 Photographia Marc Ferrez entidade coletiva 2 ""
A0270 Sobrosa Rio pessoa ou entidade 1 ""
A0271 Sobrosa, Antenor pessoa 1 ""
A0272 José Francisco Corrêa et C pessoa ou entidade 1 ""
A0273 Corrêa, José Francisco pessoa 1 ""
A0274 Castro, Jorge de pessoa 1 ""
A0275 Duarte, B. J. (Benedito Junqueira), 1910-1995 pessoa 1 ""
A0276 Vosylius, Kazys pessoa 1 ""
A0277 Leon de Rennes pessoa ou entidade 1 ""
A0278 Foto aérea Campo Marinha no Galeão entidade coletiva 1 ""
A0279 Lopes pessoa ou entidade 1 ""
A0280 Nicola Parente pessoa ou entidade 1 ""
A0281 Ferrez, Luciano (1884 - 1955) pessoa 1 ""
A0282 Jean Manzon pessoa ou entidade 1 ""
A0283 Valuos, Guilherme pessoa 1 ""
A0284 Viggiani, N pessoa 1 ""
A0285 Dutra, Olavo - Fotógrafo pessoa 1 ""
A0286 Fotógrafo: Vernaut, Benjamin pessoa 1 ""
A0287 Photographia Guimarães entidade coletiva 1 ""
A0288 E. Av. M pessoa ou entidade 1 ""
A0289 Monteiro, Augusto pessoa 1 ""
A0290 Stille, Paul pessoa 1 ""
A0291 cios e préTheodor pessoa ou entidade 1 ""
A0292 [Otto Hees?] pessoa ou entidade 1 ""
A0293 Studio Paul entidade coletiva 1 ""
A0294 Dr. Menescal pessoa ou entidade 1 ""
A0295 Rembrandt - Rio pessoa ou entidade 1 ""
A0296 Bellati, R. (Fotógrafo) pessoa 1 ""
A0297 Somlo, Tomas pessoa 1 ""
A0298 Emerico pessoa ou entidade 1 ""
A0299 Carlos Moskovics pessoa ou entidade 1 ""
A0300 Musso, Luís, m. 1908 pessoa 1 ""
A0301 Agência Nacional entidade coletiva 1 ""
A0302 Walery pessoa ou entidade 1 ""
A0303 Klumb, Henrique Revert pessoa 1 ""
A0304 Coutinho, A pessoa 1 ""
A0305 Clerget pessoa ou entidade 1 ""
A0306 Adam, Victor Jean, 1801-1866 pessoa 1 ""
A0307 Courtois, J pessoa 1 ""
A0308 Mason, Samuel J pessoa 1 ""
A0309 Bradley & Rulofson pessoa ou entidade 1 ""
A0310 H. Delie and E. Bechard pessoa ou entidade 1 ""
A0311 Noël, Alphonse Léon, 1807-1884 pessoa 1 ""
A0312 Helios (Fotógrafo) pessoa ou entidade 1 ""
A0313 Nadar, Felix, 1820-1910 pessoa 1 ""
A0314 Photographia Popular entidade coletiva 1 ""
A0315 Angerer, Ludwig, 1827-1879 pessoa 1 ""
A0316 Schoefft, O pessoa 1 ""
A0317 Mourgeon, C pessoa 1 ""
A0318 Antunes, F pessoa 1 ""
A0319 Aguiar, Francisco Marcellino de Souza, 1855-1935 pessoa 1 ""
A0320 Marc Ferrez & Filhos pessoa ou entidade 1 ""
A0321 Zaccaria, G pessoa 1 ""
A0322 Photograhia Vesuvio de Nicola Maria Parente pessoa ou entidade 1 ""
A0323 Silveira, Pedro Satyro de Souza da pessoa 1 ""
A0324 Rocha, J. C. da pessoa 1 ""
A0325 Photographia Americana de Moreira & Roltgen entidade coletiva 1 ""
A0326 Moreira & Roltgen pessoa ou entidade 1 ""
A0327 Lopes & Ca pessoa ou entidade 1 ""
A0328 Photographia Imperial de Lopes & Ca entidade coletiva 1 ""
A0329 Atelier Photograhico Hygino Soares entidade coletiva 1 ""
A0330 Nunes, Henrique, 1820-1895 pessoa 1 ""
A0331 Luys, Jules Bernard, 1828-1897 pessoa 1 ""
A0332 Wegner & Mottu pessoa ou entidade 1 ""
A0333 Brogi, Giacomo, 1822-1881 pessoa 1 ""
A0334 Con, Frederico Carlos pessoa 1 ""
A0335 Fenton, Roger, 1819-1869 pessoa 1 ""
A0336 Banchieri, Manoel pessoa 1 ""
A0337 Fratelli Alinari Fotografi pessoa ou entidade 1 ""
A0338 Photographie Technique A. Fernique pessoa ou entidade 1 ""
A0339 Typographia Imperial & Real de Vienna pessoa ou entidade 1 ""
A0340 Clairin, Georges-Jules-Victor, 1843-1919 pessoa 1 ""
A0341 Gilleta & Gilly pessoa ou entidade 1 ""
A0342 Arena, Giacomo, 1818-1906 pessoa 1 ""
A0343 Jerace, Francesco, 1854 - 1937 pessoa 1 ""
A0344 Calzolari, Icilio pessoa 1 ""
A0345 Fumeo, Pietro, 1831-1898 pessoa 1 ""
A0346 Trinquart (Fotógrafo) pessoa ou entidade 1 ""
A0347 Berthier, Paul, 1822-1912 pessoa 1 ""
A0348 Albert, Joseph, 1825-1886 pessoa 1 ""
A0349 Photographie Americaine pessoa ou entidade 1 ""
A0350 Kaun Phot pessoa ou entidade 1 ""
A0351 Mauritshuis (Haia, Holanda) pessoa 1 ""
A0352 Salentin, Hubert, 1822-1910 pessoa 1 ""
A0353 Boker, Carl, 1836-1905 pessoa 1 ""
A0354 Sonderland, F, 1836-1896 pessoa 1 ""
A0355 C. & A. Overbeck pessoa ou entidade 1 ""
A0356 Bosch, E pessoa 1 ""
A0357 Werff, Adriaen van der, 1659 - 1722 pessoa 1 ""
A0358 Gleyre, Charles, 1806-1874 pessoa 1 ""
A0359 Goupil & Cie pessoa ou entidade 1 ""
A0360 Stacey, C.A pessoa 1 ""
A0361 Draper, Henry, 1837-1882 pessoa 1 ""
A0362 Ludwig, Johann Fridrich, 1670-1752 pessoa 1 ""
A0363 Meireles, Vítor, 1832-1903 pessoa 1 ""
A0364 José da Santíssima Trindade, Bispo, 1762-1835 pessoa 1 ""
A0365 Lucarell, Mario pessoa 1 ""
A0366 Costa, Heitor da Silva, 1837-1947 pessoa 1 ""
A0367 Foto Lucarelli entidade coletiva 1 ""
A0368 Lima, José Otávio Correia, 1878-1974 pessoa 1 ""
A0369 Read, R. A pessoa 1 ""
A0370 Severino (Fotógrafo) pessoa ou entidade 1 ""
A0371 Hospe, Joseph pessoa 1 ""
A0372 Photo Lindemann entidade coletiva 1 ""
A0373 Conti, José Carlos pessoa 1 ""
A0374 Photo Studio Huberti entidade coletiva 1 ""
A0375 Boquel, Julien pessoa 1 ""
A0376 Silva, M. Nogueira da pessoa 1 ""
A0377 Hoenen, Carlos pessoa 1 ""
A0378 Fábrica de Ferro de Ipanema pessoa ou entidade 1 ""
A0379 Rio Branco, José Maria da Silva Paranhos, Barão do, 1845-1912 pessoa 1 ""
A0380 Nickelsen (Fotógrafo) pessoa ou entidade 1 ""
A0381 Lima, Antonio Mariano de, 1858-1902 pessoa 1 ""
A0382 Mello, Affonso de Oliveira pessoa 1 ""
A0383 Lavinthal, Joaquim Ferreira dos Santos pessoa 1 ""
A0384 Photo Lavinthal entidade coletiva 1 ""
A0385 Vieira, Valério, 1862-1941 pessoa 1 ""
A0386 Bate & Cia entidade coletiva 1 ""
A0387 Micheles (Fotógrafo) pessoa ou entidade 1 ""
A0388 Rochet, Louis, 1813-1878 pessoa 1 ""
A0389 Mafra, João Maximiniano pessoa 1 ""
A0390 Fleury, André Augusto de Pádua, 1830-1895 pessoa 1 ""
A0391 Faro, Gonçalo Paes de Azevedo, 1846-1900 pessoa 1 ""
A0392 Liais, Emmanuel, 1826-1900 pessoa 1 ""
A0393 Hermida Pazos, José, 1829-1921 pessoa 1 ""
A0394 Aquidabã pessoa ou entidade 1 ""
A0395 Oliveira, C. de pessoa 1 ""
A0396 Oliveira, Candido Marinho pessoa 1 ""
A0397 Satrap Photo entidade coletiva 1 ""
A0398 Agfa Brovira pessoa ou entidade 1 ""
A0399 Ferrez, Gilberto pessoa 1 ""
A0400 Boute pessoa ou entidade 1 ""
A0401 Buvelot & Prat pessoa ou entidade 1 ""
A0402 Panigai, Marco di pessoa 1 ""
A0403 David Latino & Franklin pessoa ou entidade 1 ""
A0404 Leuthold e Dursky pessoa ou entidade 1 ""
A0405 Antunes, Humberto Saraiva pessoa 1 ""
A0406 Castro pessoa ou entidade 1 ""
A0407 Comp. Lith. Hartmann-Reichenbach entidade coletiva 1 ""
A0408 Photographia Guilherme Gaensly entidade coletiva 1 ""
A0409 Papeleria Travassos pessoa ou entidade 1 ""
A0410 Phototipie Marius Bar pessoa ou entidade 1 ""
A0411 Bureu Poste pessoa ou entidade 1 ""
A0412 Edição A. Moura pessoa ou entidade 1 ""
A0413 Bureau Poste pessoa ou entidade 1 ""
A0414 Ao Cantineiro Naval pessoa ou entidade 1 ""
A0415 Henschel e Benque pessoa ou entidade 1 ""
A0416 Mello, Marcos A. de pessoa 1 ""
A0417 Soares, José Severino pessoa 1 ""
A0418 Bastos, A pessoa 1 ""
A0419 Henschel, Albert, 1827-1882 pessoa 1 ""
A0420 Bonfioti, J pessoa 1 ""
A0421 Foto Chic entidade coletiva 1 ""
A0422 Barboza, Theotonio pessoa 1 ""
A0423 Rogato, Guilherme pessoa 1 ""
A0424 Photo Skarke entidade coletiva 1 ""
A0425 Serviço Photographico de Vida Domestica entidade coletiva 1 ""
A0426 Foto Studio Gloria entidade coletiva 1 ""
A0427 Fotografia Alemã entidade coletiva 1 ""
A0428 Brady, Mathew B., ca. 1823-1896 pessoa 1 ""
A0429 Photograhia Popular Oliveira & Tondella pessoa ou entidade 1 ""
A0430 Photografia Popular Oliveira & Tondella pessoa ou entidade 1 ""
A0431 Manoel Tondella, Photografia Tondella pessoa 1 ""
A0432 Claude Lévi-Strauss pessoa ou entidade 1 ""
A0433 Monteiro,Photographie Chic Monteiro & C pessoa 1 ""
A0434 Edgard Egydio de Souza pessoa ou entidade 1 ""
A0435 S/A pessoa ou entidade 1 ""
A0436 Chapelin E Pereira pessoa ou entidade 1 ""
A0437 Poluceno & Pinho pessoa ou entidade 1 ""
A0438 <ns:Co & Pinho pessoa ou entidade 1 ""
A0439 Thiele & Kollien [?]; Photo Bippus Rio [?] entidade coletiva 1 ""
A0440 Photographia Central entidade coletiva 1 ""
A0441 Veiga, Bernardo Saturnino da pessoa 1 ""
A0442 Phototypie Berthaud pessoa ou entidade 1 ""
A0443 Marinho, P pessoa 1 ""
A0444 A. Editora entidade coletiva 1 ""
A0445 511-73, Marc pessoa 1 ""
A0446 J. Stamato pessoa ou entidade 1 ""
A0447 DADE pessoa ou entidade 1 ""
A0448 Annunciato pessoa ou entidade 1 ""
A0449 Benque pessoa ou entidade 1 ""
A0450 Chapelin pessoa ou entidade 1 ""
A0451 Scheidemantel, B pessoa 1 ""
A0452 Photo Braz Rio entidade coletiva 1 ""
A0453 Scheuenstuhl, Paulo pessoa 1 ""
A0454 Caras & Caretas pessoa ou entidade 1 ""
A0455 Leonar pessoa ou entidade 1 ""
A0456 Azevedo, J. Faria de pessoa 1 ""
A0457 Basto, F pessoa 1 ""
1 id forma_autorizada tipo ocorrencias variantes
2 A0001 Ferrez, Marc, 1843-1923 pessoa 1960 Ferrez, Marc | Marc Ferrez | Marc Ferrez (Autoria)
3 A0002 Malta, Augusto, 1864-1957 pessoa 1175 Augusto Malta | MALTA, Augusto | Malta, Augusto | Malta, Augusto,1864-1957
4 A0003 Escola de Aviação Militar entidade coletiva 596
5 A0004 Santos, Guilherme pessoa 420
6 A0005 Gutierrez, Juan, 1859-1897 pessoa 373 Gutierrez, Juan | Gutierrez, Juan, m. 1897
7 A0006 Kfuri, Jorge, 1893-1965 pessoa 294 Kfuri, Jorge
8 A0007 Klumb, Revert Henrique, fl. 1855-1880 pessoa 290 Klumb, Revert Henrique
9 A0008 Leuzinger, Georges pessoa 257
10 A0009 Escola de Aeronáutica entidade coletiva 174
11 A0010 Officina de Paulo Robin entidade coletiva 169
12 A0011 Robin, Paulo, m. 1897 pessoa 158
13 A0012 Photographia Brazileira entidade coletiva 126
14 A0013 Wischral, Arthur pessoa 124
15 A0014 Gaensly, Guilherme, 1843-1928 pessoa 123 Gaensly, Guilherme
16 A0015 Escola de Aeronáutica Militar entidade coletiva 88
17 A0016 Merrill, D. B. (Dana B.) pessoa 86
18 A0017 Pacheco, Joaquim Insley, 1830-1912 pessoa 82 Pacheco, Joaquim Insley | Pacheco, Joaquim Insley, m. 1912
19 A0018 Azevedo, Militão Augusto de pessoa 75
20 A0019 Museu Aeroespacial entidade coletiva 74
21 A0020 Lamberg, Moritz pessoa 73
22 A0021 Stahl, Augusto pessoa 72
23 A0022 Barros, Justiniano José de pessoa 72
24 A0023 Barros, Flávio de pessoa 71
25 A0024 Holland, S. H pessoa 63
26 A0025 Photographia Americana entidade coletiva 63
27 A0026 Marc Ferrez & Cia entidade coletiva 62
28 A0027 Rondon, Benjamin pessoa 62 Benjamin Rondon | [Rondon, Benjamin]
29 A0028 Gabinete Fotográfico da Comissão de Obras do Porto (RJ) entidade coletiva 58
30 A0029 Pastore, Vincenzo pessoa 58
31 A0030 Henschel, Alberto, 1827-1882 pessoa 57 Alberto Henschel | Henschel, Alberto
32 A0031 Gorham, Reginald pessoa 56
33 A0032 Pinto, J., 1884-1951 pessoa 56 J. PInto | J. Pinto | Pinto, J.
34 A0033 Torres pessoa ou entidade 55
35 A0034 BOSCAGLI, José pessoa 54
36 A0035 Mendo, Ignácio F., fl. 1870 pessoa 54
37 A0036 Krausz, Alfredo pessoa 53
38 A0037 [s.n.] pessoa ou entidade 52 [S.N] | [s.n]
39 A0038 Quaas, Otto Rudolf pessoa 51
40 A0039 Malta, Uriel, 1910-1994 pessoa 51
41 A0040 Escola de Aeronáutica do Exército entidade coletiva 46
42 A0041 Robin, Paul Théodore, m. 1897 pessoa 46
43 A0042 Frisch, Albert pessoa 45
44 A0043 Riedel, Augusto, 1836-ca.1877 pessoa 45 Riedel, Augusto
45 A0044 Klumb, Revert Henry, ca. 1826-ca. 1886 pessoa 44
46 A0045 Fidanza, Felipe Augusto, ca.1847-1904 pessoa 44 Fidanza, Felipe Augusto
47 A0046 A. Ribeiro pessoa ou entidade 44 Ribeiro, A | Ribeiro, A.
48 A0047 Frond, Victor, 1821-1881 pessoa 43 Frond, Victor
49 A0048 Rodrigues & C°. Editores e Proprietários pessoa ou entidade 39
50 A0049 Justa, O pessoa 38
51 A0050 Ribeiro, Antônio Caetano da Costa pessoa 38
52 A0051 Maison Chic pessoa ou entidade 37
53 A0052 Musso, Luiz pessoa 37
54 A0053 Musso & Cia entidade coletiva 37
55 A0054 Paul Erbe pessoa ou entidade 36
56 A0055 Guimarães, José Ferreira, 1841-1924 pessoa 36 Guimarães, José Ferreira
57 A0056 Horácio Coelho pessoa ou entidade 35
58 A0057 Prugner, Gustavo pessoa 35
59 A0058 Stahl & Cia entidade coletiva 35
60 A0059 Teixeira, José pessoa 35 José Teixeira | Teixeira, José,
61 A0060 Phototypia A. Ribeiro pessoa ou entidade 33
62 A0061 Photo Lindemann &Cª entidade coletiva 31
63 A0062 Malta, Aristógiton, 1904-1954 pessoa 31 Malta, Aristógiton
64 A0063 Mulock, Benjamin Robert, 1829-1863 pessoa 31
65 A0064 Silva, Pedro Gonsalves da pessoa 31
66 A0065 Christiano Junior pessoa ou entidade 30
67 A0066 Thomaz Farkas (Autoria) pessoa ou entidade 28 Thomaz Farkas
68 A0067 Ribeyrolles, Charles, 1812-1860 pessoa 28
69 A0068 Vianna, José Baptista Barreira pessoa 28
70 A0069 Christiano Junior, 1830-1902 pessoa 28
71 A0070 Tondella, Manoel pessoa 28
72 A0071 Amoretty, Augusto, 1845-1906 pessoa 26 Amoretty, Augusto
73 A0072 Huebner, George pessoa 26
74 A0073 Vedani, Camillo pessoa 25
75 A0074 Manuel, F. (Frédéric) pessoa 25
76 A0075 Ferreira, Antonio Luiz pessoa 24
77 A0076 Martins, Henrique pessoa 24
78 A0077 Huber, Jacques (1867-1914) pessoa 24 Huber, Jacques | Jacques Huber
79 A0078 Julien Mandel (1893 - 1961) pessoa ou entidade 23
80 A0079 Menezes, J pessoa 23
81 A0080 Dietze, Albert Richard, fl. 1869 pessoa 22
82 A0081 Parente, Nicola Maria pessoa 22
83 A0082 Abrahão, Benjamin pessoa 22
84 A0083 Henschel & Benque pessoa ou entidade 21
85 A0084 Villela, João Ferreira, fl. 1861-1880 pessoa 21 Villela, João Ferreira
86 A0085 Photo Lopes Rio entidade coletiva 20
87 A0086 Oswaldo Cruz pessoa ou entidade 20 Cruz, Oswaldo
88 A0087 Casa Leuzinger entidade coletiva 20
89 A0088 Alkmim, Chichico pessoa 20
90 A0089 Queiroz, Anastacio pessoa 20
91 A0090 Lunara pessoa ou entidade 20
92 A0091 Hees, Pedro, 1841-1880 pessoa 19
93 A0092 Ayres, Joaquim pessoa 19
94 A0093 José Louro pessoa ou entidade 19
95 A0094 Preising, Theodor pessoa 18
96 A0095 IBGE pessoa ou entidade 18
97 A0096 Garbe, Walter pessoa 17
98 A0097 Provável Uriel Malta pessoa ou entidade 16
99 A0098 Thiele & Kollien pessoa ou entidade 16
100 A0099 Pacheco, Bernardo José pessoa 16
101 A0100 Christiano Junior E Pacheco pessoa ou entidade 16
102 A0101 Mascarenhas, Therezio pessoa 16
103 A0102 Photo Mortimer entidade coletiva 15
104 A0103 Piereck, Louis, 1880-1931 pessoa 15 Piereck, Louis
105 A0104 Instituto de Expansão Comercial entidade coletiva 15
106 A0105 Lobo, Antônio Araújo de Souza; Oliveira, Antônio Barbosa pessoa 15
107 A0106 Trindade, J. S pessoa 14
108 A0107 Oficina de Paulo Robin entidade coletiva 14
109 A0108 H&J Tourte Éditeurs entidade coletiva 14
110 A0109 Corrêa, J. A pessoa 14
111 A0110 Bippus, Carlos pessoa 13
112 A0111 Papelaria e Typographia Botelho pessoa ou entidade 13
113 A0112 [sem autor] pessoa ou entidade 13
114 A0113 João Stamato pessoa ou entidade 13
115 A0114 Photographia Allemã entidade coletiva 12 Photographia Allemã (Firma)
116 A0115 Silva, Pio pessoa 12
117 A0116 Benoist, Philippe, 1813-1905 pessoa 12
118 A0117 LTM (Firma) pessoa ou entidade 12 LTM
119 A0118 Fidanza, Filipe Augusto, fl. 1861-1920 pessoa 12
120 A0119 Tondella, Manoel, Photografia Tondella pessoa 12
121 A0120 Garcia, F pessoa 11
122 A0121 Subcomissão de Estudos dos Portos de Fortaleza e Camocim (CE) pessoa ou entidade 11
123 A0122 Mulock, Benjamin pessoa 11
124 A0123 Christiano Jr. & Pacheco pessoa ou entidade 11
125 A0124 William Notman pessoa ou entidade 11
126 A0125 Centennial Photographic Co pessoa ou entidade 11
127 A0126 Boote, Samuel, 1844-1921 pessoa 11
128 A0127 Costa, Hermina de Carvalho Menna da, 18- -19- pessoa 10
129 A0128 Terragno, Luiz pessoa 10
130 A0129 Joaquim Insley Pacheco (Autoria) pessoa ou entidade 10
131 A0130 Lohse, Ernst (1873-1930) pessoa 10
132 A0131 Bocage, Francisco du pessoa 10
133 A0132 Lindemann, Rodolpho pessoa 10
134 A0133 Jacottet, Louis-Julien, 1806-1880 pessoa 10
135 A0134 Biblioteca Nacional (Brasil) entidade coletiva 10
136 A0135 Carneiro & Gaspar pessoa ou entidade 10
137 A0136 Editores & propriedade de Rodrigues & Co. Rua do Ouvidor, 57 pessoa 10
138 A0137 Passos, Elysio Pereira dos pessoa 9
139 A0138 Wessel pessoa ou entidade 9
140 A0139 Moura, Miguel de, 1883- pessoa 9 Moura, Miguel de, n. 1883
141 A0140 Florence, Hercule pessoa 9
142 A0141 Niemeyer, Louis pessoa 9
143 A0142 The Aircraft Operating Co. Ltd pessoa ou entidade 8
144 A0143 Hagmann, Gottfried (1874-1946) pessoa 8
145 A0144 Goston, João pessoa 8
146 A0145 Sorrieu, Frédéric, n. 1807 pessoa 8
147 A0146 Champagne pessoa ou entidade 8
148 A0147 Lima, Eudozio pessoa 8
149 A0148 Bate E Cia entidade coletiva 8
150 A0149 Huebner & Amaral pessoa ou entidade 8
151 A0150 Photo Bippus entidade coletiva 8
152 A0151 Rosen, Henrique, m. 1892 pessoa 8
153 A0152 Peixoto, Antonio Carlos de Sampaio, m. 1914 pessoa 8
154 A0153 King, John pessoa 7
155 A0154 Angelo Regato (Fotógrafo) pessoa ou entidade 7
156 A0155 Leuzinger, George, 1813-1892 pessoa 7
157 A0156 Perez, M pessoa 7
158 A0157 Martineau, Willian pessoa 7
159 A0158 Musso, Luís, [? -1908] pessoa 7
160 A0159 Carvalho, Alfredo Climaco de pessoa 7
161 A0160 Tondella, Manoel, Photographia Tondella entidade coletiva 7
162 A0161 Moraites, P pessoa 7
163 A0162 Scheidemantel, Bernardo, 1834-1908 pessoa 7
164 A0163 Affonso, José dos Santos pessoa 6
165 A0164 G. Leuzinger & Filhos pessoa ou entidade 6
166 A0165 Wanderley, Luiz Lavenère pessoa 6
167 A0166 Gomes Junior pessoa ou entidade 6
168 A0167 Destacamento de Aviação de Curitiba entidade coletiva 6
169 A0168 Photo Bippus Rio entidade coletiva 6
170 A0169 Photo Rotativo entidade coletiva 5
171 A0170 Thiele pessoa ou entidade 5
172 A0171 Silva, Paulo Bracy Gama da pessoa 5
173 A0172 Photographia Artística de Miguel de Moura entidade coletiva 5
174 A0173 Stahl & Wahnschaffe pessoa ou entidade 5
175 A0174 Coutinho, Abilio pessoa 5
176 A0175 Silva, Ezequiel pessoa 5
177 A0176 Barza, Constantino pessoa 5
178 A0177 Bianchi, Luis, 1876-1940 pessoa 5
179 A0178 Lavenère, L pessoa 5
180 A0179 J. J Oliveira, Manoel Tondella pessoa 5
181 A0180 Lombaerts & Comp. Editores pessoa ou entidade 4
182 A0181 Keller, Franz, 1835-1890 pessoa 4 Keller, Franz
183 A0182 Van Nyvel, Guimarães & C pessoa 4
184 A0183 Silva, Arsenio da pessoa 4
185 A0184 Büsch, Fritz pessoa 4
186 A0185 Duruy, A. (Alexandre), fl. 1845-1881 pessoa 4
187 A0186 Charpentier pessoa ou entidade 4
188 A0187 Ateliers D. A. Longuet Imp. Phot pessoa ou entidade 4
189 A0188 Ducasble, Alfredo pessoa 4
190 A0189 Frisch, Christoph Albert, 1840-1918 pessoa 4
191 A0190 Calcagno, Luiz Bartolomeu pessoa 4
192 A0191 Cardoso, Antônio Lopes pessoa 4
193 A0192 Pedro Le Houërou Photographo pessoa ou entidade 4
194 A0193 Skarke, Fernando pessoa 4
195 A0194 Livraria Lombaerts & C pessoa ou entidade 3
196 A0195 Soper, Fred Lowe, 1893-1977 pessoa 3
197 A0196 Monnerat, Roberto Mario pessoa 3
198 A0197 Law, Henry, 1824-1900 pessoa 3
199 A0198 Paranaguá, Francisco Vilela Barbosa, Marquês de, 1769-1846 pessoa 3
200 A0199 Mora (Fotógrafo) pessoa ou entidade 3
201 A0200 G. & A. Overbeck pessoa ou entidade 3 G & A Overbeck | G&A Overbeck
202 A0201 Glaziou, Auguste François Marie, 1833-1897 pessoa 3
203 A0202 Cesar, Carlos pessoa 3
204 A0203 Cunha, Silvio pessoa 3
205 A0204 Archanjo Sobrinho pessoa ou entidade 3
206 A0205 Lobo, A. de Barros pessoa 2
207 A0206 Barreiros, A pessoa 2
208 A0207 Lombaerts & Comp., Editores pessoa 2
209 A0208 Izabel Jacintha Reeckell pessoa ou entidade 2
210 A0209 Madame Reeckell pessoa ou entidade 2
211 A0210 Eduardo de Los Rios pessoa ou entidade 2
212 A0211 Photo Weiss- Estúdio/Agência entidade coletiva 2 Photo Weiss - Estúdio/Agência
213 A0212 Museu Aero Espacial entidade coletiva 2
214 A0213 Soucasaux, Francisco pessoa 2
215 A0214 Photographia Atayama entidade coletiva 2
216 A0215 Comissão de desobstrução dos rios da Baixada Fluminense (RJ) entidade coletiva 2
217 A0216 Dias, Bastos pessoa 2
218 A0217 Costa, Osvaldo Gilson Fonseca, 1948 pessoa 2
219 A0218 Campos, Augusto César Malta de, 1864-1957 pessoa 2
220 A0219 Horacio Coppola pessoa ou entidade 2
221 A0220 Rossi, Giulio, 1824-1884 pessoa 2
222 A0221 Marcel Gautherot pessoa ou entidade 2
223 A0222 Gioconda Rizzo pessoa ou entidade 2
224 A0223 Braz pessoa ou entidade 2
225 A0224 Laurens, J pessoa 2
226 A0225 Laurens, Jules-Joseph-Augustin, 1825-1901 pessoa 2
227 A0226 Bernieri, J pessoa 2
228 A0227 Sommer, Giorgio, 1834-1914 pessoa 2
229 A0228 Pacheco & Filho pessoa ou entidade 2 PACHECO & FILHO
230 A0229 Schleier J pessoa ou entidade 2
231 A0230 Lewis, John C. A pessoa 2
232 A0231 Moreira, Archimedes pessoa 2
233 A0232 Vannini, N pessoa 2
234 A0233 Fragoso, Armando pessoa 2
235 A0234 Huberti (Fotógrafo) pessoa ou entidade 2 Huberti
236 A0235 Barboza, João de Almeida pessoa 2
237 A0236 Firpo, João pessoa 2
238 A0237 Forni, Agostino pessoa 2
239 A0238 Trebby, Frederico pessoa 2
240 A0239 Galeria Universal de Carlos Cesar pessoa ou entidade 2
241 A0240 Trebby y Cia entidade coletiva 2
242 A0241 Filgueiras, A pessoa 2
243 A0242 Sá, Gazzi de, 1901-1981 pessoa 2
244 A0243 Fernandes, Gonçalves, 1909-1986 pessoa 2
245 A0244 A. Filgueiras Photo Amador entidade coletiva 2
246 A0245 Agfa Tropex pessoa ou entidade 2
247 A0246 Aliwu pessoa ou entidade 2
248 A0247 Ultzmann, Robert, 1842-1889 pessoa 2
249 A0248 Benque, Francisco e Henschel, Alberto pessoa 2
250 A0249 Carneiro, Joaquim Feliciano Alves e Tavares pessoa 2
251 A0250 Lobo, Antônio Araújo de Souza pessoa 2
252 A0251 Oliveira, Antônio Barbosa pessoa 2
253 A0252 Pinto. J pessoa ou entidade 2
254 A0253 Ducasble, Alfredo | Fotografia Parisienne entidade coletiva 2
255 A0254 Soucasaux, Augusto pessoa 2
256 A0255 s/nome pessoa ou entidade 2
257 A0256 Photographia Popular Oliveira & Tondella entidade coletiva 2
258 A0257 Tondella, Manoel. Photografia Tondella pessoa 2
259 A0258 Du Bocage, F., F. Du Bocage Photographia entidade coletiva 2
260 A0259 Mello, Borges de, Photographia modelo Borges de Mello entidade coletiva 2
261 A0260 1º Comando do Exército entidade coletiva 2
262 A0261 Silveira, J pessoa 2
263 A0262 Guimarães, Antonio de Oliveira pessoa 2
264 A0263 Furne fils et H. Tournier pessoa ou entidade 2
265 A0264 Carneiro & Smith pessoa ou entidade 2
266 A0265 Sabino pessoa ou entidade 2
267 A0266 Arthur e J. J. Wischral pessoa ou entidade 2
268 A0267 A. C. da Costa Ribeiro pessoa ou entidade 2
269 A0268 Pittigliani, Armando pessoa 2
270 A0269 Photographia Marc Ferrez entidade coletiva 2
271 A0270 Sobrosa Rio pessoa ou entidade 1
272 A0271 Sobrosa, Antenor pessoa 1
273 A0272 José Francisco Corrêa et C pessoa ou entidade 1
274 A0273 Corrêa, José Francisco pessoa 1
275 A0274 Castro, Jorge de pessoa 1
276 A0275 Duarte, B. J. (Benedito Junqueira), 1910-1995 pessoa 1
277 A0276 Vosylius, Kazys pessoa 1
278 A0277 Leon de Rennes pessoa ou entidade 1
279 A0278 Foto aérea Campo Marinha no Galeão entidade coletiva 1
280 A0279 Lopes pessoa ou entidade 1
281 A0280 Nicola Parente pessoa ou entidade 1
282 A0281 Ferrez, Luciano (1884 - 1955) pessoa 1
283 A0282 Jean Manzon pessoa ou entidade 1
284 A0283 Valuos, Guilherme pessoa 1
285 A0284 Viggiani, N pessoa 1
286 A0285 Dutra, Olavo - Fotógrafo pessoa 1
287 A0286 Fotógrafo: Vernaut, Benjamin pessoa 1
288 A0287 Photographia Guimarães entidade coletiva 1
289 A0288 E. Av. M pessoa ou entidade 1
290 A0289 Monteiro, Augusto pessoa 1
291 A0290 Stille, Paul pessoa 1
292 A0291 cios e préTheodor pessoa ou entidade 1
293 A0292 [Otto Hees?] pessoa ou entidade 1
294 A0293 Studio Paul entidade coletiva 1
295 A0294 Dr. Menescal pessoa ou entidade 1
296 A0295 Rembrandt - Rio pessoa ou entidade 1
297 A0296 Bellati, R. (Fotógrafo) pessoa 1
298 A0297 Somlo, Tomas pessoa 1
299 A0298 Emerico pessoa ou entidade 1
300 A0299 Carlos Moskovics pessoa ou entidade 1
301 A0300 Musso, Luís, m. 1908 pessoa 1
302 A0301 Agência Nacional entidade coletiva 1
303 A0302 Walery pessoa ou entidade 1
304 A0303 Klumb, Henrique Revert pessoa 1
305 A0304 Coutinho, A pessoa 1
306 A0305 Clerget pessoa ou entidade 1
307 A0306 Adam, Victor Jean, 1801-1866 pessoa 1
308 A0307 Courtois, J pessoa 1
309 A0308 Mason, Samuel J pessoa 1
310 A0309 Bradley & Rulofson pessoa ou entidade 1
311 A0310 H. Delie and E. Bechard pessoa ou entidade 1
312 A0311 Noël, Alphonse Léon, 1807-1884 pessoa 1
313 A0312 Helios (Fotógrafo) pessoa ou entidade 1
314 A0313 Nadar, Felix, 1820-1910 pessoa 1
315 A0314 Photographia Popular entidade coletiva 1
316 A0315 Angerer, Ludwig, 1827-1879 pessoa 1
317 A0316 Schoefft, O pessoa 1
318 A0317 Mourgeon, C pessoa 1
319 A0318 Antunes, F pessoa 1
320 A0319 Aguiar, Francisco Marcellino de Souza, 1855-1935 pessoa 1
321 A0320 Marc Ferrez & Filhos pessoa ou entidade 1
322 A0321 Zaccaria, G pessoa 1
323 A0322 Photograhia Vesuvio de Nicola Maria Parente pessoa ou entidade 1
324 A0323 Silveira, Pedro Satyro de Souza da pessoa 1
325 A0324 Rocha, J. C. da pessoa 1
326 A0325 Photographia Americana de Moreira & Roltgen entidade coletiva 1
327 A0326 Moreira & Roltgen pessoa ou entidade 1
328 A0327 Lopes & Ca pessoa ou entidade 1
329 A0328 Photographia Imperial de Lopes & Ca entidade coletiva 1
330 A0329 Atelier Photograhico Hygino Soares entidade coletiva 1
331 A0330 Nunes, Henrique, 1820-1895 pessoa 1
332 A0331 Luys, Jules Bernard, 1828-1897 pessoa 1
333 A0332 Wegner & Mottu pessoa ou entidade 1
334 A0333 Brogi, Giacomo, 1822-1881 pessoa 1
335 A0334 Con, Frederico Carlos pessoa 1
336 A0335 Fenton, Roger, 1819-1869 pessoa 1
337 A0336 Banchieri, Manoel pessoa 1
338 A0337 Fratelli Alinari Fotografi pessoa ou entidade 1
339 A0338 Photographie Technique A. Fernique pessoa ou entidade 1
340 A0339 Typographia Imperial & Real de Vienna pessoa ou entidade 1
341 A0340 Clairin, Georges-Jules-Victor, 1843-1919 pessoa 1
342 A0341 Gilleta & Gilly pessoa ou entidade 1
343 A0342 Arena, Giacomo, 1818-1906 pessoa 1
344 A0343 Jerace, Francesco, 1854 - 1937 pessoa 1
345 A0344 Calzolari, Icilio pessoa 1
346 A0345 Fumeo, Pietro, 1831-1898 pessoa 1
347 A0346 Trinquart (Fotógrafo) pessoa ou entidade 1
348 A0347 Berthier, Paul, 1822-1912 pessoa 1
349 A0348 Albert, Joseph, 1825-1886 pessoa 1
350 A0349 Photographie Americaine pessoa ou entidade 1
351 A0350 Kaun Phot pessoa ou entidade 1
352 A0351 Mauritshuis (Haia, Holanda) pessoa 1
353 A0352 Salentin, Hubert, 1822-1910 pessoa 1
354 A0353 Boker, Carl, 1836-1905 pessoa 1
355 A0354 Sonderland, F, 1836-1896 pessoa 1
356 A0355 C. & A. Overbeck pessoa ou entidade 1
357 A0356 Bosch, E pessoa 1
358 A0357 Werff, Adriaen van der, 1659 - 1722 pessoa 1
359 A0358 Gleyre, Charles, 1806-1874 pessoa 1
360 A0359 Goupil & Cie pessoa ou entidade 1
361 A0360 Stacey, C.A pessoa 1
362 A0361 Draper, Henry, 1837-1882 pessoa 1
363 A0362 Ludwig, Johann Fridrich, 1670-1752 pessoa 1
364 A0363 Meireles, Vítor, 1832-1903 pessoa 1
365 A0364 José da Santíssima Trindade, Bispo, 1762-1835 pessoa 1
366 A0365 Lucarell, Mario pessoa 1
367 A0366 Costa, Heitor da Silva, 1837-1947 pessoa 1
368 A0367 Foto Lucarelli entidade coletiva 1
369 A0368 Lima, José Otávio Correia, 1878-1974 pessoa 1
370 A0369 Read, R. A pessoa 1
371 A0370 Severino (Fotógrafo) pessoa ou entidade 1
372 A0371 Hospe, Joseph pessoa 1
373 A0372 Photo Lindemann entidade coletiva 1
374 A0373 Conti, José Carlos pessoa 1
375 A0374 Photo Studio Huberti entidade coletiva 1
376 A0375 Boquel, Julien pessoa 1
377 A0376 Silva, M. Nogueira da pessoa 1
378 A0377 Hoenen, Carlos pessoa 1
379 A0378 Fábrica de Ferro de Ipanema pessoa ou entidade 1
380 A0379 Rio Branco, José Maria da Silva Paranhos, Barão do, 1845-1912 pessoa 1
381 A0380 Nickelsen (Fotógrafo) pessoa ou entidade 1
382 A0381 Lima, Antonio Mariano de, 1858-1902 pessoa 1
383 A0382 Mello, Affonso de Oliveira pessoa 1
384 A0383 Lavinthal, Joaquim Ferreira dos Santos pessoa 1
385 A0384 Photo Lavinthal entidade coletiva 1
386 A0385 Vieira, Valério, 1862-1941 pessoa 1
387 A0386 Bate & Cia entidade coletiva 1
388 A0387 Micheles (Fotógrafo) pessoa ou entidade 1
389 A0388 Rochet, Louis, 1813-1878 pessoa 1
390 A0389 Mafra, João Maximiniano pessoa 1
391 A0390 Fleury, André Augusto de Pádua, 1830-1895 pessoa 1
392 A0391 Faro, Gonçalo Paes de Azevedo, 1846-1900 pessoa 1
393 A0392 Liais, Emmanuel, 1826-1900 pessoa 1
394 A0393 Hermida Pazos, José, 1829-1921 pessoa 1
395 A0394 Aquidabã pessoa ou entidade 1
396 A0395 Oliveira, C. de pessoa 1
397 A0396 Oliveira, Candido Marinho pessoa 1
398 A0397 Satrap Photo entidade coletiva 1
399 A0398 Agfa Brovira pessoa ou entidade 1
400 A0399 Ferrez, Gilberto pessoa 1
401 A0400 Boute pessoa ou entidade 1
402 A0401 Buvelot & Prat pessoa ou entidade 1
403 A0402 Panigai, Marco di pessoa 1
404 A0403 David Latino & Franklin pessoa ou entidade 1
405 A0404 Leuthold e Dursky pessoa ou entidade 1
406 A0405 Antunes, Humberto Saraiva pessoa 1
407 A0406 Castro pessoa ou entidade 1
408 A0407 Comp. Lith. Hartmann-Reichenbach entidade coletiva 1
409 A0408 Photographia Guilherme Gaensly entidade coletiva 1
410 A0409 Papeleria Travassos pessoa ou entidade 1
411 A0410 Phototipie Marius Bar pessoa ou entidade 1
412 A0411 Bureu Poste pessoa ou entidade 1
413 A0412 Edição A. Moura pessoa ou entidade 1
414 A0413 Bureau Poste pessoa ou entidade 1
415 A0414 Ao Cantineiro Naval pessoa ou entidade 1
416 A0415 Henschel e Benque pessoa ou entidade 1
417 A0416 Mello, Marcos A. de pessoa 1
418 A0417 Soares, José Severino pessoa 1
419 A0418 Bastos, A pessoa 1
420 A0419 Henschel, Albert, 1827-1882 pessoa 1
421 A0420 Bonfioti, J pessoa 1
422 A0421 Foto Chic entidade coletiva 1
423 A0422 Barboza, Theotonio pessoa 1
424 A0423 Rogato, Guilherme pessoa 1
425 A0424 Photo Skarke entidade coletiva 1
426 A0425 Serviço Photographico de Vida Domestica entidade coletiva 1
427 A0426 Foto Studio Gloria entidade coletiva 1
428 A0427 Fotografia Alemã entidade coletiva 1
429 A0428 Brady, Mathew B., ca. 1823-1896 pessoa 1
430 A0429 Photograhia Popular Oliveira & Tondella pessoa ou entidade 1
431 A0430 Photografia Popular Oliveira & Tondella pessoa ou entidade 1
432 A0431 Manoel Tondella, Photografia Tondella pessoa 1
433 A0432 Claude Lévi-Strauss pessoa ou entidade 1
434 A0433 Monteiro,Photographie Chic Monteiro & C pessoa 1
435 A0434 Edgard Egydio de Souza pessoa ou entidade 1
436 A0435 S/A pessoa ou entidade 1
437 A0436 Chapelin E Pereira pessoa ou entidade 1
438 A0437 Poluceno & Pinho pessoa ou entidade 1
439 A0438 <ns:Co & Pinho pessoa ou entidade 1
440 A0439 Thiele & Kollien [?]; Photo Bippus Rio [?] entidade coletiva 1
441 A0440 Photographia Central entidade coletiva 1
442 A0441 Veiga, Bernardo Saturnino da pessoa 1
443 A0442 Phototypie Berthaud pessoa ou entidade 1
444 A0443 Marinho, P pessoa 1
445 A0444 A. Editora entidade coletiva 1
446 A0445 511-73, Marc pessoa 1
447 A0446 J. Stamato pessoa ou entidade 1
448 A0447 DADE pessoa ou entidade 1
449 A0448 Annunciato pessoa ou entidade 1
450 A0449 Benque pessoa ou entidade 1
451 A0450 Chapelin pessoa ou entidade 1
452 A0451 Scheidemantel, B pessoa 1
453 A0452 Photo Braz Rio entidade coletiva 1
454 A0453 Scheuenstuhl, Paulo pessoa 1
455 A0454 Caras & Caretas pessoa ou entidade 1
456 A0455 Leonar pessoa ou entidade 1
457 A0456 Azevedo, J. Faria de pessoa 1
458 A0457 Basto, F pessoa 1
File diff suppressed because it is too large Load Diff
+104
View File
@@ -0,0 +1,104 @@
instituicao categoria detentor originais n
Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles Instituto Moreira Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 3928
Biblioteca Nacional consultar o detentor Biblioteca Nacional (Brasil) Biblioteca Nacional (Brasil) 1889
Museu Aeroespacial consultar o detentor Museu Aeroespacial "" 1143
Museu da Republica consultar o detentor Museu da República "" 838
Biblioteca Nacional consultar o detentor Biblioteca Nacional (Brasil) "" 826
Museu Historico Nacional consultar o detentor Museu Histórico Nacional "" 649
Fiocruz consultar o detentor Fundação Oswaldo Cruz. Casa de Oswaldo Cruz "" 548
Instituto Moreira Salles domínio público Instituto Moreira Salles Em domínio público | Liberado para uso de natureza cultural 479
Diretoria do Patrimonio Historico e Documentacao da Marinha consultar o detentor Diretoria do Patrimônio Histórico e Documentação da Marinha "" 450
Arquivo Nacional consultar o detentor Arquivo Nacional (Brasil) "" 383
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles "" 310
Arquivo Geral da Cidade do Rio de Janeiro consultar o detentor Arquivo Geral da Cidade do Rio de Janeiro "" 248
Leibniz-Institut fuer Laenderkunde, Leipzig requer autorização do detentor Convênio Leibniz-Institut fuer Laenderkunde, Leipzig/ Instituto Moreira Salles Convênio Leibniz-Institut fuer Laenderkunde, Leipzig/ Instituto Moreira Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 212
Fundacao Joaquim Nabuco consultar o detentor Fundação Joaquim Nabuco "" 189
Instituto Historico e Geografico Brasileiro domínio público Instituto Histórico e Geográfico Brasileiro Em domínio público | Liberado para uso de natureza cultural 176
Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles Instituto Moreira Salles | Requer liberação de direitos de imagem junto ao detentor indicado no Copyright 172
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles 116
Museu Paraense Emilio Goeldi consultar o detentor Museu Paraense Emílio Goeldi "" 95
Escola de Ciencias Sociais (FGV CPDOC) consultar o detentor Fundação Getulio Vargas. Escola de Ciências Sociais (FGV CPDOC) "" 79
Museu da Republica consultar o detentor Flávio de Barros / Acervo Museu da República / Imagem recuperada digitalmente pelo Instituto Moreira Salles Flávio de Barros / Acervo Museu da República / Imagem recuperada digitalmente pelo Instituto Moreira Salles 68
Instituto Brasileiro de Geografia e Estatistica consultar o detentor Instituto Brasileiro de Geografia e Estatística "" 58
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | Liberado apenas para uso de natureza cultural 52
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Acervo Instituto Moreira Salles 27
Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles Solicitar imagem junto ao detentor dos direitos indicado no Copyright 19
Instituto Historico e Geografico Brasileiro consultar o detentor Instituto Histórico e Geográfico Brasileiro "" 17
Instituto Moreira Salles requer autorização do detentor Dom João de Orleans e Bragança/ Instituto Moreira Salles Dom João de Orleans e Bragança/ Instituto Moreira Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 10
Instituto Historico e Geografico Brasileiro consultar o detentor Convênio Instituto Histórico e Geográfico Brasileiro / Instituto Moreira Salles Convênio Instituto Histórico e Geográfico Brasileiro / Instituto Moreira Salles 10
Instituto Moreira Salles requer autorização do detentor Diários Associados - Rio de Janeiro/ Acervo Instituto Moreira Salles Diários Associados - Rio de Janeiro/ Acervo Instituto Moreira Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 4
Instituto Moreira Salles requer autorização do detentor Flávio de Barros / Acervo Instituto Geográfico e Histórico da Bahia / Imagem recuperada digitalmente pelo Instituto Moreira Salles Flávio de Barros / Acervo Instituto Geográfico e Histórico da Bahia / Imagem recuperada digitalmente pelo Instituto Moreira Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 2
Biblioteca Nacional consultar o detentor Biblioteca Nacional (Brasil) Biblioteca Nacional (Brazil) 2
Biblioteca Nacional consultar o detentor Biblioteca Nacional (Brasil) Biblioteca nacional (Brasil) 2
Biblioteca Nacional consultar o detentor Biblioteca Nacional (Brasil) Biblioteca Nacional 1
Instituto Moreira Salles requer autorização do detentor Instituto Moreira Instituto Moreira | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles "Instituto Moreira Salles | dValue>
<ns:FieldValue uid=""{8b30dbb7-97ef-4a5c-8a40-18no Copyright" 1
Museu da Republica consultar o detentor Flávio de Barros/ Álbum Canônico Virtual de Canudos/ Acervo Instituto Moreira Salles/ Copyright Museu da República Flávio de Barros/ Álbum Canônico Virtual de Canudos/ Acervo Instituto Moreira Salles/ Copyright Museu da República 1
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles "Instituto Moreira Salles | s:FieldValue uid=""{48b5771a-326a-42ce-9f83-0b9c225178e4}"">
<ns:Ent" 1
Instituto Moreira Salles domínio público Instituto Moreira Salles "Em domínio público | >
<ns:Fiera uso de natureza cultural" 1
Biblioteca Nacional consultar o detentor Bibioteca Nacional (Brasil) Bibioteca Nacional (Brasil) 1
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | b4d39078a18217be451480f38ed41348631ea3208cd4aos indicado no Copyright 1
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles "Instituto Moreira Salles | lue>
ar imagem junto ao detentor dos direitos indicado no Copyright" 1
Instituto Historico e Geografico Brasileiro domínio público Instituto Histórico e Geográfico Brasileiro Em domínio público | s:Fi 1
Biblioteca Nacional consultar o detentor Bilioteca Nacional (Brasil) Bilioteca Nacional (Brasil) 1
Instituto Moreira Salles uso cultural liberado Instituto Moreira Salles <ns:Eio público | Liberado para uso de natureza cultural 1
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | elho</tar imagem junto ao detentor dos direitos indicado no Copyright 1
Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles <ns:EnumValue idlles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | 6572455391487c6de95a8490303151ec19e40cd302bc659533d2a2949624Copyright 1
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles "Instituto Moreira Salles | acbe6cdb314}"">
<nto ao detentor dos direitos indicado no Copyright" 1
Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles oryValue>FOTOGira Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles "Instituto Moreira Salles | 7094}"">
<ns:EnumValue id=""64"">Ferrez, reitos indicado no Copyright" 1
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | f05ea53de7866ce3bcunto ao detentor dos direitos indicado no Copyright 1
Instituto Moreira Salles domínio público Instituto Moreira Salles "Em domínio público | b6979}"">sp: 13,0 x 18,0 cm</ns:ultural" 1
Instituto Moreira Salles uso cultural liberado Instituto Moreira Salles "f1}"">Atual Túblico | Liberado para uso de natureza cultural" 1
Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles PALAVRAS-CHAVE:La Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | 4bb3d1a793c4ba619352175229f38606or dos direitos indicado no Copyright 1
Instituto Moreira Salles domínio público Instituto Moreira Salles "Em domínio público | lue>
</ns:FieldValue>
<na cultural" 1
Biblioteca Nacional consultar o detentor Bilbioteca Nacional (Brasil) Bilbioteca Nacional (Brasil) 1
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | 7 circa</ns:Fiem junto ao detentor dos direitos indicado no Copyright 1
Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles S:Tratuto Moreira Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
Biblioteca Nacional consultar o detentor Biblioteca Nacional (Brasil) Biblioteca Nacioinal (Brasil) 1
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | aleceu no Rio de Janeiro em 1923.</nss direitos indicado no Copyright 1
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles "Instituto Moreira Salles | 109"">Ltar imagem junto ao detentor dos direitos indicado no Copyright" 1
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | 0dlicitar imagem junto ao detentor dos direitos indicado no Copyright 1
Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles Pessoas</ns:CategoryVaes | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | 90d9-22fa7imagem junto ao detentor dos direitos indicado no Copyright 1
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles "Instituto Moreira Salles | ue>
<ns:CategoryValue>FOetentor dos direitos indicado no Copyright" 1
Diretoria do Patrimonio Historico e Documentacao da Marinha consultar o detentor Diretoria do Patrimônio Histórico e Documentação da Marinha DPHDM 1
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles "Instituto Moreira Salles | terna</ns:CategoryValue>
<ns:CategoryValitos indicado no Copyright" 1
Leibniz-Institut fuer Laenderkunde, Leipzig consultar o detentor Convênio Leibniz-Institut fuer Laenderkunde, Leipzig/ Instituto Moreira Salles Convênio Leibniz-Institut fuer Laenderkunde, Leipzig/ Instituto Moreira Salles | 969b9e69c2810518cd1da941cd001da8c71cos direitos indicado no Copyright 1
Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles Fiel | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
Instituto Moreira Salles requer autorização do detentor ro em 1923.oreira Salles ro em 1923.oreira Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | DO ACERVO:COLEÇÃOjunto ao detentor dos direitos indicado no Copyright 1
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles "Instituto Moreira Salles | ue>
</ns:FieldValue>
<ns:FieldValue uid=""{5094c229-4 no Copyright" 1
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles "Instituto Moreira Salles | 5daf98}"">Elaborado por Grandjean de Montigny em 1827,ado no Copyright" 1
Biblioteca Nacional consultar o detentor Biblioteca Nacional (Brasil) Biblioeca Nacional (Brasil) 1
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Acervo Instituto Moreira Salles | Liberado apenas para uso de natureza cultural 1
Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles {5stituto Moreira Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles goryituto Moreira Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
Leibniz-Institut fuer Laenderkunde, Leipzig consultar o detentor Convênio Leibniz-Institut fuer Laenderkunde, Leipzig/ Instituto Moreira Salles Convênio Leibniz-Institut fuer Laenderkunde, Leipzig/ Instituto Moreira Salles | 3db9 1
Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles egor | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles "Instituto Moreira Salles | EnumValue id=""160"">nto ao detentor dos direitos indicado no Copyright" 1
Instituto Historico e Geografico Brasileiro domínio público Instituto Histórico e Geográfico Brasileiro "Em domínio público | >
<ns:CategoryValue>FOTOGRAFIA:ARQU" 1
Leibniz-Institut fuer Laenderkunde, Leipzig requer autorização do detentor Leibniz-Institut für Länderkunde 9b3 | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
Leibniz-Institut fuer Laenderkunde, Leipzig consultar o detentor Convênio Leibniz-Institut fuer Laenderkunde, Leipzig/ Instituto Moreira Salles Convênio Leibniz-Institut fuer Laenderkunde, Leipzig/ Instituto Moreira Salles | c679ac249ad19699ccf88058daf8075965819afe7ba6b7772b961b58119c760bd0f6c 1
Instituto Moreira Salles domínio público Instituto Moreira Salles Em domínio público | ns:F 1
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | 074007300000000006a00000001554368720055003a007b003900380063006pyright 1
Instituto Historico e Geografico Brasileiro domínio público Instituto Histórico e Geográfico Brasileiro /ns:omínio público | Liberado para uso de natureza cultural 1
Biblioteca Nacional consultar o detentor Biblioteca Nacional (Brasil) Biblioteca Nacioanl (Brasil) 1
Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles 80stituto Moreira Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | 45c-5d93acdmagem junto ao detentor dos direitos indicado no Copyright 1
Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | ns:CategoryValue>FOTOGRAFIA:COLEÇÕES DO ACERVO:COLEÇcado no Copyright 1
1 instituicao categoria detentor originais n
2 Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles Instituto Moreira Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 3928
3 Biblioteca Nacional consultar o detentor Biblioteca Nacional (Brasil) Biblioteca Nacional (Brasil) 1889
4 Museu Aeroespacial consultar o detentor Museu Aeroespacial 1143
5 Museu da Republica consultar o detentor Museu da República 838
6 Biblioteca Nacional consultar o detentor Biblioteca Nacional (Brasil) 826
7 Museu Historico Nacional consultar o detentor Museu Histórico Nacional 649
8 Fiocruz consultar o detentor Fundação Oswaldo Cruz. Casa de Oswaldo Cruz 548
9 Instituto Moreira Salles domínio público Instituto Moreira Salles Em domínio público | Liberado para uso de natureza cultural 479
10 Diretoria do Patrimonio Historico e Documentacao da Marinha consultar o detentor Diretoria do Patrimônio Histórico e Documentação da Marinha 450
11 Arquivo Nacional consultar o detentor Arquivo Nacional (Brasil) 383
12 Instituto Moreira Salles consultar o detentor Instituto Moreira Salles 310
13 Arquivo Geral da Cidade do Rio de Janeiro consultar o detentor Arquivo Geral da Cidade do Rio de Janeiro 248
14 Leibniz-Institut fuer Laenderkunde, Leipzig requer autorização do detentor Convênio Leibniz-Institut fuer Laenderkunde, Leipzig/ Instituto Moreira Salles Convênio Leibniz-Institut fuer Laenderkunde, Leipzig/ Instituto Moreira Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 212
15 Fundacao Joaquim Nabuco consultar o detentor Fundação Joaquim Nabuco 189
16 Instituto Historico e Geografico Brasileiro domínio público Instituto Histórico e Geográfico Brasileiro Em domínio público | Liberado para uso de natureza cultural 176
17 Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles Instituto Moreira Salles | Requer liberação de direitos de imagem junto ao detentor indicado no Copyright 172
18 Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles 116
19 Museu Paraense Emilio Goeldi consultar o detentor Museu Paraense Emílio Goeldi 95
20 Escola de Ciencias Sociais (FGV CPDOC) consultar o detentor Fundação Getulio Vargas. Escola de Ciências Sociais (FGV CPDOC) 79
21 Museu da Republica consultar o detentor Flávio de Barros / Acervo Museu da República / Imagem recuperada digitalmente pelo Instituto Moreira Salles Flávio de Barros / Acervo Museu da República / Imagem recuperada digitalmente pelo Instituto Moreira Salles 68
22 Instituto Brasileiro de Geografia e Estatistica consultar o detentor Instituto Brasileiro de Geografia e Estatística 58
23 Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | Liberado apenas para uso de natureza cultural 52
24 Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Acervo Instituto Moreira Salles 27
25 Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles Solicitar imagem junto ao detentor dos direitos indicado no Copyright 19
26 Instituto Historico e Geografico Brasileiro consultar o detentor Instituto Histórico e Geográfico Brasileiro 17
27 Instituto Moreira Salles requer autorização do detentor Dom João de Orleans e Bragança/ Instituto Moreira Salles Dom João de Orleans e Bragança/ Instituto Moreira Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 10
28 Instituto Historico e Geografico Brasileiro consultar o detentor Convênio Instituto Histórico e Geográfico Brasileiro / Instituto Moreira Salles Convênio Instituto Histórico e Geográfico Brasileiro / Instituto Moreira Salles 10
29 Instituto Moreira Salles requer autorização do detentor Diários Associados - Rio de Janeiro/ Acervo Instituto Moreira Salles Diários Associados - Rio de Janeiro/ Acervo Instituto Moreira Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 4
30 Instituto Moreira Salles requer autorização do detentor Flávio de Barros / Acervo Instituto Geográfico e Histórico da Bahia / Imagem recuperada digitalmente pelo Instituto Moreira Salles Flávio de Barros / Acervo Instituto Geográfico e Histórico da Bahia / Imagem recuperada digitalmente pelo Instituto Moreira Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 2
31 Biblioteca Nacional consultar o detentor Biblioteca Nacional (Brasil) Biblioteca Nacional (Brazil) 2
32 Biblioteca Nacional consultar o detentor Biblioteca Nacional (Brasil) Biblioteca nacional (Brasil) 2
33 Biblioteca Nacional consultar o detentor Biblioteca Nacional (Brasil) Biblioteca Nacional 1
34 Instituto Moreira Salles requer autorização do detentor Instituto Moreira Instituto Moreira | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
35 Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | dValue> <ns:FieldValue uid="{8b30dbb7-97ef-4a5c-8a40-18no Copyright 1
36 Museu da Republica consultar o detentor Flávio de Barros/ Álbum Canônico Virtual de Canudos/ Acervo Instituto Moreira Salles/ Copyright Museu da República Flávio de Barros/ Álbum Canônico Virtual de Canudos/ Acervo Instituto Moreira Salles/ Copyright Museu da República 1
37 Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | s:FieldValue uid="{48b5771a-326a-42ce-9f83-0b9c225178e4}"> <ns:Ent 1
38 Instituto Moreira Salles domínio público Instituto Moreira Salles Em domínio público | > <ns:Fiera uso de natureza cultural 1
39 Biblioteca Nacional consultar o detentor Bibioteca Nacional (Brasil) Bibioteca Nacional (Brasil) 1
40 Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | b4d39078a18217be451480f38ed41348631ea3208cd4aos indicado no Copyright 1
41 Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | lue> ar imagem junto ao detentor dos direitos indicado no Copyright 1
42 Instituto Historico e Geografico Brasileiro domínio público Instituto Histórico e Geográfico Brasileiro Em domínio público | s:Fi 1
43 Biblioteca Nacional consultar o detentor Bilioteca Nacional (Brasil) Bilioteca Nacional (Brasil) 1
44 Instituto Moreira Salles uso cultural liberado Instituto Moreira Salles <ns:Eio público | Liberado para uso de natureza cultural 1
45 Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | elho</tar imagem junto ao detentor dos direitos indicado no Copyright 1
46 Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles <ns:EnumValue idlles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
47 Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | 6572455391487c6de95a8490303151ec19e40cd302bc659533d2a2949624Copyright 1
48 Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | acbe6cdb314}"> <nto ao detentor dos direitos indicado no Copyright 1
49 Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles oryValue>FOTOGira Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
50 Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | 7094}"> <ns:EnumValue id="64">Ferrez, reitos indicado no Copyright 1
51 Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | f05ea53de7866ce3bcunto ao detentor dos direitos indicado no Copyright 1
52 Instituto Moreira Salles domínio público Instituto Moreira Salles Em domínio público | b6979}">sp: 13,0 x 18,0 cm</ns:ultural 1
53 Instituto Moreira Salles uso cultural liberado Instituto Moreira Salles f1}">Atual Túblico | Liberado para uso de natureza cultural 1
54 Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles PALAVRAS-CHAVE:La Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
55 Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | 4bb3d1a793c4ba619352175229f38606or dos direitos indicado no Copyright 1
56 Instituto Moreira Salles domínio público Instituto Moreira Salles Em domínio público | lue> </ns:FieldValue> <na cultural 1
57 Biblioteca Nacional consultar o detentor Bilbioteca Nacional (Brasil) Bilbioteca Nacional (Brasil) 1
58 Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | 7 circa</ns:Fiem junto ao detentor dos direitos indicado no Copyright 1
59 Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles S:Tratuto Moreira Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
60 Biblioteca Nacional consultar o detentor Biblioteca Nacional (Brasil) Biblioteca Nacioinal (Brasil) 1
61 Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | aleceu no Rio de Janeiro em 1923.</nss direitos indicado no Copyright 1
62 Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | 109">Ltar imagem junto ao detentor dos direitos indicado no Copyright 1
63 Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | 0dlicitar imagem junto ao detentor dos direitos indicado no Copyright 1
64 Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles Pessoas</ns:CategoryVaes | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
65 Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | 90d9-22fa7imagem junto ao detentor dos direitos indicado no Copyright 1
66 Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | ue> <ns:CategoryValue>FOetentor dos direitos indicado no Copyright 1
67 Diretoria do Patrimonio Historico e Documentacao da Marinha consultar o detentor Diretoria do Patrimônio Histórico e Documentação da Marinha DPHDM 1
68 Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | terna</ns:CategoryValue> <ns:CategoryValitos indicado no Copyright 1
69 Leibniz-Institut fuer Laenderkunde, Leipzig consultar o detentor Convênio Leibniz-Institut fuer Laenderkunde, Leipzig/ Instituto Moreira Salles Convênio Leibniz-Institut fuer Laenderkunde, Leipzig/ Instituto Moreira Salles | 969b9e69c2810518cd1da941cd001da8c71cos direitos indicado no Copyright 1
70 Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles Fiel | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
71 Instituto Moreira Salles requer autorização do detentor ro em 1923.oreira Salles ro em 1923.oreira Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
72 Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | DO ACERVO:COLEÇÃOjunto ao detentor dos direitos indicado no Copyright 1
73 Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | ue> </ns:FieldValue> <ns:FieldValue uid="{5094c229-4 no Copyright 1
74 Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | 5daf98}">Elaborado por Grandjean de Montigny em 1827,ado no Copyright 1
75 Biblioteca Nacional consultar o detentor Biblioteca Nacional (Brasil) Biblioeca Nacional (Brasil) 1
76 Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Acervo Instituto Moreira Salles | Liberado apenas para uso de natureza cultural 1
77 Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles {5stituto Moreira Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
78 Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles goryituto Moreira Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
79 Leibniz-Institut fuer Laenderkunde, Leipzig consultar o detentor Convênio Leibniz-Institut fuer Laenderkunde, Leipzig/ Instituto Moreira Salles Convênio Leibniz-Institut fuer Laenderkunde, Leipzig/ Instituto Moreira Salles | 3db9 1
80 Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles egor | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
81 Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | EnumValue id="160">nto ao detentor dos direitos indicado no Copyright 1
82 Instituto Historico e Geografico Brasileiro domínio público Instituto Histórico e Geográfico Brasileiro Em domínio público | > <ns:CategoryValue>FOTOGRAFIA:ARQU 1
83 Leibniz-Institut fuer Laenderkunde, Leipzig requer autorização do detentor Leibniz-Institut für Länderkunde 9b3 | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
84 Leibniz-Institut fuer Laenderkunde, Leipzig consultar o detentor Convênio Leibniz-Institut fuer Laenderkunde, Leipzig/ Instituto Moreira Salles Convênio Leibniz-Institut fuer Laenderkunde, Leipzig/ Instituto Moreira Salles | c679ac249ad19699ccf88058daf8075965819afe7ba6b7772b961b58119c760bd0f6c 1
85 Instituto Moreira Salles domínio público Instituto Moreira Salles Em domínio público | ns:F 1
86 Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | 074007300000000006a00000001554368720055003a007b003900380063006pyright 1
87 Instituto Historico e Geografico Brasileiro domínio público Instituto Histórico e Geográfico Brasileiro /ns:omínio público | Liberado para uso de natureza cultural 1
88 Biblioteca Nacional consultar o detentor Biblioteca Nacional (Brasil) Biblioteca Nacioanl (Brasil) 1
89 Instituto Moreira Salles requer autorização do detentor Instituto Moreira Salles 80stituto Moreira Salles | Solicitar imagem junto ao detentor dos direitos indicado no Copyright 1
90 Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | 45c-5d93acdmagem junto ao detentor dos direitos indicado no Copyright 1
91 Instituto Moreira Salles consultar o detentor Instituto Moreira Salles Instituto Moreira Salles | ns:CategoryValue>FOTOGRAFIA:COLEÇÕES DO ACERVO:COLEÇcado no Copyright 1
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+50
View File
@@ -0,0 +1,50 @@
instituicao dc_type genero especie suporte presumida n
Instituto Moreira Salles Fotografia/ Papel iconográfico fotografia papel false 2633
Biblioteca Nacional Fotografia iconográfico fotografia "" false 1852
Instituto Moreira Salles Negativo/ Vidro iconográfico negativo fotográfico vidro false 1304
Museu Aeroespacial "" iconográfico fotografia "" true 1143
Museu da Republica "" iconográfico fotografia "" true 907
Instituto Moreira Salles Diapositivo/ Vidro iconográfico diapositivo vidro false 655
Museu Historico Nacional "" iconográfico fotografia "" true 649
Fiocruz "" iconográfico fotografia "" true 548
Diretoria do Patrimonio Historico e Documentacao da Marinha "" iconográfico fotografia "" true 450
Arquivo Nacional "" iconográfico fotografia "" true 383
Biblioteca Nacional "" iconográfico fotografia "" true 371
Biblioteca Nacional Manuscrito textual manuscrito "" false 294
Instituto Moreira Salles "" iconográfico fotografia "" true 263
Arquivo Geral da Cidade do Rio de Janeiro "" iconográfico fotografia "" true 248
Leibniz-Institut fuer Laenderkunde, Leipzig Fotografia/ Papel iconográfico fotografia papel false 206
Fundacao Joaquim Nabuco "" iconográfico fotografia "" true 189
Instituto Historico e Geografico Brasileiro Fotografia/ Papel iconográfico fotografia papel false 179
Biblioteca Nacional Livro bibliográfico livro "" false 127
Instituto Moreira Salles Reprodução Fotomecânica/ Papel iconográfico reprodução fotomecânica papel false 124
Museu Paraense Emilio Goeldi "" iconográfico fotografia "" true 95
Escola de Ciencias Sociais (FGV CPDOC) "" iconográfico fotografia "" true 79
Biblioteca Nacional Gravura iconográfico gravura "" false 61
Instituto Brasileiro de Geografia e Estatistica "" iconográfico fotografia "" true 58
Instituto Moreira Salles Fotografia iconográfico fotografia "" false 55
Instituto Moreira Salles NEGATIVO/ Vidro iconográfico negativo fotográfico vidro false 50
Instituto Moreira Salles FOTOGRAFIA/ Papel iconográfico fotografia papel false 41
Instituto Historico e Geografico Brasileiro "" iconográfico fotografia "" true 27
Instituto Moreira Salles Negativo flexível iconográfico negativo fotográfico flexível false 16
Biblioteca Nacional Álbum iconográfico álbum fotográfico "" false 15
Leibniz-Institut fuer Laenderkunde, Leipzig Negativo/ Vidro iconográfico negativo fotográfico vidro false 9
Instituto Moreira Salles Outros iconográfico fotografia "" true 4
Instituto Moreira Salles NEGATIVO flexível iconográfico negativo fotográfico flexível false 4
Biblioteca Nacional Desenho iconográfico desenho "" false 3
Biblioteca Nacional Artigo de Periódico bibliográfico periódico "" false 2
Instituto Moreira Salles DIAPOSITIVO/ Vidro iconográfico diapositivo vidro false 2
Diretoria do Patrimonio Historico e Documentacao da Marinha Fotografia iconográfico fotografia "" false 1
Instituto Moreira Salles 4778-rafia/ Papel iconográfico fotografia "" true 1
Instituto Moreira Salles Negativo/ Papel iconográfico negativo fotográfico papel false 1
Instituto Moreira Salles REPRODUÇÃO FOTOMECÂNICA/ Papel iconográfico reprodução fotomecânica papel false 1
Instituto Moreira Salles 481b791d7a/ Papel iconográfico fotografia "" true 1
Instituto Moreira Salles """{frodução Fotomecânica/ Papel" iconográfico fotografia "" true 1
Instituto Moreira Salles 3ceegrafia/ Papel iconográfico fotografia "" true 1
Biblioteca Nacional Vista panorâmica iconográfico fotografia "" false 1
Leibniz-Institut fuer Laenderkunde, Leipzig bee2e5afia/ Papel iconográfico fotografia "" true 1
Instituto Moreira Salles yValue>FOa/ Papel iconográfico fotografia "" true 1
Instituto Moreira Salles Fotografia/ Papel resinado iconográfico fotografia papel resinado false 1
Instituto Moreira Salles da197f8b9ebf4apel iconográfico fotografia "" true 1
Instituto Moreira Salles Fotografia/ Tecido iconográfico fotografia tecido false 1
Instituto Moreira Salles 93gativo/ Vidro iconográfico fotografia "" true 1
1 instituicao dc_type genero especie suporte presumida n
2 Instituto Moreira Salles Fotografia/ Papel iconográfico fotografia papel false 2633
3 Biblioteca Nacional Fotografia iconográfico fotografia false 1852
4 Instituto Moreira Salles Negativo/ Vidro iconográfico negativo fotográfico vidro false 1304
5 Museu Aeroespacial iconográfico fotografia true 1143
6 Museu da Republica iconográfico fotografia true 907
7 Instituto Moreira Salles Diapositivo/ Vidro iconográfico diapositivo vidro false 655
8 Museu Historico Nacional iconográfico fotografia true 649
9 Fiocruz iconográfico fotografia true 548
10 Diretoria do Patrimonio Historico e Documentacao da Marinha iconográfico fotografia true 450
11 Arquivo Nacional iconográfico fotografia true 383
12 Biblioteca Nacional iconográfico fotografia true 371
13 Biblioteca Nacional Manuscrito textual manuscrito false 294
14 Instituto Moreira Salles iconográfico fotografia true 263
15 Arquivo Geral da Cidade do Rio de Janeiro iconográfico fotografia true 248
16 Leibniz-Institut fuer Laenderkunde, Leipzig Fotografia/ Papel iconográfico fotografia papel false 206
17 Fundacao Joaquim Nabuco iconográfico fotografia true 189
18 Instituto Historico e Geografico Brasileiro Fotografia/ Papel iconográfico fotografia papel false 179
19 Biblioteca Nacional Livro bibliográfico livro false 127
20 Instituto Moreira Salles Reprodução Fotomecânica/ Papel iconográfico reprodução fotomecânica papel false 124
21 Museu Paraense Emilio Goeldi iconográfico fotografia true 95
22 Escola de Ciencias Sociais (FGV CPDOC) iconográfico fotografia true 79
23 Biblioteca Nacional Gravura iconográfico gravura false 61
24 Instituto Brasileiro de Geografia e Estatistica iconográfico fotografia true 58
25 Instituto Moreira Salles Fotografia iconográfico fotografia false 55
26 Instituto Moreira Salles NEGATIVO/ Vidro iconográfico negativo fotográfico vidro false 50
27 Instituto Moreira Salles FOTOGRAFIA/ Papel iconográfico fotografia papel false 41
28 Instituto Historico e Geografico Brasileiro iconográfico fotografia true 27
29 Instituto Moreira Salles Negativo flexível iconográfico negativo fotográfico flexível false 16
30 Biblioteca Nacional Álbum iconográfico álbum fotográfico false 15
31 Leibniz-Institut fuer Laenderkunde, Leipzig Negativo/ Vidro iconográfico negativo fotográfico vidro false 9
32 Instituto Moreira Salles Outros iconográfico fotografia true 4
33 Instituto Moreira Salles NEGATIVO flexível iconográfico negativo fotográfico flexível false 4
34 Biblioteca Nacional Desenho iconográfico desenho false 3
35 Biblioteca Nacional Artigo de Periódico bibliográfico periódico false 2
36 Instituto Moreira Salles DIAPOSITIVO/ Vidro iconográfico diapositivo vidro false 2
37 Diretoria do Patrimonio Historico e Documentacao da Marinha Fotografia iconográfico fotografia false 1
38 Instituto Moreira Salles 4778-rafia/ Papel iconográfico fotografia true 1
39 Instituto Moreira Salles Negativo/ Papel iconográfico negativo fotográfico papel false 1
40 Instituto Moreira Salles REPRODUÇÃO FOTOMECÂNICA/ Papel iconográfico reprodução fotomecânica papel false 1
41 Instituto Moreira Salles 481b791d7a/ Papel iconográfico fotografia true 1
42 Instituto Moreira Salles "{frodução Fotomecânica/ Papel iconográfico fotografia true 1
43 Instituto Moreira Salles 3ceegrafia/ Papel iconográfico fotografia true 1
44 Biblioteca Nacional Vista panorâmica iconográfico fotografia false 1
45 Leibniz-Institut fuer Laenderkunde, Leipzig bee2e5afia/ Papel iconográfico fotografia true 1
46 Instituto Moreira Salles yValue>FOa/ Papel iconográfico fotografia true 1
47 Instituto Moreira Salles Fotografia/ Papel resinado iconográfico fotografia papel resinado false 1
48 Instituto Moreira Salles da197f8b9ebf4apel iconográfico fotografia true 1
49 Instituto Moreira Salles Fotografia/ Tecido iconográfico fotografia tecido false 1
50 Instituto Moreira Salles 93gativo/ Vidro iconográfico fotografia true 1
+6
View File
@@ -0,0 +1,6 @@
# Nível 0 — acervo da entidade custodiadora
## 3.1 Âmbito e conteúdo
Cópias digitais de acervos fotográficos brasileiros, mantidas para preservação
e consulta. Hoje, uma coleção: a Brasiliana Fotográfica (BR RJXYZ.BF).
+143
View File
@@ -0,0 +1,143 @@
# Nível 1 — Coleção Brasiliana Fotográfica (cópia digital)
Cada seção `## N.N` preenche o elemento de mesmo número da NOBRADE no nível 1.
Lido por `pipeline/nobrade/montar.py`. Seções vazias são ignoradas. Fatos
conferidos em 2026-09-30; fontes no fim.
## 2.2 História administrativa/Biografia
Coleção formada em setembro de 2026 para preservar uma cópia integral da
Brasiliana Fotográfica, portal lançado em 17 de abril de 2015 pela Fundação
Biblioteca Nacional e pelo Instituto Moreira Salles para reunir, num único
repositório DSpace, acervos fotográficos dos séculos XIX e XX de instituições
brasileiras e estrangeiras.
O eixo temático é o do próprio portal: a fotografia produzida no Brasil ou
sobre o Brasil.
## 2.3 História arquivística
Natureza da acumulação: coleção. Reunida intencionalmente por cópia digital,
sem transferência de custódia dos originais, que permanecem nas 15
instituições de origem (5.1 de cada dossiê).
A Biblioteca Nacional foi consultada antes da coleta. Confirmou que o material
é público e que não tinha equipe técnica para fornecer um dump; a coleta por
raspagem, em ritmo cortês e com identificação, foi o caminho combinado.
Intervenções técnicas, em ordem:
1. Metadados (setembro de 2026): 13.060 itens enumerados pelo índice de
navegação ao vivo do DSpace (`browse?type=title`), comunidade a comunidade.
O sitemap oficial, gerado em abril de 2019, lista só cerca de 41% do acervo
e foi descartado como fonte. O registro completo de cada item
(`?show=full`) foi colhido a partir de um navegador real, porque o
Cloudflare do site bloqueia automação.
2. Arquivos: para cada item foi guardado o bitstream do DSpace como imagem de
preservação (maior resolução disponível; digitalizações de até 34,7 MB), a
miniatura gerada pelo DSpace e, quando existia, a cópia legada do
objdigital.bn.br, de resolução bem menor, guardada como procedência. 121
itens tinham de 2 a 8 imagens reais, e todas foram guardadas (nível 5).
3. Cada arquivo foi baixado, somado (SHA-256), enviado ao bucket e apagado do
disco local. O ledger do envio é a fonte dos elementos 5.2 e 1.5 de cada
dossiê.
4. Coleta concluída em 13 de setembro de 2026.
Sinistros e dispersões: 69 itens não têm imagem de preservação porque a origem
responde HTTP 500 ao bitstream, embora a página do item responda 200. Foram
feitas três rodadas de tentativa. Nesses itens a cópia guarda só a miniatura
(ver 6.1 de cada um e `errors.md`). Arquivos que chegaram corrompidos ou que
eram pirâmides de blocos (DZI) em vez de imagem foram rejeitados pelo ledger e
refeitos.
## 2.4 Procedência
Brasiliana Fotográfica (https://brasilianafotografica.bn.gov.br/), repositório
DSpace 4.2 mantido pela Biblioteca Nacional, handles `20.500.12156.1/*`. Cópia
obtida por raspagem combinada com a Biblioteca Nacional, 9–13 de setembro de 2026.
Inclui também os 636 posts do blog editorial do portal, usados em 5.4 e nas
fontes das autoridades.
## 3.2 Avaliação, eliminação e temporalidade
Nenhum item foi eliminado: a coleção é uma cópia integral. Entre as versões de
um mesmo arquivo foi mantida a de maior resolução (preservação), e a cópia
legada do objdigital foi guardada como procedência, nunca como substituta.
Arquivos rejeitados na validação (corrompidos, em formato de blocos, ou de
licença em vez de imagem) foram descartados e registrados no ledger.
## 3.3 Incorporações
Não há incorporações previstas. Uma nova coleta completa pode ser feita se a
origem publicar itens novos; o `fetched_at` de cada dossiê permite comparar.
## 3.4 Sistema de arranjo
Arranjo em quatro níveis abaixo da coleção:
- seção (nível 2): instituição de origem, conforme a comunidade do DSpace;
- série (nível 3): coleção ou fundo de origem, normalizado a partir de
`dc.source`. Itens sem coleção identificável ficam na série AV (Avulsos) da
seção;
- dossiê (nível 4): um item do DSpace, identificado pelo número do handle;
- item documental (nível 5): cada imagem do dossiê, numerada `01`, `02`…
Código de referência: `BR RJXYZ.BF.<seção>.<série>.<handle>.<imagem>`.
## 4.2 Condições de reprodução
Cada dossiê traz em 4.2 a condição informada pela origem (domínio público, uso
cultural liberado, reprodução sujeita a autorização, ou não informada) e o
detentor dos direitos. As instituições têm políticas distintas: a decisão de
reproduzir é item a item, junto ao detentor indicado.
## 4.3 Idioma
Descrições em português. Há legendas e títulos originais em francês, inglês,
latim, alemão, italiano, ucraniano e húngaro, registrados em 4.3 de cada
dossiê (ISO 639-2).
## 4.4 Características físicas e requisitos técnicos
Arquivos digitais JPEG (com alguns PNG e PDF), abertos em qualquer visualizador
de imagem. Os maiores passam de 8.000 px no lado maior. Nenhum requisito
especial.
## 4.5 Instrumentos de pesquisa
- Mural 3D navegável com busca e filtros: https://xn--2dk.xyz/brasiliana/
- Esta descrição em EAD 3: `descricao/ead/brasiliana.xml` (no bucket, em
`s3://brasiliana/descricao/`).
- Catálogo bruto em Dublin Core: `s3://brasiliana/catalogo.jsonl`.
## 5.1 Existência e localização dos originais
Os originais pertencem às 15 instituições de origem, listadas como seções. Cada
dossiê indica a instituição, o endereço do item na Brasiliana Fotográfica e,
quando a origem publica, o código ou a notação da instituição.
## 6.2 Notas gerais
Os valores dos metadados de origem que foram normalizados (datas, direitos,
nomes) estão preservados em 6.2 de cada dossiê e no `catalogo.jsonl`. Valores
visivelmente corrompidos na origem, com fragmentos de XML ou hash no lugar do
texto, foram desconsiderados e anotados.
## 7.1 Nota do arquivista
Descrição gerada automaticamente a partir dos metadados Dublin Core colhidos,
por `pipeline/nobrade`, com tabelas de revisão em `descricao/revisao/`.
Fontes: registros `?show=full` do DSpace, ledger de envio do bucket, blog da
Brasiliana Fotográfica. Responsável: rafapolo.
## 8.1 Pontos de acesso e indexação de assuntos
Pontos de acesso: título (1.2), autores em forma autorizada ISAAR(CPF)
(`descricao/autoridades.jsonl`, com as variantes como remissivas), data
tópica e lugares (`dc.coverage`), assuntos (`dc.subject`, com os termos em
português separados das traduções inglesas) e período (ISO 8601-2). Os
assuntos seguem o vocabulário da origem, sem controle adicional nesta versão.
### Fontes
- Lançamento da Brasiliana Fotográfica (FBN e IMS, 17 abr. 2015): https://sul21.com.br/?p=79211
- Coleta, ledger e falhas: `README.md`, `tasks/PLANO.md`, `errors.md`, `pipeline/subidor.sqlite` (tabela `enviados`).
+12
View File
@@ -0,0 +1,12 @@
# Seção AGCRJ
Fatos conferidos em 2026-09-30.
## 2.2 História administrativa
Arquivo público do município do Rio de Janeiro. O conjunto inclui a Coleção Augusto Malta, fotógrafo contratado pela prefeitura no início do século XX, e fundos da administração municipal, como Viação e Obras e Secretaria de Obras Públicas.
### Fontes
- https://www.rio.rj.gov.br/web/arquivogeral
- séries: descricao/revisao/series.tsv
+12
View File
@@ -0,0 +1,12 @@
# Seção AN
Fatos conferidos em 2026-09-30.
## 2.2 História administrativa
Arquivo Nacional, criado em 2 de janeiro de 1838 como Arquivo Público do Império, no Rio de Janeiro. É o órgão central do Sistema de Gestão de Documentos e Arquivos (SIGA) da administração pública federal.
### Fontes
- https://www.gov.br/pt-br/orgaos/arquivo-nacional
- Decreto nº 4.915, de 12 de dezembro de 2003
+13
View File
@@ -0,0 +1,13 @@
# Seção BN
Fatos conferidos em 2026-09-30.
## 2.2 História administrativa
Biblioteca nacional do Brasil, fundada no Rio de Janeiro em 29 de outubro de 1810 a partir da Real Biblioteca trazida de Portugal pela corte em 1808; recebeu o nome de Biblioteca Nacional em 1876. Mantém a Brasiliana Fotográfica, lançada com o Instituto Moreira Salles em 2015. A maior parte do seu conjunto aqui vem da Coleção D. Thereza Christina Maria, doada por D. Pedro II em 1891 e inscrita no Registro Memória do Mundo da UNESCO em 2003.
### Fontes
- https://en.wikipedia.org/wiki/National_Library_of_Brazil
- https://bndigital.bn.gov.br/projetos/terezacristina/histcolecao_en.htm
- https://sul21.com.br/?p=79211
+12
View File
@@ -0,0 +1,12 @@
# Seção COC
Fatos conferidos em 2026-09-30.
## 2.2 História administrativa
Casa de Oswaldo Cruz, unidade da Fundação Oswaldo Cruz dedicada à memória e à história das ciências e da saúde. O conjunto vem de fundos institucionais e pessoais ligados à saúde pública, como o Fundo Instituto Oswaldo Cruz e o Fundo Belisário Penna.
### Fontes
- https://www.coc.fiocruz.br/
- séries: descricao/revisao/series.tsv
+12
View File
@@ -0,0 +1,12 @@
# Seção CPDOC
Fatos conferidos em 2026-09-30.
## 2.2 História administrativa
Centro de Pesquisa e Documentação de História Contemporânea do Brasil, da Fundação Getulio Vargas, criado em 25 de junho de 1973 no Rio de Janeiro. É pioneiro na organização de arquivos pessoais de figuras da vida pública brasileira, e desde 2013 também é a Escola de Ciências Sociais da FGV.
### Fontes
- https://en.wikipedia.org/wiki/CPDOC
- https://revistapesquisa.fapesp.br/cpdoc-chega-a-sao-paulo/
+12
View File
@@ -0,0 +1,12 @@
# Seção DPHDM
Fatos conferidos em 2026-09-30.
## 2.2 História administrativa
Órgão da Marinha do Brasil responsável pelo patrimônio histórico e documental naval. O conjunto é formado sobretudo por álbuns fotográficos de viagens, de escolas de aprendizes marinheiros e da aviação naval, além da Coleção Revolta da Armada.
### Fontes
- https://www.marinha.mil.br/dphdm/
- séries: descricao/revisao/series.tsv
+12
View File
@@ -0,0 +1,12 @@
# Seção FUNDAJ
Fatos conferidos em 2026-09-30.
## 2.2 História administrativa
Fundação Joaquim Nabuco, instituição federal de pesquisa, cultura e educação sediada no Recife. O conjunto documenta sobretudo Pernambuco e o Nordeste.
### Fontes
- https://www.gov.br/fundaj/
- lugares: descricao/revisao/lugares.tsv
+11
View File
@@ -0,0 +1,11 @@
# Seção IBGE
Fatos conferidos em 2026-09-30.
## 2.2 História administrativa
Instituto Brasileiro de Geografia e Estatística. O conjunto documenta municípios brasileiros, trabalhos geográficos de campo e eventos institucionais.
### Fontes
- séries: descricao/revisao/series.tsv
+12
View File
@@ -0,0 +1,12 @@
# Seção IFL
Fatos conferidos em 2026-09-30.
## 2.2 História administrativa
Leibniz-Institut für Länderkunde, instituto de pesquisa em geografia regional sediado em Leipzig, Alemanha. Participa da Brasiliana Fotográfica por convênio com o Instituto Moreira Salles.
### Fontes
- https://ifl-leipzig.de/
- convênio: dc.source e dc.rights dos itens
+12
View File
@@ -0,0 +1,12 @@
# Seção IHGB
Fatos conferidos em 2026-09-30.
## 2.2 História administrativa
Instituto Histórico e Geográfico Brasileiro, fundado em 21 de outubro de 1838 no Rio de Janeiro. Participa da Brasiliana Fotográfica por convênio com o Instituto Moreira Salles.
### Fontes
- https://en.wikipedia.org/wiki/Brazilian_Historic_and_Geographic_Institute
- convênio: dc.source e dc.rights dos itens
+13
View File
@@ -0,0 +1,13 @@
# Seção IMS
Fatos conferidos em 2026-09-30.
## 2.2 História administrativa
Instituição cultural sem fins lucrativos criada em 1992 pelo diplomata e banqueiro Walther Moreira Salles; o primeiro centro cultural abriu naquele ano em Poços de Caldas (MG), e hoje há também sedes no Rio de Janeiro e em São Paulo. Seu acervo fotográfico, com coleções como Gilberto Ferrez, Mestres do Século XIX e Pedro Corrêa do Lago, é o maior conjunto da Brasiliana Fotográfica, portal que o IMS lançou com a Biblioteca Nacional em 2015.
### Fontes
- https://en.wikipedia.org/wiki/Moreira_Salles_Institute
- https://ims.com.br/en/about-ims/
- https://sul21.com.br/?p=79211
+12
View File
@@ -0,0 +1,12 @@
# Seção MHN
Fatos conferidos em 2026-09-30.
## 2.2 História administrativa
Museu Histórico Nacional, Rio de Janeiro, criado pelo decreto nº 15.596, de 2 de agosto de 1922, no centenário da Independência, e aberto ao público em 12 de outubro de 1922. O conjunto inclui as coleções Miguel Calmon e Juan Gutierrez.
### Fontes
- https://www.infoescola.com/historia/museu-historico-nacional/
- séries: descricao/revisao/series.tsv
+11
View File
@@ -0,0 +1,11 @@
# Seção MPEG
Fatos conferidos em 2026-09-30.
## 2.2 História administrativa
Museu Paraense Emílio Goeldi, instituição de pesquisa sediada em Belém e dedicada ao estudo da Amazônia.
### Fontes
- https://www.gov.br/museugoeldi/
+12
View File
@@ -0,0 +1,12 @@
# Seção MR
Fatos conferidos em 2026-09-30.
## 2.2 História administrativa
Museu instalado no Palácio do Catete, Rio de Janeiro, antiga sede da Presidência da República. O conjunto inclui as coleções Família Passos, Getúlio Vargas e Nilo Peçanha e as fotografias de Flávio de Barros sobre Canudos.
### Fontes
- https://www.gov.br/museus/pt-br/museus-ibram/museu-da-republica
- séries: descricao/revisao/series.tsv
+13
View File
@@ -0,0 +1,13 @@
# Seção MUSAL
Fatos conferidos em 2026-09-30.
## 2.2 História administrativa
Museu da Força Aérea Brasileira, inaugurado em 1976 nas instalações da antiga Escola de Aeronáutica, no Campo dos Afonsos, Rio de Janeiro, e administrado pelo Instituto Histórico-Cultural da Aeronáutica (INCAER). O conjunto reúne sobretudo fotografias aéreas das décadas de 1930 e 1940.
### Fontes
- https://en.wikipedia.org/wiki/Museu_Aeroespacial
- https://www2.fab.mil.br/musal/
- datas: descricao/unidades.jsonl (1.3 dos dossiês da seção)
+6
View File
@@ -0,0 +1,6 @@
# Textos das séries (nível 3)
Um arquivo `<SEÇÃO>.<SÉRIE>.md` (ex.: `IMS.GF.md`) com seções `## 2.2`,
`## 3.1` ou `## 3.4` substitui o texto gerado para aquela série. Sem arquivo,
o 3.1 é o resumo automático: quantidade, datas-limite, principais autores e
lugares. Os códigos das séries estão em `../revisao/series.tsv`.
+133
View File
@@ -0,0 +1,133 @@
#!/usr/bin/env python3
"""Derivadas de acesso (CONARQ, Res. 31/2010) a partir da matriz de preservação.
Gera, para cada item, duas cópias WebP em sRGB, sem metadados embutidos e sem
nunca ampliar (o que for menor que o alvo fica no tamanho original):
derivados/medio/<handle>.webp 1.200 px no lado maior NARA 2004 "Access – Recommended"
derivados/grande/<handle>.webp 2.000 px no lado maior NARA 2004 "Larger Alternative"
A miniatura (derivados/thumb256/, 256 px) já existe e não muda. Ver a tabela
de tamanhos em MANIFEST.md e CONARQ.md.
Roda no finland (tráfego intra-Hetzner, o bucket é hel1):
scp pipeline/deriva-acesso.py derivar.jsonl finland:/root/brasiliana/
ssh finland 'cd /root/brasiliana && set -a && . /root/.s3env && set +a && \
nohup python3 deriva-acesso.py derivar.jsonl > deriva-acesso.log 2>&1 &'
`derivar.jsonl`: uma linha {handle, fonte} por item, fonte = chave no bucket da
imagem de preservação (ou, sem ela, da imagem servida pelo DSpace). O progresso
vai para `deriva-acesso.resultados.jsonl`; rodar de novo retoma de onde parou.
Opções: --seco (gera em /tmp e não sobe), --limite N, --threads N.
"""
import argparse
import hashlib
import json
import os
import shutil
import subprocess
import sys
import tempfile
import threading
import time
from concurrent.futures import ThreadPoolExecutor, as_completed
import boto3
BUCKET = os.environ.get('ARCHIVE_BUCKET', 'brasiliana')
ENDPOINT = os.environ.get('S3_ENDPOINT', 'https://hel1.your-objectstorage.com')
ALVOS = [ # (pasta, lado maior em px, qualidade WebP)
('medio', 1200, 80),
('grande', 2000, 82),
]
CACHE = 'public, max-age=604800'
trava = threading.Lock()
def processa(s3, item, seco, saida_seca):
h = item['handle']
pasta = h.replace('/', '_')
tmp = tempfile.mkdtemp(prefix='deriva-')
try:
ext = os.path.splitext(item['fonte'])[1] or '.img'
src = os.path.join(tmp, 'src' + ext)
s3.download_file(BUCKET, item['fonte'], src)
feitos = []
for nome, lado, q in ALVOS:
out = os.path.join(tmp, f'{nome}.webp')
# "WxH>" = só reduz; sRGB na saída (NARA pede sRGB nas derivadas de acesso)
r = subprocess.run(['vipsthumbnail', src, '--size', f'{lado}x{lado}>',
'--export-profile', 'srgb', '-o', f'{out}[Q={q},strip]'],
capture_output=True, text=True, timeout=600)
if r.returncode != 0 or not os.path.exists(out):
# perfil de cor ausente ou ilegível: tenta sem conversão de perfil
r = subprocess.run(['vipsthumbnail', src, '--size', f'{lado}x{lado}>',
'-o', f'{out}[Q={q},strip]'], capture_output=True, text=True, timeout=600)
if r.returncode != 0:
raise RuntimeError(f'vipsthumbnail {nome}: {r.stderr.strip()[:300]}')
dims = subprocess.run(['vipsheader', '-f', 'width', out], capture_output=True, text=True).stdout.strip(), \
subprocess.run(['vipsheader', '-f', 'height', out], capture_output=True, text=True).stdout.strip()
dado = open(out, 'rb').read()
chave = f'derivados/{nome}/{pasta}.webp'
if seco:
shutil.copy(out, os.path.join(saida_seca, f'{pasta}.{nome}.webp'))
else:
s3.put_object(Bucket=BUCKET, Key=chave, Body=dado, ACL='public-read',
ContentType='image/webp', CacheControl=CACHE)
feitos.append({'tipo': f'derivado-{nome}', 'chave': chave, 'bytes': len(dado),
'sha256': hashlib.sha256(dado).hexdigest(), 'w': int(dims[0]), 'h': int(dims[1])})
return {'handle': h, 'fonte': item['fonte'], 'ok': True, 'arquivos': feitos,
'quando': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())}
except Exception as e: # noqa: BLE001 — um item ruim não para a fila
return {'handle': h, 'fonte': item['fonte'], 'ok': False, 'erro': f'{type(e).__name__}: {e}'[:400]}
finally:
shutil.rmtree(tmp, ignore_errors=True)
def main():
ap = argparse.ArgumentParser()
ap.add_argument('lista')
ap.add_argument('--seco', action='store_true')
ap.add_argument('--limite', type=int, default=0)
ap.add_argument('--threads', type=int, default=4)
ap.add_argument('--resultados', default='deriva-acesso.resultados.jsonl')
a = ap.parse_args()
itens = [json.loads(l) for l in open(a.lista, encoding='utf-8') if l.strip()]
feitos = set()
if os.path.exists(a.resultados) and not a.seco:
for l in open(a.resultados, encoding='utf-8'):
r = json.loads(l)
if r.get('ok'):
feitos.add(r['handle'])
fila = [i for i in itens if i['handle'] not in feitos]
if a.limite:
fila = fila[:a.limite]
saida_seca = tempfile.mkdtemp(prefix='deriva-seco-') if a.seco else None
print(f'{len(itens)} itens, {len(feitos)} já feitos, {len(fila)} na fila'
+ (f' (seco → {saida_seca})' if a.seco else ''), flush=True)
s3 = boto3.client('s3', endpoint_url=ENDPOINT)
t0, n, erros = time.time(), 0, 0
with ThreadPoolExecutor(a.threads) as ex, open(a.resultados if not a.seco else os.devnull, 'a', encoding='utf-8') as res:
for fut in as_completed([ex.submit(processa, s3, i, a.seco, saida_seca) for i in fila]):
r = fut.result()
n += 1
erros += not r['ok']
with trava:
res.write(json.dumps(r, ensure_ascii=False) + '\n')
res.flush()
if not r['ok']:
print(f"ERRO {r['handle']}: {r['erro']}", flush=True)
if n % 100 == 0 or n == len(fila):
dt = time.time() - t0
print(f'{n}/{len(fila)} · {erros} erros · {n / dt * 60:.0f}/min · '
f'faltam ~{(len(fila) - n) / max(n / dt, 1e-9) / 60:.0f} min', flush=True)
print('FIM', flush=True)
return 1 if erros else 0
if __name__ == '__main__':
sys.exit(main())
View File
+53
View File
@@ -0,0 +1,53 @@
"""python -m nobrade (de dentro de pipeline/)
Gera a descrição NOBRADE completa em descricao/: unidades, autoridades,
tabelas de revisão, pendências, EAD 3, EAC-CPF e CSV do AtoM, e valida os XML
contra os XSD de nobrade/xsd/ quando o xmllint está disponível.
"""
import shutil
import subprocess
import sys
from collections import defaultdict
from pathlib import Path
from . import exporta, montar, valida
from .config import SAIDA
def main():
print('montando unidades…', flush=True)
unidades, aut = montar.monta()
lista = sorted(unidades.values(), key=lambda u: (u['nivel'], u['id']))
lista = [{k: v for k, v in u.items() if not k.startswith('_') and v is not None} for u in lista]
pend = valida.valida(lista)
print(f'{len(lista)} unidades, {len(aut.registros)} autoridades, {pend} pendências obrigatórias')
print('exportando EAD 3, EAC-CPF e AtoM…', flush=True)
exporta.ead(lista, aut.registros)
usos = defaultdict(list)
for u in lista:
if u['nivel'] == 4:
for p in u['2.1']:
if p.get('id'):
usos[p['id']].append(u['id'])
exporta.eac(list(aut.registros.values()), usos)
exporta.atom(lista)
if shutil.which('xmllint') and '--sem-xsd' not in sys.argv:
xsd = Path(__file__).parent / 'xsd'
r = subprocess.run(['xmllint', '--noout', '--huge', '--schema', xsd / 'ead3.xsd',
SAIDA / 'ead' / 'brasiliana.xml'], capture_output=True, text=True)
print('EAD 3:', (r.stderr.strip().splitlines() or ['?'])[-1])
eacs = sorted((SAIDA / 'eac').glob('*.xml'))
r = subprocess.run(['xmllint', '--noout', '--schema', xsd / 'cpf.xsd', *eacs],
capture_output=True, text=True)
falhas = [x for x in r.stderr.splitlines() if 'fails to validate' in x or 'error' in x.lower()]
print(f'EAC-CPF: {len(eacs)} arquivos, {len(falhas)} com erro')
for x in falhas[:10]:
print(' ', x)
return 1 if pend else 0
if __name__ == '__main__':
sys.exit(main())
+119
View File
@@ -0,0 +1,119 @@
"""Registros de autoridade (ISAAR(CPF)) para produtores — elemento 2.1 e 8.1.
Junta as grafias de `dc.contributor` ("Malta, Augusto", "Malta, Augusto,
1864-1957", "Marc Ferrez" e "Ferrez, Marc") numa forma autorizada, com as
variantes como remissivas (proc. 8.1.4).
"""
from __future__ import annotations
import re
import unicodedata
from collections import Counter, defaultdict
ANONIMO = re.compile(r'(?i)^\s*(an[oô]nimo|autoria n[aã]o identificada|s/\s*autor|sem autor|desconhecid[oa]|'
r'n[aã]o identificad[oa]|autor n[aã]o identificado|autor desconhecido)\s*\.?$')
COLETIVA = re.compile(r'(?i)\b(escola|officina|oficina|photographia|fotografia|photo|foto|studio|est[uú]dio|atelier|'
r'casa|companhia|cia\.?|museu|instituto|minist[eé]rio|servi[cç]o|diretoria|departamento|'
r'comiss[aã]o|biblioteca|arquivo|editora|lith|litografia|tipografia|typ|&|irm[aã]os|'
r'sociedade|empresa|jornal|revista|ag[eê]ncia|governo|prefeitura|marinha|ex[eé]rcito|'
r'for[cç]a|aeron[aá]utica|avia[cç][aã]o|universidade|fundação)\b')
DATAS = re.compile(r',?\s*((?:ca\.\s*|fl\.\s*|m\.\s*|n\.\s*)?\d{4}\??(?:\s*-\s*(?:ca\.\s*)?\d{0,4}\??)?)\.?\s*$')
PARTICULAS = {'de', 'da', 'do', 'das', 'dos', 'e', 'von', 'van', 'du', 'del', 'di'}
def _chave(s: str) -> str:
s = ''.join(c for c in unicodedata.normalize('NFD', s.lower()) if unicodedata.category(c) != 'Mn')
s = re.sub(r'\(.*?\)', '', s)
return re.sub(r'[^\w,]+', ' ', s).strip(' ,')
def _separa_datas(nome: str) -> tuple[str, str | None]:
nome = nome.strip().rstrip('.')
if m := DATAS.search(nome):
if ',' in nome[:m.start()] or m[1].startswith(('fl', 'm.', 'n.', 'ca')):
return nome[:m.start()].strip(' ,'), m[1]
return nome, None
def _inverte(nome: str) -> str | None:
"""'Marc Ferrez' → 'Ferrez, Marc'. Só para nomes de pessoa sem vírgula."""
partes = nome.split()
if len(partes) < 2 or ',' in nome:
return None
i = len(partes) - 1
while i > 1 and partes[i - 1].lower() in PARTICULAS:
i -= 1
return f"{' '.join(partes[i:])}, {' '.join(partes[:i])}"
def periodo(datas: str | None) -> tuple[int, int] | None:
"""Anos prováveis de atividade: fl. A-B, ou nascimento+15 até a morte."""
if not datas:
return None
anos = [int(a) for a in re.findall(r'\d{4}', datas)]
if not anos:
return None
if datas.startswith('fl'):
return (anos[0], anos[-1]) if len(anos) > 1 else (anos[0], anos[0])
if datas.startswith('m.'):
return None
if len(anos) == 2:
return anos[0] + 15, anos[1]
return None
class Autoridades:
def __init__(self):
self.contagem: Counter = Counter()
def registra(self, nome: str):
if nome and nome.strip() and not ANONIMO.match(nome):
self.contagem[nome.strip()] += 1
def resolve(self):
"""Agrupa as grafias. Depois disso `forma(nome)` devolve o id da autoridade."""
grupos: dict[str, Counter] = defaultdict(Counter)
for nome, n in self.contagem.items():
base, _ = _separa_datas(nome)
grupos[_chave(base)][nome] += n
# grafias diretas ("Marc Ferrez") que batem com uma invertida já conhecida
for k in list(grupos):
if ',' in k:
continue
nome = next(iter(grupos[k]))
if COLETIVA.search(nome):
continue
inv = _inverte(_separa_datas(nome)[0])
if inv and _chave(inv) in grupos and _chave(inv) != k:
grupos[_chave(inv)].update(grupos.pop(k))
self.registros: dict[str, dict] = {}
self._id_de: dict[str, str] = {}
for k, variantes in sorted(grupos.items(), key=lambda kv: -sum(kv[1].values())):
# forma autorizada: a variante mais completa (com datas) e mais usada
# (datas com início e fim > só uma data > nenhuma), depois frequência
def peso(v):
dt = _separa_datas(v)[1] or ''
return (len(re.findall(r'\d{4}', dt)), variantes[v], v)
forma = max(variantes, key=peso)
forma = forma.strip().rstrip('.')
base, datas = _separa_datas(forma)
tipo = 'entidade coletiva' if COLETIVA.search(base) else ('pessoa' if ',' in base else 'pessoa ou entidade')
if re.match(r'(?i)fam[ií]lia\b', base):
tipo = 'família'
aid = 'A' + str(len(self.registros) + 1).zfill(4)
self.registros[aid] = {
'id': aid, 'forma_autorizada': forma, 'nome': base, 'datas_existencia': datas,
'tipo': tipo, 'variantes': sorted(v for v in variantes if v.strip().rstrip('.') != forma),
'ocorrencias': sum(variantes.values()), 'periodo_atividade': periodo(datas),
'fontes': [],
}
for v in variantes:
self._id_de[v] = aid
def id(self, nome: str) -> str | None:
return self._id_de.get((nome or '').strip())
def __getitem__(self, aid: str) -> dict:
return self.registros[aid]
+177
View File
@@ -0,0 +1,177 @@
"""Normalizadores de campo único: espécie/suporte (1.5), características
físicas (1.5/4.4), direitos (4.2), idioma (4.3), lugar (1.3.1 data tópica) e
assuntos (8.1)."""
from __future__ import annotations
import re
import unicodedata
CORROMPIDO = re.compile(r'[<>{}]|ns:|PALAVRAS-CHAVE|^[0-9a-f]{6,}|\d[a-f]\d[a-f]\d')
def sem_acento(s: str) -> str:
return ''.join(c for c in unicodedata.normalize('NFD', s) if unicodedata.category(c) != 'Mn')
def corrompido(v: str | None) -> bool:
return bool(v) and bool(CORROMPIDO.search(v))
# ── 1.5 espécie e suporte (a partir de dc.type) ─────────────────────────────
ESPECIES = [ # (padrão, gênero, espécie)
(r'^negativo', 'iconográfico', 'negativo fotográfico'),
(r'^diapositivo', 'iconográfico', 'diapositivo'),
(r'reprodu[cç][aã]o fotomec', 'iconográfico', 'reprodução fotomecânica'),
(r'^(fotografia|vista panor)', 'iconográfico', 'fotografia'),
(r'^gravura', 'iconográfico', 'gravura'),
(r'^desenho', 'iconográfico', 'desenho'),
(r'^[áa]lbum', 'iconográfico', 'álbum fotográfico'),
(r'^manuscrito', 'textual', 'manuscrito'),
(r'^livro', 'bibliográfico', 'livro'),
(r'^artigo de peri', 'bibliográfico', 'periódico'),
]
def especie(tipo: str | None) -> dict:
"""{'genero', 'especie', 'suporte', 'presumida'}. Sem dc.type (ou com lixo),
presume fotografia — o acervo inteiro é um repositório fotográfico — e marca."""
t = (tipo or '').strip()
if t and not corrompido(t):
base, _, sup = t.partition('/')
b = sem_acento(base.strip().lower())
for pat, gen, esp in ESPECIES:
if re.search(pat, b) or re.search(pat, base.strip().lower()):
suporte = sup.strip().lower() or None
if esp == 'negativo fotográfico' and 'flex' in b:
suporte = 'flexível'
return {'genero': gen, 'especie': esp, 'suporte': suporte, 'presumida': False}
return {'genero': 'iconográfico', 'especie': 'fotografia', 'suporte': None, 'presumida': True,
'original': t or None}
# ── características físicas que algumas instituições põem em dc.description ──
FISICO = re.compile(
r'(?i)^\s*(p\s*&\s*b|p/b|preto e branco|cor(ida)?|colorid[ao]|s[ée]pia|'
r'albumina|gelatina|prata|col[oó]dio|cianotipia|platina|carv[aã]o|ambr[oó]tipo|daguerre[oó]tipo|'
r'negativo|acetato|nitrato|vidro|papel|cart[aã]o|\d+[,.]?\d*\s*x\s*\d+|processo:|segunda gera)')
def e_fisico(v: str) -> bool:
return bool(FISICO.match(v)) and len(v) < 120
def cor(fisico: list[str]) -> str | None:
t = ' '.join(fisico).lower()
if re.search(r'p\s*&\s*b|p/b|preto e branco', t):
return 'p&b'
if re.search(r'colorid|\bcor\b', t):
return 'cor'
return None
# ── 4.2 condições de reprodução ─────────────────────────────────────────────
def direitos(textos: list[str], instituicao: str) -> dict:
"""{'categoria', 'detentor', 'texto', 'originais'}."""
limpos = list(dict.fromkeys(t.strip() for t in textos if t and t.strip() and t.strip() != 'None'))
junto = sem_acento(' '.join(limpos).lower())
if re.search(r'dominio publico|omínio público|omi?nio publico', junto):
cat = 'domínio público'
elif 'liberado para uso de natureza cultural' in junto:
cat = 'uso cultural liberado'
elif re.search(r'solicitar|requer libera', junto):
cat = 'requer autorização do detentor'
else:
cat = 'consultar o detentor'
detentor = None
for t in limpos:
a = sem_acento(t.lower())
if corrompido(t) or re.search(r'dominio publico|solicitar|requer|liberado', a) or len(t) < 6:
continue
if 'bibli' in a and 'nac' in a:
detentor = 'Biblioteca Nacional (Brasil)'
elif 'moreira' in a and 'salles' in a and '/' not in t:
detentor = 'Instituto Moreira Salles'
else:
detentor = t
break
detentor = detentor or instituicao
frases = {
'domínio público': 'Imagem em domínio público.',
'uso cultural liberado': 'Uso liberado para fins de natureza cultural.',
'requer autorização do detentor': 'Reprodução sujeita a autorização do detentor dos direitos.',
'consultar o detentor': 'Condições de reprodução não informadas na origem; consultar o detentor.',
}
return {'categoria': cat, 'detentor': detentor,
'texto': f'{frases[cat]} Detentor indicado: {detentor}.',
'originais': limpos or None}
# ── 4.3 idioma ───────────────────────────────────────────────────────────────
NOMES_IDIOMA = {'por': 'português', 'fre': 'francês', 'eng': 'inglês', 'lat': 'latim', 'ger': 'alemão',
'ita': 'italiano', 'ukr': 'ucraniano', 'hun': 'húngaro', 'spa': 'espanhol'}
def idiomas(vs: list[str]) -> list[dict]:
out = []
for v in vs:
c = (v or '').strip().lower()
if c in NOMES_IDIOMA and c not in [o['codigo'] for o in out]:
out.append({'codigo': c, 'nome': NOMES_IDIOMA[c]})
return out
# ── 1.3.1 data tópica e 8.1 lugares ─────────────────────────────────────────
UF = {'AC', 'AL', 'AP', 'AM', 'BA', 'CE', 'DF', 'ES', 'GO', 'MA', 'MT', 'MS', 'MG', 'PA', 'PB', 'PR', 'PE',
'PI', 'RJ', 'RN', 'RS', 'RO', 'RR', 'SC', 'SP', 'SE', 'TO'}
ESTADOS = {'rio de janeiro': 'RJ', 'sao paulo': 'SP', 'bahia': 'BA', 'pernambuco': 'PE', 'minas gerais': 'MG',
'para': 'PA', 'amazonas': 'AM', 'parana': 'PR', 'rio grande do sul': 'RS', 'santa catarina': 'SC',
'ceara': 'CE', 'maranhao': 'MA', 'espirito santo': 'ES', 'goias': 'GO', 'mato grosso': 'MT',
'paraiba': 'PB', 'alagoas': 'AL', 'sergipe': 'SE', 'piaui': 'PI', 'rio grande do norte': 'RN'}
PAISES = {'brasil', 'brazil'}
def lugar(coberturas: list[str]) -> str | None:
"""A forma mais específica de cidade: 'Cidade (UF)'. Junta 'Rio de Janeiro' + 'RJ'."""
cs = [c.strip() for c in coberturas if c and c.strip() and not corrompido(c)]
for c in cs:
if m := re.fullmatch(r'(.+?)\s*(?:\(|,\s*|\s-\s*)([A-Z]{2})\)?', c):
if m[2] in UF and sem_acento(m[1].lower()) not in PAISES:
return f'{m[1].strip()} ({m[2]})'
ufs = [c for c in cs if c in UF]
for c in cs:
k = sem_acento(c.lower())
if k in PAISES or c in UF or '(estado)' in k or 'state' in k:
continue
if re.search(r'\(([^)]+)\)$', c): # "Paris (França)", "Rio de Janeiro (Brazil)"
nome, pais = re.match(r'(.+?)\s*\(([^)]+)\)$', c).groups()
if sem_acento(pais.lower()) in PAISES:
uf = ESTADOS.get(sem_acento(nome.lower()))
return f'{nome} ({uf})' if uf else nome
return c
uf = ufs[0] if ufs else ESTADOS.get(k)
return f'{c} ({uf})' if uf else c
return None
# ── 8.1 assuntos: separa as traduções inglesas que o DSpace da BN repete ─────
EN = {'the', 'and', 'of', 'in', 'on', 'women', 'men', 'children', 'streets', 'street', 'buildings', 'building',
'churches', 'church', 'views', 'view', 'slaves', 'railroads', 'railroad', 'harbors', 'harbor', 'landscapes',
'portraits', 'bridges', 'rivers', 'houses', 'squares', 'parks', 'gardens', 'mountains', 'beaches',
'ships', 'soldiers', 'history', 'photographs', 'people', 'indians', 'coffee', 'workers', 'palaces',
'monuments', 'waterfalls', 'boats', 'plantations', 'aerial', 'military', 'city', 'cities', 'public',
'social', 'life', 'customs', 'description', 'travel', 'transportation', 'agriculture', 'industry',
'architecture', 'fountains', 'hospitals', 'schools', 'markets', 'lakes', 'bays', 'islands', 'forts',
'wars', 'war', 'emperors', 'kings', 'queens', 'nobility', 'family', 'families', 'politicians'}
PT = {'de', 'da', 'do', 'das', 'dos', 'e', 'em', 'no', 'na', 'nos', 'nas', 'para', 'com'}
def idioma_termo(t: str) -> str:
if re.search(r'[ãõçáéíóúâêô]', t.lower()):
return 'por'
palavras = set(re.findall(r'[a-z]+', t.lower()))
if palavras & PT:
return 'por'
if palavras & EN or re.search(r'\((?:brazil|state)', t.lower()):
return 'eng'
return 'por'
+78
View File
@@ -0,0 +1,78 @@
"""Constantes da descrição NOBRADE — decisões registradas em CONARQ.md §5."""
from pathlib import Path
RAIZ = Path(__file__).resolve().parents[2]
PIPELINE = RAIZ / 'pipeline'
CATALOGO = PIPELINE / 'catalogo.jsonl'
LEDGER = PIPELINE / 'subidor.sqlite'
POSTS = PIPELINE / 'wordpress-posts.jsonl'
ERROS = RAIZ / 'errors.md'
AJUSTES = Path(__file__).resolve().parent / 'ajustes'
SAIDA = RAIZ / 'descricao'
TEXTOS = SAIDA / 'textos'
REVISAO = SAIDA / 'revisao'
# 1.1 — código da entidade custodiadora. PROVISÓRIO até o CONARQ atribuir um
# (proc. 1.1.1). Trocar aqui regenera todos os códigos de referência.
# Formato do CODEARQ, como o AGCRJ usa: país, espaço, UF + sigla, e as partes
# da unidade separadas por ponto — BR RJAGCRJ.SOP.NL.AVE.03.01
PAIS = 'BR'
ENTIDADE = 'RJXYZ'
ENTIDADE_NOME = 'xyz — cópia digital de acervos fotográficos'
ENTIDADE_SITE = 'https://xn--2dk.xyz/brasiliana/'
COLECAO = 'BF'
COLECAO_TITULO = 'Coleção Brasiliana Fotográfica (cópia digital)'
RESPONSAVEL = 'rafapolo'
# Derivadas de acesso no bucket (CONARQ Res. 31/2010; tamanhos pela NARA 2004):
# thumb256/ 256 px (navegação) · medio/ 1.200 px (acesso) · grande/ 2.000 px
# (acesso ampliado). GRANDE liga a troca para grande/ no zoom do visor —
# só True depois que pipeline/deriva-acesso.py cobriu o acervo inteiro.
GRANDE = True
BUCKET = 's3://brasiliana'
REGRAS = ('NOBRADE: Norma brasileira de descrição arquivística (CONARQ, 2006); '
'ISAD(G) 2ª ed. (CIA, 2000); ISAAR(CPF) 2ª ed. (CIA, 2004); '
'datas em ISO 8601-2 (EDTF); idiomas em ISO 639-2; países em ISO 3166.')
ORIGEM_NOME = 'Brasiliana Fotográfica'
ORIGEM_SITE = 'https://brasilianafotografica.bn.gov.br/'
HANDLE_URL = 'https://brasilianafotografica.bn.gov.br/brasiliana/handle/{}'
# Nível 2 — uma seção por instituição de origem (campo `community` do catálogo).
# sigla → (nome autorizado, cidade)
INSTITUICOES = {
'Instituto Moreira Salles': ('IMS', 'Instituto Moreira Salles', 'Rio de Janeiro (RJ)'),
'Biblioteca Nacional': ('BN', 'Biblioteca Nacional (Brasil)', 'Rio de Janeiro (RJ)'),
'Museu Aeroespacial': ('MUSAL', 'Museu Aeroespacial', 'Rio de Janeiro (RJ)'),
'Museu da Republica': ('MR', 'Museu da República', 'Rio de Janeiro (RJ)'),
'Museu Historico Nacional': ('MHN', 'Museu Histórico Nacional', 'Rio de Janeiro (RJ)'),
'Fiocruz': ('COC', 'Fundação Oswaldo Cruz. Casa de Oswaldo Cruz', 'Rio de Janeiro (RJ)'),
'Diretoria do Patrimonio Historico e Documentacao da Marinha':
('DPHDM', 'Diretoria do Patrimônio Histórico e Documentação da Marinha', 'Rio de Janeiro (RJ)'),
'Arquivo Nacional': ('AN', 'Arquivo Nacional (Brasil)', 'Rio de Janeiro (RJ)'),
'Arquivo Geral da Cidade do Rio de Janeiro':
('AGCRJ', 'Arquivo Geral da Cidade do Rio de Janeiro', 'Rio de Janeiro (RJ)'),
'Leibniz-Institut fuer Laenderkunde, Leipzig':
('IFL', 'Leibniz-Institut für Länderkunde', 'Leipzig (Alemanha)'),
'Instituto Historico e Geografico Brasileiro':
('IHGB', 'Instituto Histórico e Geográfico Brasileiro', 'Rio de Janeiro (RJ)'),
'Fundacao Joaquim Nabuco': ('FUNDAJ', 'Fundação Joaquim Nabuco', 'Recife (PE)'),
'Museu Paraense Emilio Goeldi': ('MPEG', 'Museu Paraense Emílio Goeldi', 'Belém (PA)'),
'Escola de Ciencias Sociais (FGV CPDOC)':
('CPDOC', 'Fundação Getulio Vargas. Escola de Ciências Sociais (FGV CPDOC)', 'Rio de Janeiro (RJ)'),
'Instituto Brasileiro de Geografia e Estatistica':
('IBGE', 'Instituto Brasileiro de Geografia e Estatística', 'Rio de Janeiro (RJ)'),
}
# 4.1 — obrigatório nos níveis 0 e 1
ACESSO = ('Sem restrição de acesso à descrição. As cópias digitais são mantidas '
f'para preservação em {BUCKET} e consultáveis pelo mural em {ENTIDADE_SITE}. '
'O acesso aos originais segue as regras de cada instituição de origem '
'(ver 5.1 em cada dossiê).')
def codigo(*partes: str) -> str:
"""BR RJXYZ, BR RJXYZ.BF, BR RJXYZ.BF.IMS.GF.12345.01 …"""
return f'{PAIS} ' + '.'.join((ENTIDADE,) + tuple(p for p in partes if p))
+348
View File
@@ -0,0 +1,348 @@
"""Normalização de dc.date para o elemento 1.3 da NOBRADE.
Saída de `interpreta(texto)`:
forma — como a NOBRADE manda exibir: `1914`, `[1860]`, `[1902?]`,
`[ca. 1905]`, `[193-]`, `[18--?]`, `8/2/1890-18/4/1890`
iso — ISO 8601-2 (EDTF), para indexação e intercâmbio (proc. 1.3.2.7):
`1914`, `1902?`, `1905~`, `193X`, `18XX?`, `1931/1937`, `../1921`
inicio, fim — anos inteiros (ou None) para filtrar e ordenar
qualidade — `exata` | `atribuida` | `incerta` | `aproximada`
tipo — `produção` (padrão) ou `publicação`
motivo — quando não deu para interpretar: `sem data`, `registro de sistema`,
`ilegível`
A regra geral: tira do texto as marcas (colchetes, `?`, `circa`, qualificadores
entre parênteses), interpreta o que sobra como ponto ou intervalo e remonta a
forma com as marcas no padrão da norma (proc. 1.3.2.1–1.3.2.4).
"""
from __future__ import annotations
import re
import unicodedata
from dataclasses import dataclass, field
from datetime import date
MESES = {
'jan': 1, 'janeiro': 1, 'fev': 2, 'fevereiro': 2, 'mar': 3, 'março': 3, 'marco': 3,
'abr': 4, 'abril': 4, 'mai': 5, 'maio': 5, 'jun': 6, 'junho': 6,
'jul': 7, 'julho': 7, 'ago': 8, 'agosto': 8, 'set': 9, 'setembro': 9,
'out': 10, 'outubro': 10, 'nov': 11, 'novembro': 11, 'dez': 12, 'dezembro': 12,
}
MES_RE = '(' + '|'.join(sorted(MESES, key=len, reverse=True)) + r')\.?'
SEM_DATA = re.compile(r'^(s\.?\s*/?\s*d\.?|s/data|sem data|s\.?\s*n\.?|n[aã]o identificad[ao])$', re.I)
@dataclass
class Ponto:
ano: int
mes: int | None = None
dia: int | None = None
prec: str = 'ano' # dia | mes | ano | decada | seculo
def forma(self) -> str:
if self.prec == 'dia':
return f'{self.dia}/{self.mes}/{self.ano}'
if self.prec == 'mes':
return f'{self.mes}/{self.ano}'
if self.prec == 'decada':
return f'{self.ano // 10}-'
if self.prec == 'seculo':
return f'{self.ano // 100}--'
return str(self.ano)
def iso(self) -> str:
if self.prec == 'dia':
return f'{self.ano:04d}-{self.mes:02d}-{self.dia:02d}'
if self.prec == 'mes':
return f'{self.ano:04d}-{self.mes:02d}'
if self.prec == 'decada':
return f'{self.ano // 10}X'
if self.prec == 'seculo':
return f'{self.ano // 100}XX'
return f'{self.ano:04d}'
def limites(self) -> tuple[int, int]:
if self.prec == 'decada':
return self.ano, self.ano + 9
if self.prec == 'seculo':
return self.ano, self.ano + 99
return self.ano, self.ano
@dataclass
class Data:
original: str
inicio_p: Ponto | None = None
fim_p: Ponto | None = None
relacao: str = '' # '' | 'antes' | 'depois'
colchete: bool = False
incerta: bool = False
aproximada: bool = False
tipo: str = 'produção'
motivo: str = ''
notas: list[str] = field(default_factory=list)
@property
def ok(self) -> bool:
return self.inicio_p is not None
@property
def qualidade(self) -> str:
if self.aproximada:
return 'aproximada'
if self.incerta:
return 'incerta'
if self.colchete:
return 'atribuida'
return 'exata'
def forma(self) -> str:
if not self.ok:
return '[s.d.]'
a = self.inicio_p.forma()
if self.relacao == 'antes':
s = f'antes de {a}'
elif self.relacao == 'depois':
s = f'depois de {a}'
elif self.fim_p and self.fim_p != self.inicio_p:
s = f'{a}-{self.fim_p.forma()}'
else:
s = a
if self.aproximada:
s = 'ca. ' + s
if self.incerta:
s += '?'
if self.colchete or self.aproximada or self.incerta or self.relacao:
s = f'[{s}]'
return s
def iso(self) -> str | None:
if not self.ok:
return None
q = ('%' if self.incerta else '~') if self.aproximada else ('?' if self.incerta else '')
a = self.inicio_p.iso() + q
if self.relacao == 'antes':
return f'../{a}'
if self.relacao == 'depois':
return f'{a}/..'
if self.fim_p and self.fim_p != self.inicio_p:
return f'{a}/{self.fim_p.iso()}{q}'
return a
def anos(self) -> tuple[int | None, int | None]:
if not self.ok:
return None, None
i, f = self.inicio_p.limites()
if self.fim_p:
f = self.fim_p.limites()[1]
if self.relacao == 'antes':
return None, f
if self.relacao == 'depois':
return i, None
return i, f
def registro(self) -> dict:
i, f = self.anos()
return {
'original': self.original, 'forma': self.forma(), 'iso': self.iso(),
'inicio': i, 'fim': f, 'qualidade': self.qualidade if self.ok else None,
'tipo': self.tipo, 'motivo': self.motivo or None,
'notas': self.notas or None,
}
def _sem_acento(s: str) -> str:
return ''.join(c for c in unicodedata.normalize('NFD', s) if unicodedata.category(c) != 'Mn')
def _ano(s: str, base: int | None = None) -> int:
n = int(s)
if len(s) == 2:
return (base // 100 * 100 if base else 1900) + n
return n
def _ponto(s: str) -> tuple[Ponto | None, bool]:
"""Um ponto no tempo. Devolve (ponto, incerto) — incerto quando o próprio
formato carrega a dúvida, como `193?` (década) ou `?/08/1938` (dia)."""
s = s.strip(' .,:;')
s = re.sub(r'^[-–]\s*', '', s)
if not s:
return None, False
if m := re.fullmatch(r'(\d{4})', s):
return Ponto(int(m[1])), False
if m := re.fullmatch(r'(\d{3})-', s):
return Ponto(int(m[1]) * 10, prec='decada'), False
if m := re.fullmatch(r'(\d{3})-?\?', s):
return Ponto(int(m[1]) * 10, prec='decada'), True
if m := re.fullmatch(r'(\d{2})(?:-{2,3}|_)', s):
return Ponto(int(m[1]) * 100, prec='seculo'), False
if m := re.fullmatch(r'(\d{2})(?:-{2})?\?', s):
return Ponto(int(m[1]) * 100, prec='seculo'), True
if m := re.fullmatch(r'(\d{3})--', s): # [186--]: década escrita com traço a mais
return Ponto(int(m[1]) * 10, prec='decada'), False
# dia/mês/ano, com separadores tortos: 22-12--1938, 14 -07-1928, 05/12-1934
if m := re.fullmatch(r'(\d{1,2})\s*[-/.]\s*(\d{1,2})\s*[-/.]+\s*(\d{4}|\d{2})', s):
d, mo, a = int(m[1]), int(m[2]), _ano(m[3])
if 1 <= mo <= 12 and 1 <= d <= 31:
return Ponto(a, mo, d, 'dia'), len(m[3]) == 2
if m := re.fullmatch(r'(\d{4})\s*[-/]\s*(\d{1,2})\s*[-/]\s*(\d{1,2})', s):
a, mo, d = int(m[1]), int(m[2]), int(m[3])
if 1 <= mo <= 12 and 1 <= d <= 31:
return Ponto(a, mo, d, 'dia'), False
# dia desconhecido: 2-/12/1923, ?/08/1938
if m := re.fullmatch(r'(?:\d?-|\?)\s*/\s*(\d{1,2})\s*/\s*(\d{4})', s):
return Ponto(int(m[2]), int(m[1]), prec='mes'), False
if m := re.fullmatch(r'(\d{1,2})\s*/\s*(\d{4})', s):
if 1 <= int(m[1]) <= 12:
return Ponto(int(m[2]), int(m[1]), prec='mes'), False
if m := re.fullmatch(r'(\d{4})\s*/\s*(\d{1,2})', s):
if 1 <= int(m[2]) <= 12:
return Ponto(int(m[1]), int(m[2]), prec='mes'), False
t = _sem_acento(s.lower())
if m := re.fullmatch(rf'(\d{{1,2}})\s*(?:de\s+)?{MES_RE}\s*,?\s*(?:de\s+)?(\d{{4}})', t):
return Ponto(int(m[3]), MESES[m[2]], int(m[1]), 'dia'), False
if m := re.fullmatch(rf'{MES_RE}\s*,?\s*(?:de\s+)?(\d{{4}})', t):
return Ponto(int(m[2]), MESES[m[1]], prec='mes'), False
if m := re.fullmatch(r'(?:decada de )?(\d{3})\d(?: decada)?( provavel)?', t):
if 'decada' in t:
return Ponto(int(m[1]) * 10, prec='decada'), bool(m[2])
if m := re.fullmatch(r'(\d{2}) seculo', t):
return Ponto((int(m[1]) - 1) * 100, prec='seculo'), False
return None, False
def _intervalo(s: str) -> tuple[Ponto | None, Ponto | None, bool]:
t = _sem_acento(s.lower()).strip(' .,:;')
t = re.sub(r'^entre\s+', '', t)
p, inc = _ponto(t)
if p:
return p, None, inc
# dias ou meses coordenados: "15 e 16 de outubro de 1930", "outubro e novembro de 1930"
if m := re.fullmatch(rf'(\d{{1,2}})\s+e\s+(\d{{1,2}})\s+(?:de\s+)?{MES_RE}\s+(?:de\s+)?(\d{{4}})', t):
mo, a = MESES[m[3]], int(m[4])
return Ponto(a, mo, int(m[1]), 'dia'), Ponto(a, mo, int(m[2]), 'dia'), False
if m := re.fullmatch(rf'{MES_RE}\s+e\s+{MES_RE}\s+(?:de\s+)?(\d{{4}})', t):
a = int(m[3])
return Ponto(a, MESES[m[1]], prec='mes'), Ponto(a, MESES[m[2]], prec='mes'), False
# 1859-61: segundo ano abreviado
if m := re.fullmatch(r'(\d{4})\s*-\s*(\d{2})', t):
a = int(m[1])
b = _ano(m[2], a)
if b > a:
return Ponto(a), Ponto(b), False
# o traço separa só entre um ano e o início do outro — `193-` é década, não intervalo
for sep in (r'\s+e\s+', r'\s+a\s+', r'(?<=[\d?])\s*[-–]\s*(?=\d)', r'\s*/\s*'):
partes = re.split(sep, t)
if len(partes) != 2:
continue
# "/" só separa anos inteiros (1952/1953); com meses é data (1910/12)
if sep == r'\s*/\s*' and not all(re.fullmatch(r'\d{4}', p) for p in partes):
continue
a, ia = _ponto(partes[0])
b, ib = _ponto(partes[1])
if a and b and b.limites()[1] >= a.limites()[0]:
return a, b, ia or ib
return None, None, False
ANO_MIN, ANO_MAX = 1500, date.today().year
def _plausivel(d: Data) -> Data:
"""Um ano fora do possível ("20-12-1395") é erro de digitação na origem: não vira data."""
anos = [x for x in d.anos() if x is not None]
if anos and (min(anos) < ANO_MIN or max(anos) > ANO_MAX):
d.notas.append(f'ano implausível na origem ({d.original}); data desconsiderada')
d.inicio_p = d.fim_p = None
d.relacao = ''
d.motivo = 'ilegível'
return d
def interpreta(texto: str | None) -> Data:
original = (texto or '').strip()
d = Data(original)
s = original
if not s:
d.motivo = 'sem data'
return d
if re.fullmatch(r'\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z', s):
# carimbo de registro no DSpace gravado no campo errado — não é produção
d.motivo = 'registro de sistema'
d.notas.append(f'dc.date traz a data de registro no sistema de origem ({s}), não a de produção')
return d
# partes separadas por ";" com qualificador: fica a de produção, o resto vira nota
partes = [p.strip() for p in re.split(r';(?![^(]*\))', s) if p.strip()]
if len(partes) > 1:
principal = next((p for p in partes if re.search(r'produ', p, re.I)), partes[0])
d.notas += [f'dc.date também registra: {p}' for p in partes if p is not principal]
s = principal
if m := re.search(r'\(([^)]*)\)\s*$', s):
q = m[1].lower()
if 'publica' in q:
d.tipo = 'publicação'
if 'atribu' in q:
d.colchete = True
s = s[:m.start()].strip()
if re.search(r'[\[\]{]', s):
d.colchete = True
s = re.sub(r'[\[\]{}]', '', s)
s = re.sub(r'^\s*-\s*', '', s)
s = re.sub(r'^(RJ|[A-Z]{2}),\s*', '', s) # [RJ, ca. 1860]: lugar vai na data tópica
s = re.sub(r'(\d)\.(\d{3})\b', r'\1\2', s) # 1.885 → 1885
s = re.sub(r'\s*:?\.\s*$', '', s).strip()
if SEM_DATA.fullmatch(s):
d.motivo = 'sem data'
return d
s, n = re.subn(r'\b(circa|cica|cira|ca\.?|c\.)\s*|(?<=\[)c(?=\d)|^c(?=\d)', '', s, flags=re.I)
if n:
d.aproximada = True
s, n = re.subn(r'\s*\b(anterior|antes de)\b\s*', ' ', s, flags=re.I)
if n:
d.relacao = 'antes'
s, n = re.subn(r'\s*\b(posterior|depois de)\b\s*', ' ', s, flags=re.I)
if n:
d.relacao = 'depois'
s = s.strip()
# interrogação no fim vale para a data inteira; dentro de um ponto (193?) é o ponto que diz
if re.search(r'\d{4}\s*\?\s*$', s) or re.search(r'\d{4}\?\s*\]?$', original):
d.incerta = True
s = re.sub(r'\s*\?\s*$', '', s)
# "Foto aérea da Fábrica ... - SP - 23-06-1933": só a data do fim interessa
if not re.match(r'[\d?]', s) and not re.match(rf'(?i){MES_RE}|entre|decada|década', _sem_acento(s)):
if m := re.search(r'(\d{1,2}-\d{1,2}-\d{4}|\d{4})\s*$', s):
d.notas.append(f'data extraída do texto: {original}')
s = m[1]
p, inc = _ponto(s)
if p:
d.inicio_p, d.incerta = p, d.incerta or inc
return _plausivel(d)
a, b, inc = _intervalo(s)
if a:
d.inicio_p, d.fim_p, d.incerta = a, b, d.incerta or inc
return _plausivel(d)
# "1900-" (colchete aberto): dali em diante
if m := re.fullmatch(r'(\d{4})\s*-', s):
d.inicio_p, d.relacao = Ponto(int(m[1])), 'depois'
return d
d.motivo = 'ilegível'
return d
def atribuida(inicio: int, fim: int, base: str) -> dict:
"""Data atribuída pelo arquivista a partir de outra fonte (proc. 1.3.3.2)."""
d = Data('', Ponto(inicio), Ponto(fim) if fim != inicio else None, incerta=True, colchete=True)
r = d.registro()
r['original'] = None
r['notas'] = [f'data atribuída pelo arquivista: {base}']
return r
+352
View File
@@ -0,0 +1,352 @@
"""Exportação da descrição: EAD 3 (descrições), EAC-CPF (autoridades) e CSV
de importação do AtoM (modelo ISAD). A NOBRADE não impõe formato; recomenda o
EAD para intercâmbio (nota 13).
Correspondência NOBRADE → EAD 3:
1.1 unitid · 1.2 unittitle · 1.3 unitdate (@normal em ISO 8601-2) ·
1.4 @level · 1.5 physdesc + physdescstructured · 2.1 origination ·
2.2 bioghist · 2.3 custodhist · 2.4 acqinfo · 3.1 scopecontent ·
3.2 appraisal · 3.3 accruals · 3.4 arrangement · 4.1 accessrestrict ·
4.2 userestrict · 4.3 langmaterial · 4.4 phystech · 4.5 otherfindaid ·
5.1 originalsloc · 5.2 altformavail + dao · 5.3 relatedmaterial ·
5.4 bibliography · 6.1 odd[@localtype=conservacao] · 6.2 odd ·
7.1 processinfo · 7.2 control/conventiondeclaration · 7.3 control/maintenancehistory ·
8.1 controlaccess
"""
from __future__ import annotations
import csv
import re
import xml.etree.ElementTree as ET
from collections import defaultdict
from datetime import date
from .config import ENTIDADE, ENTIDADE_NOME, PAIS, REGRAS, SAIDA
EAD = 'http://ead3.archivists.org/schema/'
CPF = 'urn:isbn:1-931666-33-4'
XLINK = 'http://www.w3.org/1999/xlink'
NIVEL_EAD = {1: ('collection', None), 2: ('otherlevel', 'seção'), 3: ('series', None),
4: ('file', None), 5: ('item', None)}
HOJE = date.today().isoformat()
# ── texto plano de cada elemento (usado por EAD, AtoM e mural) ──────────────
def texto(u: dict, el: str) -> str | None:
v = u.get(el)
if v is None:
return None
if el == '1.2':
return v['titulo']
if el == '1.3':
p = v.get('producao') or {}
return p.get('forma')
if el == '1.5':
return v.get('texto')
if el == '2.1':
return '; '.join(p['forma'] for p in v)
if el == '4.2':
return v['texto'] if isinstance(v, dict) else v
if el == '4.3':
return '; '.join(i['nome'] for i in v) if isinstance(v, list) else v
if el == '5.1':
return v.get('texto') or v.get('instituicao') if isinstance(v, dict) else v
if el == '5.2':
if isinstance(v, str):
return v
partes = [f"{c['tipo']}: {c['chave']} (SHA-256 {c['sha256']})" for c in v.get('nesta_entidade') or []]
partes += [f"{c['entidade']}: {c['url']}" for c in v.get('em_outras_entidades') or []]
return '; '.join(partes) or None
if el in ('5.3', '5.4', '6.2') and isinstance(v, list):
return '\n'.join(v)
if el == '7.3':
return '; '.join(f'{k}: {x}' for k, x in v.items())
if el == '8.1' and isinstance(v, dict):
return None
return v if isinstance(v, str) else None
# ── EAD 3 ────────────────────────────────────────────────────────────────────
def _sub(pai, tag, txt=None, **attrs):
e = ET.SubElement(pai, f'{{{EAD}}}{tag}', {k.rstrip('_'): str(x) for k, x in attrs.items() if x is not None})
if txt is not None:
e.text = txt
return e
def _paragrafos(pai, tag, txt, head=None, **attrs):
if not txt:
return
e = _sub(pai, tag, **attrs)
if head:
_sub(e, 'head', head)
for par in [p.strip() for p in re.split(r'\n\s*\n|\n(?=[-\d])', txt) if p.strip()]:
_sub(e, 'p', re.sub(r'\s+', ' ', par))
def _nome(pai, forma: str, aid: str | None, tipo: str | None, relator=None):
tag = {'entidade coletiva': 'corpname', 'família': 'famname'}.get(tipo, 'persname')
e = _sub(pai, tag, identifier=aid, relator=relator)
_sub(e, 'part', forma)
return e
def _componente(pai, u: dict, aut: dict, tag='c'):
nivel, outro = NIVEL_EAD[u['nivel']]
c = pai if tag == 'archdesc' else _sub(pai, 'c', level=nivel, otherlevel=outro, id=_xmlid(u['id']))
did = _sub(c, 'did')
_sub(did, 'unitid', u['1.1'], countrycode=PAIS, repositorycode=f'{PAIS}-{ENTIDADE}')
_sub(did, 'unittitle', u['1.2']['titulo'])
p = u['1.3'].get('producao') or {}
cert = {'aproximada': 'approximate', 'incerta': 'uncertain', 'atribuida': 'inferred',
'atribuída pelo arquivista': 'inferred'}.get(p.get('qualidade'))
_sub(did, 'unitdate', p.get('forma') or '[s.d.]', normal=p.get('iso'),
datechar='publication' if p.get('tipo') == 'publicação' else 'creation', certainty=cert,
unitdatetype='inclusive' if u['nivel'] < 4 else None)
orig = _sub(did, 'origination')
for pr in u['2.1']:
_nome(orig, pr['forma'], pr.get('id'), (aut.get(pr.get('id')) or {}).get('tipo'),
relator=pr.get('funcao'))
dim = u['1.5']
_sub(did, 'physdesc', dim['texto'])
for esp, n in (dim.get('por_especie') or {}).items():
ps = _sub(did, 'physdescstructured', physdescstructuredtype='materialtype', coverage='part')
_sub(ps, 'quantity', str(n))
_sub(ps, 'unittype', esp)
if isinstance(u.get('4.3'), list):
lm = _sub(did, 'langmaterial')
for i in u['4.3']:
_sub(lm, 'language', i['nome'], langcode=i['codigo'])
if u['nivel'] == 5:
for cp in (u.get('5.2') or {}).get('nesta_entidade') or []:
_sub(did, 'dao', daotype='derived', href=cp['chave'], linktitle=cp['tipo'],
identifier=f"sha256:{cp['sha256']}")
_paragrafos(c, 'bioghist', u.get('2.2'))
_paragrafos(c, 'custodhist', u.get('2.3'))
_paragrafos(c, 'acqinfo', u.get('2.4'))
_paragrafos(c, 'scopecontent', u.get('3.1'))
_paragrafos(c, 'appraisal', u.get('3.2'))
_paragrafos(c, 'accruals', u.get('3.3'))
_paragrafos(c, 'arrangement', u.get('3.4'))
_paragrafos(c, 'accessrestrict', u.get('4.1'))
_paragrafos(c, 'userestrict', texto(u, '4.2'))
_paragrafos(c, 'phystech', u.get('4.4'))
_paragrafos(c, 'otherfindaid', u.get('4.5'))
_paragrafos(c, 'originalsloc', texto(u, '5.1'))
if u['nivel'] != 5:
_paragrafos(c, 'altformavail', texto(u, '5.2'))
if isinstance(u.get('5.3'), list):
rm = _sub(c, 'relatedmaterial')
for x in u['5.3']:
_sub(rm, 'p', x)
if isinstance(u.get('5.4'), list):
bib = _sub(c, 'bibliography')
for x in u['5.4']:
_sub(bib, 'bibref', x)
elif u.get('5.4'):
_paragrafos(c, 'bibliography', u['5.4'])
_paragrafos(c, 'odd', u.get('6.1'), head='Notas sobre conservação', localtype='conservacao')
_paragrafos(c, 'odd', texto(u, '6.2'), head='Notas gerais')
_paragrafos(c, 'processinfo', u.get('7.1'))
ca = u.get('8.1')
if isinstance(ca, dict):
ctl = _sub(c, 'controlaccess')
for s in ca.get('assuntos') or []:
_sub(_sub(ctl, 'subject', lang='por'), 'part', s)
for s in ca.get('assuntos_eng') or []:
_sub(_sub(ctl, 'subject', lang='eng'), 'part', s)
if u['1.3'].get('topica'):
_sub(_sub(ctl, 'geogname', localtype='data tópica'), 'part', u['1.3']['topica'])
for s in ca.get('lugares') or []:
_sub(_sub(ctl, 'geogname'), 'part', s)
for pr in u['2.1']:
if pr.get('id'):
_nome(ctl, pr['forma'], pr['id'], (aut.get(pr['id']) or {}).get('tipo'))
if len(ctl) == 0:
c.remove(ctl)
elif ca:
_paragrafos(c, 'processinfo', ca, head='Pontos de acesso e indexação')
return c
def _xmlid(cod: str) -> str:
return 'u-' + re.sub(r'[^\w.-]', '_', cod)
def ead(unidades: list[dict], aut: dict):
filhos = defaultdict(list)
por_id = {}
for u in unidades:
por_id[u['id']] = u
if u.get('pai'):
filhos[u['pai']].append(u['id'])
col = next(u for u in unidades if u['nivel'] == 1)
ET.register_namespace('', EAD)
raiz = ET.Element(f'{{{EAD}}}ead')
ctrl = _sub(raiz, 'control', langencoding='iso639-2b', scriptencoding='iso15924',
dateencoding='iso8601', countryencoding='iso3166-1', repositoryencoding='iso15511')
_sub(ctrl, 'recordid', col['id'])
fd = _sub(ctrl, 'filedesc')
ts = _sub(fd, 'titlestmt')
_sub(ts, 'titleproper', col['1.2']['titulo'])
_sub(ctrl, 'maintenancestatus', value='new')
ag = _sub(ctrl, 'maintenanceagency', countrycode=PAIS)
_sub(ag, 'agencycode', f'{PAIS}-{ENTIDADE}')
_sub(ag, 'agencyname', ENTIDADE_NOME)
ld = _sub(ctrl, 'languagedeclaration')
_sub(ld, 'language', 'português', langcode='por')
_sub(ld, 'script', 'latino', scriptcode='Latn')
cd = _sub(ctrl, 'conventiondeclaration')
_sub(cd, 'citation', REGRAS)
mh = _sub(ctrl, 'maintenancehistory')
ev = _sub(mh, 'maintenanceevent')
_sub(ev, 'eventtype', value='created')
_sub(ev, 'eventdatetime', HOJE, standarddatetime=HOJE)
_sub(ev, 'agenttype', value='machine')
_sub(ev, 'agent', 'pipeline/nobrade')
arch = _sub(raiz, 'archdesc', level='collection')
_componente(arch, col, aut, tag='archdesc')
rep = arch.find(f'{{{EAD}}}did')
r = _sub(rep, 'repository')
_sub(_sub(r, 'corpname', identifier=f'{PAIS}-{ENTIDADE}'), 'part', ENTIDADE_NOME)
dsc = _sub(arch, 'dsc')
def desce(pai_xml, cod):
for fid in sorted(filhos[cod], key=lambda x: (len(x), x)):
c = _componente(pai_xml, por_id[fid], aut)
desce(c, fid)
desce(dsc, col['id'])
(SAIDA / 'ead').mkdir(exist_ok=True)
ET.indent(raiz, space=' ')
ET.ElementTree(raiz).write(SAIDA / 'ead' / 'brasiliana.xml', encoding='utf-8', xml_declaration=True)
# ── EAC-CPF ──────────────────────────────────────────────────────────────────
def _c(pai, tag, txt=None, **attrs):
e = ET.SubElement(pai, f'{{{CPF}}}{tag}', {k.rstrip('_'): str(x) for k, x in attrs.items() if x is not None})
if txt is not None:
e.text = txt
return e
def eac(autoridades: list[dict], usos: dict[str, list[str]]):
ET.register_namespace('', CPF)
ET.register_namespace('xlink', XLINK)
pasta = SAIDA / 'eac'
pasta.mkdir(exist_ok=True)
for a in autoridades:
raiz = ET.Element(f'{{{CPF}}}eac-cpf')
ctrl = _c(raiz, 'control')
_c(ctrl, 'recordId', f"{PAIS}-{ENTIDADE}-{a['id']}")
_c(ctrl, 'maintenanceStatus', 'new')
ag = _c(ctrl, 'maintenanceAgency')
_c(ag, 'agencyCode', f'{PAIS}-{ENTIDADE}')
_c(ag, 'agencyName', ENTIDADE_NOME)
ld = _c(ctrl, 'languageDeclaration')
_c(ld, 'language', 'português', languageCode='por')
_c(ld, 'script', 'latino', scriptCode='Latn')
cd = _c(ctrl, 'conventionDeclaration')
_c(cd, 'citation', 'ISAAR(CPF) 2ª ed.; NOBRADE (CONARQ, 2006), proc. 8.1.3–8.1.4')
mh = _c(ctrl, 'maintenanceHistory')
ev = _c(mh, 'maintenanceEvent')
_c(ev, 'eventType', 'created')
_c(ev, 'eventDateTime', HOJE, standardDateTime=HOJE)
_c(ev, 'agentType', 'machine')
_c(ev, 'agent', 'pipeline/nobrade')
if a['fontes']:
src = _c(ctrl, 'sources')
for f in a['fontes']:
s = _c(src, 'source')
_c(s, 'sourceEntry', f)
cpf = _c(raiz, 'cpfDescription')
ident = _c(cpf, 'identity')
_c(ident, 'entityType', {'entidade coletiva': 'corporateBody', 'família': 'family'}.get(a['tipo'], 'person'))
ne = _c(ident, 'nameEntry', localType='autorizada')
_c(ne, 'part', a['nome'])
if a['datas_existencia']:
_c(ne, 'useDates').append(_data_eac(a['datas_existencia']))
_c(ne, 'authorizedForm', 'NOBRADE')
for v in a['variantes']:
nv = _c(ident, 'nameEntry', localType='variante')
_c(nv, 'part', v)
_c(nv, 'alternativeForm', 'NOBRADE')
desc = _c(cpf, 'description')
if a['datas_existencia']:
ex = _c(desc, 'existDates')
ex.append(_data_eac(a['datas_existencia']))
bh = _c(desc, 'biogHist')
_c(bh, 'p', f"Autor de {a['ocorrencias']} dossiês da Coleção Brasiliana Fotográfica (cópia digital)."
+ (f" Tipo presumido: {a['tipo']}." if a['tipo'] == 'pessoa ou entidade' else ''))
if usos.get(a['id']):
rel = _c(cpf, 'relations')
for cod in usos[a['id']][:500]:
r = _c(rel, 'resourceRelation', resourceRelationType='creatorOf')
_c(r, 'relationEntry', cod)
ET.indent(raiz, space=' ')
ET.ElementTree(raiz).write(pasta / f"{a['id']}.xml", encoding='utf-8', xml_declaration=True)
def _data_eac(datas: str):
anos = re.findall(r'\d{4}', datas)
if len(anos) >= 2:
e = ET.Element(f'{{{CPF}}}dateRange')
_c(e, 'fromDate', datas.split('-')[0].strip(), standardDate=anos[0])
_c(e, 'toDate', datas.split('-')[-1].strip(), standardDate=anos[1])
return e
e = ET.Element(f'{{{CPF}}}date', standardDate=anos[0] if anos else None)
e.text = datas
return e
# ── AtoM (modelo CSV ISAD da versão 2.x) ────────────────────────────────────
ATOM = ['legacyId', 'parentId', 'identifier', 'title', 'levelOfDescription', 'extentAndMedium',
'repository', 'archivalHistory', 'acquisition', 'scopeAndContent', 'appraisal', 'accruals',
'arrangement', 'accessConditions', 'reproductionConditions', 'language', 'physicalCharacteristics',
'findingAids', 'locationOfOriginals', 'locationOfCopies', 'relatedUnitsOfDescription',
'publicationNote', 'generalNote', 'subjectAccessPoints', 'placeAccessPoints', 'nameAccessPoints',
'descriptionIdentifier', 'rules', 'archivistNote', 'eventDates', 'eventTypes', 'eventStartDates',
'eventEndDates', 'eventActors', 'culture']
NIVEL_ATOM = {1: 'Coleção', 2: 'Seção', 3: 'Série', 4: 'Dossiê', 5: 'Item documental'}
def atom(unidades: list[dict]):
with (SAIDA / 'atom.csv').open('w', encoding='utf-8', newline='') as f:
w = csv.DictWriter(f, fieldnames=ATOM)
w.writeheader()
for u in unidades:
if u['nivel'] == 0:
continue
p = u['1.3'].get('producao') or {}
ca = u.get('8.1') if isinstance(u.get('8.1'), dict) else {}
w.writerow({
'legacyId': u['id'], 'parentId': u['pai'] if u['nivel'] > 1 else '',
'identifier': u['1.1'].split('.')[-1] if u['nivel'] > 1 else u['1.1'],
'title': u['1.2']['titulo'], 'levelOfDescription': NIVEL_ATOM[u['nivel']],
'extentAndMedium': texto(u, '1.5'), 'repository': ENTIDADE_NOME,
'archivalHistory': u.get('2.3'), 'acquisition': u.get('2.4'),
'scopeAndContent': u.get('3.1'), 'appraisal': u.get('3.2'), 'accruals': u.get('3.3'),
'arrangement': u.get('3.4'), 'accessConditions': u.get('4.1'),
'reproductionConditions': texto(u, '4.2'),
'language': '|'.join(i['codigo'] for i in u['4.3']) if isinstance(u.get('4.3'), list) else '',
'physicalCharacteristics': u.get('4.4'), 'findingAids': u.get('4.5'),
'locationOfOriginals': texto(u, '5.1'), 'locationOfCopies': texto(u, '5.2'),
'relatedUnitsOfDescription': texto(u, '5.3'), 'publicationNote': texto(u, '5.4'),
'generalNote': '\n'.join(x for x in [u.get('6.1'), texto(u, '6.2')] if x),
'subjectAccessPoints': '|'.join(ca.get('assuntos') or []),
'placeAccessPoints': '|'.join(ca.get('lugares') or []),
'nameAccessPoints': '|'.join(ca.get('nomes') or []),
'descriptionIdentifier': u['id'], 'rules': u.get('7.2') or '',
'archivistNote': u.get('7.1'),
'eventDates': p.get('forma'), 'eventTypes': 'Produção',
'eventStartDates': f"{p['inicio']}-01-01" if p.get('inicio') else '',
'eventEndDates': f"{p['fim']}-12-31" if p.get('fim') else '',
'eventActors': '|'.join(x['forma'] for x in u['2.1'] if x.get('id')),
'culture': 'pt_BR',
})
+500
View File
@@ -0,0 +1,500 @@
"""Monta a descrição multinível (níveis 0–5) a partir do catálogo, do ledger do
bucket e dos posts do blog. Escreve descricao/unidades.jsonl,
descricao/autoridades.jsonl e as tabelas de revisão.
Cada unidade é um objeto com `id` (= código de referência), `pai`, `nivel` e os
elementos da NOBRADE pelo número: "1.1", "1.2", … "8.1".
"""
from __future__ import annotations
import ast
import json
import re
import sqlite3
from collections import Counter, defaultdict
from datetime import date, datetime
import polars as pl
from . import campos, datas, series
from .autoridades import Autoridades
from .config import (ACESSO, BUCKET, CATALOGO, COLECAO, COLECAO_TITULO, ENTIDADE_NOME, HANDLE_URL,
INSTITUICOES, LEDGER, ORIGEM_NOME, ORIGEM_SITE, POSTS, REGRAS, RESPONSAVEL, REVISAO,
SAIDA, TEXTOS, codigo)
NIVEIS = {0: 'acervo da entidade custodiadora', 1: 'coleção', 2: 'seção', 3: 'série',
4: 'dossiê', 5: 'item documental'}
MESES_ABNT = ['jan.', 'fev.', 'mar.', 'abr.', 'maio', 'jun.', 'jul.', 'ago.', 'set.', 'out.', 'nov.', 'dez.']
HOJE = date.today().isoformat()
# ── leitura das fontes ──────────────────────────────────────────────────────
def _valores(item: dict) -> dict[str, list[str]]:
vs = defaultdict(list)
for row in item.get('full_table') or []:
v = (row.get('value') or '').strip()
if v and v not in vs[row['field']]:
vs[row['field']].append(v)
return vs
def _ledger() -> dict[str, list[dict]]:
arquivos = defaultdict(list)
if not LEDGER.exists():
return arquivos
con = sqlite3.connect(LEDGER)
for h, nome, b, sha, quando, tipo in con.execute(
'select handle, nome, bytes, sha256, quando, tipo from enviados order by handle, tipo, nome'):
arquivos[h].append({'nome': nome, 'bytes': b, 'sha256': sha, 'quando': quando, 'tipo': tipo})
return arquivos
def _abnt(post: dict) -> str:
autor = (post.get('autor') or '').strip()
partes = autor.split()
autor_abnt = f'{partes[-1].upper()}, {" ".join(partes[:-1])}' if len(partes) > 1 else autor.upper()
d = datetime.fromisoformat(post['data_iso'][:10])
acesso = (post.get('fetched_at') or HOJE)[:10]
a = datetime.fromisoformat(acesso)
return (f"{autor_abnt}. {post['titulo']}. {ORIGEM_NOME}, Rio de Janeiro, "
f"{d.day} {MESES_ABNT[d.month - 1]} {d.year}. Disponível em: {post['url']}. "
f"Acesso em: {a.day} {MESES_ABNT[a.month - 1]} {a.year}.")
def _posts() -> tuple[dict[str, list[dict]], list[dict]]:
por_handle, todos = defaultdict(list), []
if not POSTS.exists():
return por_handle, todos
for linha in POSTS.open(encoding='utf-8'):
p = json.loads(linha)
if p.get('erro') or not p.get('titulo'):
continue
hs = p.get('handles_referenciados') or []
if isinstance(hs, str):
hs = ast.literal_eval(hs)
cats = p.get('categorias') or []
if isinstance(cats, str):
cats = ast.literal_eval(cats)
ref = {'titulo': p['titulo'], 'url': p['url'], 'autor': p.get('autor'), 'data': p['data_iso'][:10],
'categorias': cats, 'abnt': _abnt(p)}
todos.append(ref)
for h in hs:
por_handle[h].append(ref)
return por_handle, todos
def _textos(caminho) -> dict[str, str]:
"""Um .md com seções "## 2.3 História arquivística" → {'2.3': texto}."""
if not caminho.exists():
return {}
out, atual, buf = {}, None, []
for linha in caminho.read_text(encoding='utf-8').splitlines():
if m := re.match(r'^##\s+(\d\.\d)\b', linha):
if atual:
out[atual] = '\n'.join(buf).strip()
atual, buf = m[1], []
elif linha.startswith('#'): # outro título (### Fontes…) fecha a seção e fica fora da descrição
if atual:
out[atual] = '\n'.join(buf).strip()
atual, buf = None, []
elif atual:
buf.append(linha)
if atual:
out[atual] = '\n'.join(buf).strip()
return {k: v for k, v in out.items() if v}
def _mb(b: int) -> str:
return f'{b / 1e6:.1f} MB'.replace('.', ',') if b < 1e9 else f'{b / 1e9:.1f} GB'.replace('.', ',')
def _formato(nome: str) -> str:
ext = nome.rsplit('.', 1)[-1].lower() if '.' in nome else ''
return {'jpg': 'JPEG', 'jpeg': 'JPEG', 'png': 'PNG', 'tif': 'TIFF', 'tiff': 'TIFF', 'webp': 'WebP',
'pdf': 'PDF', 'gif': 'GIF'}.get(ext, ext.upper() or 'desconhecido')
def _limites(ds: list[dict]) -> dict:
ini = [d['inicio'] for d in ds if d and d.get('inicio')]
fim = [d['fim'] for d in ds if d and d.get('fim')]
if not ini and not fim:
return {'forma': '[s.d.]', 'iso': None, 'inicio': None, 'fim': None, 'qualidade': None,
'tipo': 'produção'}
a, b = min(ini or fim), max(fim or ini)
return {'forma': f'{a}-{b}' if a != b else str(a), 'iso': f'{a}/{b}' if a != b else str(a),
'inicio': a, 'fim': b, 'qualidade': 'datas-limite', 'tipo': 'produção'}
def _robustos(ds: list[dict]) -> dict:
"""Datas-limite para atribuir a dossiês sem data: o miolo (percentis 10–90)
das datas conhecidas, para que um punhado de extremos não vire [1800-1999?]."""
anos = sorted(d['inicio'] for d in ds if d and d.get('inicio'))
if not anos:
return {'inicio': None, 'fim': None}
return {'inicio': anos[int(len(anos) * .1)], 'fim': anos[min(len(anos) - 1, int(len(anos) * .9))]}
def _dimensao(especies: Counter, n_itens: int, bytes_: int) -> dict:
partes = [f'{n} {e}' for e, n in especies.most_common()]
return {'por_especie': dict(especies), 'arquivos_digitais': n_itens, 'bytes': bytes_,
'texto': f"iconográfico: {', '.join(partes)}; eletrônico: {n_itens} arquivos digitais ({_mb(bytes_)})"}
# ── montagem ────────────────────────────────────────────────────────────────
def monta():
SAIDA.mkdir(exist_ok=True)
REVISAO.mkdir(parents=True, exist_ok=True)
ledger = _ledger()
posts_de, posts = _posts()
itens = []
for linha in CATALOGO.open(encoding='utf-8'):
if linha.strip():
it = json.loads(linha)
it['_v'] = _valores(it)
itens.append(it)
# séries (nível 3)
fontes = [(it['handle'], it['community'], (it['_v']['dc.source'] or [None])[0]) for it in itens]
serie_de, series_ = series.monta(fontes)
# autoridades
aut = Autoridades()
for it in itens:
for f in ('dc.contributor', 'dc.contributor.author', 'dc.contributor.other'):
for v in it['_v'][f]:
aut.registra(v)
aut.resolve()
for reg in aut.registros.values(): # biografias no blog (3.4) → fontes da autoridade
if reg['tipo'] == 'pessoa' and ',' in reg['nome']:
sob, nome = [x.strip() for x in reg['nome'].split(',', 1)]
primeiro = nome.split()[0] if nome else ''
for p in posts:
if 'Biografia' in p['categorias'] and sob in p['titulo'] and primeiro in p['titulo']:
reg['fontes'].append(p['abnt'])
unidades: dict[str, dict] = {}
filhos = defaultdict(list)
rev_datas, rev_tipos, rev_direitos, rev_lugares = [], [], [], []
def add(u: dict):
unidades[u['id']] = u
if u['pai']:
filhos[u['pai']].append(u['id'])
# níveis 4 e 5
for it in itens:
v, h = it['_v'], it['handle']
inst = it['community']
sigla_i, nome_i, cidade_i = INSTITUICOES[inst]
sg, notacao = serie_de[h]
num = h.rsplit('/', 1)[-1]
cod = codigo(COLECAO, sigla_i, sg, num)
pasta = h.replace('/', '_')
titulo = (v['dc.title'] or [it.get('title') or ''])[0].strip()
titulo_atribuido = False
if not titulo: # proc. 1.2: título atribuído a partir da própria unidade, entre colchetes
base = next((x for x in v['dc.description'] + v['dc.subject'] + v['dc.coverage']
if not campos.corrompido(x)), 'Sem título')
titulo, titulo_atribuido = f"[{base.split('. ')[0][:90]}]", True
d = datas.interpreta((v['dc.date'] or [''])[0])
data = d.registro()
if len(v['dc.date']) > 1:
data['notas'] = (data['notas'] or []) + [f'outra data na origem: {x}' for x in v['dc.date'][1:]]
produtores = []
for f in ('dc.contributor', 'dc.contributor.author', 'dc.contributor.other'):
for nome in v[f]:
aid = aut.id(nome)
if aid and aid not in [p['id'] for p in produtores]:
produtores.append({'id': aid, 'forma': aut[aid]['forma_autorizada'],
'funcao': 'autor' if f != 'dc.contributor.other' else 'outro'})
if not produtores:
produtores = [{'id': None, 'forma': 'Autoria não identificada', 'funcao': 'autor'}]
descricoes = [x for x in v['dc.description'] if not campos.corrompido(x)]
fisico = [x for x in descricoes if campos.e_fisico(x)]
conteudo = [x for x in descricoes if x not in fisico]
esp = campos.especie((v['dc.type'] or [None])[0])
cor = campos.cor(fisico)
arquivos = ledger.get(h, [])
preserv = sorted((a for a in arquivos if a['tipo'] == 'preservacao'),
key=lambda a: (a['nome'] != 'imagem.jpg', a['nome']))
imagens = preserv or [a for a in arquivos if a['tipo'] == 'thumbnail']
total = sum(a['bytes'] or 0 for a in imagens)
direitos = campos.direitos(v['dc.rights'] + [str(it.get('rights') or '')], nome_i)
lugar = campos.lugar(v['dc.coverage'])
assuntos = [s for s in v['dc.subject'] if not campos.corrompido(s)]
codigo_origem = next((re.sub(r'\.\w{3,4}$', '', x) for x in v['dc.identifier'] + v['dc.description']
if re.match(r'BR ?[A-Z]{2}[A-Z]{2,}\s', x)), None)
sophia = next((x for x in v['dc.relation'] if 'sophia' in x), None)
objdigital = [x for x in v['dc.identifier'] if 'objdigital' in x]
notas = ['Título atribuído pelo arquivista: a origem não informa título.'] if titulo_atribuido else []
if d.original and data['forma'] != d.original:
notas.append(f'Data como consta na origem: {d.original}')
notas += data['notas'] or []
if esp['presumida']:
notas.append('Espécie documental não informada na origem; presumida fotografia'
+ (f" (valor na origem: {esp['original']})" if esp.get('original') else '') + '.')
if direitos['originais']:
notas.append('Direitos como constam na origem: ' + ' | '.join(direitos['originais']))
lixo = [f"{f}: {x[:60]}" for f, xs in v.items() for x in xs if campos.corrompido(x)
and f in ('dc.type', 'dc.rights', 'dc.source', 'dc.subject', 'dc.date', 'dc.coverage')]
if lixo:
notas.append('Valores corrompidos na origem, desconsiderados: ' + '; '.join(lixo))
conservacao = None
if not preserv:
conservacao = ('Arquivo de preservação indisponível na origem (o repositório responde HTTP 500 '
'ao bitstream; ver errors.md). A cópia guarda apenas a miniatura gerada pelo DSpace.')
dossie = {
'id': cod, 'pai': codigo(COLECAO, sigla_i, sg), 'nivel': 4, 'handle': h,
'1.1': cod,
'1.2': {'titulo': titulo, 'atribuido': titulo.startswith('[')},
'1.3': {'producao': data, 'topica': lugar},
'1.4': {'nivel': 4, 'nome': NIVEIS[4]},
'1.5': {'genero': esp['genero'], 'especie': esp['especie'], 'suporte': esp['suporte'], 'cor': cor,
'fisico': fisico or None, 'arquivos_digitais': len(imagens), 'bytes': total,
'texto': (f"1 {esp['especie']}" + (f' {cor}' if cor else '')
+ (f", {esp['suporte']}" if esp['suporte'] else '')
+ (f" ({'; '.join(fisico)})" if fisico else '')
+ f"; {len(imagens)} arquivo{'s' if len(imagens) != 1 else ''} digita"
+ f"{'is' if len(imagens) != 1 else 'l'} ({_mb(total)})")},
'2.1': produtores,
'2.3': (f"Registrado no repositório DSpace da {ORIGEM_NOME}"
+ (f" em {v['dc.date.accessioned'][0][:10]}" if v['dc.date.accessioned'] else '')
+ f". Cópia digital capturada em {it['fetched_at'][:10]} e armazenada em "
f"{BUCKET}/itens/{pasta}/ com SHA-256 de cada arquivo."),
'2.4': (f"{ORIGEM_NOME} ({ORIGEM_SITE}), repositório mantido pela Biblioteca Nacional; "
f"coleta combinada com a Biblioteca Nacional, em {it['fetched_at'][:10]}. Handle {h}."),
'3.1': ' '.join(conteudo) or None,
'4.2': direitos,
'4.3': campos.idiomas(v['dc.language']) or None,
'4.4': (f"Arquivo{'s' if len(imagens) > 1 else ''} digita{'is' if len(imagens) > 1 else 'l'} "
f"{', '.join(sorted({_formato(a['nome']) for a in imagens})) or '—'}; "
'abre em qualquer visualizador de imagem.'
+ (f" Original: {'; '.join(fisico)}." if fisico else '')),
'5.1': {'instituicao': nome_i, 'local': cidade_i, 'url': HANDLE_URL.format(h),
'codigo_na_origem': codigo_origem, 'notacao_na_origem': notacao, 'sophia': sophia,
'texto': f"Original sob a guarda de {nome_i}, {cidade_i}"
+ (f", código {codigo_origem}" if codigo_origem else '')
+ (f", notação {notacao}" if notacao else '') + f". {HANDLE_URL.format(h)}"},
'5.2': {'nesta_entidade': [{'tipo': a['tipo'], 'chave': (f"{BUCKET}/derivados/thumb256/{a['nome']}"
if a['tipo'] == 'derivado-thumb256'
else f"{BUCKET}/itens/{pasta}/{a['tipo']}/{a['nome']}"),
'bytes': a['bytes'], 'sha256': a['sha256']} for a in arquivos],
'em_outras_entidades': [{'entidade': 'Biblioteca Nacional (Brasil) — BNDigital', 'url': u}
for u in objdigital] or None},
'5.3': (v['dc.relation.ispartof'] + v['dcterms.relation']) or None,
'5.4': [p['abnt'] for p in posts_de.get(h, [])] or None,
'6.1': conservacao,
'6.2': notas or None,
'7.1': (f'Descrição gerada pelo pipeline/nobrade a partir dos metadados Dublin Core colhidos '
f'da {ORIGEM_NOME} ({it["source_url"]}); responsável: {RESPONSAVEL}.'),
'7.3': {'coleta': it['fetched_at'][:10], 'descricao': HOJE},
'8.1': {'assuntos': [s for s in assuntos if campos.idioma_termo(s) == 'por'] or None,
'assuntos_eng': [s for s in assuntos if campos.idioma_termo(s) == 'eng'] or None,
'lugares': [c for c in v['dc.coverage'] if not campos.corrompido(c)] or None,
'nomes': [p['forma'] for p in produtores if p['id']] or None,
'periodo': data['iso']},
'_sd': not d.ok, '_especie': esp['especie'], '_serie': (inst, sg),
}
add(dossie)
rev_datas.append({'handle': h, 'original': d.original, 'forma': data['forma'], 'iso': data['iso'],
'inicio': data['inicio'], 'fim': data['fim'], 'qualidade': data['qualidade'],
'motivo': data['motivo']})
rev_tipos.append({'instituicao': inst, 'dc_type': (v['dc.type'] or [''])[0], 'genero': esp['genero'],
'especie': esp['especie'], 'suporte': esp['suporte'] or '', 'presumida': esp['presumida']})
rev_direitos.append({'instituicao': inst, 'categoria': direitos['categoria'], 'detentor': direitos['detentor'],
'originais': ' | '.join(direitos['originais'] or [])})
rev_lugares.append({'coverage': ' | '.join(v['dc.coverage']), 'data_topica': lugar or ''})
for i, a in enumerate(imagens, 1):
ci = f'{cod}.{i:02d}'
add({
'id': ci, 'pai': cod, 'nivel': 5, 'handle': h,
'1.1': ci,
'1.2': {'titulo': f"{titulo} [imagem {i} de {len(imagens)}]", 'atribuido': True},
'1.3': {'producao': data},
'1.4': {'nivel': 5, 'nome': NIVEIS[5]},
'1.5': {'genero': 'eletrônico', 'especie': 'arquivo de imagem', 'bytes': a['bytes'],
'texto': f"1 arquivo digital {_formato(a['nome'])} ({_mb(a['bytes'] or 0)})"},
'2.1': produtores,
'4.4': f"{_formato(a['nome'])}; SHA-256 {a['sha256']}"
+ ('; miniatura — preservação indisponível na origem' if a['tipo'] == 'thumbnail' else ''),
'5.2': {'nesta_entidade': [{'tipo': a['tipo'], 'chave': f"{BUCKET}/itens/{pasta}/{a['tipo']}/{a['nome']}",
'bytes': a['bytes'], 'sha256': a['sha256']}]},
'7.3': {'descricao': HOJE},
})
# níveis 3, 2, 1, 0 — de baixo para cima, agregando os filhos
textos1 = _textos(TEXTOS / 'nivel1.md')
textos0 = _textos(TEXTOS / 'nivel0.md')
por_serie = defaultdict(list)
for u in unidades.values():
if u['nivel'] == 4:
por_serie[u['_serie']].append(u)
# datas atribuídas aos s.d. (proc. 1.3.3.2): período do fotógrafo, senão datas-limite da série
rev_por_handle = {r['handle']: r for r in rev_datas}
lim_secao = {inst: _robustos([u['1.3']['producao'] for (i, _), us in por_serie.items() if i == inst
for u in us if not u['_sd']]) for inst, _ in por_serie}
lim_serie = {k: _robustos([u['1.3']['producao'] for u in us if not u['_sd']]) for k, us in por_serie.items()}
for k, us in por_serie.items():
for u in us:
if not u['_sd']:
continue
per = next((aut[p['id']]['periodo_atividade'] for p in u['2.1']
if p['id'] and aut[p['id']]['periodo_atividade']), None)
if per:
nova = datas.atribuida(*per, 'período de atividade do autor')
elif lim_serie[k]['inicio']:
nova = datas.atribuida(lim_serie[k]['inicio'], lim_serie[k]['fim'], 'miolo das datas conhecidas da série (percentis 10–90)')
elif lim_secao[k[0]]['inicio']:
nova = datas.atribuida(lim_secao[k[0]]['inicio'], lim_secao[k[0]]['fim'],
'miolo das datas conhecidas da instituição de origem (percentis 10–90)')
else:
continue
nova['original'] = u['1.3']['producao']['original']
nova['notas'] = nova['notas'] + (u['1.3']['producao']['notas'] or [])
u['1.3']['producao'] = nova
u['8.1']['periodo'] = nova['iso']
for fid in filhos[u['id']]:
unidades[fid]['1.3']['producao'] = nova
r = rev_por_handle[u['handle']]
r.update(forma=nova['forma'], iso=nova['iso'], inicio=nova['inicio'], fim=nova['fim'],
qualidade='atribuída pelo arquivista')
def agrega(us: list[dict]) -> dict:
esp = Counter(u['_especie'] for u in us)
n = sum(u['1.5']['arquivos_digitais'] for u in us)
b = sum(u['1.5']['bytes'] for u in us)
autores = Counter(p['forma'] for u in us for p in u['2.1'] if p['id'])
lugares = Counter(u['1.3']['topica'] for u in us if u['1.3'].get('topica'))
return {'data': _limites([u['1.3']['producao'] for u in us]), 'dim': _dimensao(esp, n, b),
'autores': autores, 'lugares': lugares, 'dossies': len(us)}
def resumo(a: dict) -> str:
s = f"{a['dossies']} dossiês, {a['data']['forma']}."
if a['autores']:
s += ' Principais autores: ' + '; '.join(f'{k} ({n})' for k, n in a['autores'].most_common(5)) + '.'
if a['lugares']:
s += ' Principais lugares: ' + '; '.join(f'{k} ({n})' for k, n in a['lugares'].most_common(5)) + '.'
return s
rev_series = []
por_secao = defaultdict(list)
for (inst, sg), us in sorted(por_serie.items()):
sigla_i, nome_i, cidade_i = INSTITUICOES[inst]
info = series_[(inst, sg)]
cod = codigo(COLECAO, sigla_i, sg)
a = agrega(us)
t = _textos(TEXTOS / 'series' / f'{sigla_i}.{sg}.md')
titulo = info['titulo'] if sg != 'AV' else f'Avulsos — {nome_i}'
produtor = re.sub(r'(?i)^(cole[cç][aã]o( particular)?|fundo|arquivo|s[ée]rie|conv[eê]nio)\s+(d[aeo]s?\s+)?', '', titulo)
add({
'id': cod, 'pai': codigo(COLECAO, sigla_i), 'nivel': 3,
'1.1': cod, '1.2': {'titulo': titulo, 'atribuido': sg == 'AV'},
'1.3': {'producao': a['data']}, '1.4': {'nivel': 3, 'nome': NIVEIS[3]},
'1.5': a['dim'],
'2.1': [{'id': None, 'forma': nome_i if sg == 'AV' else produtor, 'funcao': 'colecionador'}],
'2.2': t.get('2.2'),
'3.1': t.get('3.1') or resumo(a),
'3.4': t.get('3.4') or ('Dossiês ordenados pelo número do handle na origem.' if sg != 'AV' else
'Reúne os dossiês sem coleção/fundo de origem identificável em dc.source; '
'a notação da origem, quando há, fica em 5.1 de cada dossiê.'),
'5.1': {'instituicao': nome_i, 'local': cidade_i,
'variantes_na_origem': dict(info['variantes'].most_common()) or None},
'7.3': {'descricao': HOJE},
})
por_secao[inst].extend(us)
for var, n in (info['variantes'].most_common() or [('', info['n'])]):
rev_series.append({'instituicao': inst, 'codigo': cod, 'titulo': titulo, 'dc_source': var, 'n': n})
todos = []
for inst, us in sorted(por_secao.items(), key=lambda kv: -len(kv[1])):
sigla_i, nome_i, cidade_i = INSTITUICOES[inst]
cod = codigo(COLECAO, sigla_i)
a = agrega(us)
t = _textos(TEXTOS / 'secoes' / f'{sigla_i}.md')
add({
'id': cod, 'pai': codigo(COLECAO), 'nivel': 2,
'1.1': cod, '1.2': {'titulo': f'Seção {nome_i}', 'atribuido': True},
'1.3': {'producao': a['data']}, '1.4': {'nivel': 2, 'nome': NIVEIS[2]},
'1.5': a['dim'],
'2.1': [{'id': None, 'forma': nome_i, 'funcao': 'instituição custodiadora dos originais'}],
'2.2': t.get('2.2'),
'3.1': t.get('3.1') or resumo(a),
'3.4': f"{len(filhos[cod])} séries, por coleção ou fundo de origem.",
'5.1': {'instituicao': nome_i, 'local': cidade_i},
'7.3': {'descricao': HOJE},
})
todos.extend(us)
a = agrega(todos)
c1 = codigo(COLECAO)
add({
'id': c1, 'pai': codigo(), 'nivel': 1,
'1.1': c1, '1.2': {'titulo': COLECAO_TITULO, 'atribuido': False},
'1.3': {'producao': a['data'], 'acumulacao': {'forma': '2026', 'iso': '2026'}},
'1.4': {'nivel': 1, 'nome': NIVEIS[1]}, '1.5': a['dim'],
'2.1': [{'id': None, 'forma': ENTIDADE_NOME, 'funcao': 'colecionador'}],
'2.2': textos1.get('2.2'), '2.3': textos1.get('2.3'), '2.4': textos1.get('2.4'),
'3.1': textos1.get('3.1') or resumo(a), '3.2': textos1.get('3.2'), '3.3': textos1.get('3.3'),
'3.4': textos1.get('3.4'),
'4.1': textos1.get('4.1') or ACESSO, '4.2': textos1.get('4.2'),
'4.3': textos1.get('4.3'), '4.4': textos1.get('4.4'), '4.5': textos1.get('4.5'),
'5.1': textos1.get('5.1'), '5.4': textos1.get('5.4'),
'6.2': textos1.get('6.2'),
'7.1': textos1.get('7.1'), '7.2': REGRAS, '7.3': {'descricao': HOJE},
'8.1': textos1.get('8.1'),
})
c0 = codigo()
add({
'id': c0, 'pai': None, 'nivel': 0,
'1.1': c0, '1.2': {'titulo': f'Acervo {ENTIDADE_NOME}', 'atribuido': False},
'1.3': {'producao': a['data']}, '1.4': {'nivel': 0, 'nome': NIVEIS[0]}, '1.5': a['dim'],
'2.1': [{'id': None, 'forma': ENTIDADE_NOME, 'funcao': 'entidade custodiadora'}],
'2.2': textos0.get('2.2'), '3.1': textos0.get('3.1'),
'4.1': textos0.get('4.1') or ACESSO, '7.2': REGRAS, '7.3': {'descricao': HOJE},
})
# 1.4: títulos dos níveis superiores (proc. 1.1.4)
for u in unidades.values():
cad, p = [], u['pai']
while p:
cad.append(unidades[p]['1.2']['titulo'])
p = unidades[p]['pai']
u['1.4']['hierarquia'] = list(reversed(cad)) or None
ordem = sorted(unidades.values(), key=lambda u: (u['nivel'], u['id']))
with (SAIDA / 'unidades.jsonl').open('w', encoding='utf-8') as f:
for u in ordem:
f.write(json.dumps({k: x for k, x in u.items() if not k.startswith('_') and x is not None},
ensure_ascii=False) + '\n')
with (SAIDA / 'autoridades.jsonl').open('w', encoding='utf-8') as f:
for r in aut.registros.values():
f.write(json.dumps(r, ensure_ascii=False) + '\n')
# tabelas de revisão
pl.DataFrame(rev_datas, infer_schema_length=None).filter(pl.col('qualidade').is_null() | (pl.col('qualidade') != 'exata')) \
.sort('motivo', 'original', nulls_last=True).write_csv(REVISAO / 'datas.tsv', separator='\t')
pl.DataFrame(rev_series, infer_schema_length=None).sort('codigo', 'n', descending=[False, True]) \
.write_csv(REVISAO / 'series.tsv', separator='\t')
pl.DataFrame(rev_tipos, infer_schema_length=None).group_by(pl.all()).len('n').sort('n', descending=True) \
.write_csv(REVISAO / 'tipos.tsv', separator='\t')
pl.DataFrame(rev_direitos, infer_schema_length=None).group_by(pl.all()).len('n').sort('n', descending=True) \
.write_csv(REVISAO / 'direitos.tsv', separator='\t')
pl.DataFrame(rev_lugares, infer_schema_length=None).group_by(pl.all()).len('n').sort('n', descending=True) \
.write_csv(REVISAO / 'lugares.tsv', separator='\t')
pl.DataFrame([{'id': r['id'], 'forma_autorizada': r['forma_autorizada'], 'tipo': r['tipo'],
'ocorrencias': r['ocorrencias'], 'variantes': ' | '.join(r['variantes'])}
for r in aut.registros.values()], infer_schema_length=None).write_csv(REVISAO / 'autoridades.tsv', separator='\t')
return unidades, aut
+80
View File
@@ -0,0 +1,80 @@
"""Leva a descrição NOBRADE para o mural: grava no `meta` de cada peça do
web/atlas/atlas-map.json o código de referência, a data normalizada, a série
e o suporte, sem re-renderizar os atlas .webp.
python -m nobrade.mural (de dentro de pipeline/, depois de python -m nobrade)
Campos novos em meta (curtos: o mapa inteiro desce para o navegador):
ref código de referência (1.1) dt data na forma da NOBRADE (1.3)
ano ano inicial, para o histograma si índice em `series` do mapa (nível 3)
sup espécie e suporte (1.5) rep categoria de reprodução (4.2)
ai índice em `autoridades` (2.1, forma autorizada ISAAR(CPF))
dq 1 quando a data foi atribuída pelo arquivista (proc. 1.3.3.2)
No topo do mapa: `series`, `autoridades`, `instituicoes` (community → nome
autorizado), `colecao` (código e título do nível 1) e `grande` (há derivada
de 2.000 px para o zoom).
"""
import json
from .config import COLECAO_TITULO, GRANDE, INSTITUICOES, RAIZ, SAIDA, codigo
MAPA = RAIZ / 'web' / 'atlas' / 'atlas-map.json'
def ano(p: dict):
"""O ano que posiciona a peça no histograma — só quando a data é precisa o
bastante (até 30 anos). "[18--]" ou "[1880-1930?]" ficam na ficha, fora do filtro."""
i, f = p.get('inicio'), p.get('fim')
if i and f and f - i <= 30:
return i
return None
def main():
series, dossies = {}, {}
for linha in (SAIDA / 'unidades.jsonl').open(encoding='utf-8'):
u = json.loads(linha)
if u['nivel'] == 3:
series[u['id']] = u['1.2']['titulo']
elif u['nivel'] == 4:
dossies[u['handle']] = u
d = json.loads(MAPA.read_text(encoding='utf-8'))
titulos = sorted(set(series.values()), key=str.casefold)
idx = {t: i for i, t in enumerate(titulos)}
d['series'] = titulos
formas = sorted({p['forma'] for u in dossies.values() for p in u['2.1'] if p.get('id')}, key=str.casefold)
ai = {f: i for i, f in enumerate(formas)}
d['autoridades'] = formas
d['instituicoes'] = {k: v[1] for k, v in INSTITUICOES.items()}
d['colecao'] = {'codigo': codigo('BF'), 'titulo': COLECAO_TITULO}
d['grande'] = GRANDE # o visor só pede derivados/grande/ quando isto é verdade
feitos = 0
for h, e in d['map'].items():
u = dossies.get(h)
if not u:
continue
p = u['1.3']['producao']
dim = u['1.5']
sup = dim['especie'] + (f" {dim['cor']}" if dim.get('cor') else '') + (f", {dim['suporte']}" if dim.get('suporte') else '')
e['meta'].update({
'ref': u['1.1'], 'dt': p.get('forma'), 'ano': ano(p),
'si': idx[series[u['pai']]], 'sup': sup, 'rep': u['4.2']['categoria'],
})
aut = next((p['forma'] for p in u['2.1'] if p.get('id')), None)
if e['meta'].get('ano') is None:
e['meta'].pop('ano', None)
e['meta'].pop('ai', None)
e['meta'].pop('dq', None)
if aut:
e['meta']['ai'] = ai[aut]
if (p.get('notas') or [''])[0].startswith('data atribuída pelo arquivista'):
e['meta']['dq'] = 1
feitos += 1
MAPA.write_text(json.dumps(d, ensure_ascii=False, separators=(',', ':')), encoding='utf-8')
print(f'{feitos} de {len(d["map"])} peças com descrição NOBRADE; {len(titulos)} séries')
if __name__ == '__main__':
main()
+165
View File
@@ -0,0 +1,165 @@
"""Nível 3 — séries a partir de `dc.source`.
O campo traz, misturados, o nome da coleção/fundo de origem ("Coleção Gilberto
Ferrez" e "Gilberto Ferrez"), sufixos da instituição ("… / Museu da
República"), notações de caixa ("CX 14") e lixo de extração. A regra:
1. limpa o valor até uma chave (sem prefixo Coleção/Fundo/Arquivo, sem sufixo
institucional, sem notação no fim, sem acento, sem pontuação);
2. chaves com pelo menos MINIMO itens viram série;
3. valor raro que contém a chave de uma série vai para ela (os "Negativo de
vidro MPEG639, Coleção Fotográfica do Museu Paraense…");
4. o resto vai para a série AV (Avulsos) da instituição, e o valor original
fica como notação na origem (5.1).
Correções manuais em `ajustes/series.tsv` (instituicao, dc.source, titulo)
prevalecem sobre a regra.
"""
from __future__ import annotations
import csv
import re
import unicodedata
from collections import Counter, defaultdict
from .config import AJUSTES
MINIMO = 3
# variantes que a limpeza não junta sozinha: chave → chave canônica
ALIAS = {
'd teresa cristina maria': 'thereza christina maria',
'teresa cristina maria': 'thereza christina maria',
'federacao brasileira para o progresso feminino fbpf': 'federacao brasileira pelo progresso feminino',
'federacao brasileira para o progresso feminino': 'federacao brasileira pelo progresso feminino',
'fotografica mpeg': 'fotografica do museu paraense emilio goeldi',
'brascan cem anos no brasil': 'brascan cem anos no brasil',
'escola de ciencias sociais fgv cpdoc': 'escola de ciencias sociais fgv cpdoc',
'escola de ciencias sociais': 'escola de ciencias sociais fgv cpdoc',
'dos eventos institucionais': 'eventos institucionais',
'mestres do sec xix': 'mestres do seculo xix',
'cristovao barcellos': 'cristovao barcelos',
}
# notação de caixa/negativo/foto: é localização na origem (5.1), não série
NOTACAO = re.compile(r'(?i)^\s*(cx|caixas?|nv|foto|negativo|estampa)\b')
PREFIXO = re.compile(r'^(convenio|colecao particular|colecao|fundo|arquivo|acervo|serie)\s+(d[aeo]s?\s+)?')
LIXO = re.compile(r'[<>{}]|ns:|^[0-9a-f]{12,}')
def sem_acento(s: str) -> str:
return ''.join(c for c in unicodedata.normalize('NFD', s) if unicodedata.category(c) != 'Mn')
def limpa(v: str) -> str:
s = v.strip()
s = re.sub(r'\s*/\s*(acervo|museu|ibge|instituto moreira).*$', '', s, flags=re.I)
s = re.sub(r'\s+-\s+(museu|funda|fgv|ibge).*$', '', s, flags=re.I)
s = re.sub(r'\s*\((museu|ibram)[^)]*\)', '', s, flags=re.I)
s = re.sub(r'\s*/\s*ibge$', '', s, flags=re.I)
s = re.sub(r'\s*(?:-\s*|\()\s*\w*\d\w*\)?\s*$', '', s) # "- 1123K", "(148T)", "- EFi9"
s = sem_acento(s.lower())
s = re.sub(r'\bsec\.?\s', 'sec ', s)
s = re.sub(r'[^\w\s]', ' ', s)
s = re.sub(r'\s+', ' ', s).strip()
s = PREFIXO.sub('', s)
return ALIAS.get(s, s)
def sigla(titulo: str, usadas: set[str]) -> str:
if m := re.match(r'(?i)[áa]lbum\s+(\d+)', titulo):
base = f'A{m[1]}'
usadas.add(base)
return base
miolo = PREFIXO.sub('', sem_acento(titulo.lower()))
palavras = [p for p in re.findall(r'[a-z0-9]+', miolo) if p not in {'de', 'da', 'do', 'das', 'dos', 'e', 'a', 'o'}]
base = ''.join(p[0] for p in palavras).upper()[:6] or 'S'
if len(base) < 2 and palavras:
base = palavras[0][:4].upper()
s, n = base, 2
while s in usadas or s == 'AV':
s, n = f'{base}{n}', n + 1
usadas.add(s)
return s
def _titulo(variantes: Counter) -> str:
"""A variante mais frequente; se ela não diz o que é, herda o tipo
(Coleção/Fundo/Série) de outra variante — "Thereza Christina Maria" +
"Coleção D. Teresa…" → "Coleção Thereza Christina Maria"."""
tipo_re = r'(?i)^(cole[cç][aã]o( particular)?|fundo|arquivo|s[ée]rie|conv[eê]nio|[áa]lbum)\b'
_, v = max((n, v) for v, n in variantes.items())
v = re.sub(r'\s+', ' ', v).strip()
v = re.sub(r'\s*[-/]\s*(Acervo|Museu|Fundação|Instituto Moreira|IBGE).*$', '', v)
v = re.sub(r'\s*\((Museu|IBRAM)[^)]*\)', '', v)
if not re.match(tipo_re, v):
tipos = Counter(m[1].capitalize() for x in variantes if (m := re.match(tipo_re, x.strip())))
v = f"{tipos.most_common(1)[0][0] if tipos else 'Coleção'} {v}"
return v
def _ajustes() -> dict[tuple[str, str], str]:
p = AJUSTES / 'series.tsv'
if not p.exists():
return {}
with p.open(encoding='utf-8') as f:
return {(r['instituicao'], r['dc_source']): r['titulo'] for r in csv.DictReader(f, delimiter='\t')}
def monta(fontes: list[tuple[str, str, str | None]]):
"""fontes: (handle, instituição, dc.source | None).
Devolve (por_handle, series): por_handle[handle] = (sigla, notação na origem
ou None); series[(instituição, sigla)] = {'titulo', 'variantes', 'n'}.
"""
ajuste = _ajustes()
chaves = defaultdict(Counter) # (inst, chave) → Counter(valor original)
for _, inst, v in fontes:
if v and not LIXO.search(v) and not NOTACAO.match(v) and (inst, v) not in ajuste:
chaves[(inst, limpa(v))][v] += 1
series: dict[tuple[str, str], dict] = {}
sigla_de: dict[tuple[str, str], str] = {}
usadas: dict[str, set[str]] = defaultdict(set)
fortes = defaultdict(list) # inst → [chave]
for (inst, chave), variantes in sorted(chaves.items(), key=lambda kv: -sum(kv[1].values())):
if not chave or sum(variantes.values()) < MINIMO:
continue
titulo = _titulo(variantes)
sg = sigla(titulo, usadas[inst])
sigla_de[(inst, chave)] = sg
series[(inst, sg)] = {'titulo': titulo, 'variantes': variantes, 'n': 0}
fortes[inst].append(chave)
for (inst, v), titulo in ajuste.items():
k = (inst, 'ajuste:' + titulo)
if k not in sigla_de:
sg = sigla(titulo, usadas[inst])
sigla_de[k] = sg
series[(inst, sg)] = {'titulo': titulo, 'variantes': Counter(), 'n': 0}
por_handle = {}
for handle, inst, v in fontes:
sg = None
if v and (inst, v) in ajuste:
sg = sigla_de[(inst, 'ajuste:' + ajuste[(inst, v)])]
series[(inst, sg)]['variantes'][v] += 1
elif v and not LIXO.search(v):
chave = limpa(v)
sg = sigla_de.get((inst, chave))
if sg is None:
# o valor raro contém o nome de uma série forte da mesma instituição?
for forte in sorted(fortes[inst], key=len, reverse=True):
if len(forte) > 5 and re.search(rf'\b{re.escape(forte)}\b', chave):
sg = sigla_de[(inst, forte)]
series[(inst, sg)]['variantes'][v] += 1
break
if sg is None:
sg = 'AV'
series.setdefault((inst, 'AV'), {'titulo': 'Avulsos', 'variantes': Counter(), 'n': 0})
series[(inst, sg)]['n'] += 1
# o valor original fica como notação na origem quando não é o próprio nome da série
notacao = v if v and (sg == 'AV' or limpa(v) not in {limpa(x) for x in [series[(inst, sg)]['titulo']]}) else None
por_handle[handle] = (sg, notacao)
return por_handle, series
+85
View File
@@ -0,0 +1,85 @@
"""Validador dos elementos obrigatórios da NOBRADE, por nível.
Obrigatórios: 1.1, 1.2, 1.3 (data de produção), 1.4, 1.5, 2.1; 4.1 só nos
níveis 0 e 1. Além deles, lista avisos que não reprovam mas pedem revisão.
Escreve descricao/pendencias.md e devolve o número de pendências.
"""
from __future__ import annotations
from collections import Counter, defaultdict
from .config import SAIDA
def verifica(u: dict) -> tuple[list[str], list[str]]:
erros, avisos = [], []
n = u['nivel']
if not u.get('1.1'):
erros.append('1.1 código de referência ausente')
if not (u.get('1.2') or {}).get('titulo', '').strip():
erros.append('1.2 título ausente')
prod = (u.get('1.3') or {}).get('producao') or {}
if not prod.get('inicio') and not prod.get('fim'):
erros.append('1.3 data de produção ausente')
if not (u.get('1.4') or {}).get('nome'):
erros.append('1.4 nível ausente')
if not (u.get('1.5') or {}).get('texto'):
erros.append('1.5 dimensão e suporte ausente')
if not u.get('2.1'):
erros.append('2.1 produtor ausente')
if n <= 1 and not u.get('4.1'):
erros.append('4.1 condições de acesso ausente (obrigatório nos níveis 0 e 1)')
if n == 4:
if prod.get('qualidade') == 'atribuída pelo arquivista' or (prod.get('notas') or [''])[0].startswith('data atribuída'):
avisos.append('1.3 data atribuída pelo arquivista — conferir')
if prod.get('motivo') == 'ilegível':
avisos.append('1.3 data da origem ilegível')
if all(p.get('id') is None for p in u.get('2.1') or []):
avisos.append('2.1 autoria não identificada')
if u['id'].split('.')[-2] == 'AV':
avisos.append('nível 3 em Avulsos — série de origem não identificada')
if any('presumida' in x for x in u.get('6.2') or []):
avisos.append('1.5 espécie presumida')
if any('corrompidos' in x for x in u.get('6.2') or []):
avisos.append('valores corrompidos na origem')
if u.get('6.1'):
avisos.append('6.1 preservação indisponível na origem')
if (u.get('4.2') or {}).get('categoria') == 'consultar o detentor':
avisos.append('4.2 condição de reprodução não informada na origem')
if not (u.get('3.1') or '').strip():
avisos.append('3.1 sem âmbito e conteúdo')
return erros, avisos
def valida(unidades) -> int:
erros, avisos = defaultdict(list), defaultdict(list)
por_nivel = Counter()
for u in unidades:
por_nivel[u['nivel']] += 1
e, a = verifica(u)
for x in e:
erros[x].append(u['id'])
for x in a:
avisos[x].append(u['id'])
total = sum(len(v) for v in erros.values())
linhas = ['# Pendências da descrição NOBRADE', '',
'Gerado por `python -m nobrade`. Obrigatórios reprovam; avisos pedem revisão.', '',
'| Nível | Unidades |', '|---|--:|']
nomes = {0: 'acervo', 1: 'coleção', 2: 'seção', 3: 'série', 4: 'dossiê', 5: 'item'}
linhas += [f'| {n} {nomes[n]} | {c:,} |'.replace(',', '.') for n, c in sorted(por_nivel.items())]
linhas += ['', f'## Obrigatórios faltando: {total}', '']
if not erros:
linhas.append('Nenhum. Todas as unidades têm os elementos obrigatórios do seu nível.')
for k, ids in sorted(erros.items(), key=lambda kv: -len(kv[1])):
linhas += [f'### {k} — {len(ids)}', '', *[f'- `{i}`' for i in ids[:50]]]
if len(ids) > 50:
linhas.append(f'- … e mais {len(ids) - 50}')
linhas.append('')
linhas += ['', '## Avisos', '', '| Aviso | Dossiês |', '|---|--:|']
linhas += [f'| {k} | {len(v):,} |'.replace(',', '.') for k, v in sorted(avisos.items(), key=lambda kv: -len(kv[1]))]
linhas.append('')
(SAIDA / 'pendencias.md').write_text('\n'.join(linhas), encoding='utf-8')
return total
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+33
View File
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Subconjunto do xlink.xsd da LoC (http://www.loc.gov/standards/xlink/xlink.xsd),
que responde 403 a clientes fora do navegador: só o que o cpf.xsd usa. -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.w3.org/1999/xlink"
xmlns:xlink="http://www.w3.org/1999/xlink"
attributeFormDefault="qualified">
<xs:attribute name="href" type="xs:anyURI"/>
<xs:attribute name="role" type="xs:string"/>
<xs:attribute name="arcrole" type="xs:string"/>
<xs:attribute name="title" type="xs:string"/>
<xs:attribute name="show">
<xs:simpleType><xs:restriction base="xs:string">
<xs:enumeration value="new"/><xs:enumeration value="replace"/><xs:enumeration value="embed"/>
<xs:enumeration value="other"/><xs:enumeration value="none"/>
</xs:restriction></xs:simpleType>
</xs:attribute>
<xs:attribute name="actuate">
<xs:simpleType><xs:restriction base="xs:string">
<xs:enumeration value="onLoad"/><xs:enumeration value="onRequest"/>
<xs:enumeration value="other"/><xs:enumeration value="none"/>
</xs:restriction></xs:simpleType>
</xs:attribute>
<xs:attributeGroup name="simpleLink">
<xs:attribute name="type" type="xs:string" fixed="simple" form="qualified"/>
<xs:attribute ref="xlink:href" use="optional"/>
<xs:attribute ref="xlink:role" use="optional"/>
<xs:attribute ref="xlink:arcrole" use="optional"/>
<xs:attribute ref="xlink:title" use="optional"/>
<xs:attribute ref="xlink:show" use="optional"/>
<xs:attribute ref="xlink:actuate" use="optional"/>
</xs:attributeGroup>
</xs:schema>
+287
View File
@@ -0,0 +1,287 @@
<?xml version='1.0'?>
<?xml-stylesheet href="../2008/09/xsd.xsl" type="text/xsl"?>
<xs:schema targetNamespace="http://www.w3.org/XML/1998/namespace"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns ="http://www.w3.org/1999/xhtml"
xml:lang="en">
<xs:annotation>
<xs:documentation>
<div>
<h1>About the XML namespace</h1>
<div class="bodytext">
<p>
This schema document describes the XML namespace, in a form
suitable for import by other schema documents.
</p>
<p>
See <a href="http://www.w3.org/XML/1998/namespace.html">
http://www.w3.org/XML/1998/namespace.html</a> and
<a href="http://www.w3.org/TR/REC-xml">
http://www.w3.org/TR/REC-xml</a> for information
about this namespace.
</p>
<p>
Note that local names in this namespace are intended to be
defined only by the World Wide Web Consortium or its subgroups.
The names currently defined in this namespace are listed below.
They should not be used with conflicting semantics by any Working
Group, specification, or document instance.
</p>
<p>
See further below in this document for more information about <a
href="#usage">how to refer to this schema document from your own
XSD schema documents</a> and about <a href="#nsversioning">the
namespace-versioning policy governing this schema document</a>.
</p>
</div>
</div>
</xs:documentation>
</xs:annotation>
<xs:attribute name="lang">
<xs:annotation>
<xs:documentation>
<div>
<h3>lang (as an attribute name)</h3>
<p>
denotes an attribute whose value
is a language code for the natural language of the content of
any element; its value is inherited. This name is reserved
by virtue of its definition in the XML specification.</p>
</div>
<div>
<h4>Notes</h4>
<p>
Attempting to install the relevant ISO 2- and 3-letter
codes as the enumerated possible values is probably never
going to be a realistic possibility.
</p>
<p>
See BCP 47 at <a href="http://www.rfc-editor.org/rfc/bcp/bcp47.txt">
http://www.rfc-editor.org/rfc/bcp/bcp47.txt</a>
and the IANA language subtag registry at
<a href="http://www.iana.org/assignments/language-subtag-registry">
http://www.iana.org/assignments/language-subtag-registry</a>
for further information.
</p>
<p>
The union allows for the 'un-declaration' of xml:lang with
the empty string.
</p>
</div>
</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:union memberTypes="xs:language">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value=""/>
</xs:restriction>
</xs:simpleType>
</xs:union>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="space">
<xs:annotation>
<xs:documentation>
<div>
<h3>space (as an attribute name)</h3>
<p>
denotes an attribute whose
value is a keyword indicating what whitespace processing
discipline is intended for the content of the element; its
value is inherited. This name is reserved by virtue of its
definition in the XML specification.</p>
</div>
</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:NCName">
<xs:enumeration value="default"/>
<xs:enumeration value="preserve"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="base" type="xs:anyURI"> <xs:annotation>
<xs:documentation>
<div>
<h3>base (as an attribute name)</h3>
<p>
denotes an attribute whose value
provides a URI to be used as the base for interpreting any
relative URIs in the scope of the element on which it
appears; its value is inherited. This name is reserved
by virtue of its definition in the XML Base specification.</p>
<p>
See <a
href="http://www.w3.org/TR/xmlbase/">http://www.w3.org/TR/xmlbase/</a>
for information about this attribute.
</p>
</div>
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="id" type="xs:ID">
<xs:annotation>
<xs:documentation>
<div>
<h3>id (as an attribute name)</h3>
<p>
denotes an attribute whose value
should be interpreted as if declared to be of type ID.
This name is reserved by virtue of its definition in the
xml:id specification.</p>
<p>
See <a
href="http://www.w3.org/TR/xml-id/">http://www.w3.org/TR/xml-id/</a>
for information about this attribute.
</p>
</div>
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attributeGroup name="specialAttrs">
<xs:attribute ref="xml:base"/>
<xs:attribute ref="xml:lang"/>
<xs:attribute ref="xml:space"/>
<xs:attribute ref="xml:id"/>
</xs:attributeGroup>
<xs:annotation>
<xs:documentation>
<div>
<h3>Father (in any context at all)</h3>
<div class="bodytext">
<p>
denotes Jon Bosak, the chair of
the original XML Working Group. This name is reserved by
the following decision of the W3C XML Plenary and
XML Coordination groups:
</p>
<blockquote>
<p>
In appreciation for his vision, leadership and
dedication the W3C XML Plenary on this 10th day of
February, 2000, reserves for Jon Bosak in perpetuity
the XML name "xml:Father".
</p>
</blockquote>
</div>
</div>
</xs:documentation>
</xs:annotation>
<xs:annotation>
<xs:documentation>
<div xml:id="usage" id="usage">
<h2><a name="usage">About this schema document</a></h2>
<div class="bodytext">
<p>
This schema defines attributes and an attribute group suitable
for use by schemas wishing to allow <code>xml:base</code>,
<code>xml:lang</code>, <code>xml:space</code> or
<code>xml:id</code> attributes on elements they define.
</p>
<p>
To enable this, such a schema must import this schema for
the XML namespace, e.g. as follows:
</p>
<pre>
&lt;schema . . .>
. . .
&lt;import namespace="http://www.w3.org/XML/1998/namespace"
schemaLocation="http://www.w3.org/2001/xml.xsd"/>
</pre>
<p>
or
</p>
<pre>
&lt;import namespace="http://www.w3.org/XML/1998/namespace"
schemaLocation="http://www.w3.org/2009/01/xml.xsd"/>
</pre>
<p>
Subsequently, qualified reference to any of the attributes or the
group defined below will have the desired effect, e.g.
</p>
<pre>
&lt;type . . .>
. . .
&lt;attributeGroup ref="xml:specialAttrs"/>
</pre>
<p>
will define a type which will schema-validate an instance element
with any of those attributes.
</p>
</div>
</div>
</xs:documentation>
</xs:annotation>
<xs:annotation>
<xs:documentation>
<div id="nsversioning" xml:id="nsversioning">
<h2><a name="nsversioning">Versioning policy for this schema document</a></h2>
<div class="bodytext">
<p>
In keeping with the XML Schema WG's standard versioning
policy, this schema document will persist at
<a href="http://www.w3.org/2009/01/xml.xsd">
http://www.w3.org/2009/01/xml.xsd</a>.
</p>
<p>
At the date of issue it can also be found at
<a href="http://www.w3.org/2001/xml.xsd">
http://www.w3.org/2001/xml.xsd</a>.
</p>
<p>
The schema document at that URI may however change in the future,
in order to remain compatible with the latest version of XML
Schema itself, or with the XML namespace itself. In other words,
if the XML Schema or XML namespaces change, the version of this
document at <a href="http://www.w3.org/2001/xml.xsd">
http://www.w3.org/2001/xml.xsd
</a>
will change accordingly; the version at
<a href="http://www.w3.org/2009/01/xml.xsd">
http://www.w3.org/2009/01/xml.xsd
</a>
will not change.
</p>
<p>
Previous dated (and unchanging) versions of this schema
document are at:
</p>
<ul>
<li><a href="http://www.w3.org/2009/01/xml.xsd">
http://www.w3.org/2009/01/xml.xsd</a></li>
<li><a href="http://www.w3.org/2007/08/xml.xsd">
http://www.w3.org/2007/08/xml.xsd</a></li>
<li><a href="http://www.w3.org/2004/10/xml.xsd">
http://www.w3.org/2004/10/xml.xsd</a></li>
<li><a href="http://www.w3.org/2001/03/xml.xsd">
http://www.w3.org/2001/03/xml.xsd</a></li>
</ul>
</div>
</div>
</xs:documentation>
</xs:annotation>
</xs:schema>
+83 -21
View File
@@ -28,23 +28,26 @@ scraping é o caminho combinado. Ritmo cortês e identificação continuam valen
--- ---
## 1. Estado em 2026-09-10 ## 1. Estado em 2026-09-30
| | | **Coleta concluída em 2026-09-13.** Conferido em 2026-09-30 contra o ledger
(`pipeline/subidor.sqlite`, tabela `enviados`) e a listagem do bucket.
| | Estado |
|---|---| |---|---|
| Fase 1 (metadados) | ✅ **completa** — 13.059 registros, 0 erros. 1 falso-positivo conhecido (`.../1`, é a página raiz da comunidade, não um item — excluir na contagem final) | | Fase 1 (metadados) | ✅ `catalogo.jsonl` com **13.060 itens** (o falso-positivo `/1` não está nele), também no bucket, idêntico ao local |
| Catálogo | `pipeline/catalogo.jsonl`, re-exportado depois dos reparos (152 itens com `all_preservation_urls`) | | Imagem de preservação | ✅ **12.991 itens**, 13.194 arquivos, 127,4 GB (121 itens com 2 a 8 imagens: 203 extras) |
| Download principal (1 imagem/item) | 🟡 em andamento no navegador | | Sem preservação | ⚠️ **69 itens**: a origem responde HTTP 500 ao bitstream (`errors.md`). Todos, menos o `7523`, têm a miniatura |
| Thumbnails | 🟡 em andamento no navegador | | Miniatura do DSpace | ✅ 13.060 arquivos em 13.059 itens |
| Extras (itens com múltiplos bitstreams, 115 itens) | ✅ completo | | Fase 4 (legado objdigital) | ✅ 2.137 arquivos (1.899 JPG, 213 PDF, 25 outros), 9,6 GB |
| Fase 4 (legado objdigital) | 🟡 em andamento, local (`baixador.py --somente-legado`), 2.707 itens com `legacy_url` | | Derivados | ✅ `thumb256` 13.059 e `medio` 13.059 |
| `subidor.py` | rodando em `pipeline/`, `--vigiar`, roteia preservacao/thumbnail/legado certo | | Blog | ✅ 636 posts em `wordpress/` + `wordpress-posts.jsonl` |
| Bucket | ✅ 81.269 objetos, 139,2 GB, mais 487 objetos (172 MB) em `descricao/` |
| `MANIFEST.md` | ✅ versão final no bucket (2026-09-30) |
| Descrição NOBRADE | ✅ ver §9, também no bucket em `descricao/` |
| Mural | ✅ no ar em https://xn--2dk.xyz/brasiliana/; o visor NOBRADE está no branch `feat/nobrade` (§9, fase 7) |
Não existe mais aba do Brave rodando isso — é uma aba de Chrome comum, Nenhum navegador ou subidor precisa estar rodando: a fila local está zerada.
conectada via extensão Claude-in-Chrome. `coletor.js`/`coletor-resume.js`
grava em IndexedDB a cada item; fechar a aba não perde nada, mas o *loop*
para e precisa recolar o script certo pra retomar (ver `tasks/TODO.md`
pros comandos exatos de cada trilha ativa).
--- ---
@@ -112,7 +115,7 @@ página). `baixador.py` na Finlândia fica só pra Fase 4 (objdigital, domínio
diferente, sem esse bloqueio — ver 2.11). diferente, sem esse bloqueio — ver 2.11).
### 2.7 Itens com múltiplos bitstreams reais — não é caso raro ### 2.7 Itens com múltiplos bitstreams reais — não é caso raro
115 itens (de ~13.058) têm **2 a 6 imagens reais** no bundle ORIGINAL, não 115 itens (de ~13.058) têm **2 a 6 imagens reais** no bundle ORIGINAL (contagem final no ledger: 121 itens, 2 a 8 imagens), não
uma. `citation_pdf_url` não é gerado pra esses (o gerador de citação do uma. `citation_pdf_url` não é gerado pra esses (o gerador de citação do
DSpace não sabe qual é "a" imagem quando há mais de uma) — por isso ficam DSpace não sabe qual é "a" imagem quando há mais de uma) — por isso ficam
sem `preservation_url` na extração simples. Sintoma: `full_table` tem sem `preservation_url` na extração simples. Sintoma: `full_table` tem
@@ -382,12 +385,20 @@ Sem os dois é pasta de imagens, não arquivo.
## 7. Pendências ## 7. Pendências
1. Terminar a Fase 1 e exportar o catálogo. 1. ~~Terminar a Fase 1 e exportar o catálogo.~~ ✅ 13.060 itens, 2026-09-13.
2. Medir a fração da trilha B (`BAIXA.quantos()`) — de graça, sem requisição. 2. ~~Medir a fração da trilha B.~~ Obsoleto: desde 2026-09-10 tudo roda por uma
3. Confirmar a projeção de ~116 GB (hoje: 6 arquivos medidos). trilha única no navegador (ver 2.6), e a coleta acabou.
4. Decidir sobre os PDFs de álbum do objdigital — objetos distintos, o de 3. ~~Confirmar a projeção de ~116 GB.~~ ✅ Medido: 127,4 GB de preservação e
71,9 MB provavelmente não é caso isolado. 139,2 GB no bucket, somando tudo.
5. Gerar `MANIFEST.md` e `catalogo.jsonl` no bucket ao final. 4. ~~Decidir sobre os PDFs de álbum do objdigital.~~ ✅ Guardados como cópia
legada: são 213 PDF entre os 2.137 arquivos de `legado/`.
5. ~~Gerar `MANIFEST.md` e `catalogo.jsonl` no bucket.~~ ✅ `catalogo.jsonl`
no bucket é idêntico ao local (ETag multipart confere); `MANIFEST.md`
finalizado e reenviado em 2026-09-30.
6. Os 69 itens sem preservação dependem da origem voltar a servir o
bitstream (`errors.md`). Não há ação possível do nosso lado.
7. O que falta da descrição e do mural está em §9 (0.2, 7.4). Lista única de
tarefas abertas: [`tasks.md`](tasks.md).
## 8. Direitos ## 8. Direitos
@@ -395,3 +406,54 @@ Majoritariamente domínio público por antiguidade, mas as 15 instituições tê
políticas distintas. `dc.rights` e a instituição de origem são preservados políticas distintas. `dc.rights` e a instituição de origem são preservados
**por item**: a decisão de redistribuir é item a item, não do acervo em bloco. **por item**: a decisão de redistribuir é item a item, não do acervo em bloco.
Arquivar para si é uma coisa; republicar é outra. Arquivar para si é uma coisa; republicar é outra.
## 9. Descrição arquivística (NOBRADE)
Resumo da norma e decisões de aplicação em [`CONARQ.md`](../CONARQ.md).
Implementação no branch `feat/nobrade`: `cd pipeline && python3 -m nobrade && python3 -m nobrade.mural`.
| # | Tarefa | Entrega | Depende de | Estado |
|---|---|---|---|---|
| **0 — Decisões** |||||
| 0.1 | Definir nome da entidade custodiadora e código provisório (`BR RJXYZ`) | `pipeline/nobrade/config.py` | — | ✅ provisório `BR RJXYZ` |
| 0.2 | Pedir código de entidade ao CONARQ | `descricao/pedido-codigo-conarq.md` | 0.1 | 📝 rascunho pronto (formulário CODEARQ, Res. CONARQ 28/2009); envio é do usuário |
| 0.3 | Fixar a convenção do código de referência (`BR RJXYZ.BF.IMS.GF.12345.01`) | `CONARQ.md` §5.2 | 0.1 | ✅ |
| **1 — Normalizadores (cada um gera uma tabela de revisão)** |||||
| 1.1 | Datas: mais de 20 formatos de `dc.date` → forma NOBRADE (`[1860?]`, `[18--]`) + ISO 8601 + original | `descricao/revisao/datas.tsv` | — | ✅ |
| 1.2 | Atribuir data aproximada aos `s.d.` a partir do fotógrafo | coluna em `datas.tsv` | 1.1, 1.4 | ✅ |
| 1.3 | Séries: 2.657 combinações de `dc.source` → séries canônicas por instituição | `descricao/revisao/series.tsv` | — | ✅ |
| 1.4 | Autoridades: fotógrafos (`dc.contributor`) e colecionadores, com variantes deduplicadas | `descricao/autoridades.jsonl` | — | ✅ |
| 1.5 | Suporte/espécie: `dc.type` → gênero + espécie + suporte | `descricao/revisao/tipos.tsv` | — | ✅ |
| 1.6 | Direitos: `dc.rights` → ~4 categorias, mantendo o original | `descricao/revisao/direitos.tsv` | — | ✅ |
| 1.7 | Data tópica: `dc.coverage` → cidade (UF) | campo 1.3 | — | ✅ |
| 1.8 | Assuntos: `dc.subject` separado em pt/en | campo 8.1 | — | ✅ |
| **2 — Montagem da hierarquia** |||||
| 2.1 | `nobrade`: níveis 0→5 com `id`, `parent_id`, `nivel`, `codigo` | `descricao/unidades.jsonl` | 0.3, 1.3 | ✅ |
| 2.2 | Preencher os elementos por nível a partir dos normalizadores | campos `"1.3"`, `"2.1"`… | 1.x, 2.1 | ✅ |
| 2.3 | Nível 5 para os handles com várias imagens | registros filhos | 2.1 | ✅ toda imagem é nível 5 |
| 2.4 | Somar dimensão e suporte nos níveis 1–3 | campo 1.5 agregado | 2.2 | ✅ |
| **3 — Textos dos níveis altos** |||||
| 3.1 | Nível 1: história arquivística, procedência, acesso, arranjo | `descricao/textos/nivel1.md` | — | ✅ |
| 3.2 | Nível 2: breve histórico das 15 instituições | `descricao/textos/secoes/` | — | ✅ fatos conferidos na web, fontes em cada arquivo (2026-09-30) |
| 3.3 | Nível 3: âmbito e conteúdo das séries principais | `descricao/textos/series/` | 1.3 | ✅ resumo automático |
| 3.4 | Biografias de fotógrafos a partir dos posts do WordPress | campo 2.2 das autoridades | 1.4 | ✅ fontes nas autoridades |
| **4 — Relações e fontes** |||||
| 4.1 | 5.1 Originais: instituição + handle + Sophia + objdigital | campo automático | 2.1 | ✅ |
| 4.2 | 5.2 Cópias: preservação, legado, miniaturas no S3 | campo automático | 2.1 | ✅ |
| 4.3 | 5.4 Publicações: posts do WordPress → handles citados | campo 5.4 | — | ✅ |
| **5 — Validação** |||||
| 5.1 | Validador dos 7 obrigatórios por nível | `descricao/pendencias.md` | 2.x | ✅ |
| 5.2 | Rodar, corrigir e repetir até zerar as pendências | relatório limpo | 5.1 | ✅ 0 pendências |
| **6 — Exportação e publicação** |||||
| 6.1 | Exportar EAD 3 | `descricao/ead/brasiliana.xml` | 5.2 | ✅ valida |
| 6.2 | Exportar EAC-CPF | `descricao/eac/*.xml` | 1.4 | ✅ valida |
| 6.3 | Validar contra os XSD | xmllint limpo | 6.1, 6.2 | ✅ |
| 6.4 | Subir `descricao/` para `s3://brasiliana/descricao/` e atualizar o MANIFEST | objetos no bucket | 6.3 | ✅ 487 objetos, 172 MB, com `manifest-sha256.txt`; MANIFEST final (2026-09-30) |
| 6.5 | (opcional) CSV de importação do AtoM | `descricao/atom.csv` | 5.2 | ✅ |
| **7 — Mural** |||||
| 7.1 | Cartão vira visor: painel à esquerda (desktop) ou folha abaixo da imagem (celular); palco com zoom real (roda, pinça, duplo clique, arrastar, + − encaixar, F = só a imagem); barra "← mural \| filtros (n)" no topo do painel para voltar ao Atlas 3D e abrir os filtros por cima do visor | `web/wall.html` | 2.2 | ✅ |
| 7.2 | Ficha arquivística recolhível com os obrigatórios NOBRADE: código (clique copia), nível, arranjo clicável (Brasiliana › instituição › série), data na forma da norma + "na origem", selo "atribuída" nas datas atribuídas pelo arquivista, produtor na forma autorizada ISAAR, dimensão e suporte, original (5.1), reprodução (4.2), citar (copia a referência com o código) | `web/wall.html`, `nobrade/mural.py` | 2.2 | ✅ |
| 7.2b | Filtros reagrupados pela NOBRADE: Arranjo (instituição → série em cascata), Data, Pontos de acesso (autor pela autoridade ISAAR, lugar, assunto, pessoa, coleção citada), Suporte e uso (espécie e suporte da 1.5, e condição de reprodução da 4.2, filtro novo); link direto `#BR RJXYZ…` abre a peça pelo código de referência | `web/wall.html` | 7.2 | ✅ |
| 7.2c | Correções de dados que saíram do visor: ano implausível na origem (ex. `20-12-1395`) vira data ilegível, com nota; datas atribuídas por série ou instituição usam o miolo p10–p90 (`[1933-1943?]` em vez de `[1800-1999?]`); o histograma do mural só usa datas com até 30 anos de amplitude | `nobrade/datas.py`, `montar.py`, `mural.py` | 1.1 | ✅ |
| 7.3 | Publicar em `xyz/brasiliana` | commit | 7.x | ✅ publicado em 30/09 (`index.html` + `atlas-map.json`), no ar em https://xn--2dk.xyz/brasiliana/ |
| 7.4 | Derivadas de acesso `medio/` (1.200 px) e `grande/` (2.000 px), tamanhos pela NARA 2004 e CONARQ Res. 31/2010 | `derivados/medio/`, `derivados/grande/` | 7.1 | ✅ 2026-10-01: 13.059 itens cada, gerados no finland por `pipeline/deriva-acesso.py`; o visor troca para `grande/` no zoom |
+7 -731
View File
@@ -1,738 +1,14 @@
# TODO — Brasiliana → S3 # TODO — notas técnicas (Brasiliana → S3)
> **Handoff em 2026-09-10 ~15h UTC**: sessão `fix-image-pipeline-extras` perdeu > Só o que está **aberto**. O que foi concluído, com os achados e o histórico
> conexão com a extensão Claude-in-Chrome e encerrou a pedido do usuário. > das sessões, está em [`tasks/done/`](done/); a última versão completa deste
> Trabalho passado pra sessão `chrome-extension-connection` (tem o navegador > arquivo, com os achados 2.15–2.28 e 3.1–3.5 citados abaixo, é
> conectado). Ver mensagem de handoff enviada via SendMessage pro contexto > [`done/TODO-2026-09-30.md`](done/TODO-2026-09-30.md). Plano, estado e
> completo do estado no momento da troca — resumo abaixo já reflete isso. > descrição NOBRADE: [`PLANO.md`](PLANO.md). Scripts e estado em `pipeline/`.
>
> **Atualização ~17h UTC (mesma sessão)**: aba antiga do coletor não é
> acessível por esta sessão (grupo de abas é por sessão) mas continuou
> rodando sozinha o tempo todo — confirmado por progresso do
> `bras_baixados` no localStorage (compartilhado por origem). Por isso o
> download principal (`BAIXA`) **não foi reiniciado nesta aba** (evitar
> duplicar ~8 mil downloads pesados em paralelo); só os 78 itens do achado
> 2.11 foram baixados cirurgicamente aqui. `BAIXA_THUMB` v2 foi iniciado
> numa aba nova (chave `bras_thumbs_v2`, começa do zero, ~13.059 itens).
> Durante a sessão houve uma queda de rede/extensão de alguns minutos
> (mesmo tipo de falha que derrubou a sessão anterior) — gerou ~1.280 erros
> transitórios no thumb v2 que precisam de uma segunda passada
> (`BAIXA_THUMB.retomar()`) depois que a primeira terminar.
> Ver `tasks/PLANO.md` pro histórico/achados/runbook. Itens concluídos saem
> daqui e vão pra `tasks/done/` (ex.: `tasks/done/TODO-2026-09-10.md`).
> Scripts e estado em `pipeline/` (reorganização de 2026-09-10).
## Em andamento (não mexer, só monitorar)
- [x] **Upload pro S3 — CONCLUÍDO.** A fila de `~/Downloads` está em **0**; tudo
que foi baixado está no bucket. Total no ledger: **41.444 objetos**.
O `pipeline/vigia-30min.sh` segue de pé: a cada 30 min sobe o que aparecer
e apaga do disco só depois do HEAD confirmar no bucket.
**Não editar `vigia-30min.sh` nem `rodar-paralelo.sh` enquanto rodam**
(o bash lê o script aos poucos) e **não relançar o `subidor.py` antigo**
(achado 2.22). Threads: 6, não 16 — ver achado 2.24.
- [ ] **Download principal** (1 imagem de preservação por item) — navegador. **2026-09-11 20:45 UTC**: **12.986/13.059 (99,44%), faltam 73** — medido pela fonte autoritativa (bucket ∪ fila local), não pelo `bras_baixados`. Parado há ~9h (último arquivo em `~/Downloads` às 13:19 local = 11:19 UTC). Lista exata dos 73 em **`pipeline/faltantes-preservacao.jsonl`** (`{handle, url}`). **Script `pipeline/baixar-faltantes-73.js` colado e rodado pelo usuário ~22:52 local (20:52 UTC)** — lista embutida, chave própria `bras_faltantes_73`, imune ao achado 2.16. **Resultado parcial: 2/73** (`10993`, `10995`, 31 MB). Os outros 71 estão falhando — ver achado 2.17. **Recontagem de 12/09: faltam 211, não 73 — ver achado 2.23.**
### Achado 2.17 — os 71 restantes falham, e não é malformação de URL (2026-09-11 21:25 UTC)
`bras_faltantes_73` = 2 e só 2 arquivos de preservação novos apareceram em
`~/Downloads` (22:52 local). O disco e a chave concordam — aqui o achado 2.16
não se aplica, o número é real.
Os 71 que falham têm URL estruturalmente idêntica às 2 que passaram
(mesmo host, mesmo `/brasiliana/bitstream/PREFIX/ID/SEQ/arquivo`, 21 dos 71 com
`%20` no nome, igual às que funcionaram). Diferenças observadas, nenhuma
conclusiva: as 2 que passaram são `SEQ=1`; entre as 71 há `SEQ` 1 (58), 4 (11),
3 (1) e 5 (1).
Hipótese principal: **as 2 que passaram estavam em cache de borda do Cloudflare**
— exatamente o caso do item 6066 descrito no cabeçalho do
`baixador-navegador.js` (`cf-cache-status: HIT`), e não a regra geral. Se for
isso, o `fetch` de aba não basta para estes 71 e o problema é de origem, não de
script.
**Próximo passo (precisa do console da aba)**: rodar `FALTA.status()` e
`FALTA.erros()` — o script guarda `{handle, url, erro}` de cada falha, e o
código HTTP decide o caminho:
- **404** → bitstream não existe nesse `SEQ`; reparar `preservation_url` no
catálogo (mesma família dos achados 2.9/2.11/2.13) e regerar o script.
- **403** → bloqueio de origem/Cloudflare; nem a aba resolve, precisa de outra saída.
- **500** → transitório; `FALTA.retomar()` mais tarde deve pegar.
Enquanto isso o script pode ainda estar rodando: cada erro dorme 60 s de backoff,
então 71 falhas levam ~71 min a partir das 22:52 local (fim previsto ~00:05).
### Achado 2.18 — é recusa da origem, não URL errada; e a v1 do script ajudou a causar (2026-09-12)
`FALTA.status()` do usuário: `atual: "43/73"`, `erros: 101`, `feito: 0`,
`fase: "baixando"`.
Três leituras, em ordem de importância:
1. **`feito: 0` no item 43** — `10993` e `10995` são os itens 1 e 2 da lista e
baixaram com sucesso às 22:52; nesta passada **falharam**. Mesma URL, uma hora
depois. Logo **não é URL errada, é a origem recusando**.
2. **`erros: 101` com `atual: 43/73`** — mais erros que itens tentados só é
possível com **dois ou mais loops concorrentes** somando no mesmo `S`. Cada
`iniciar()`/`retomar()` sobre um script já rodando cria outro loop. Isso
quebrou a pausa de 3 s combinada com a BN e provavelmente disparou rate-limit.
3. `total: 73` (e não 71) — o `FEITOS` foi lido vazio na largada dessa passada.
**Hipóteses mortas** (não perder tempo com elas de novo):
- *Sequência errada no `preservation_url`*: os 2 que funcionaram têm exatamente
a mesma forma dos 13 "divergentes" (catálogo `seq=1`, thumb em `seq=3`), e 58
dos 71 têm `seq` coerente com o thumb e falham igual.
- *Bloqueio geral do Cloudflare*: **71/71 desses itens têm thumb baixado com
sucesso** — o item responde; só o bitstream de preservação não.
**`pipeline/baixar-faltantes-v2.js`** corrige os defeitos da v1 (que eram meus):
guarda contra `iniciar()` duplo, **aborta depois de 5 erros seguidos** em vez de
moer os 71 com 60 s cada, pausa de 5 s, backoff de 30 s, e registra o código HTTP
separado (`FALTA.resumo()` devolve a tabela de códigos). Recarregar a aba antes
de colar — `parar()` não alcança closures de colagens anteriores.
- [x] **Thumbnails** — ✅ concluído 100% (13.059/13.059). `retomar()` já foi rodado uma vez (08h local); **não re-rodar**.
- [x] **Fase 4 (legado objdigital)** — ✅ concluído (2ª passada terminou): 2.137 ok / 565 erro (2.702/2.707 processados; os 565 são 404 permanentes confirmados via curl direto, atrito real da fonte legada, não bug). Confirmado em 2026-09-11 ~20h UTC: `select erro,count(*)` devolve **só `HTTP 404` (565)** — nenhum `HTTP 0` restante, então a 3ª passada não tem o que reprocessar; **não reiniciar de novo**.
- [x] ~~`subidor.py`~~ **substituído pelo `subidor-paralelo.py` em 2026-09-12 (achado 2.22); o texto a seguir é histórico.** (`pipeline/`, `--vigiar`, PID 97295) — vivo há 1d8h, vigiando `~/Downloads`. **2026-09-11 ~20h UTC**: fila local de **19.897 arquivos `BRAS__` / ~77 GB** (12.511 thumb, 1.660 `__imagem`, 5.726 com nome original). Bucket: 33.388 objetos / 60,3 GB, 8.080 itens com `metadata.json` (61,9% dos 13.059). **2026-09-12 09:45 UTC**: 16.207 enviados, fila de 18.286. Taxa nas horas acordadas ≈ **650–740 arq/h ≈ 2,0–2,4 GB/h**.
⚠️ **O relógio é de horas ACORDADAS, não de horas corridas.** Os envios pararam
às 22:30 UTC de 11/set e só voltaram às 09:00 UTC de 12/set — **10,5 h de
silêncio**, que é a máquina dormindo (00:30–11:00 local), não falha do subidor
(o processo seguiu vivo e voltou sozinho). Por isso:
- fila de 18.286 ÷ ~700 arq/h = **~26 h de máquina acordada**
- em dias normais (~14 h acordado), isso vira **~2 dias de calendário**
- com `caffeinate -is` segurando a máquina acordada, ~26 h corridas
Vale decidir isso conscientemente: é a diferença entre terminar em ~1 dia ou ~2.
### Achado 2.15 — aba do coletor inalcançável, e storage da origem aparece vazio (2026-09-11 ~20h UTC)
Tentativa de retomar a trilha 1 sozinho falhou, mas rendeu dois fatos novos:
1. Sobraram instâncias **headless do Chrome** de uma sessão anterior, uma delas
lançada com o **perfil padrão** (`--user-data-dir` default). Mortas (PIDs
89329, 89327, 14818); o Chrome real do usuário (PID 57263, aberto desde
9/set) foi preservado. **Nunca subir headless sem `--user-data-dir` próprio**
— disputa o perfil onde mora todo o estado do coletor.
2. Numa aba nova em `https://brasilianafotografica.bn.gov.br` (mesmo perfil,
mesma origem), `localStorage` devolve **0 chaves** e `indexedDB.databases()`
devolve **[]** — enquanto `ler-localstorage.js`, lendo o leveldb do disco do
mesmo perfil/origem, devolve `bras_baixados: 12.974`. Ou seja: o contexto vivo
e o disco discordam. Não dá pra `BAIXA.retomar()` numa aba nova: sem o
IndexedDB `bras`, `alvos()` devolveria `[]`.
**Não colar `baixador-navegador.js` numa aba nesse estado**: se o storage
estiver mesmo zerado, `FEITOS` começa vazio e a fila vira os ~13 mil itens
inteiros de novo (centenas de GB, e carga indevida na fonte). O caminho seguro
é o usuário voltar na **aba original do coletor** (a que já tem `BAIXA` no
`window`) e rodar `BAIXA.status()` / `BAIXA.retomar()` lá.
### Achado 2.16 — `bras_baixados` anda PRA TRÁS; não usar como medida (2026-09-11 20:45 UTC)
O contador caiu de **12.974 → 12.111** entre 20:14 e 20:43 UTC (três leituras
seguidas devolvem 12.111; o leveldb foi escrito pelo Chrome às 22:24 local, 19
min antes da leitura — é gravação real, não cache velho).
Causa provável: `marcar()` reescreve o **array inteiro** a partir do `FEITOS`
carregado quando o script foi colado. Qualquer aba com snapshot velho que ainda
marque um item sobrescreve a lista boa por uma mais curta. Com duas abas vivas
(v1 e v2 conviveram), a lista é sempre a do último escritor, não a união.
**Consequência prática**: `bras_baixados` **não** mede progresso — subestima. A
medida autoritativa é *bucket ∪ fila local em `~/Downloads`*:
```
# handles com preservação no bucket (do aws s3 ls --recursive)
awk '... itens/<handle>/<arquivo!=metadata.json, sem "thumb">' → 8.080
# handles de preservação ainda na fila local
ls ~/Downloads | grep '^BRAS__' | grep -v thumb | sed -E 's/^BRAS__(.+)__.*/\1/' → 7.271
# união → 12.986 de 13.059 (faltam 73, listados em pipeline/faltantes-preservacao.jsonl)
```
Isso também refaz a conta do achado 2.15: o risco de recolar o script não é
"85 itens", é **re-baixar ~950+** que o contador esqueceu (ou tudo, se o
storage estiver mesmo zerado).
## Concluído agora
- [x] **Thumbnails contaminados com bitstream de LICENÇA** (achado 2.8b): 2.653 arquivos locais apagados de `~/Downloads`, 146 já subidos removidos do bucket, `subidor.py` blindado com validação de magic bytes (rejeita e apaga automaticamente qualquer coisa que não comece com JPEG/PNG, mesmo que o nome diga o contrário). `baixador-thumb.js` v2 escrito com validação + fallback — falta só reconectar o navegador pra trocar o script rodando.
- [x] **WordPress → .md**: 636/637 posts colhidos (1 erro), exportados e convertidos — `wordpress/{id}-{slug}.md` no repo (front-matter YAML: id/url/título/autor/data/categorias/handles referenciados) + `wordpress-posts.jsonl` e a pasta `wordpress/` subindo pro bucket agora.
- [x] **Bug de corrida em arquivo temporário**: `baixador.py` e `subidor.py` moram na mesma pasta e usavam o mesmo nome fixo (`.tmp/metadata.json`) — rodando ao mesmo tempo, um apagava o arquivo que o outro tinha acabado de criar. Derrubou o `baixador.py` de verdade (crash, não só log de erro). Corrigido: nome agora inclui o PID. 3 itens (`1081,1082,1084`) já tinham subido um HTML de visualizador como se fosse "legado" antes da correção — limpo do bucket, metadata regenerado.
- [x] **PDFs de álbum perdidos no objdigital**: 44 itens (achado 2.9 do PLANO.md) tinham PDF disponível mas a extração pegava um `.htm` de landing page em vez do PDF de verdade. Corrigido em `catalogo.jsonl` e no IndexedDB antes do `baixador.py --somente-legado` alcançar esses handles (confirmado: nada contaminado no bucket). `baixador.py` reiniciado (PID 37909) com o catálogo corrigido.
## Concluído nesta sessão (chrome-extension-connection, ~17h UTC)
- [x] `pipeline/reparo-hash-url.js` colado e rodado — 78/78 corrigidos no IndexedDB
- [x] **Achado 2.13 (novo)**: mesmo bug do `#` reaparecia no redirect do DSpace (forma antiga → canônica). Fix: usar `/bitstream/handle/PREFIX/ID/arquivo` direto. `preservation_url` dos 78 reescrito de novo com a forma canônica.
- [x] Os 78 itens baixados cirurgicamente — **concluído 78/78, 0 erros** (script à parte, não o `BAIXA.retomar()` geral — aba antiga com o loop principal continua rodando sozinha, ver nota de handoff acima)
- [x] `BAIXA_THUMB` v2 iniciado (aba nova, não foi possível parar a v1 na aba antiga — ver nota acima; sem risco de dado ruim no bucket graças à validação de magic bytes já no `subidor.py`)
- [x] **Thumbnails v2: CONCLUÍDO 100%** — `BAIXA_THUMB.retomar()` rodado (2026-09-11 ~08h local) recuperou todos os 1.281 erros da queda de rede (13.059/13.059 ok, 0 erro permanente)
- [x] `baixador.py --somente-legado` reiniciado uma vez (2026-09-11 ~08h local, PID 88387) depois que a passada anterior terminou (2.113 ok, 589 erro de 2.702 processados) — idempotente, só reprocessa não-'ok'
- [x] Checagem de status a cada 30 min retomada nesta sessão (ver `/loop`)
## Mural (`web/wall.html`) — sessão `fix-mobile-wall-click-layout`, 2026-09-12
No ar em <https://xn--2dk.xyz/brasiliana/>. Commits em `rafapolo/xyz`:
`d8c3364` e `a6085fa` (empurrados pela sessão paralela `brasiliano-ae`, contêm
trabalho das duas) e `f645008`. O mural é publicado copiando
`web/wall.html` → `xyz/brasiliana/index.html` e `web/atlas/atlas-map.json` →
`xyz/brasiliana/atlas/atlas-map.json`.
### Achado 3.1 — a metade descritiva do catálogo nunca chegou ao mural
Buscar "indigenista" não achava nada, mesmo com 42 peças classificadas
`dc.subject = Política indigenista`. A busca livre estava certa (varre todo o
`meta` recursivamente); quem descartava era o **`summarize()` do
`web/build-atlas.js`**, que projetava 8 campos e jogava fora assunto,
descrição, lugar, fonte, editor, relação e código de arquivo.
Havia um segundo bug atrás: `pickDC()` devolve só a **primeira** ocorrência do
campo. Como o catálogo repete `dc.subject` (78.835 linhas para 13.060
registros, ~6 por item), mesmo incluindo o campo sobreviveria um assunto por
peça. O `pickAll()` novo coleta todas, deduplicadas, na ordem.
Regras que ficaram (espelhadas em `pipeline/reprojeta-meta-mapa.mjs`):
- entram: `dc.subject`, `dc.description`, `dc.coverage`, `dc.source`,
`dc.publisher`, `dc.relation`, `dc.identifier`
- ficam de fora: `dc.language` (é sempre `"por"` — casaria ~2.000 itens por
acidente, já que a busca é por substring) e `dc.format` (`"JPG"`)
- `dc.identifier` e `dc.relation` entram **sem as URLs**: era 1,1 MB de texto
que ninguém busca, escondendo o que presta — os códigos de arquivo
(`013RJ012036`) e os nomes de coleção (`Gilberto Ferrez`, `Diários
Associados`)
- `handle` e `source_url` **saíram** do `meta`: o primeiro é a chave sob a qual
o item já está arquivado no mapa, o segundo é o mesmo endereço para todos com
o handle no meio. O mural remonta a URL numa linha (`sourceUrl()`) e injeta o
handle na palha da busca, então buscar `5546` continua achando a peça.
Verificado no navegador: `indigenista` → 42, `Gilberto Ferrez` → 2.120,
`013RJ012036` → 2, `amazônia` → 156, `5546` → 1. E o ruído sumiu: `show=full`
e `brasilianafotografica` saíram de 12.552 para 0.
### Achado 3.2 — não vale pré-comprimir o `atlas-map.json`
Medido, não chutado:
- **No fio já vem gzipado.** `curl -sI` em <https://xn--2dk.xyz/brasiliana/atlas/atlas-map.json>
responde `content-encoding: gzip`. Pré-comprimir só moveria os mesmos bytes,
ao custo de um `DecompressionStream` no carregador e de um arquivo ilegível.
(O host não oferece brotli, e `DecompressionStream` não decodifica brotli.)
- **No repositório também.** O git comprime todo blob com zlib no pack, então
um JSON de 8 MB não ocupa 8 MB lá dentro — ocupa aproximadamente o que o
`.gz` ocuparia, e ainda dá diff.
Encolher o **conteúdo** foi o que valeu, e só até certo ponto — o gzip come
quase todo o ganho estrutural:
| variante | cru | gzip |
|---|---|---|
| com os campos descritivos | 9,61 MB | 1,11 MB |
| **sem `source_url` e `meta.handle`** (feito) | **8,00 MB** | **1,05 MB** |
| + dicionário nos campos de vocabulário pequeno | 6,96 MB | 0,99 MB |
| + dicionário de assuntos/lugares/descrições | 5,14 MB | 0,93 MB |
As duas últimas linhas quase dobram a economia crua e rendem 30-60 KB no fio
cada, em troca de uma camada de dicionário no carregador — troca ruim. Onde o
tamanho cru ainda pesa é o `JSON.parse` no celular, não o download. Referência:
antes de tudo isso o mapa era 5,52 MB / 0,73 MB.
### Consertos de interação (todos verificados por CDP num Chrome real)
- **Toque numa peça abria e fechava a ficha no mesmo gesto** (metade de cima da
tela). Um toque dispara `pointerup` e depois um `click` de compatibilidade,
que caía no backdrop recém-aparecido; a guarda de 400 ms usava
`stopPropagation()`, que **não alcança listeners do mesmo nó** — e quem fecha
a ficha é um listener do próprio `#card-wrap`. Agora é
`stopImmediatePropagation()`.
- **Tela inicial "sem estilo"**: `#title-screen` era irmão flex do `<p>` e,
invisível, ainda tomava metade da linha; e a regra `#loading p` pegava também
o subtítulo, jogando-o em maiúsculas com tracking. Virou `position:absolute` e
`#loading-msg`.
- **Painel de filtros fugia do dedo** no arrasto da década: o chip do filtro
aparecia e inseria uma linha inteira acima do corpo; o badge de contagem
crescia o header. Chips agora só com o painel fechado, badge reserva a caixa
com `visibility`.
- **Movimento da parede**: a câmera mirava o *alvo* enquanto estava atrás dele
(inclinava a vista a cada arrasto — era isso que fazia a parede "nadar"); o
easing era fração por frame (a 120 Hz convergia 2× mais rápido que a 60).
Agora constante de tempo, `lookAt` removido, e soltar em movimento joga a
parede com desaceleração. Zoom do scroll virou multiplicativo.
- **Back/forward do navegador** andam pelas peças abertas, com `#handle` na URL
(link direto reabre a peça). Mudar um filtro recolhe a ficha com **um** passo
de histórico, mesmo com `apply()` rodando a cada frame do slider.
- **Filtros alcançáveis com a peça aberta**: o painel estava em `z-index: 15`
debaixo do `#card-wrap` (20). Agora 25 (scrim 24), e no celular a ficha
estaciona acima do peek da sheet para não cobrir ‹ anterior / próxima ›.
### Achado 3.5 — o mural entrava em loop de carregamento no celular
Relato do usuário (14/09): no celular a tela inicial ficou em loop. Causa, lida
no carregador: o celular **decodificava cada página em 8192×8192** (~268 MB) e
só então reduzia para 4096 num canvas, retendo os canvases além das texturas —
pico de ~800 MB. O iOS não lança erro por falta de memória: mata a aba e a
**recarrega sozinho**, e a página recomeçava o mesmo carregamento. Não havia
tratamento de erro nenhum: fetch falho ou decodificação recusada deixavam a
barra parada para sempre.
Correção (commit `xyz` e `brasiliano` de 14/09):
- **Páginas leves** `atlas-m-0..3.webp` (3072², peça de 48 px), geradas pelo
`build-atlas.js` (`--so-mobile` regera só elas) e registradas em
`atlas-map.json` no campo `mobile`. Mesma posição de cada peça, então a conta de
uv não muda. 6,8 MB no total contra 42 MB; 36 MB decodificados por página.
- **Modo leve** em toque, `maxTextureSize` < 8192 ou `deviceMemory` ≤ 4, ou
forçado com `localStorage.mural_leve = '1'`.
- **Guarda contra loop**: marca `mural_carregando` em `sessionStorage` antes da
parte pesada, apagada só depois de dois quadros renderizados. Se a página abre
com a marca, a tentativa anterior morreu → vai direto para o modo leve e
mostra "modo leve — a tentativa anterior não terminou".
- **Nunca recarrega sozinho**: HTTP de erro, decodificação recusada e
`webglcontextlost` mostram aviso com botão "tentar de novo" (que recarrega uma
vez, já no modo leve). Progresso parado por 30 s mostra "o carregamento parou
de avançar" sem derrubar o que ainda pode estar vivo.
Verificado com Chrome real via `puppeteer-core` (perfil próprio, WebGL
swiftshader), emulando celular com toque — roteiros em
`scratchpad/teste-mural/testa.mjs` e `testa2.mjs`:
| cenário | resultado |
|---|---|
| A — celular carrega | só as 4 páginas leves, capa some em 8,3 s, marca apagada |
| C — marca de crash no desktop | aviso de modo leve, nenhuma página pesada, sem recarga |
| D — página falha no download | aviso com botão, **nenhuma recarga em 10 s** |
| E — botão tentar de novo | recarrega uma vez, termina no modo leve, sem 2ª recarga |
| F — perda de contexto WebGL | aviso com botão, sem recarga |
| G — download travado | aviso "parou de avançar" em 33 s, sem recarga |
**Verificado em produção** (14/09, após o deploy do GitHub Pages levar 62 s):
o cenário A contra `https://xn--2dk.xyz/brasiliana/` baixou só as 4 páginas
leves, a capa sumiu em 9 s pela rede real, sem falha, e a marca foi apagada.
O card no modo leve recorta a peça certa: a mesma peça tirada do atlas normal e
do leve difere 4/255 em média; a vizinha, 41,5/255.
**Limite do teste**: não há iPhone de verdade aqui — o limite de memória do iOS
não se emula no Chrome. O que está provado é que o celular não decodifica mais
8192² e que nenhum caminho de falha recarrega sozinho.
**Armadilha de teste**: `framenavigated` do Puppeteer conta a `about:blank`
inicial e mudanças de histórico do mural, então contar navegações dá falso
positivo de recarga. Usar uma marca em `window`, que só some numa recarga real.
## Miniaturas derivadas + reconciliação do ledger — 2026-09-12
Mural no ar com **13.059 peças** (antes 12.552): commits `bba32f6`,
`6a82a5e`, `1ecded1` e `e930158` em `rafapolo/xyz`. Desta vez o `atlas/` inteiro foi junto, não só o
`atlas-map.json` — o formato do map mudou (ver achado 3.4).
**Números fechados em 13/09 (medidos contra catálogo × ledger):**
| | |
|---|--:|
| itens no catálogo | 13.060 |
| com imagem de preservação | 12.991 |
| com thumbnail do DSpace | 13.059 |
| com miniatura derivada (`derivados/thumb256/`) | 13.059 |
| **no mural** | **13.059** |
| fora do mural | **1** — só `7523` |
Os 8 que faltavam (`7802`, `7814`, `7817`, `7848`, `7852`, `7861`, `7875`,
`8075`) entraram: eles **têm** `thumbnail/thumb_3.jpg` de imagem real no
bucket (109–250 KB). A afirmação anterior de que o thumbnail deles era texto
de licença estava errada — o texto era o `thumb_2` do material antigo do
finland, não o objeto do bucket.
Os 73 faltantes de preservação (achado 2.17/2.18) **não** ficam de fora do
mural: têm thumbnail do DSpace, que basta para o tile de 128px. Faltar
preservação e faltar no mural são coisas diferentes.
- [x] **Miniaturas derivadas — 13.051 itens (99,93%)**
em `s3://brasiliana/derivados/thumb256/` (256px WebP q80, ~8 KB cada,
100 MB no total). Prefixo `derivados/` deliberadamente fora de `itens/`:
`itens/` é material de origem, `derivados/` é reconstruível do zero.
Misturar os dois apagaria a procedência que o MANIFEST garante.
Composição final (medida, igual à do MANIFEST): **12.849 derivadas da
imagem de preservação** + **202 derivadas do `thumbnail/` do DSpace**
(itens com miniatura mas sem preservação coletada). Caminho até lá:
6.338 no finland a partir do bucket, 6.483 locais a partir de
`~/Downloads`, 164 do DSpace, e +66 do material do achado 2.21.
- [x] **MANIFEST.md atualizado e subido** — seção `derivados/`, os achados
2.19 e 2.20 abaixo, e a nota de que `thumbnail/` do DSpace não é
miniatura (achado 3.3). Re-subido em 12/09 com 13.051 / 99,93%, os 9
ausentes nomeados e a divergência 13.058 × 13.060 anotada.
- [x] **`build-atlas.js` parou de descartar item sem título** — a guarda
`if (!o.title) continue` escondia do mural `11749` (Museu Aeroespacial) e
`6241` (Instituto Moreira Salles), que têm imagem; o card já cai pra
"(sem título)" sozinho. 12.983 → 12.985.
- [x] **Wordmark "Acervo Brasiliana" ganhou fundo preto** — só tinha
`text-shadow`, que some sobre peça clara, e peça clara é metade do
acervo. Mesmo preto da dica do rodapé.
- [x] **Rótulo de contagem deixou de dizer "no acervo"** — dizia
"N peças no acervo" como se o mural fosse o acervo inteiro; agora diz
"peças com imagem". Foi essa frase que levantou a dúvida de que faltavam
miniaturas.
- [x] **`web/build-atlas.js` ganhou `--thumbs=DIR`** — a fonte antiga
(`~/Downloads`) é varrida pelo `subidor.py` conforme sobe, então nunca
tem o acervo inteiro ao mesmo tempo. Agora a fonte é reconstruível do
bucket.
- [x] **Ledger `subidor.sqlite` reconciliado com o bucket**: 28.553 linhas =
28.553 objetos, zero divergência nos dois sentidos. Backups em
`/private/tmp/claude-501/.../scratchpad/subidor.sqlite.bak-*`.
- 145 linhas de `thumbnail` sem objeto no bucket — são os bitstreams de
LICENÇA do achado 2.8b, removidos do bucket mas deixados no ledger
(426–815 bytes, só **5 sha256 distintos** entre os 145). Apagadas.
- 3 objetos no bucket sem linha nenhuma — inseridos, sha256 recalculado
do próprio objeto.
- 2.137 objetos `legado/` que **nenhum** ledger de upload conhecia: o
`baixador.py` só anota no `baixador.sqlite`. Importados, para que
`subidor.sqlite` seja ledger único.
- 13.051 derivados registrados como `tipo='derivado-thumb256'`.
- 63 "órfãos" de preservação/thumbnail eram **falso positivo**: gravados
durante a própria listagem do bucket. Conferidos no S3, estão lá.
### Achado 2.24 — 16 threads estouram o OpenSSL do macOS (SIGSEGV)
O `subidor-paralelo.py` morreu com **segmentation fault** no arranque da
passada das 10:56 de 13/09, e por isso **nada subiu durante horas** (o
`vigia-30min` só tentaria de novo meia hora depois). O relatório do macOS
aponta a pilha dentro do `libcrypto`:
```
libcrypto.3.dylib ossl_x509_store_ctx_get_by_subject
libcrypto.3.dylib X509_STORE_CTX_get1_issuer
libssl.3.dylib ssl_verify_internal / tls_post_process_server_certificate
```
É corrida de thread na verificação de certificado TLS quando muitas threads
fazem handshake ao mesmo tempo — bug do OpenSSL, não do nosso código. Com 4
threads subiu 50 arquivos a 19 GB/h sem problema. **Default baixado para 6
threads** no `subidor-paralelo.py`, no `vigia-30min.sh` e no
`rodar-paralelo.sh`. Não vale voltar a subir: acima de ~8 o ganho é nulo (o
link satura) e o risco de crash volta.
### Achado 2.25 — 75 itens com HTTP 500 persistente na origem (não é só o 7523)
Passada de 13/09 com a aba conectada: **108 imagens novas baixaram**, e **74
falharam com erro que não passa** — 45 × HTTP 500, 26 de rede e 3 de blob
curto, com retry sem recuperar nenhuma. Somando o `7523`, são **75 itens**
cujos bitstreams de preservação a origem não serve. Lista em
`pipeline/falhas-500-2026-09-13.txt`.
Isso substitui o achado 2.23 (que falava em 211 faltantes): os outros 136
baixaram. Nenhum dos 75 fica fora do mural — todos têm thumbnail do DSpace.
Diagnóstico que vale registrar: os 500 são **do item, não do ritmo**. Com 3
requisições simultâneas, `6545` e `6555` davam 500 enquanto `1014`, `8128`,
`10039`, `14358` e `6520` davam 200 no mesmo instante, inclusive em série com
3 s de espaçamento. E os itens ruins são vizinhos de id, então em ordem
crescente eles davam erros seguidos e disparavam o aborto automático — por
isso o motor passou a **embaralhar** a lista.
### Achado 2.26 — nova rodada sobre os 75 (13/09 noite): o que recupera e a armadilha da sequência
**Recuperados (3):** `6433` e `6520` por curl — a origem serve a ~11 KB/s, e o
"erro de rede" do navegador era estouro de tempo; `6656` no navegador na
**sequência 3** (5,4 MB, 1604×2612) — o catálogo apontava a sequência 2, que é
o texto de licença.
**Curl não escala:** depois dos 2 primeiros o Cloudflare devolveu `403`
(5.484 bytes) para 23 seguidos. Parado para não piorar o bloqueio.
**Armadilha — não aceitar "qualquer imagem em qualquer sequência".** A 1ª
versão do motor que varria as sequências 1–6 trouxe 8 "sucessos"; **7 eram o
`thumbnail/thumb_3.jpg` que já estava no bucket** (sha256 idêntico, 27–170 KB,
~800 px). Retidos antes de subir e descartados. A estrutura típica de um item
DSpace deste acervo:
| sequência | conteúdo |
|--:|---|
| 1 | imagem de preservação (nos itens com defeito: `HTTP 500`) |
| 2 | bitstream de licença (texto, 426–821 bytes) |
| 3 | thumbnail gerado pelo DSpace |
| 4–6 | inexistente |
A versão corrigida calcula SHA-256 no navegador e rejeita qualquer candidato
cujo hash já esteja no ledger como `thumbnail` ou `legado`, e grava com prefixo
`HOLD__` (o `subidor-paralelo.py` ignora) para conferência antes de subir.
### Achado 2.27 — os itens do IMS morrem num corte de 300 s; o `500` é o mesmo por sequência e por nome
Terceira rodada sobre os 75 (13/09, 21h), com um motor que registra o tempo de
cada tentativa. Três comportamentos distintos, todos da origem:
- **Corte em ~300 s sem resposta** (`rede@301s`), em 12 itens do Instituto
Moreira Salles (`8145`–`8316`). A requisição não recebe nem cabeçalho: um
teste com `Range: bytes=0-1023` estourou 18 s sem resposta, então não é
transferência lenta que cai no meio — o servidor trava antes de responder e
algo no caminho corta em 5 min. Retomar em pedaços não ajuda.
- **Corte em ~32 s** em 3 itens (`8271`, `8275`, `8277`): mesma família, limite
diferente.
- **`500` imediato** (0 s) em 11 itens (`8739`–`9148`). A forma canônica
`/bitstream/handle/20.500.12156.1/<id>/<arquivo>` — que busca pelo nome em
vez da sequência — **também devolve `500` em 0,2 s** (`8739`, `6545`). O
defeito está no servidor localizar o bitstream, não no endereçamento.
Estrutura das sequências nos itens do IMS: **1 = preservação, 2 = thumbnail**
(sem bitstream de licença, ao contrário dos do Museu Aeroespacial/Arquivo
Nacional/Fiocruz, onde 2 é licença e 3 é thumbnail). Varrer 1–6 nesses itens só
gasta tempo: 3–6 não existem.
Recuperado nesta rodada: `8396` (Biblioteca Nacional, sequência 3, 13,5 MB,
3361×4453) — mesmo padrão de `6656` e `7939`, onde o catálogo aponta a
sequência 2 (licença) e a imagem está na 3.
### Achado 2.28 — a cópia legada: só existe para a Biblioteca Nacional, e 25 "cópias" são páginas HTML
Medido em 14/09. A cópia legada vem do `objdigital.bn.br` e **só existe para
itens da Biblioteca Nacional**: 2.702 dos 13.060 têm `legacy_url`, todos da BN.
Os 16% de cobertura não são falta — os outros 10.358 itens não têm cópia legada
na origem.
| | |
|---|--:|
| elegíveis (`legacy_url` no catálogo) | 2.702 |
| no bucket como `legado/` | 2.137 |
| — imagens JPG | 1.899 (859 MB) |
| — PDF de álbum | 213 (8,3 GB) |
| — **páginas HTML** | **25** (~2,4 KB cada) |
| HTTP 404 permanente | 565 (499 jpg, 41 html, 22 pdf, 2 htm, 1 sid) |
**As 25 páginas HTML não são imagem.** São o visualizador Seadragon do
objdigital (`viewer.openDzi("GeneratedImages/dzc_output.xml")`): a imagem mora
numa pirâmide de tiles Deep Zoom ao lado da página. Itens: `586`, `587`, `630`,
`802`–`806`, `808`, `809`, `811`, `812`, `814`, `816`, `817`, `870`, `1080`,
`1083`, `1085`, `1086`, `3198`, `3545`, `3546`, `3866`, `6655`. **Todos têm
imagem de preservação no bucket**, então nenhum ficou sem imagem. Não foram
apagados — é decisão do usuário (ver pendência). Mesma família do bug de
`1081`/`1082`/`1084` (HTML de visualizador subido como legado), que foi limpo
na época; estes 25 escaparam.
**O objdigital não saiu do ar — mudou de endereço.** Em 14/09 a porta 80
fechou nos dois IPs (`200.9.175.46`, `177.223.196.160`), mas a 443 está aberta
e o site responde em **`https://objdigital.bn.br/objdigital2/acervo_digital/...`**
(o próprio visualizador Seadragon carrega o script desse prefixo). Prova de que
é a mesma fonte: 3 cópias legadas sorteadas do bucket, baixadas pelo endereço
novo, voltaram com **sha256 idêntico**. Correção de uma afirmação anterior
desta sessão: o `icon573843.jpg` usado como "controle" **não** tinha baixado
antes — ele é um dos 565 erros (item `10`), e responde `200` no endereço novo.
Consequência: **a maior parte dos 565 "404 permanentes" existe no endereço
novo.** Sondagem completa por `HEAD` em 14/09 (`pipeline/legado-caminho-novo.tsv`):
| no endereço novo | itens |
|---|--:|
| `200` com `image/jpeg` | 330 |
| `200` com `application/pdf` | 18 (o maior, 52 MB) |
| `200` com `text/html` (visualizador Deep Zoom, não arquivo) | 41 |
| `404` de verdade | 176 |
Recuperáveis como arquivo: **348** (~0,3 GB). As 41 páginas HTML somam-se às 25
já no bucket: **66 itens** cuja imagem só existe como pirâmide de tiles. A pirâmide Deep Zoom das 25 páginas HTML
também responde (item `3545`: `dzc_output.xml`, 5744×4245, tiles de 256 px).
**O `baixador.py` usa o endereço antigo (`http://…/acervo_digital/`) e precisa
ser atualizado antes de qualquer nova passada.
### Achado 2.22 — o gargalo do upload era o `subidor.py`, não o link; troca pelo paralelo
Eu tinha escrito aqui que o gargalo era o link de casa. **Errado.** Medido em
12/09 (`networkQuality`): **69 Mbps de upload (~31 GB/h)**, contra ~1,3 GB/h
reais. O `subidor.py` sobe um arquivo por vez, espera 1,5 s de "estabilidade" e
dispara **três** `aws s3 cp` por arquivo (arquivo, `metadata.json`, manifest),
cada um pagando a partida do aws-cli: ~5 s por arquivo, seja miniatura de 74 KB
ou preservação de 40 MB.
Além de lento, ele estava estragando duas coisas:
- **873 manifests com linha errada**, `derivado-thumb256/<handle>.webp`. É
consequência de eu ter registrado os derivados no ledger: ele lista toda
linha do handle, e esse caminho não existe em `itens/<handle>/`.
- **Duplicatas `(N)` voltando ao bucket** depois da limpeza do achado 2.20
(ex.: `5304`, `thumb_2.jpg` e `thumb_2 (1).jpg` com o mesmo sha256).
Substituto: `pipeline/subidor-paralelo.py` (boto3, threads, HEAD antes de apagar
o local, manifest uma vez por item, sem linha de derivado, duplicata e rejeito
registrados) + `pipeline/rodar-paralelo.sh`. Teste com boto3 contra o bucket:
PUT de 20 MB a 27 Mbps num único stream.
Testes antes de soltar, com o que cada um mostrou:
1. Lote de 30: todos eram rebaixa já presente no bucket e foram **apagados do
disco sem HEAD e sem registro**. Foi o que motivou a conferência por HEAD e a
tabela `descartados`. Para esses 30, a garantia é só o ledger, reconciliado
com o bucket às 12:50.
2. Lote de 150: 150 descartes, 150 conferidos no bucket.
3. Lote de 800: 319 enviados (319 conferidos, `image/jpeg`) + 481 descartes
conferidos; manifests dos 319 sem linha de derivado, sha do metadata batendo.
4. Primeira execução real (18:4x UTC) **interrompida**: o log mostrava TIFF
indo para `rejeitados/` (achado 2.19, correção). Assinaturas corrigidas; os 21
da quarentena (19 TIFF + 2 BMP) voltaram para a fila; relançado às 18:59.
Antes do relançamento, **180 arquivos locais (0,25 GB) já presentes no S3** foram
apagados do disco a pedido, cada um com MD5 local = ETag do objeto e registro em
`descartados`. Os outros 13.922 não estavam no bucket.
### Achado 2.23 — faltam 211 preservações depois da fila, não 73
Cruzando catálogo × (ledger ∪ fila) em 12/09: **12.849 / 13.060** itens terão
imagem de preservação quando a fila acabar (thumbnail: 13.059). Os 211:
- **71** da lista conhecida (`faltantes-preservacao.jsonl`, recusa da origem);
- **1** sem `preservation_url` no catálogo;
- **139** fora de qualquer lista. Exemplo: `10039`–`10049`, que no bucket têm só
`thumbnail/` e `metadata.json`. Desses: 8 rejeitados no upload antigo, 12 com só
`legado/`, ~119 sem rastro (nem bucket, nem fila, nem log).
Hipóteses, nenhuma confirmada: (a) o "12.986/13.059" do achado 2.16 contou
objetos `legado/` e `manifest` como preservação, porque o `awk` só excluía
`metadata.json` e thumbnail; (b) parte dos ~119 pode ser TIFF apagado pelo
`subidor.py` antigo antes do trecho que o `subidor.log` cobre.
### Achado 2.21 — a sessão de 11/09 já tinha as miniaturas no finland, e eu não olhei
`/root/brasiliana-wall/` no finland tinha, desde 11/09 13:17–13:41:
`downloads-flat/` (20.411 arquivos, todos `THUMB__`, 2,2 GB), `s3-thumbs/`
(5.168 handles do bucket, 851 MB) e o `web/atlas/` cujos quatro `.webp` batem
byte a byte com o que estava publicado no `xyz` até 12/09. **O mural de 12.552
peças foi construído lá**, a partir das miniaturas do DSpace — não de
`~/Downloads`, como o comentário do `build-atlas.js` leva a crer.
A união desses dois diretórios cobre **13.041 handles**, praticamente todos
JPEG válido. Eu puxei ~63 GB de imagens de preservação do bucket para derivar
12.985 miniaturas sem ver que 3 GB de miniatura já estavam no disco da mesma
máquina, cobrindo mais itens que o meu resultado. Aproveitados depois: +66
peças (74 no delta, 8 eram licença).
**Lição de runbook**: antes de gerar qualquer coisa no finland, `ls /root` e
`cat /root/.bash_history`. Sessões anteriores deixam material lá e nada no
projeto local registra isso.
Limpeza feita em 12/09: `/root/brasiliana-wall` e `/root/thumbs` apagados
(3,4 GB; disco 27 → 31 GB livres), depois de verificar que os 13.041 handles
estavam **todos** cobertos pelo bucket (7.038) ou pela fila do Mac (6.785) —
zero cópias exclusivas. Ficaram de pé, de propósito: `/root/.s3env` (600, de
08/09, anterior às nossas sessões — pode ser setup permanente da máquina) e
`/root/brasiliana/` (44 MB, `baixador.py` + catálogo + sqlite com 13 linhas).
### Achado 2.19 — a contaminação de LICENÇA também atinge a preservação, não só a miniatura
O achado 2.8b tratou isso como problema da trilha de thumbnail. Não é: os
handles **`20.500.12156.1/6656`** e **`20.500.12156.1/7939`** têm, em
`~/Downloads`, um "imagem.jpg" que é na verdade o bitstream de LICENÇA do
DSpace — 777 bytes de texto UTF-8 com CRLF e extensão `.jpg`. A validação de
magic bytes do `subidor.py` barra no upload, então **nada disso chegou ao
bucket**; o efeito é que esses dois itens não têm imagem coletada e ninguém
percebeu, porque a fila local os contava como prontos.
Implicação: qualquer contagem de "preservação pronta" que leia `~/Downloads`
pelo nome do arquivo está 2 itens otimista. A contagem pelo bucket está certa.
**Atualização 12/09**: não são 2, são 10. Ao derivar as miniaturas do material
do finland (achado 2.21) apareceram mais **oito** com o mesmo defeito, todos
na trilha de thumbnail: `7802`, `7814`, `7817`, `7848`, `7852`, `7861`,
`7875`, `8075`. São exatamente os itens que sobram fora do mural. O bloco
`78xx` sugere que a contaminação vem em lote, por faixa de handle — vale
varrer essa faixa inteira antes de dar o acervo por fechado.
**Correção 12/09 (noite) — a regra de validação estava errada.** O `subidor.py`
só aceitava JPEG/PNG e **apagava** o resto como "bitstream de licença". Pelo
próprio `subidor.log`, dos **40** arquivos que ele apagou assim, **só 1 era
texto de licença**: 36 eram **TIFF** (`II*\0`, ~8 MB, com extensão `.jpg`),
2 **BMP** e 1 **ZIP** (`001AAN014011.jpg.zip`, item `2384`). Resultado, item a
item (lista com URL em `pipeline/apagados-pelo-subidor-antigo.jsonl`):
- **8 itens ficaram sem nenhuma imagem de preservação**: `14358`, `14359`,
`14360`, `14361`, `14362`, `14363`, `14364`, `14368` (TIFF, série "Alb 0261").
- **18 itens** perderam só bitstreams extras (`extra_seqN`, TIFF), mas têm a
imagem principal no bucket ou na fila. `10993`/`10995` (BMP) e `2384` (ZIP)
voltaram por rebaixa e estão na fila.
O `subidor-paralelo.py` aceita TIFF/BMP/GIF/JP2/WebP pela assinatura e manda
qualquer outra coisa para `pipeline/rejeitados/` com linha na tabela
`rejeitados` — nunca apaga. Os 8 casos `78xx` de thumbnail com texto de licença
(acima) foram detectados pelo `vipsthumbnail`, não por essa regra, e continuam
valendo.
### Achado 2.20 — 3.511 duplicatas `(N)` no bucket, do Chrome rebaixando por cima
Objetos `arquivo (1).jpg` convivendo com `arquivo.jpg` byte a byte idêntico —
sufixo que o Chrome põe ao rebaixar um arquivo que já existe em `~/Downloads`,
e que o `subidor.py` subiu como se fosse nome legítimo. Confirmadas idênticas
por **ETag + tamanho** (não só tamanho) antes de apagar: 3.511 objetos,
0,39 GB, removidos do bucket e do ledger na mesma passada.
**Não** foram tocados, e precisam de decisão:
- **30 objetos** cujo gêmeo tem tamanho **diferente** — não são duplicata,
são versões distintas do mesmo nome. Precisam de conferência individual.
- **43 objetos** cujo nome tem `(N)` mas que são o **único** arquivo do item —
candidatos a renomear, nunca a apagar.
`aws s3api list-objects-v2` com `--query "Contents[].[Key,Size,ETag]"` resolve
isso sem baixar nada; o ETag é o MD5 pra upload simples (só os 2.612 objetos
multipart do bucket não servem pra comparação direta).
### Achado 3.3 — o `thumbnail/` do DSpace não é uma miniatura
Medido em amostra de 300: **721 a 3.709 px no maior lado, média 1.087**; menor
lado nunca abaixo de 462. São derivados de resolução média, não miniaturas de
listagem. Duas consequências:
1. Servem tão bem quanto a imagem de preservação pro tile de 128px do mural —
por isso deu pra cobrir os 164 itens sem preservação sem perda visível.
2. A linha "Miniatura | ~13.005 elegíveis" do MANIFEST descreve ~1 MB por
arquivo, não ~8 KB. Quem ler esperando miniatura vai baixar 100x mais do
que imagina.
### Achado 3.4 — publicar o mural agora exige mandar o `atlas/` junto
O `wall.html` de 12:32 passou a derivar `handle` (chave do map) e `source_url`
(mesmo prefixo pra todo item) em JS, em vez de lê-los de cada peça. O
`summarize()` do `build-atlas.js` acompanhou. Resultado: **8,2 MB de map com
12.983 peças contra 10 MB com 12.552** — menos peso com 431 peças a mais.
Mas isso quebra a nota antiga de que "o `atlas/` já está commitado lá e não
muda a cada alteração do mural": map e `wall.html` agora são um par acoplado
por formato. Publicar um sem o outro deixa o mural sem link e sem busca por
handle.
## Pendente ## Pendente
- [ ] **`dc.rights` ausente em 5.833 itens (44,7%)** — confirmado como característica real da fonte, não bug. Só precisa ficar documentado no MANIFEST final, sem ação de reparo. Movido para [`tasks.md`](tasks.md), a lista única de tarefas abertas do projeto.
- [ ] **`web/build-atlas.js` não está versionado em lugar nenhum** — `brasiliano/` não é repo git e o `xyz` só recebe o `index.html` e o `atlas/`. A correção do `summarize()`/`pickAll()` (achado 3.1) vive só no disco desta máquina; um `rm` leva junto. Mesma exposição vale para `pipeline/` inteiro.
- [ ] **Encolher mais o `atlas-map.json` só com dicionário** (achado 3.2): 8,00 → 5,14 MB crus por ~120 KB no fio. Só vale se o `JSON.parse` no celular virar problema medido — não antes.
- [ ] **30 objetos `(N)` com tamanho diferente do gêmeo** (achado 2.20) — conferência individual, não dá pra automatizar com segurança.
- [ ] **43 objetos `(N)` que são o único arquivo do item** (achado 2.20) — renomear tirando o sufixo, pra o nome não mentir sobre haver um original ao lado.
- [ ] **Handles `6656` e `7939` sem imagem de preservação** (achado 2.19) — rebaixar; o que há hoje na fila local é o bitstream de licença.
- [ ] **Conferir os códigos HTTP que nunca foram tabulados** — o runbook do achado 2.18 manda rodar `FALTA.erros()` no console e rotear por código (404 → reparar URL, 403 → bloqueio de origem, 500 → transitório, retomar). **Esse passo nunca foi executado**: o achado 2.18 concluiu "é recusa da origem" a partir do `status()` agregado, não da tabela de erros por handle. Sem isso não dá pra saber quantos dos 71 são reparáveis.
- [ ] **Reconferir o handle `7523` (HTTP 500)** — registrado uma vez e tratado como falha permanente da origem desde então, mas 500 costuma ser transitório e nunca houve segunda tentativa. **Não dá pra testar por `curl`, e agora está provado com controle** (12/09): com User-Agent, Accept, Accept-Language e Referer de Chrome, o `7523` devolve `403` de 5.484 bytes (página do Cloudflare) — e o item `10`, que sabidamente funciona e está no bucket, devolve **exatamente o mesmo `403` de 5.484 bytes**. É bloqueio geral a requisição sem sessão real, nada específico do `7523`. Precisa da aba; a extensão Claude-in-Chrome seguia desconectada em duas tentativas no mesmo dia.
- [ ] **Reconciliar 13.058 vs 13.060** — o MANIFEST fala em 13.058 itens reais, o `catalogo.jsonl` tem 13.060 handles distintos. Diferença de 2 nunca explicada; anotada no MANIFEST como pendência.
- [ ] **Depois que os 212 faltantes baixarem e subirem** (pedido do usuário, 13/09):
1. conferir se **todos** os itens têm miniatura em `derivados/thumb256/` e gerar
as que faltarem (as novas preservações não têm derivado ainda);
2. **regerar o mural 3D** com o conjunto completo — de preferência derivando
no finland direto do bucket (`itens/*/preservacao/*`), que é tráfego
intra-Hetzner, em vez de puxar pro Mac;
3. republicar `wall.html` + `atlas/` no `rafapolo/xyz` (par acoplado, achado 3.4).
- [ ] **Quando o `rodar-paralelo.sh` terminar** (log termina em `===== ... FIM`):
1. conferir no log as três fases sem `!!!`, a linha `FIM da fila` (enviados,
duplicatas, rejeitados, falhas) e os `pendente:` que ficaram no disco;
2. `ls pipeline/rejeitados/` + `select * from rejeitados` — só deve ter texto
de licença; imagem ali é bug de assinatura;
3. reconciliar ledger × bucket (mesmo diff do achado de 12/09: 0 divergências
nos dois sentidos) e amostrar manifests (`grep derivado` = 0);
4. varrer `~/Downloads`: apagar o que tiver MD5 = ETag no bucket (mesmo
método dos 180 de 12/09), manter o resto;
5. atualizar a tabela de contagens do MANIFEST com os números fechados.
- [ ] **Rebaixar o que o `subidor.py` antigo apagou** (achado 2.19, correção): 8 itens sem preservação (`14358`–`14364`, `14368`) + ~20 `extra_seqN` em TIFF — lista com URL em `pipeline/apagados-pelo-subidor-antigo.jsonl`. Precisa da aba do navegador.
- [x] ~~Recontar os faltantes de preservação (211)~~ — feito em 13/09: 136 baixaram, sobraram **75** com defeito de origem (achado 2.25), listados em `pipeline/falhas-500-2026-09-13.txt`. Script usado: `pipeline/baixar-faltantes-v3.js` (ou o motor `F5` colado direto na aba).
- [ ] **`subidor.py` antigo: aposentar ou corrigir a regra de assinatura** antes de qualquer uso futuro — do jeito que está, apaga TIFF.
- [ ] **Rebaixar os 69 que sobraram** (achados 2.25–2.27; 6 recuperados em 13/09 à noite) quando a origem se recuperar — todos têm thumbnail, falta a preservação. Um `FALTA3.retomar()`/`F5.iniciar()` na aba basta; o que já baixou fica marcado no `localStorage` (`bras_faltantes_v3`).
- [ ] **Handle `8396` sem imagem e sem diagnóstico** — não está em `pipeline/faltantes-preservacao.jsonl` nem nas exceções conhecidas do MANIFEST; apareceu ao cruzar catálogo × miniaturas. Precisa de uma tentativa avulsa pra saber se é recusa da origem (achado 2.18) ou outra coisa.
- [ ] **`.git` do `rafapolo/xyz` está em 2,5 GB** e cada publicação do atlas soma ~51 MB permanentes (binário não faz delta). Se o mural for republicar atlas com frequência, tirar os `.webp` do git — LFS, ou servir do próprio bucket, que já tem os thumbs em `derivados/thumb256/`.
- [ ] **Crawl da Fase 1 pode ter mais buracos** (achado 2.10 do PLANO.md): 2 itens reais (`1799`, `4798`) foram achados faltando no catálogo só porque o WordPress os citava — já corrigidos, mas não existe verificação exaustiva de que a enumeração por `browse?type=title` pegou 100% de cada comunidade. Sem ideia barata de auditar isso por completo agora.
- [ ] **Baixar os 348 legados recuperáveis pelo endereço novo** (achado 2.28) — atualizar antes o `baixador.py` para `https://objdigital.bn.br/objdigital2/acervo_digital/`.
- [ ] **Decidir o que fazer com as 66 páginas HTML de visualizador** (25 já em `legado/` + 41 no endereço novo; achado 2.28): apagar do bucket e do ledger (não são imagem), ou montar a imagem a partir dos tiles Deep Zoom quando o objdigital voltar. Todos os 25 itens já têm preservação.
## Ao final (não fazer antes do download terminar)
- [x] Gerar `MANIFEST.md` (o que é, como foi coletado, quando) — feito; atualizado em 2026-09-12 com `derivados/` e os achados 2.19/2.20/3.3
- [ ] Confirmar no bucket que a contagem de itens/checksums bate com os 13.058 itens reais esperados
## Notas técnicas úteis pra retomar ## Notas técnicas úteis pra retomar
+776
View File
@@ -0,0 +1,776 @@
# TODO — Brasiliana → S3
> **Handoff em 2026-09-10 ~15h UTC**: sessão `fix-image-pipeline-extras` perdeu
> conexão com a extensão Claude-in-Chrome e encerrou a pedido do usuário.
> Trabalho passado pra sessão `chrome-extension-connection` (tem o navegador
> conectado). Ver mensagem de handoff enviada via SendMessage pro contexto
> completo do estado no momento da troca — resumo abaixo já reflete isso.
>
> **Atualização ~17h UTC (mesma sessão)**: aba antiga do coletor não é
> acessível por esta sessão (grupo de abas é por sessão) mas continuou
> rodando sozinha o tempo todo — confirmado por progresso do
> `bras_baixados` no localStorage (compartilhado por origem). Por isso o
> download principal (`BAIXA`) **não foi reiniciado nesta aba** (evitar
> duplicar ~8 mil downloads pesados em paralelo); só os 78 itens do achado
> 2.11 foram baixados cirurgicamente aqui. `BAIXA_THUMB` v2 foi iniciado
> numa aba nova (chave `bras_thumbs_v2`, começa do zero, ~13.059 itens).
> Durante a sessão houve uma queda de rede/extensão de alguns minutos
> (mesmo tipo de falha que derrubou a sessão anterior) — gerou ~1.280 erros
> transitórios no thumb v2 que precisam de uma segunda passada
> (`BAIXA_THUMB.retomar()`) depois que a primeira terminar.
> Ver `tasks/PLANO.md` pro histórico/achados/runbook. Itens concluídos saem
> daqui e vão pra `tasks/done/` (ex.: `tasks/done/TODO-2026-09-10.md`).
> Scripts e estado em `pipeline/` (reorganização de 2026-09-10).
## Em andamento (não mexer, só monitorar)
- [x] **Upload pro S3 — CONCLUÍDO.** A fila de `~/Downloads` está em **0**; tudo
que foi baixado está no bucket. Total no ledger: **41.444 objetos**.
O `pipeline/vigia-30min.sh` segue de pé: a cada 30 min sobe o que aparecer
e apaga do disco só depois do HEAD confirmar no bucket.
**Não editar `vigia-30min.sh` nem `rodar-paralelo.sh` enquanto rodam**
(o bash lê o script aos poucos) e **não relançar o `subidor.py` antigo**
(achado 2.22). Threads: 6, não 16 — ver achado 2.24.
- [ ] **Download principal** (1 imagem de preservação por item) — navegador. **2026-09-11 20:45 UTC**: **12.986/13.059 (99,44%), faltam 73** — medido pela fonte autoritativa (bucket ∪ fila local), não pelo `bras_baixados`. Parado há ~9h (último arquivo em `~/Downloads` às 13:19 local = 11:19 UTC). Lista exata dos 73 em **`pipeline/faltantes-preservacao.jsonl`** (`{handle, url}`). **Script `pipeline/baixar-faltantes-73.js` colado e rodado pelo usuário ~22:52 local (20:52 UTC)** — lista embutida, chave própria `bras_faltantes_73`, imune ao achado 2.16. **Resultado parcial: 2/73** (`10993`, `10995`, 31 MB). Os outros 71 estão falhando — ver achado 2.17. **Recontagem de 12/09: faltam 211, não 73 — ver achado 2.23.**
### Achado 2.17 — os 71 restantes falham, e não é malformação de URL (2026-09-11 21:25 UTC)
`bras_faltantes_73` = 2 e só 2 arquivos de preservação novos apareceram em
`~/Downloads` (22:52 local). O disco e a chave concordam — aqui o achado 2.16
não se aplica, o número é real.
Os 71 que falham têm URL estruturalmente idêntica às 2 que passaram
(mesmo host, mesmo `/brasiliana/bitstream/PREFIX/ID/SEQ/arquivo`, 21 dos 71 com
`%20` no nome, igual às que funcionaram). Diferenças observadas, nenhuma
conclusiva: as 2 que passaram são `SEQ=1`; entre as 71 há `SEQ` 1 (58), 4 (11),
3 (1) e 5 (1).
Hipótese principal: **as 2 que passaram estavam em cache de borda do Cloudflare**
— exatamente o caso do item 6066 descrito no cabeçalho do
`baixador-navegador.js` (`cf-cache-status: HIT`), e não a regra geral. Se for
isso, o `fetch` de aba não basta para estes 71 e o problema é de origem, não de
script.
**Próximo passo (precisa do console da aba)**: rodar `FALTA.status()` e
`FALTA.erros()` — o script guarda `{handle, url, erro}` de cada falha, e o
código HTTP decide o caminho:
- **404** → bitstream não existe nesse `SEQ`; reparar `preservation_url` no
catálogo (mesma família dos achados 2.9/2.11/2.13) e regerar o script.
- **403** → bloqueio de origem/Cloudflare; nem a aba resolve, precisa de outra saída.
- **500** → transitório; `FALTA.retomar()` mais tarde deve pegar.
Enquanto isso o script pode ainda estar rodando: cada erro dorme 60 s de backoff,
então 71 falhas levam ~71 min a partir das 22:52 local (fim previsto ~00:05).
### Achado 2.18 — é recusa da origem, não URL errada; e a v1 do script ajudou a causar (2026-09-12)
`FALTA.status()` do usuário: `atual: "43/73"`, `erros: 101`, `feito: 0`,
`fase: "baixando"`.
Três leituras, em ordem de importância:
1. **`feito: 0` no item 43** — `10993` e `10995` são os itens 1 e 2 da lista e
baixaram com sucesso às 22:52; nesta passada **falharam**. Mesma URL, uma hora
depois. Logo **não é URL errada, é a origem recusando**.
2. **`erros: 101` com `atual: 43/73`** — mais erros que itens tentados só é
possível com **dois ou mais loops concorrentes** somando no mesmo `S`. Cada
`iniciar()`/`retomar()` sobre um script já rodando cria outro loop. Isso
quebrou a pausa de 3 s combinada com a BN e provavelmente disparou rate-limit.
3. `total: 73` (e não 71) — o `FEITOS` foi lido vazio na largada dessa passada.
**Hipóteses mortas** (não perder tempo com elas de novo):
- *Sequência errada no `preservation_url`*: os 2 que funcionaram têm exatamente
a mesma forma dos 13 "divergentes" (catálogo `seq=1`, thumb em `seq=3`), e 58
dos 71 têm `seq` coerente com o thumb e falham igual.
- *Bloqueio geral do Cloudflare*: **71/71 desses itens têm thumb baixado com
sucesso** — o item responde; só o bitstream de preservação não.
**`pipeline/baixar-faltantes-v2.js`** corrige os defeitos da v1 (que eram meus):
guarda contra `iniciar()` duplo, **aborta depois de 5 erros seguidos** em vez de
moer os 71 com 60 s cada, pausa de 5 s, backoff de 30 s, e registra o código HTTP
separado (`FALTA.resumo()` devolve a tabela de códigos). Recarregar a aba antes
de colar — `parar()` não alcança closures de colagens anteriores.
- [x] **Thumbnails** — ✅ concluído 100% (13.059/13.059). `retomar()` já foi rodado uma vez (08h local); **não re-rodar**.
- [x] **Fase 4 (legado objdigital)** — ✅ concluído (2ª passada terminou): 2.137 ok / 565 erro (2.702/2.707 processados; os 565 são 404 permanentes confirmados via curl direto, atrito real da fonte legada, não bug). Confirmado em 2026-09-11 ~20h UTC: `select erro,count(*)` devolve **só `HTTP 404` (565)** — nenhum `HTTP 0` restante, então a 3ª passada não tem o que reprocessar; **não reiniciar de novo**.
- [x] ~~`subidor.py`~~ **substituído pelo `subidor-paralelo.py` em 2026-09-12 (achado 2.22); o texto a seguir é histórico.** (`pipeline/`, `--vigiar`, PID 97295) — vivo há 1d8h, vigiando `~/Downloads`. **2026-09-11 ~20h UTC**: fila local de **19.897 arquivos `BRAS__` / ~77 GB** (12.511 thumb, 1.660 `__imagem`, 5.726 com nome original). Bucket: 33.388 objetos / 60,3 GB, 8.080 itens com `metadata.json` (61,9% dos 13.059). **2026-09-12 09:45 UTC**: 16.207 enviados, fila de 18.286. Taxa nas horas acordadas ≈ **650–740 arq/h ≈ 2,0–2,4 GB/h**.
⚠️ **O relógio é de horas ACORDADAS, não de horas corridas.** Os envios pararam
às 22:30 UTC de 11/set e só voltaram às 09:00 UTC de 12/set — **10,5 h de
silêncio**, que é a máquina dormindo (00:30–11:00 local), não falha do subidor
(o processo seguiu vivo e voltou sozinho). Por isso:
- fila de 18.286 ÷ ~700 arq/h = **~26 h de máquina acordada**
- em dias normais (~14 h acordado), isso vira **~2 dias de calendário**
- com `caffeinate -is` segurando a máquina acordada, ~26 h corridas
Vale decidir isso conscientemente: é a diferença entre terminar em ~1 dia ou ~2.
### Achado 2.15 — aba do coletor inalcançável, e storage da origem aparece vazio (2026-09-11 ~20h UTC)
Tentativa de retomar a trilha 1 sozinho falhou, mas rendeu dois fatos novos:
1. Sobraram instâncias **headless do Chrome** de uma sessão anterior, uma delas
lançada com o **perfil padrão** (`--user-data-dir` default). Mortas (PIDs
89329, 89327, 14818); o Chrome real do usuário (PID 57263, aberto desde
9/set) foi preservado. **Nunca subir headless sem `--user-data-dir` próprio**
— disputa o perfil onde mora todo o estado do coletor.
2. Numa aba nova em `https://brasilianafotografica.bn.gov.br` (mesmo perfil,
mesma origem), `localStorage` devolve **0 chaves** e `indexedDB.databases()`
devolve **[]** — enquanto `ler-localstorage.js`, lendo o leveldb do disco do
mesmo perfil/origem, devolve `bras_baixados: 12.974`. Ou seja: o contexto vivo
e o disco discordam. Não dá pra `BAIXA.retomar()` numa aba nova: sem o
IndexedDB `bras`, `alvos()` devolveria `[]`.
**Não colar `baixador-navegador.js` numa aba nesse estado**: se o storage
estiver mesmo zerado, `FEITOS` começa vazio e a fila vira os ~13 mil itens
inteiros de novo (centenas de GB, e carga indevida na fonte). O caminho seguro
é o usuário voltar na **aba original do coletor** (a que já tem `BAIXA` no
`window`) e rodar `BAIXA.status()` / `BAIXA.retomar()` lá.
### Achado 2.16 — `bras_baixados` anda PRA TRÁS; não usar como medida (2026-09-11 20:45 UTC)
O contador caiu de **12.974 → 12.111** entre 20:14 e 20:43 UTC (três leituras
seguidas devolvem 12.111; o leveldb foi escrito pelo Chrome às 22:24 local, 19
min antes da leitura — é gravação real, não cache velho).
Causa provável: `marcar()` reescreve o **array inteiro** a partir do `FEITOS`
carregado quando o script foi colado. Qualquer aba com snapshot velho que ainda
marque um item sobrescreve a lista boa por uma mais curta. Com duas abas vivas
(v1 e v2 conviveram), a lista é sempre a do último escritor, não a união.
**Consequência prática**: `bras_baixados` **não** mede progresso — subestima. A
medida autoritativa é *bucket ∪ fila local em `~/Downloads`*:
```
# handles com preservação no bucket (do aws s3 ls --recursive)
awk '... itens/<handle>/<arquivo!=metadata.json, sem "thumb">' → 8.080
# handles de preservação ainda na fila local
ls ~/Downloads | grep '^BRAS__' | grep -v thumb | sed -E 's/^BRAS__(.+)__.*/\1/' → 7.271
# união → 12.986 de 13.059 (faltam 73, listados em pipeline/faltantes-preservacao.jsonl)
```
Isso também refaz a conta do achado 2.15: o risco de recolar o script não é
"85 itens", é **re-baixar ~950+** que o contador esqueceu (ou tudo, se o
storage estiver mesmo zerado).
## Concluído agora
- [x] **Thumbnails contaminados com bitstream de LICENÇA** (achado 2.8b): 2.653 arquivos locais apagados de `~/Downloads`, 146 já subidos removidos do bucket, `subidor.py` blindado com validação de magic bytes (rejeita e apaga automaticamente qualquer coisa que não comece com JPEG/PNG, mesmo que o nome diga o contrário). `baixador-thumb.js` v2 escrito com validação + fallback — falta só reconectar o navegador pra trocar o script rodando.
- [x] **WordPress → .md**: 636/637 posts colhidos (1 erro), exportados e convertidos — `wordpress/{id}-{slug}.md` no repo (front-matter YAML: id/url/título/autor/data/categorias/handles referenciados) + `wordpress-posts.jsonl` e a pasta `wordpress/` subindo pro bucket agora.
- [x] **Bug de corrida em arquivo temporário**: `baixador.py` e `subidor.py` moram na mesma pasta e usavam o mesmo nome fixo (`.tmp/metadata.json`) — rodando ao mesmo tempo, um apagava o arquivo que o outro tinha acabado de criar. Derrubou o `baixador.py` de verdade (crash, não só log de erro). Corrigido: nome agora inclui o PID. 3 itens (`1081,1082,1084`) já tinham subido um HTML de visualizador como se fosse "legado" antes da correção — limpo do bucket, metadata regenerado.
- [x] **PDFs de álbum perdidos no objdigital**: 44 itens (achado 2.9 do PLANO.md) tinham PDF disponível mas a extração pegava um `.htm` de landing page em vez do PDF de verdade. Corrigido em `catalogo.jsonl` e no IndexedDB antes do `baixador.py --somente-legado` alcançar esses handles (confirmado: nada contaminado no bucket). `baixador.py` reiniciado (PID 37909) com o catálogo corrigido.
## Concluído nesta sessão (chrome-extension-connection, ~17h UTC)
- [x] `pipeline/reparo-hash-url.js` colado e rodado — 78/78 corrigidos no IndexedDB
- [x] **Achado 2.13 (novo)**: mesmo bug do `#` reaparecia no redirect do DSpace (forma antiga → canônica). Fix: usar `/bitstream/handle/PREFIX/ID/arquivo` direto. `preservation_url` dos 78 reescrito de novo com a forma canônica.
- [x] Os 78 itens baixados cirurgicamente — **concluído 78/78, 0 erros** (script à parte, não o `BAIXA.retomar()` geral — aba antiga com o loop principal continua rodando sozinha, ver nota de handoff acima)
- [x] `BAIXA_THUMB` v2 iniciado (aba nova, não foi possível parar a v1 na aba antiga — ver nota acima; sem risco de dado ruim no bucket graças à validação de magic bytes já no `subidor.py`)
- [x] **Thumbnails v2: CONCLUÍDO 100%** — `BAIXA_THUMB.retomar()` rodado (2026-09-11 ~08h local) recuperou todos os 1.281 erros da queda de rede (13.059/13.059 ok, 0 erro permanente)
- [x] `baixador.py --somente-legado` reiniciado uma vez (2026-09-11 ~08h local, PID 88387) depois que a passada anterior terminou (2.113 ok, 589 erro de 2.702 processados) — idempotente, só reprocessa não-'ok'
- [x] Checagem de status a cada 30 min retomada nesta sessão (ver `/loop`)
## Mural (`web/wall.html`) — sessão `fix-mobile-wall-click-layout`, 2026-09-12
No ar em <https://xn--2dk.xyz/brasiliana/>. Commits em `rafapolo/xyz`:
`d8c3364` e `a6085fa` (empurrados pela sessão paralela `brasiliano-ae`, contêm
trabalho das duas) e `f645008`. O mural é publicado copiando
`web/wall.html` → `xyz/brasiliana/index.html` e `web/atlas/atlas-map.json` →
`xyz/brasiliana/atlas/atlas-map.json`.
### Achado 3.1 — a metade descritiva do catálogo nunca chegou ao mural
Buscar "indigenista" não achava nada, mesmo com 42 peças classificadas
`dc.subject = Política indigenista`. A busca livre estava certa (varre todo o
`meta` recursivamente); quem descartava era o **`summarize()` do
`web/build-atlas.js`**, que projetava 8 campos e jogava fora assunto,
descrição, lugar, fonte, editor, relação e código de arquivo.
Havia um segundo bug atrás: `pickDC()` devolve só a **primeira** ocorrência do
campo. Como o catálogo repete `dc.subject` (78.835 linhas para 13.060
registros, ~6 por item), mesmo incluindo o campo sobreviveria um assunto por
peça. O `pickAll()` novo coleta todas, deduplicadas, na ordem.
Regras que ficaram (espelhadas em `pipeline/reprojeta-meta-mapa.mjs`):
- entram: `dc.subject`, `dc.description`, `dc.coverage`, `dc.source`,
`dc.publisher`, `dc.relation`, `dc.identifier`
- ficam de fora: `dc.language` (é sempre `"por"` — casaria ~2.000 itens por
acidente, já que a busca é por substring) e `dc.format` (`"JPG"`)
- `dc.identifier` e `dc.relation` entram **sem as URLs**: era 1,1 MB de texto
que ninguém busca, escondendo o que presta — os códigos de arquivo
(`013RJ012036`) e os nomes de coleção (`Gilberto Ferrez`, `Diários
Associados`)
- `handle` e `source_url` **saíram** do `meta`: o primeiro é a chave sob a qual
o item já está arquivado no mapa, o segundo é o mesmo endereço para todos com
o handle no meio. O mural remonta a URL numa linha (`sourceUrl()`) e injeta o
handle na palha da busca, então buscar `5546` continua achando a peça.
Verificado no navegador: `indigenista` → 42, `Gilberto Ferrez` → 2.120,
`013RJ012036` → 2, `amazônia` → 156, `5546` → 1. E o ruído sumiu: `show=full`
e `brasilianafotografica` saíram de 12.552 para 0.
### Achado 3.2 — não vale pré-comprimir o `atlas-map.json`
Medido, não chutado:
- **No fio já vem gzipado.** `curl -sI` em <https://xn--2dk.xyz/brasiliana/atlas/atlas-map.json>
responde `content-encoding: gzip`. Pré-comprimir só moveria os mesmos bytes,
ao custo de um `DecompressionStream` no carregador e de um arquivo ilegível.
(O host não oferece brotli, e `DecompressionStream` não decodifica brotli.)
- **No repositório também.** O git comprime todo blob com zlib no pack, então
um JSON de 8 MB não ocupa 8 MB lá dentro — ocupa aproximadamente o que o
`.gz` ocuparia, e ainda dá diff.
Encolher o **conteúdo** foi o que valeu, e só até certo ponto — o gzip come
quase todo o ganho estrutural:
| variante | cru | gzip |
|---|---|---|
| com os campos descritivos | 9,61 MB | 1,11 MB |
| **sem `source_url` e `meta.handle`** (feito) | **8,00 MB** | **1,05 MB** |
| + dicionário nos campos de vocabulário pequeno | 6,96 MB | 0,99 MB |
| + dicionário de assuntos/lugares/descrições | 5,14 MB | 0,93 MB |
As duas últimas linhas quase dobram a economia crua e rendem 30-60 KB no fio
cada, em troca de uma camada de dicionário no carregador — troca ruim. Onde o
tamanho cru ainda pesa é o `JSON.parse` no celular, não o download. Referência:
antes de tudo isso o mapa era 5,52 MB / 0,73 MB.
### Consertos de interação (todos verificados por CDP num Chrome real)
- **Toque numa peça abria e fechava a ficha no mesmo gesto** (metade de cima da
tela). Um toque dispara `pointerup` e depois um `click` de compatibilidade,
que caía no backdrop recém-aparecido; a guarda de 400 ms usava
`stopPropagation()`, que **não alcança listeners do mesmo nó** — e quem fecha
a ficha é um listener do próprio `#card-wrap`. Agora é
`stopImmediatePropagation()`.
- **Tela inicial "sem estilo"**: `#title-screen` era irmão flex do `<p>` e,
invisível, ainda tomava metade da linha; e a regra `#loading p` pegava também
o subtítulo, jogando-o em maiúsculas com tracking. Virou `position:absolute` e
`#loading-msg`.
- **Painel de filtros fugia do dedo** no arrasto da década: o chip do filtro
aparecia e inseria uma linha inteira acima do corpo; o badge de contagem
crescia o header. Chips agora só com o painel fechado, badge reserva a caixa
com `visibility`.
- **Movimento da parede**: a câmera mirava o *alvo* enquanto estava atrás dele
(inclinava a vista a cada arrasto — era isso que fazia a parede "nadar"); o
easing era fração por frame (a 120 Hz convergia 2× mais rápido que a 60).
Agora constante de tempo, `lookAt` removido, e soltar em movimento joga a
parede com desaceleração. Zoom do scroll virou multiplicativo.
- **Back/forward do navegador** andam pelas peças abertas, com `#handle` na URL
(link direto reabre a peça). Mudar um filtro recolhe a ficha com **um** passo
de histórico, mesmo com `apply()` rodando a cada frame do slider.
- **Filtros alcançáveis com a peça aberta**: o painel estava em `z-index: 15`
debaixo do `#card-wrap` (20). Agora 25 (scrim 24), e no celular a ficha
estaciona acima do peek da sheet para não cobrir ‹ anterior / próxima ›.
### Achado 3.5 — o mural entrava em loop de carregamento no celular
Relato do usuário (14/09): no celular a tela inicial ficou em loop. Causa, lida
no carregador: o celular **decodificava cada página em 8192×8192** (~268 MB) e
só então reduzia para 4096 num canvas, retendo os canvases além das texturas —
pico de ~800 MB. O iOS não lança erro por falta de memória: mata a aba e a
**recarrega sozinho**, e a página recomeçava o mesmo carregamento. Não havia
tratamento de erro nenhum: fetch falho ou decodificação recusada deixavam a
barra parada para sempre.
Correção (commit `xyz` e `brasiliano` de 14/09):
- **Páginas leves** `atlas-m-0..3.webp` (3072², peça de 48 px), geradas pelo
`build-atlas.js` (`--so-mobile` regera só elas) e registradas em
`atlas-map.json` no campo `mobile`. Mesma posição de cada peça, então a conta de
uv não muda. 6,8 MB no total contra 42 MB; 36 MB decodificados por página.
- **Modo leve** em toque, `maxTextureSize` < 8192 ou `deviceMemory` ≤ 4, ou
forçado com `localStorage.mural_leve = '1'`.
- **Guarda contra loop**: marca `mural_carregando` em `sessionStorage` antes da
parte pesada, apagada só depois de dois quadros renderizados. Se a página abre
com a marca, a tentativa anterior morreu → vai direto para o modo leve e
mostra "modo leve — a tentativa anterior não terminou".
- **Nunca recarrega sozinho**: HTTP de erro, decodificação recusada e
`webglcontextlost` mostram aviso com botão "tentar de novo" (que recarrega uma
vez, já no modo leve). Progresso parado por 30 s mostra "o carregamento parou
de avançar" sem derrubar o que ainda pode estar vivo.
Verificado com Chrome real via `puppeteer-core` (perfil próprio, WebGL
swiftshader), emulando celular com toque — roteiros em
`scratchpad/teste-mural/testa.mjs` e `testa2.mjs`:
| cenário | resultado |
|---|---|
| A — celular carrega | só as 4 páginas leves, capa some em 8,3 s, marca apagada |
| C — marca de crash no desktop | aviso de modo leve, nenhuma página pesada, sem recarga |
| D — página falha no download | aviso com botão, **nenhuma recarga em 10 s** |
| E — botão tentar de novo | recarrega uma vez, termina no modo leve, sem 2ª recarga |
| F — perda de contexto WebGL | aviso com botão, sem recarga |
| G — download travado | aviso "parou de avançar" em 33 s, sem recarga |
**Verificado em produção** (14/09, após o deploy do GitHub Pages levar 62 s):
o cenário A contra `https://xn--2dk.xyz/brasiliana/` baixou só as 4 páginas
leves, a capa sumiu em 9 s pela rede real, sem falha, e a marca foi apagada.
O card no modo leve recorta a peça certa: a mesma peça tirada do atlas normal e
do leve difere 4/255 em média; a vizinha, 41,5/255.
**Limite do teste**: não há iPhone de verdade aqui — o limite de memória do iOS
não se emula no Chrome. O que está provado é que o celular não decodifica mais
8192² e que nenhum caminho de falha recarrega sozinho.
**Armadilha de teste**: `framenavigated` do Puppeteer conta a `about:blank`
inicial e mudanças de histórico do mural, então contar navegações dá falso
positivo de recarga. Usar uma marca em `window`, que só some numa recarga real.
## Miniaturas derivadas + reconciliação do ledger — 2026-09-12
Mural no ar com **13.059 peças** (antes 12.552): commits `bba32f6`,
`6a82a5e`, `1ecded1` e `e930158` em `rafapolo/xyz`. Desta vez o `atlas/` inteiro foi junto, não só o
`atlas-map.json` — o formato do map mudou (ver achado 3.4).
**Números fechados em 13/09 (medidos contra catálogo × ledger):**
| | |
|---|--:|
| itens no catálogo | 13.060 |
| com imagem de preservação | 12.991 |
| com thumbnail do DSpace | 13.059 |
| com miniatura derivada (`derivados/thumb256/`) | 13.059 |
| **no mural** | **13.059** |
| fora do mural | **1** — só `7523` |
Os 8 que faltavam (`7802`, `7814`, `7817`, `7848`, `7852`, `7861`, `7875`,
`8075`) entraram: eles **têm** `thumbnail/thumb_3.jpg` de imagem real no
bucket (109–250 KB). A afirmação anterior de que o thumbnail deles era texto
de licença estava errada — o texto era o `thumb_2` do material antigo do
finland, não o objeto do bucket.
Os 73 faltantes de preservação (achado 2.17/2.18) **não** ficam de fora do
mural: têm thumbnail do DSpace, que basta para o tile de 128px. Faltar
preservação e faltar no mural são coisas diferentes.
- [x] **Miniaturas derivadas — 13.051 itens (99,93%)**
em `s3://brasiliana/derivados/thumb256/` (256px WebP q80, ~8 KB cada,
100 MB no total). Prefixo `derivados/` deliberadamente fora de `itens/`:
`itens/` é material de origem, `derivados/` é reconstruível do zero.
Misturar os dois apagaria a procedência que o MANIFEST garante.
Composição final (medida, igual à do MANIFEST): **12.849 derivadas da
imagem de preservação** + **202 derivadas do `thumbnail/` do DSpace**
(itens com miniatura mas sem preservação coletada). Caminho até lá:
6.338 no finland a partir do bucket, 6.483 locais a partir de
`~/Downloads`, 164 do DSpace, e +66 do material do achado 2.21.
- [x] **MANIFEST.md atualizado e subido** — seção `derivados/`, os achados
2.19 e 2.20 abaixo, e a nota de que `thumbnail/` do DSpace não é
miniatura (achado 3.3). Re-subido em 12/09 com 13.051 / 99,93%, os 9
ausentes nomeados e a divergência 13.058 × 13.060 anotada.
- [x] **`build-atlas.js` parou de descartar item sem título** — a guarda
`if (!o.title) continue` escondia do mural `11749` (Museu Aeroespacial) e
`6241` (Instituto Moreira Salles), que têm imagem; o card já cai pra
"(sem título)" sozinho. 12.983 → 12.985.
- [x] **Wordmark "Acervo Brasiliana" ganhou fundo preto** — só tinha
`text-shadow`, que some sobre peça clara, e peça clara é metade do
acervo. Mesmo preto da dica do rodapé.
- [x] **Rótulo de contagem deixou de dizer "no acervo"** — dizia
"N peças no acervo" como se o mural fosse o acervo inteiro; agora diz
"peças com imagem". Foi essa frase que levantou a dúvida de que faltavam
miniaturas.
- [x] **`web/build-atlas.js` ganhou `--thumbs=DIR`** — a fonte antiga
(`~/Downloads`) é varrida pelo `subidor.py` conforme sobe, então nunca
tem o acervo inteiro ao mesmo tempo. Agora a fonte é reconstruível do
bucket.
- [x] **Ledger `subidor.sqlite` reconciliado com o bucket**: 28.553 linhas =
28.553 objetos, zero divergência nos dois sentidos. Backups em
`/private/tmp/claude-501/.../scratchpad/subidor.sqlite.bak-*`.
- 145 linhas de `thumbnail` sem objeto no bucket — são os bitstreams de
LICENÇA do achado 2.8b, removidos do bucket mas deixados no ledger
(426–815 bytes, só **5 sha256 distintos** entre os 145). Apagadas.
- 3 objetos no bucket sem linha nenhuma — inseridos, sha256 recalculado
do próprio objeto.
- 2.137 objetos `legado/` que **nenhum** ledger de upload conhecia: o
`baixador.py` só anota no `baixador.sqlite`. Importados, para que
`subidor.sqlite` seja ledger único.
- 13.051 derivados registrados como `tipo='derivado-thumb256'`.
- 63 "órfãos" de preservação/thumbnail eram **falso positivo**: gravados
durante a própria listagem do bucket. Conferidos no S3, estão lá.
### Achado 2.24 — 16 threads estouram o OpenSSL do macOS (SIGSEGV)
O `subidor-paralelo.py` morreu com **segmentation fault** no arranque da
passada das 10:56 de 13/09, e por isso **nada subiu durante horas** (o
`vigia-30min` só tentaria de novo meia hora depois). O relatório do macOS
aponta a pilha dentro do `libcrypto`:
```
libcrypto.3.dylib ossl_x509_store_ctx_get_by_subject
libcrypto.3.dylib X509_STORE_CTX_get1_issuer
libssl.3.dylib ssl_verify_internal / tls_post_process_server_certificate
```
É corrida de thread na verificação de certificado TLS quando muitas threads
fazem handshake ao mesmo tempo — bug do OpenSSL, não do nosso código. Com 4
threads subiu 50 arquivos a 19 GB/h sem problema. **Default baixado para 6
threads** no `subidor-paralelo.py`, no `vigia-30min.sh` e no
`rodar-paralelo.sh`. Não vale voltar a subir: acima de ~8 o ganho é nulo (o
link satura) e o risco de crash volta.
### Achado 2.25 — 75 itens com HTTP 500 persistente na origem (não é só o 7523)
Passada de 13/09 com a aba conectada: **108 imagens novas baixaram**, e **74
falharam com erro que não passa** — 45 × HTTP 500, 26 de rede e 3 de blob
curto, com retry sem recuperar nenhuma. Somando o `7523`, são **75 itens**
cujos bitstreams de preservação a origem não serve. Lista em
`pipeline/falhas-500-2026-09-13.txt`.
Isso substitui o achado 2.23 (que falava em 211 faltantes): os outros 136
baixaram. Nenhum dos 75 fica fora do mural — todos têm thumbnail do DSpace.
Diagnóstico que vale registrar: os 500 são **do item, não do ritmo**. Com 3
requisições simultâneas, `6545` e `6555` davam 500 enquanto `1014`, `8128`,
`10039`, `14358` e `6520` davam 200 no mesmo instante, inclusive em série com
3 s de espaçamento. E os itens ruins são vizinhos de id, então em ordem
crescente eles davam erros seguidos e disparavam o aborto automático — por
isso o motor passou a **embaralhar** a lista.
### Achado 2.26 — nova rodada sobre os 75 (13/09 noite): o que recupera e a armadilha da sequência
**Recuperados (3):** `6433` e `6520` por curl — a origem serve a ~11 KB/s, e o
"erro de rede" do navegador era estouro de tempo; `6656` no navegador na
**sequência 3** (5,4 MB, 1604×2612) — o catálogo apontava a sequência 2, que é
o texto de licença.
**Curl não escala:** depois dos 2 primeiros o Cloudflare devolveu `403`
(5.484 bytes) para 23 seguidos. Parado para não piorar o bloqueio.
**Armadilha — não aceitar "qualquer imagem em qualquer sequência".** A 1ª
versão do motor que varria as sequências 1–6 trouxe 8 "sucessos"; **7 eram o
`thumbnail/thumb_3.jpg` que já estava no bucket** (sha256 idêntico, 27–170 KB,
~800 px). Retidos antes de subir e descartados. A estrutura típica de um item
DSpace deste acervo:
| sequência | conteúdo |
|--:|---|
| 1 | imagem de preservação (nos itens com defeito: `HTTP 500`) |
| 2 | bitstream de licença (texto, 426–821 bytes) |
| 3 | thumbnail gerado pelo DSpace |
| 4–6 | inexistente |
A versão corrigida calcula SHA-256 no navegador e rejeita qualquer candidato
cujo hash já esteja no ledger como `thumbnail` ou `legado`, e grava com prefixo
`HOLD__` (o `subidor-paralelo.py` ignora) para conferência antes de subir.
### Achado 2.27 — os itens do IMS morrem num corte de 300 s; o `500` é o mesmo por sequência e por nome
Terceira rodada sobre os 75 (13/09, 21h), com um motor que registra o tempo de
cada tentativa. Três comportamentos distintos, todos da origem:
- **Corte em ~300 s sem resposta** (`rede@301s`), em 12 itens do Instituto
Moreira Salles (`8145`–`8316`). A requisição não recebe nem cabeçalho: um
teste com `Range: bytes=0-1023` estourou 18 s sem resposta, então não é
transferência lenta que cai no meio — o servidor trava antes de responder e
algo no caminho corta em 5 min. Retomar em pedaços não ajuda.
- **Corte em ~32 s** em 3 itens (`8271`, `8275`, `8277`): mesma família, limite
diferente.
- **`500` imediato** (0 s) em 11 itens (`8739`–`9148`). A forma canônica
`/bitstream/handle/20.500.12156.1/<id>/<arquivo>` — que busca pelo nome em
vez da sequência — **também devolve `500` em 0,2 s** (`8739`, `6545`). O
defeito está no servidor localizar o bitstream, não no endereçamento.
Estrutura das sequências nos itens do IMS: **1 = preservação, 2 = thumbnail**
(sem bitstream de licença, ao contrário dos do Museu Aeroespacial/Arquivo
Nacional/Fiocruz, onde 2 é licença e 3 é thumbnail). Varrer 1–6 nesses itens só
gasta tempo: 3–6 não existem.
Recuperado nesta rodada: `8396` (Biblioteca Nacional, sequência 3, 13,5 MB,
3361×4453) — mesmo padrão de `6656` e `7939`, onde o catálogo aponta a
sequência 2 (licença) e a imagem está na 3.
### Achado 2.28 — a cópia legada: só existe para a Biblioteca Nacional, e 25 "cópias" são páginas HTML
Medido em 14/09. A cópia legada vem do `objdigital.bn.br` e **só existe para
itens da Biblioteca Nacional**: 2.702 dos 13.060 têm `legacy_url`, todos da BN.
Os 16% de cobertura não são falta — os outros 10.358 itens não têm cópia legada
na origem.
| | |
|---|--:|
| elegíveis (`legacy_url` no catálogo) | 2.702 |
| no bucket como `legado/` | 2.137 |
| — imagens JPG | 1.899 (859 MB) |
| — PDF de álbum | 213 (8,3 GB) |
| — **páginas HTML** | **25** (~2,4 KB cada) |
| HTTP 404 permanente | 565 (499 jpg, 41 html, 22 pdf, 2 htm, 1 sid) |
**As 25 páginas HTML não são imagem.** São o visualizador Seadragon do
objdigital (`viewer.openDzi("GeneratedImages/dzc_output.xml")`): a imagem mora
numa pirâmide de tiles Deep Zoom ao lado da página. Itens: `586`, `587`, `630`,
`802`–`806`, `808`, `809`, `811`, `812`, `814`, `816`, `817`, `870`, `1080`,
`1083`, `1085`, `1086`, `3198`, `3545`, `3546`, `3866`, `6655`. **Todos têm
imagem de preservação no bucket**, então nenhum ficou sem imagem. Não foram
apagados — é decisão do usuário (ver pendência). Mesma família do bug de
`1081`/`1082`/`1084` (HTML de visualizador subido como legado), que foi limpo
na época; estes 25 escaparam.
**O objdigital não saiu do ar — mudou de endereço.** Em 14/09 a porta 80
fechou nos dois IPs (`200.9.175.46`, `177.223.196.160`), mas a 443 está aberta
e o site responde em **`https://objdigital.bn.br/objdigital2/acervo_digital/...`**
(o próprio visualizador Seadragon carrega o script desse prefixo). Prova de que
é a mesma fonte: 3 cópias legadas sorteadas do bucket, baixadas pelo endereço
novo, voltaram com **sha256 idêntico**. Correção de uma afirmação anterior
desta sessão: o `icon573843.jpg` usado como "controle" **não** tinha baixado
antes — ele é um dos 565 erros (item `10`), e responde `200` no endereço novo.
Consequência: **a maior parte dos 565 "404 permanentes" existe no endereço
novo.** Sondagem completa por `HEAD` em 14/09 (`pipeline/legado-caminho-novo.tsv`):
| no endereço novo | itens |
|---|--:|
| `200` com `image/jpeg` | 330 |
| `200` com `application/pdf` | 18 (o maior, 52 MB) |
| `200` com `text/html` (visualizador Deep Zoom, não arquivo) | 41 |
| `404` de verdade | 176 |
Recuperáveis como arquivo: **348** (~0,3 GB). As 41 páginas HTML somam-se às 25
já no bucket: **66 itens** cuja imagem só existe como pirâmide de tiles. A pirâmide Deep Zoom das 25 páginas HTML
também responde (item `3545`: `dzc_output.xml`, 5744×4245, tiles de 256 px).
**O `baixador.py` usa o endereço antigo (`http://…/acervo_digital/`) e precisa
ser atualizado antes de qualquer nova passada.
### Achado 2.22 — o gargalo do upload era o `subidor.py`, não o link; troca pelo paralelo
Eu tinha escrito aqui que o gargalo era o link de casa. **Errado.** Medido em
12/09 (`networkQuality`): **69 Mbps de upload (~31 GB/h)**, contra ~1,3 GB/h
reais. O `subidor.py` sobe um arquivo por vez, espera 1,5 s de "estabilidade" e
dispara **três** `aws s3 cp` por arquivo (arquivo, `metadata.json`, manifest),
cada um pagando a partida do aws-cli: ~5 s por arquivo, seja miniatura de 74 KB
ou preservação de 40 MB.
Além de lento, ele estava estragando duas coisas:
- **873 manifests com linha errada**, `derivado-thumb256/<handle>.webp`. É
consequência de eu ter registrado os derivados no ledger: ele lista toda
linha do handle, e esse caminho não existe em `itens/<handle>/`.
- **Duplicatas `(N)` voltando ao bucket** depois da limpeza do achado 2.20
(ex.: `5304`, `thumb_2.jpg` e `thumb_2 (1).jpg` com o mesmo sha256).
Substituto: `pipeline/subidor-paralelo.py` (boto3, threads, HEAD antes de apagar
o local, manifest uma vez por item, sem linha de derivado, duplicata e rejeito
registrados) + `pipeline/rodar-paralelo.sh`. Teste com boto3 contra o bucket:
PUT de 20 MB a 27 Mbps num único stream.
Testes antes de soltar, com o que cada um mostrou:
1. Lote de 30: todos eram rebaixa já presente no bucket e foram **apagados do
disco sem HEAD e sem registro**. Foi o que motivou a conferência por HEAD e a
tabela `descartados`. Para esses 30, a garantia é só o ledger, reconciliado
com o bucket às 12:50.
2. Lote de 150: 150 descartes, 150 conferidos no bucket.
3. Lote de 800: 319 enviados (319 conferidos, `image/jpeg`) + 481 descartes
conferidos; manifests dos 319 sem linha de derivado, sha do metadata batendo.
4. Primeira execução real (18:4x UTC) **interrompida**: o log mostrava TIFF
indo para `rejeitados/` (achado 2.19, correção). Assinaturas corrigidas; os 21
da quarentena (19 TIFF + 2 BMP) voltaram para a fila; relançado às 18:59.
Antes do relançamento, **180 arquivos locais (0,25 GB) já presentes no S3** foram
apagados do disco a pedido, cada um com MD5 local = ETag do objeto e registro em
`descartados`. Os outros 13.922 não estavam no bucket.
### Achado 2.23 — faltam 211 preservações depois da fila, não 73
Cruzando catálogo × (ledger ∪ fila) em 12/09: **12.849 / 13.060** itens terão
imagem de preservação quando a fila acabar (thumbnail: 13.059). Os 211:
- **71** da lista conhecida (`faltantes-preservacao.jsonl`, recusa da origem);
- **1** sem `preservation_url` no catálogo;
- **139** fora de qualquer lista. Exemplo: `10039`–`10049`, que no bucket têm só
`thumbnail/` e `metadata.json`. Desses: 8 rejeitados no upload antigo, 12 com só
`legado/`, ~119 sem rastro (nem bucket, nem fila, nem log).
Hipóteses, nenhuma confirmada: (a) o "12.986/13.059" do achado 2.16 contou
objetos `legado/` e `manifest` como preservação, porque o `awk` só excluía
`metadata.json` e thumbnail; (b) parte dos ~119 pode ser TIFF apagado pelo
`subidor.py` antigo antes do trecho que o `subidor.log` cobre.
### Achado 2.21 — a sessão de 11/09 já tinha as miniaturas no finland, e eu não olhei
`/root/brasiliana-wall/` no finland tinha, desde 11/09 13:17–13:41:
`downloads-flat/` (20.411 arquivos, todos `THUMB__`, 2,2 GB), `s3-thumbs/`
(5.168 handles do bucket, 851 MB) e o `web/atlas/` cujos quatro `.webp` batem
byte a byte com o que estava publicado no `xyz` até 12/09. **O mural de 12.552
peças foi construído lá**, a partir das miniaturas do DSpace — não de
`~/Downloads`, como o comentário do `build-atlas.js` leva a crer.
A união desses dois diretórios cobre **13.041 handles**, praticamente todos
JPEG válido. Eu puxei ~63 GB de imagens de preservação do bucket para derivar
12.985 miniaturas sem ver que 3 GB de miniatura já estavam no disco da mesma
máquina, cobrindo mais itens que o meu resultado. Aproveitados depois: +66
peças (74 no delta, 8 eram licença).
**Lição de runbook**: antes de gerar qualquer coisa no finland, `ls /root` e
`cat /root/.bash_history`. Sessões anteriores deixam material lá e nada no
projeto local registra isso.
Limpeza feita em 12/09: `/root/brasiliana-wall` e `/root/thumbs` apagados
(3,4 GB; disco 27 → 31 GB livres), depois de verificar que os 13.041 handles
estavam **todos** cobertos pelo bucket (7.038) ou pela fila do Mac (6.785) —
zero cópias exclusivas. Ficaram de pé, de propósito: `/root/.s3env` (600, de
08/09, anterior às nossas sessões — pode ser setup permanente da máquina) e
`/root/brasiliana/` (44 MB, `baixador.py` + catálogo + sqlite com 13 linhas).
### Achado 2.19 — a contaminação de LICENÇA também atinge a preservação, não só a miniatura
O achado 2.8b tratou isso como problema da trilha de thumbnail. Não é: os
handles **`20.500.12156.1/6656`** e **`20.500.12156.1/7939`** têm, em
`~/Downloads`, um "imagem.jpg" que é na verdade o bitstream de LICENÇA do
DSpace — 777 bytes de texto UTF-8 com CRLF e extensão `.jpg`. A validação de
magic bytes do `subidor.py` barra no upload, então **nada disso chegou ao
bucket**; o efeito é que esses dois itens não têm imagem coletada e ninguém
percebeu, porque a fila local os contava como prontos.
Implicação: qualquer contagem de "preservação pronta" que leia `~/Downloads`
pelo nome do arquivo está 2 itens otimista. A contagem pelo bucket está certa.
**Atualização 12/09**: não são 2, são 10. Ao derivar as miniaturas do material
do finland (achado 2.21) apareceram mais **oito** com o mesmo defeito, todos
na trilha de thumbnail: `7802`, `7814`, `7817`, `7848`, `7852`, `7861`,
`7875`, `8075`. São exatamente os itens que sobram fora do mural. O bloco
`78xx` sugere que a contaminação vem em lote, por faixa de handle — vale
varrer essa faixa inteira antes de dar o acervo por fechado.
**Correção 12/09 (noite) — a regra de validação estava errada.** O `subidor.py`
só aceitava JPEG/PNG e **apagava** o resto como "bitstream de licença". Pelo
próprio `subidor.log`, dos **40** arquivos que ele apagou assim, **só 1 era
texto de licença**: 36 eram **TIFF** (`II*\0`, ~8 MB, com extensão `.jpg`),
2 **BMP** e 1 **ZIP** (`001AAN014011.jpg.zip`, item `2384`). Resultado, item a
item (lista com URL em `pipeline/apagados-pelo-subidor-antigo.jsonl`):
- **8 itens ficaram sem nenhuma imagem de preservação**: `14358`, `14359`,
`14360`, `14361`, `14362`, `14363`, `14364`, `14368` (TIFF, série "Alb 0261").
- **18 itens** perderam só bitstreams extras (`extra_seqN`, TIFF), mas têm a
imagem principal no bucket ou na fila. `10993`/`10995` (BMP) e `2384` (ZIP)
voltaram por rebaixa e estão na fila.
O `subidor-paralelo.py` aceita TIFF/BMP/GIF/JP2/WebP pela assinatura e manda
qualquer outra coisa para `pipeline/rejeitados/` com linha na tabela
`rejeitados` — nunca apaga. Os 8 casos `78xx` de thumbnail com texto de licença
(acima) foram detectados pelo `vipsthumbnail`, não por essa regra, e continuam
valendo.
### Achado 2.20 — 3.511 duplicatas `(N)` no bucket, do Chrome rebaixando por cima
Objetos `arquivo (1).jpg` convivendo com `arquivo.jpg` byte a byte idêntico —
sufixo que o Chrome põe ao rebaixar um arquivo que já existe em `~/Downloads`,
e que o `subidor.py` subiu como se fosse nome legítimo. Confirmadas idênticas
por **ETag + tamanho** (não só tamanho) antes de apagar: 3.511 objetos,
0,39 GB, removidos do bucket e do ledger na mesma passada.
**Não** foram tocados, e precisam de decisão:
- **30 objetos** cujo gêmeo tem tamanho **diferente** — não são duplicata,
são versões distintas do mesmo nome. Precisam de conferência individual.
- **43 objetos** cujo nome tem `(N)` mas que são o **único** arquivo do item —
candidatos a renomear, nunca a apagar.
`aws s3api list-objects-v2` com `--query "Contents[].[Key,Size,ETag]"` resolve
isso sem baixar nada; o ETag é o MD5 pra upload simples (só os 2.612 objetos
multipart do bucket não servem pra comparação direta).
### Achado 3.3 — o `thumbnail/` do DSpace não é uma miniatura
Medido em amostra de 300: **721 a 3.709 px no maior lado, média 1.087**; menor
lado nunca abaixo de 462. São derivados de resolução média, não miniaturas de
listagem. Duas consequências:
1. Servem tão bem quanto a imagem de preservação pro tile de 128px do mural —
por isso deu pra cobrir os 164 itens sem preservação sem perda visível.
2. A linha "Miniatura | ~13.005 elegíveis" do MANIFEST descreve ~1 MB por
arquivo, não ~8 KB. Quem ler esperando miniatura vai baixar 100x mais do
que imagina.
### Achado 3.4 — publicar o mural agora exige mandar o `atlas/` junto
O `wall.html` de 12:32 passou a derivar `handle` (chave do map) e `source_url`
(mesmo prefixo pra todo item) em JS, em vez de lê-los de cada peça. O
`summarize()` do `build-atlas.js` acompanhou. Resultado: **8,2 MB de map com
12.983 peças contra 10 MB com 12.552** — menos peso com 431 peças a mais.
Mas isso quebra a nota antiga de que "o `atlas/` já está commitado lá e não
muda a cada alteração do mural": map e `wall.html` agora são um par acoplado
por formato. Publicar um sem o outro deixa o mural sem link e sem busca por
handle.
## Pendente
- [ ] **`dc.rights` ausente em 5.833 itens (44,7%)** — confirmado como característica real da fonte, não bug. Só precisa ficar documentado no MANIFEST final, sem ação de reparo.
- [ ] **`web/build-atlas.js` não está versionado em lugar nenhum** — `brasiliano/` não é repo git e o `xyz` só recebe o `index.html` e o `atlas/`. A correção do `summarize()`/`pickAll()` (achado 3.1) vive só no disco desta máquina; um `rm` leva junto. Mesma exposição vale para `pipeline/` inteiro.
- [ ] **Encolher mais o `atlas-map.json` só com dicionário** (achado 3.2): 8,00 → 5,14 MB crus por ~120 KB no fio. Só vale se o `JSON.parse` no celular virar problema medido — não antes.
- [ ] **30 objetos `(N)` com tamanho diferente do gêmeo** (achado 2.20) — conferência individual, não dá pra automatizar com segurança.
- [ ] **43 objetos `(N)` que são o único arquivo do item** (achado 2.20) — renomear tirando o sufixo, pra o nome não mentir sobre haver um original ao lado.
- [ ] **Handles `6656` e `7939` sem imagem de preservação** (achado 2.19) — rebaixar; o que há hoje na fila local é o bitstream de licença.
- [ ] **Conferir os códigos HTTP que nunca foram tabulados** — o runbook do achado 2.18 manda rodar `FALTA.erros()` no console e rotear por código (404 → reparar URL, 403 → bloqueio de origem, 500 → transitório, retomar). **Esse passo nunca foi executado**: o achado 2.18 concluiu "é recusa da origem" a partir do `status()` agregado, não da tabela de erros por handle. Sem isso não dá pra saber quantos dos 71 são reparáveis.
- [ ] **Reconferir o handle `7523` (HTTP 500)** — registrado uma vez e tratado como falha permanente da origem desde então, mas 500 costuma ser transitório e nunca houve segunda tentativa. **Não dá pra testar por `curl`, e agora está provado com controle** (12/09): com User-Agent, Accept, Accept-Language e Referer de Chrome, o `7523` devolve `403` de 5.484 bytes (página do Cloudflare) — e o item `10`, que sabidamente funciona e está no bucket, devolve **exatamente o mesmo `403` de 5.484 bytes**. É bloqueio geral a requisição sem sessão real, nada específico do `7523`. Precisa da aba; a extensão Claude-in-Chrome seguia desconectada em duas tentativas no mesmo dia.
- [ ] **Reconciliar 13.058 vs 13.060** — o MANIFEST fala em 13.058 itens reais, o `catalogo.jsonl` tem 13.060 handles distintos. Diferença de 2 nunca explicada; anotada no MANIFEST como pendência.
- [ ] **Depois que os 212 faltantes baixarem e subirem** (pedido do usuário, 13/09):
1. conferir se **todos** os itens têm miniatura em `derivados/thumb256/` e gerar
as que faltarem (as novas preservações não têm derivado ainda);
2. **regerar o mural 3D** com o conjunto completo — de preferência derivando
no finland direto do bucket (`itens/*/preservacao/*`), que é tráfego
intra-Hetzner, em vez de puxar pro Mac;
3. republicar `wall.html` + `atlas/` no `rafapolo/xyz` (par acoplado, achado 3.4).
- [ ] **Quando o `rodar-paralelo.sh` terminar** (log termina em `===== ... FIM`):
1. conferir no log as três fases sem `!!!`, a linha `FIM da fila` (enviados,
duplicatas, rejeitados, falhas) e os `pendente:` que ficaram no disco;
2. `ls pipeline/rejeitados/` + `select * from rejeitados` — só deve ter texto
de licença; imagem ali é bug de assinatura;
3. reconciliar ledger × bucket (mesmo diff do achado de 12/09: 0 divergências
nos dois sentidos) e amostrar manifests (`grep derivado` = 0);
4. varrer `~/Downloads`: apagar o que tiver MD5 = ETag no bucket (mesmo
método dos 180 de 12/09), manter o resto;
5. atualizar a tabela de contagens do MANIFEST com os números fechados.
- [ ] **Rebaixar o que o `subidor.py` antigo apagou** (achado 2.19, correção): 8 itens sem preservação (`14358`–`14364`, `14368`) + ~20 `extra_seqN` em TIFF — lista com URL em `pipeline/apagados-pelo-subidor-antigo.jsonl`. Precisa da aba do navegador.
- [x] ~~Recontar os faltantes de preservação (211)~~ — feito em 13/09: 136 baixaram, sobraram **75** com defeito de origem (achado 2.25), listados em `pipeline/falhas-500-2026-09-13.txt`. Script usado: `pipeline/baixar-faltantes-v3.js` (ou o motor `F5` colado direto na aba).
- [ ] **`subidor.py` antigo: aposentar ou corrigir a regra de assinatura** antes de qualquer uso futuro — do jeito que está, apaga TIFF.
- [ ] **Rebaixar os 69 que sobraram** (achados 2.25–2.27; 6 recuperados em 13/09 à noite) quando a origem se recuperar — todos têm thumbnail, falta a preservação. Um `FALTA3.retomar()`/`F5.iniciar()` na aba basta; o que já baixou fica marcado no `localStorage` (`bras_faltantes_v3`).
- [ ] **Handle `8396` sem imagem e sem diagnóstico** — não está em `pipeline/faltantes-preservacao.jsonl` nem nas exceções conhecidas do MANIFEST; apareceu ao cruzar catálogo × miniaturas. Precisa de uma tentativa avulsa pra saber se é recusa da origem (achado 2.18) ou outra coisa.
- [ ] **`.git` do `rafapolo/xyz` está em 2,5 GB** e cada publicação do atlas soma ~51 MB permanentes (binário não faz delta). Se o mural for republicar atlas com frequência, tirar os `.webp` do git — LFS, ou servir do próprio bucket, que já tem os thumbs em `derivados/thumb256/`.
- [ ] **Crawl da Fase 1 pode ter mais buracos** (achado 2.10 do PLANO.md): 2 itens reais (`1799`, `4798`) foram achados faltando no catálogo só porque o WordPress os citava — já corrigidos, mas não existe verificação exaustiva de que a enumeração por `browse?type=title` pegou 100% de cada comunidade. Sem ideia barata de auditar isso por completo agora.
- [ ] **Baixar os 348 legados recuperáveis pelo endereço novo** (achado 2.28) — atualizar antes o `baixador.py` para `https://objdigital.bn.br/objdigital2/acervo_digital/`.
- [ ] **Decidir o que fazer com as 66 páginas HTML de visualizador** (25 já em `legado/` + 41 no endereço novo; achado 2.28): apagar do bucket e do ledger (não são imagem), ou montar a imagem a partir dos tiles Deep Zoom quando o objdigital voltar. Todos os 25 itens já têm preservação.
## Ao final (não fazer antes do download terminar)
- [x] Gerar `MANIFEST.md` (o que é, como foi coletado, quando) — feito; atualizado em 2026-09-12 com `derivados/` e os achados 2.19/2.20/3.3
- [ ] Confirmar no bucket que a contagem de itens/checksums bate com os 13.058 itens reais esperados
## Notas técnicas úteis pra retomar
- Downloads automáticos do Chrome exigem permissão manual em `chrome://settings/content/automaticDownloads` (site adicionado: `https://brasilianafotografica.bn.gov.br`) — já concedida, vale pra novos scripts também, não só o original.
- `BRAS`, `BAIXA`, `BAIXA_THUMB`, `BAIXA_EXTRA` — todos no `window` da mesma aba, mesmo IndexedDB (`bras`). Todos sobrevivem a fechar/reabrir a aba (dado fica salvo), mas o *loop* para e precisa recolar o script certo pra retomar.
- **Regerar as miniaturas derivadas** (tudo reconstruível, nada precisa ser
guardado): no finland, `apt install libvips-tools parallel` + s5cmd; pra cada
chave de `itens/*/preservacao/*`, `s5cmd cat` num tmp e
`vipsthumbnail "$TMP" --size 256 --output "$OUT[Q=80,strip]"`, com
`parallel -j 10`. ~640 thumbs/min, tráfego intra-Hetzner (bucket é `hel1`, o
finland também) — não passa pelo link de casa. O que ainda está só em
`~/Downloads` sai mais barato derivado localmente com `magick`: mandar os
71 GB pro finland custaria os mesmos dias do upload pendente.
- **Cuidado ao parsear `s5cmd ls`**: nomes de arquivo do acervo têm espaço
**duplo** (`48094 Álbum 311 - ...jpg`). `awk '{$1="";$2="";$3=""; print}'
recolapsa esses espaços e produz chaves que não existem — 31 downloads
falharam assim antes de eu perceber. Use
`sed -E 's|^[0-9/]+ +[0-9:]+ +[0-9]+ ||'`, que preserva o resto literal.
- **`sqlite3` desta máquina tem `.sqliterc` forçando modo box**: qualquer
script que leia a saída precisa de `sqlite3 -init /dev/null -noheader
-separator $'\t'`, senão vem borda de tabela no lugar dos dados (me custou
um diff inteiro de falso positivo).
- **`until ! pgrep -f X; do sleep; done` nunca termina**: a linha de comando do
próprio loop contém `X`, então o `pgrep -f` se acha e a condição nunca vira
falsa. Um loop desses ficou girando horas depois do trabalho acabar (12/09,
morto à mão). Esperar por PID (`while kill -0 $PID`) ou usar `pgrep -f
'[t]humb-local'` para o padrão não casar consigo mesmo.
- **Parar processo lançado em background: SIGTERM, não SIGINT.** Processo
iniciado com `&` num shell não interativo herda o SIGINT ignorado (o
`subidor.py` ficou 60 s vivo depois do `kill -INT`). Com SIGTERM, o `aws s3
cp` filho termina órfão, o que é inofensivo: sem linha no ledger e sem
apagar o local, o próximo uploader sobe de novo a mesma chave.
- **Upload de casa: 69 Mbps** (`networkQuality -s`, 12/09); download 312 Mbps.
- **Assinaturas aceitas como imagem** (`subidor-paralelo.py`): JPEG `FFD8`, PNG,
TIFF `II*\0`/`MM\0*`, GIF, JP2, BMP `BM`, WebP. Content-Type sai do conteúdo,
não da extensão (TIFF chega com nome `.jpg`).
- **`vipsthumbnail --output` é relativo à pasta do arquivo de entrada**, não ao
diretório corrente: `vipsthumbnail tmp/x.img --output out/y.webp` tenta
gravar em `tmp/out/y.webp` e falha. Usar caminho absoluto na saída. (Custou
uma miniatura "refeita" que não foi refeita, em 13/09.)
- Scripts-fonte em `pipeline/`: `coletor.js` / `coletor-resume.js` (metadados), `baixador-navegador.js` (preservação, todos os itens), `baixador-thumb.js` (miniaturas), `baixador-extras.js` (2a+ imagem de itens multi-bitstream), `reparo-multibitstream.js` (enumera bitstreams reais de um item).
+89
View File
@@ -0,0 +1,89 @@
# Tarefas abertas
Lista única do que falta fazer no projeto, atualizada em 2026-10-01. O que
está concluído fica no histórico: [`PLANO.md`](PLANO.md) (estado e §9 da
descrição NOBRADE), [`done/`](done/) (sessões anteriores, com os achados
citados abaixo) e [`../CONARQ.md`](../CONARQ.md) (decisões da norma).
Legenda de quem destrava cada uma: **você** = decisão ou ação do usuário ·
**aba** = precisa do Chrome com sessão real na Brasiliana · **servidor** =
roda no `finland` · **local** = roda nesta máquina.
## 1. Descrição arquivística (NOBRADE)
- [ ] **Enviar o pedido de código de entidade ao CONARQ** — *você*.
Rascunho com os 17 campos do formulário CODEARQ em
[`descricao/pedido-codigo-conarq.md`](../descricao/pedido-codigo-conarq.md);
os dados do requerente estão em `[[…]]`. Um acervo só de cópias pode não se
enquadrar no cadastro (ressalva anotada no rascunho).
- [ ] **Trocar o código provisório quando o CONARQ responder** — *local*.
`ENTIDADE` (`RJXYZ`) e `ENTIDADE_NOME` em `pipeline/nobrade/config.py`; depois
`cd pipeline && python3 -m nobrade && python3 -m nobrade.mural`, subir
`descricao/` de novo e republicar o mural (ver §2).
- [ ] **Revisar as 813 datas atribuídas pelo arquivista** — *você*.
`descricao/revisao/datas.tsv`, qualidade "atribuída pelo arquivista". A
maioria vem do período de atividade do autor ou do miolo das datas da série.
- [ ] **Revisar as 115 séries** — *você*. `descricao/revisao/series.tsv`.
Correções vão em `pipeline/nobrade/ajustes/series.tsv` (colunas
`instituicao`, `dc_source`, `titulo`) e prevalecem na próxima geração.
Atenção ao Museu Aeroespacial: 1.050 dos 1.143 itens caíram em Avulsos,
porque o `dc.source` dele só traz caixa/negativo.
- [ ] **Controlar o vocabulário dos assuntos** (8.1) — *você + local*. Hoje
segue o da origem; a norma pede vocabulário controlado com fonte validadora
(ex.: termos da Biblioteca Nacional). Baixa prioridade.
> **Regra:** toda vez que `python -m nobrade` rodar, `descricao/` precisa
> subir de novo para `s3://brasiliana/descricao/` (com `manifest-sha256.txt`),
> senão o bucket deixa de bater com o repositório.
## 2. Mural (`web/wall.html`)
- [ ] **`.git` do `rafapolo/xyz` em 2,5 GB** — *você*. Cada republicação dos
`.webp` do atlas soma ~51 MB permanentes. Se o atlas for regerado com
frequência, tirar os `.webp` do git (LFS ou servir do bucket). Publicar só
`index.html` + `atlas-map.json` não pesa.
- [ ] **Encolher o `atlas-map.json` com dicionário** (achado 3.2) — *local*.
Hoje 10,4 MB com os campos NOBRADE. Só vale se o `JSON.parse` no celular
virar problema medido.
- [ ] **Integrar o branch `feat/nobrade` ao `main`** — *você*. O mural
publicado já é o deste branch.
## 3. Acervo no bucket
- [ ] **9 matrizes com JPEG corrompido** — *aba*. Itens `6574`, `6969`,
`6975`, `6994`, `7153`, `7161`, `7169`, `7173`, `7203`: o arquivo de
preservação está inteiro (SHA-256 confere com o ledger) mas os dados JPEG
quebram (`Corrupt JPEG data: found marker 0xd9 instead of RST7`).
Rebaixar da origem para saber se o defeito é dela ou da coleta; se vier
bom, substituir e regerar as derivadas com `pipeline/deriva-acesso.py`
(hoje elas saem da imagem do DSpace).
- [ ] **Rebaixar os 69 itens sem preservação** — *aba*, quando a origem
voltar. A origem responde HTTP 500 ao bitstream (achados 2.25–2.27); todos
têm miniatura. `FALTA3.retomar()`/`F5.iniciar()` na aba basta; o progresso
fica em `bras_faltantes_v3`. Lista em [`../errors.md`](../errors.md).
- [ ] **30 arquivos `extra_seqN` apagados pelo `subidor.py` antigo**
(achado 2.19) — *aba*. Os 8 itens principais já têm preservação de novo;
estes extras (vários TIFF) não estão no ledger. Lista com URL em
`pipeline/apagados-pelo-subidor-antigo.jsonl`; enumerar item a item com
`reparo-multibitstream.js` antes de rebaixar.
- [ ] **Baixar os 348 legados recuperáveis pelo endereço novo** (achado
2.28) — *local*. Antes, apontar o `baixador.py` para
`https://objdigital.bn.br/objdigital2/acervo_digital/`.
- [ ] **Decidir o destino das 66 páginas HTML de visualizador** (achado 2.28)
— *você*. 25 já estão em `legado/` e 41 no endereço novo. Apagar do bucket e
do ledger (não são imagem), ou montar a imagem a partir dos tiles Deep Zoom
quando o objdigital voltar. Os 25 itens já têm preservação.
- [ ] **30 objetos `(N)` com tamanho diferente do gêmeo** (achado 2.20) —
*você*. São versões distintas, não duplicatas; conferência individual.
- [ ] **43 objetos `(N)` que são o único arquivo do item** (achado 2.20) —
*local*. Renomear tirando o sufixo, para o nome não sugerir um original ao
lado.
- [ ] **Conferir os checksums do bucket** — *servidor*. As contagens e os
tamanhos já batem com o ledger (2026-09-30); falta recalcular o SHA-256 de
uma amostra (ou de tudo, no `finland`) contra os `manifest-sha256.txt`.
- [ ] **Aposentar ou corrigir o `subidor.py` antigo** — *local*. A regra de
assinatura dele apaga TIFF; o que roda hoje é o `subidor-paralelo.py`.
- [ ] **Auditar se o crawl da Fase 1 deixou buracos** (achado 2.10) — sem
método barato ainda. Dois itens (`1799`, `4798`) só apareceram porque o blog
os citava.
File diff suppressed because one or more lines are too long
+709 -358
View File
File diff suppressed because it is too large Load Diff