# BTB - Web service
Inicialmente só serão permitidas requests para a tela principal, ou seja, telas como subojeto não terão suas próprias requests. Elas poderão utilizar as requests da tela principal, porém não poderão ter requests exclusivas para os subobjetos, por exemplo.
## 1 Cadastro de requisição
### 1.1 DER

- Criar tabela de request
```sql=
CREATE TABLE request (
id UUID NOT NULL,
remote_request_id UUID NOT NULL,
meta_screen_id UUID NOT NULL,
nickname VARCHAR(255),
CONSTRAINT pk_request PRIMARY KEY(id)
);
ALTER TABLE request ADD CONSTRAINT fk_request_meta_screen_id
FOREIGN KEY (meta_screen_id) REFERENCES meta_screen(id)
ON DELETE RESTRICT ON UPDATE RESTRICT;
```
- Criar tabela de parâmetro
```sql=
CREATE TABLE parameter (
id UUID NOT NULL,
request_id UUID,pa
meta_attribute_id UUID NOT NULL,
parent_parameter_id UUID,
name VARCHAR(255) NOT NULL,
type VARCHAR(255) NOT NULL,
CONSTRAINT pk_parameter PRIMARY KEY(id)
);
ALTER TABLE parameter ADD CONSTRAINT fk_parameter_request_id
FOREIGN KEY (request_id) REFERENCES request(id)
ON DELETE RESTRICT ON UPDATE RESTRICT;
ALTER TABLE parameter ADD CONSTRAINT fk_parameter_parent_parameter_id
FOREIGN KEY (parent_parameter_id) REFERENCES parameter(id)
ON DELETE RESTRICT ON UPDATE RESTRICT;
ALTER TABLE parameter ADD CONSTRAINT fk_parameter_meta_attribute_id
FOREIGN KEY (meta_attribute_id) REFERENCES meta_attribute(id)
ON DELETE RESTRICT ON UPDATE RESTRICT;
CREATE UNIQUE INDEX idx_request_parameter_name_type
ON parameter (request_id, name, type);
```
- Criar tabela de bind de respostas
```sql=
CREATE TABLE response_bind (
id UUID NOT NULL,
response_path VARCHAR(255) NOT NULL,
meta_attribute_id UUID NOT NULL,
button_element_id UUID NOT NULL,
CONSTRAINT pk_response_bind PRIMARY KEY(id)
);
ALTER TABLE response_bind
ADD CONSTRAINT fk_response_bind_button_element_id
FOREIGN KEY (button_element_id) REFERENCES meta_screen_element(id)
ON DELETE RESTRICT ON UPDATE RESTRICT;
```
- Adicionar coluna `request_id`
```sql=
ALTER TABLE meta_screen_element ADD COLUMN request_id UUID;
```
- Popular tabela request
```sql=
INSERT INTO request VALUES (
SELECT uuid_generate_v4() AS id,
mse.remote_lookup_request_id AS remote_request_id,
mse.meta_screen_id AS meta_screen_id
FROM meta_screen_element mse
WHERE mse.remote_lookup_request_id IS NOT NULL
);
```
- Update request id
```sql=
UPDATE meta_screen_element mse
SET mse.request_id=(SELECT r.id FROM request r
WHERE r.remote_request_id = mse.remote_lookup_request_id
AND r.meta_screend = mse.meta_screen_id)
WHERE mse.remote_lookup_request_id IS NOT NULL;
```
- Criar chave estrangeira de request na tabela de elementos
```sql=
ALTER TABLE meta_screen_element
ADD CONSTRAINT fk_meta_screen_element_request_id
FOREIGN KEY (request_id) REFERENCES request (id)
ON DELETE RESTRICT ON UPDATE RESTRICT;
```
### 1.2 POST
_/meta-screens/{screenId}/requests_
```json=
{
"remoteRequestId": "123",
"nickname": "busca com razão social",
"parameters": [
{"name": "versao", "type": "URL", "metaAttributeId": "1"},
{"name": "id", "type": "URL", "metaAttributeId": "2"},
{"name": "x-customized-header", "type": "HEADER", "metaAttributeId": "3"},
{"name": "razaoSocial", "type": "BODY", "metaAttributeId": "4"},
{"name": "nomeFantasia", "type": "BODY", "metaAttributeId": "5"},
{"name": "data", "type": "BODY", "metaAttributeId": "6"},
{"name": "rua", "type": "BODY", "metaAttributeId": "7"},
{"name": "numero", "type": "BODY", "metaAttributeId": "8"},
{"name": "bairro", "type": "BODY", "metaAttributeId": "9"},
{"name": "grupos", "type": "BODY", "metaAttributeId": "10"},
{"name": "funcionarios", "type": "BODY", "metaAttributeId": "11",
"children": [
{"nome": "id", "type": "BODY", "metaAttributeId": "11.1"},
{"nome": "nome", "type": "BODY", "metaAttributeId": "11.2"},
{"nome": "subordinados", "type": "BODY", "metaAttributeId": "11.3",
"children": [
{"nome": "id", "type": "BODY", "metaAttributeId": "11.3.1"},
{"nome": "nome", "type": "BODY", "metaAttributeId": "11.3.2"}
]},
]}
}
```
- O parâmetro deve receber o valor de um atributo
- Somente pode ser inserido em `FormScreen`
- Para parâmetros de url e header será permitido vincular apenas atributos simples do objeto ou subobjeto da tela:
- TextAttribute
- DateAttribute
- DateTimeAttribute
- BooleanAttribute
- NumberAttribute
- FormulaAttribute
- IdentifierAttribute
- LookupAttribute
- Apenas se `multipleItems` for `false`
- Deve ser utilizado o identificador
- RemoteLookupAttribute
- Apenas se `multipleItems` for `false`
- Deve ser utilizado o identificador
- Para parâmetros de body será permitido vincular todos os atributos do objeto.
- Quando a request estiver vinculada a um atributo do tipo subobjeto devem ser apresentados como campos simples:
- Atributos do atributo vinculado;
- Atributos dos pais do atributo vinculado;
- Atributos do objeto;
- Para parâmetros com filhos será permitido somente subobjetos multi valorados. E para os parâmetros filhos só será permito attributos filhos do subobjeto informado no parâmetro pai.
### 1.3 PUT
- _/meta-screens/{screenId}/requests/{id}_
```json=
{
"remoteRequestId": "123",
"nickname": "busca com razão social",
"parameters": [
{"id": "1", "name": "versao", "type": "URL", "metaAttributeId": "1"},
{"id": "2", "name": "id", "type": "URL", "metaAttributeId": "2"},
{"id": "3", "name": "x-customized-header", "type": "HEADER", "metaAttributeId": "3"},
{"id": "4", "name": "razaoSocial", "type": "BODY", "metaAttributeId": "4"},
{"id": "5", "name": "nomeFantasia", "type": "BODY", "metaAttributeId": "5"},
{"id": "6", "name": "data", "type": "BODY", "metaAttributeId": "6"},
{"id": "7", "name": "rua", "type": "BODY", "metaAttributeId": "7"},
{"id": "8", "name": "numero", "type": "BODY", "metaAttributeId": "8"},
{"id": "9", "name": "bairro", "type": "BODY", "metaAttributeId": "9"},
{"id": "10", "name": "grupos", "type": "BODY", "metaAttributeId": "10"},
{"id": "11", "name": "funcionarios", "type": "BODY", "metaAttributeId": "11",
"children": [
{"id": "12", "name": "id", "type": "BODY", "metaAttributeId": "11.1"},
// Parâmetro nome foi alterado nomeCompleto, por isso ele deve ser removido
// e um novo parâmetro nomeCompleto é adicionado.
{"name": "nomeCompleto", "type": "BODY", "metaAttributeId": "11.2"},
{"id": "14", "name": "subordinados", "type": "BODY", "metaAttributeId": "11.3",
"children": [
{"id": "15", "name": "id", "type": "BODY", "metaAttributeId": "11.3.1"},
{"id": "16", "name": "nome", "type": "BODY", "metaAttributeId": "11.3.2"}
]},
]}
}
```
- Deve aplicar as mesmas regras de [1.2 POST](#12-POST).
- Além dessas regras, o campo `remoteRequestId` não pode ser alterado
### 1.4 GET
_/meta-screens/{screenId}/requests/{id}_
```json=
{
"remoteRequestId": "123",
"nickname": "busca com razão social",
"parameters": [
{"id": "1", "name": "versao", "type": "URL", "metaAttributeId": "1"},
{"id": "2", "name": "id", "type": "URL", "metaAttributeId": "2"},
{"id": "3", "name": "x-customized-header", "type": "HEADER", "metaAttributeId": "3"},
{"id": "4", "name": "razaoSocial", "type": "BODY", "metaAttributeId": "4"},
{"id": "5", "name": "nomeFantasia", "type": "BODY", "metaAttributeId": "5"},
{"id": "6", "name": "data", "type": "BODY", "metaAttributeId": "6"},
{"id": "7", "name": "rua", "type": "BODY", "metaAttributeId": "7"},
{"id": "8", "name": "numero", "type": "BODY", "metaAttributeId": "8"},
{"id": "9", "name": "bairro", "type": "BODY", "metaAttributeId": "9"},
{"id": "10", "name": "grupos", "type": "BODY", "metaAttributeId": "10"},
{"id": "11", "name": "funcionarios", "type": "BODY", "metaAttributeId": "11",
"children": [
{"id": "12", "name": "id", "type": "BODY", "metaAttributeId": "11.1"},
{"id": "17", "name": "nomeCompleto", "type": "BODY", "metaAttributeId": "11.2"},
{"id": "14", "name": "subordinados", "type": "BODY", "metaAttributeId": "11.3",
"children": [
{"id": "15", "name": "id", "type": "BODY", "metaAttributeId": "11.3.1"},
{"id": "16", "name": "nome", "type": "BODY", "metaAttributeId": "11.3.2"}
]},
]}
}
```
### 1.5 DELETE
_/meta-screens/{screenId}/request/{id}_
Apenas requests que não estiverem vinculadas a um elemento da tela podem ser removidas.
## 2 Elemento botão
### 2.1 DER

### 2.2 CRUD
_/meta-screens/{screenId}/meta-screen-elements/{id}_
```json=
{
"name": "_buscarDados",
"label": "Buscar dados"
"note": "Busca os dados da requisição externa",
"order": 1,
"type": "ButtomElement",
"requestId": "123456789",
"responseBinds": [{
"metaAttributeId": "123",
"responsePath": "$.name"
}]
}
```
- POST:
- Deve manter as mesmas regras padrões dos elementos
- Somente pode ser inserido em `FormScreen`
- Os campos `note` e `responseBinds` não são obrigatórios
- requestId
- É obrigatório
- Deve ser uma request vinculada com a mesma tela que o botão
- O campos `responsePath` deve ser seguir o pattern definido em [https://goessner.net/articles/JsonPath/](https://goessner.net/articles/JsonPath/).
- PUT:
- Deve permitir, mantendo as mesmas regras padrões dos elementos (permitindo alterar somente: label, note e responseBinds).
- A ordem só pode ser alterada pela API de reordenação.
- Atributos de sistma não podem ser bindados com uma resposta
- Atributos stubs tbm não podem ser bindados com uma resposta
- DELETE:
- Deve manter as mesmas regras padrões dos elementos
### 2.3 Telas
[Protótipo Figma](https://www.figma.com/proto/eXqAy9XCwYgdtWKykanppV/Funcionalidades-em-an%C3%A1lise?node-id=283%3A5971&viewport=1382%2C-686%2C0.07927602529525757&scaling=scale-down)
### 2.4 Execução da request (Ymir)
No ymir, quando o usuário clicar nesse elemento deve ser chamada a execução dessa request no remote service. Essa execução deve seguir conforme descrito [aqui](https://hackmd.io/QCzrjEt0Q9KHIUhddp9IYQ#24-Execu%C3%A7%C3%A3o-da-request).
Os parâmetros a serem enviados no payload de execução serão preenchidos conforme os binds feitos no cadastro da requisição na tela ([1.2 POST](#12-POST)).
Atributos:
- **IdentifierAttribute, TextAttribute, DateAttribute, DateTimeAttribute**
- Retorna o valor simples como string.
- Ex: "texto", "2020-03-04", "2020-03-05T09:12:38.7177-03:".
- **BooleanAttribute, NumberAttribute, FormulaAttribute**
- Retorna o valor simples.
- Ex: true, 123, 456.
- **LookupAttribute, RemoteLookupAttribute**
- Como valor deve ser utilizado o identificador do item
- `multipleItems` = `false`
- Retorna o valor simples.
- Ex: "Valor"
- `multipleItems` = `true`
- Retorna um array dos valores.
- Ex: ["Valor1", "Valor2"]
- **SubobjectAttribute**
- `multipleItems` = `false`
- Retorna o valor simples.
- Ex: {id: "1", name: "subattributeNome"}
- `multipleItems` = `true`
- Retorna um array dos valores.
- Ex: [{id: "1", name: "subobject 1"}, {id: "2", name: "subobject 2"}]
- **StubAttribute**
- Retorna o valor do estado da tela.
Ao realizar a execução o botão deve ficar em estado de loading até que a requisição seja retornada.
### 2.5 Resposta da request
Após realizar a execução da request o retorno desse request pode ser positiva, para esse caso deve ser aplicado os bind de retorno, ou pode ser negativa, nesse caso deve ser tratado exibindo am feedkback para o usuario.
#### 2.5.1 Reposta positiva
Quando o retorno da request for positivo, o ymir deve pegar os `responseBinds` do botão e preencher os atributos bindados conforme a resposta da request.
Ex:
Json resposta
```json=
{
"descricao": "radinho de pilha"
"data": "2020-03-12"
"valor": 765.43
"ativo": true
}
```
botão
```json=
{
"name": "_buscar",
"label": "Buscar valor do radinho"
"note": "",
"order": 1,
"type": "ButtomElement",
"requestId": "123",
"responseBinds": [{
"metaAttributeId": "1",
"responsePath": "$.descricao"
},{
"metaAttributeId": "2",
"responsePath": "$.data"
},{
"metaAttributeId": "3",
"responsePath": "$.valor"
},{
"metaAttributeId": "4",
"responsePath": "$.ativo"
}]
}
```
- O atributo com o id igual a `1` vai receber o valor `"radinho de pilha"`
- O atributo com o id igual a `2` vai receber o valor `2020-03-12`
- O atributo com o id igual a `3` vai receber o valor `765.43`
- O atributo com o id igual a `4` vai receber o valor `true`
Os atributos devem ser preenchidos conforme as regras:
- **NumberAttribute**
- Só aceita valores numéricos
- **TextAttribute**
- Só aceita valores de textos
- **BooleanAttribute**
- Só aceita valores boleanos
- **DateAttribute e DateTimeAttribute**
- Só aceita valores em texto
- E o texto deve seguir o padrão ISO 8601
- **StubAttribute**
- Não é permitido
- **LookupAttribute, RemoteLookupAttribute**
- Caso esteja com `multipleItems` = `false`
- Só aceita valores de texto simples
- Caso contrário
- Só aceita array com valores
- **IdentifierAttribute**
- Não é permitido
- **FormulaAttribute**
- Não é permitido
- **SubobjectAttribute**
- Não é permitido
Caso a request retorne status de sucesso, deve ser apresentado o seguinte dialog de feeadback para o usuario:

Caso as regras de valores não sejam atendidas, deve ser retornado um erro no campo informando que o formato do valor está inválido. Ex:

Quando o retorno de um atributo é nulo, não iremos alterar o valor atual do atributo. Porém ainda temos duas opções:
- **OPÇÃO 1**: não informar o usuario que o campo não foi atualizado
- **OPÇÃO 2**: Informar o usuário com um alerta no campo
- Essa funcionalidade não está disponivel para todos os elementos, ou seja, implicaria em nós implementarmos esse feedback para os elementos que não possuem essa funcionalidade.
### 2.5.2 Sem acesso a internet
Caso o usuario esteja sem acesso a internet deve ser exibido o seguinte snackbar:

### 2.5.3 Resposta negativa
Caso a requisição falhe e retorne status maiores que 299 deve ser exibido os seguintes dialogs para cada cenário:
- Status entre 300 e 399:

- Status entre 500 e 599:

- Status igual a 400:

- Status igual a 401:

- Status igual a 403:

- Status igual a 404:

- Status igual a 405:

- Status igual a 408:

- Status igual a 422:

- Demais status 400+:

Caso o usuario clique em "Retorno completo da requisição" deve ser apresentado o body da response como o exemplo abaixo:

## 3 Meta Attributes
Para os meta attributes duas novas regras de remoção devem ser adicionada, são elas:
- Não é permitido remover um meta attribute vinculado a um parâmetro de request
- Não é permitido remover um meta attribute vinculado a rum response bind
## 4 Custom entries
- Deve ser adicionado a propriedade `requests` para a `screen`
- Deve conter todos os campos da request [1.4 GET de request](#14-GET)
- Deve ser adicionado o tipo de elemento `ButtomElement`
:::spoiler
```json=
{
"items": [
{
"id": "6fec7c5b-6bea-4369-abe0-7ece02e27e47",
"type": "CRUD_FEATURE",
"path": "/custom/bolacha",
"standard": false,
"contextUrl": "/api/v3/business-template-builder/router/business-template-builder/bolacha/9a556015-9624-44fb-ba54-e6c423854be3",
"title": "Bolacha",
"majorVersion": "bd5839ad-9624-49ac-b7be-520e2289831a",
"routes": [
{
"url": "/custom/bolacha",
"$type": "ref",
"values": [
"items/6fec7c5b-6bea-4369-abe0-7ece02e27e47/metaScreens",
"27e6a0c4-de35-4d52-be50-5b98309c8844"
]
},
{
"url": "/custom/bolacha/*",
"$type": "ref",
"values": [
"items/6fec7c5b-6bea-4369-abe0-7ece02e27e47/metaScreens",
"3713a640-6c19-499c-89a6-97ecb924ac66"
]
}
],
"metaScreens": [
{
"type": "LIST_META_SCREEN",
"id": "27e6a0c4-de35-4d52-be50-5b98309c8844",
"title": "bolachas",
"name": "_bolachas",
"standard": false,
"metaScreenElements": [
{
"id": "b959944e-bc52-4b95-a0e0-378921396941",
"name": "_id",
"standard": false,
"label": "Identifier",
"order": 0,
"type": "TextColumnElement",
"metaAttribute": {
"type": "IdentifierAttribute",
"name": "id",
"standard": true
}
},
{
"id": "862ec765-64cd-430e-9035-a3cc85e1dbc4",
"name": "_nome",
"standard": false,
"label": "nome",
"order": 1,
"type": "TextColumnElement",
"metaAttribute": {
"type": "TextAttribute",
"name": "_nome",
"standard": false,
"textMaxLength": 255
}
}
]
},
{
"type": "FORM_META_SCREEN",
"id": "3713a640-6c19-499c-89a6-97ecb924ac66",
"title": "bolacha",
"name": "_bolacha",
"standard": false,
// Requests da tela
"requests": [
{
"id": "291e3042-8da5-4826-a361-10effe5aa380"
"remoteRequestId": "aa69ddeb-f945-44ba-9eb3-40e7d01b8df4"
"parameters": [
{"id": "1", "name": "versao", "type": "URL", "value": "v2"},
{"id": "2", "name": "id", "type": "URL", "metaAttributeId": "2"},
{"id": "3", "name": "x-customized-header", "type": "HEADER", "metaAttributeId": "3"},
{"id": "4", "name": "razaoSocial", "type": "BODY", "metaAttributeId": "4"},
{"id": "5", "name": "nomeFantasia", "type": "BODY", "metaAttributeId": "5"},
{"id": "6", "name": "data", "type": "BODY", "metaAttributeId": "6"},
{"id": "7", "name": "rua", "type": "BODY", "metaAttributeId": "7"},
{"id": "8", "name": "numero", "type": "BODY", "metaAttributeId": "8"},
{"id": "9", "name": "bairro", "type": "BODY", "metaAttributeId": "9"},
{"id": "10", "name": "grupos", "type": "BODY", "metaAttributeId": "10"},
{"id": "11", "name": "funcionarios", "type": "BODY", "metaAttributeId": "11",
"children": [
{"id": "12", "name": "id", "type": "BODY", "metaAttributeId": "11.1"},
{"id": "17", "name": "nomeCompleto", "type": "BODY", "metaAttributeId": "11.2"},
{"id": "14", "name": "subordinados", "type": "BODY", "metaAttributeId": "11.3",
"children": [
{"id": "15", "name": "id", "type": "BODY", "metaAttributeId": "11.3.1"},
{"id": "16", "name": "nome", "type": "BODY", "metaAttributeId": "11.3.2"}
]},
]}
},
{
"id": "97d167c9-92ee-4ccf-9e97-165f352e95ce"
"remoteRequestId": "43906b64-ef45-4a1f-ba37-eca7a814585d"
}
]
"metaScreenElements": [
{
"id": "fdf3c3ff-0e29-4f01-83c9-3bb554dac920",
"name": "_nome",
"standard": false,
"label": "nome",
"order": 0,
"type": "InputTextElement",
"metaAttribute": {
"type": "TextAttribute",
"name": "_nome",
"standard": false,
"textMaxLength": 255
},
"required": false,
"customized": true
},
{
"id": "073b7522-3a21-4843-91cd-ae0f07ab46e8",
"name": "_marca",
"standard": false,
"label": "marca",
"order": 1,
"type": "RemoteLookupElement",
"metaAttribute": {
"type": "RemoteLookupAttribute",
"name": "_marca",
"standard": false,
"multipleItems": true
},
"required": false,
"customized": true,
"requestId": "291e3042-8da5-4826-a361-10effe5aa380",
"pathItemsResponse": "result.items",
"mapItem": {
"identifier": "item.id",
"display": "item.name"
}
},{
// Novo elemento de tela - ButtonElement
"id": "291e3042-8da5-4826-a361-10effe5aa380",
"name": "_executa",
"standard": false,
"label": "executa",
"order": 2,
"type": "ButtomElement",
"requestId": "97d167c9-92ee-4ccf-9e97-165f352e95ce",
"customized": true,
"responseBinds": [{
"metaAttributeId": "123",
"responsePath": "$.name"
}]
}
]
}
]
}
]
}
```
:::
## 5 Sync
Uma nova entidade precisara ser sincronizada:
- Request
Dessa forma as entidades Parameter e ResponseBind serão sincronizadas em cascata pelas entidades Request e MetaScreenElement respectivamente.
## 6 Remote lookup
Para seguir um mesmo padrão em todos os pontos onde acessamos um json, vamos precisar realizar uma alteração no remote lookup. Essa alteração consiste em mudar a forma que ele especifica os campos do json que quer acessar.
Hoje o usuário segue um padrão definido apenas para o remote lookup. Ex:
- Para o campo pathItemsResponse ele informa `result.items`
- Para o campo identifier ele informa `item.id`
- Para o campo display ele informa `item.nome`
A partir de agora passaremos a utilizar o pattern definido em [https://goessner.net/articles/JsonPath/](https://goessner.net/articles/JsonPath/).
ou seja o exemplo ficaria assim:
- Para o campo pathItemsResponse ele informa `$.items`
- Para o campo identifier ele informa `@.id`
- Para o campo display ele informa `@.nome`
As validações referentes ao pattern utilizado hoje devem ser removidas.
E devemos fazer a migração de um pattern para o o outro.
```sql=
UPDATE meta_screen_element
SET remote_lookup_path_items_response = regexp_replace(
remote_lookup_path_items_response,
'result([\.]?)([\w\.]*)', '$\1\2'),
remote_lookup_identifier_item = regexp_replace(
remote_lookup_identifier_item,
'item([\.]?)([\w\.]*)', '@\1\2'),
remote_lookup_display_item = regexp_replace(
remote_lookup_display_item,
'item([\.]?)([\w\.]*)', '@\1\2')
WHERE element_type = 'RemoteLookupElement';
```
regexp_replace conforme documentação [https://www.postgresql.org/docs/9.6/functions-matching.html#FUNCTIONS-POSIX-TABLE](https://www.postgresql.org/docs/9.6/functions-matching.html#FUNCTIONS-POSIX-TABLE)
## 7 Items futuros
Futuramente deverá ser possível:
- Vincular uma request a um contexto, como por exemplo um sub objeto.
- Informar valores _defaults_ para os parâmetros.
{"metaMigratedAt":"2023-06-15T04:53:05.428Z","metaMigratedFrom":"YAML","title":"BTB - Web service","breaks":true,"contributors":"[{\"id\":\"ca1f1f43-a8d6-4b1d-add2-5d8ec02aa9ca\",\"add\":25430,\"del\":25589},{\"id\":\"1fab477c-cf40-49da-9ef7-9c39004d03df\",\"add\":44943,\"del\":19700},{\"id\":\"a613ab59-5c0b-4a40-ab61-7e9a5128f4d5\",\"add\":324,\"del\":3},{\"id\":\"2cac3049-a1e9-4619-8b62-d77063290643\",\"add\":17,\"del\":16}]"}