Compare commits
10
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09f4568b5c | ||
|
|
da105a1a46 | ||
|
|
fd37348811 | ||
|
|
ff7dc3cf3f | ||
|
|
2667af317b | ||
|
|
dfb6362e30 | ||
|
|
f05cdc5b9d | ||
|
|
5c84619e5d | ||
|
|
23b56e8c87 | ||
|
|
e92df83a78 |
+11
@@ -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*
|
||||||
|
|||||||
@@ -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,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
@@ -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.
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
@@ -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.
|
||||||
@@ -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 |
|
||||||
@@ -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 ""
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||||
|
@@ -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).
|
||||||
@@ -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`).
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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/
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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/
|
||||||
@@ -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
|
||||||
@@ -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)
|
||||||
@@ -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`.
|
||||||
@@ -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())
|
||||||
@@ -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())
|
||||||
@@ -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]
|
||||||
@@ -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'
|
||||||
@@ -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))
|
||||||
@@ -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
|
||||||
@@ -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',
|
||||||
|
})
|
||||||
@@ -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
|
||||||
@@ -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()
|
||||||
@@ -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
|
||||||
@@ -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
@@ -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>
|
||||||
@@ -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>
|
||||||
|
<schema . . .>
|
||||||
|
. . .
|
||||||
|
<import namespace="http://www.w3.org/XML/1998/namespace"
|
||||||
|
schemaLocation="http://www.w3.org/2001/xml.xsd"/>
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
or
|
||||||
|
</p>
|
||||||
|
<pre>
|
||||||
|
<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>
|
||||||
|
<type . . .>
|
||||||
|
. . .
|
||||||
|
<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
@@ -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
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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).
|
||||||
@@ -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
+659
-350
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user