Saiba como adaptar seu desenvolvimento para catálogo no Mercado Livre

Saiba como adaptar seu desenvolvimento para catálogo

Agora os vendedores podem criar via API, publicações em catálogo a partir de suas publicações atuais ou de forma direta, sem utilizar uma publicação já existente e assim competir para ganhar a exposição na página do produto, onde estarão posicionadas nos primeiros lugares dos resultados nas buscas.
Antes de começar, não esqueça de ler a documentação sobre Domínios e Produtos, que ajudará você a ter as informações certas para seus produtos.
Prepare seu desenvolvimento com a ajuda deste manual!

 

Como o catálogo funciona?

Tradicionalmente no Mercado Livre, os anúncios são criados exclusivamente pelos vendedores e são eles quem fornecem as informações sobre o que estão vendendo (títulos, fotos e descrições), bem como as condições de venda (preço, envio, meios de pagamento etc.).
A partir de agora, além da forma tradicional de anunciar, é possível criar anúncios de catálogo, onde o conteúdo do anúncio (títulos, fotos, descrições e ficha técnica) são fornecidos pelo Mercado Livre. Os produtos são vendidos através de uma página unificada, na qual as vendas são orientadas para o vendedor que oferecer as melhores condições de venda e melhor experiência para os compradores.

 

Onde os compradores encontram os anúncios de catálogo?

Na hora da busca, os compradores verão os produtos de catálogo nos primeiros resultados. Ao acessar um produto, o vendedor que oferecer as melhores condições de venda e de preço terá a possibilidade de vender esse produto. Na página de produto, também haverá um link para ver a lista completa dos vendedores que oferecem o mesmo produto. Serão destacados os vendedores que oferecem o produto em outras condições de venda relevantes para o comprador como, por exemplo, com “frete grátis” ou “envio no mesmo dia”.
Diferentemente dos anúncios tradicionais que têm sua própria fileira nos resultados de busca, os anúncios de catálogo não têm uma fileira exclusiva nos resultados, mas obtêm suas visitas e vendas através das fileiras destinadas a produtos de catálogo, os quais aparecem no início da lista.
Saiba mais sobre o catálogo.

Em resumo:

  • Até hoje, eram os vendedores que criavam e atualizavam os anúncios, gerando seu conteúdo e determinando suas condições de venda.
  • A partir de agora, além da forma tradicional de anunciar, é possível anunciar no catálogo através de um produto descrito pelo Mercado Livre.
  • Os vendedores obtêm as vendas dos produtos competindo com outros vendedores que procuram oferecer as melhores condições e experiência de compra.
  • Os produtos ocuparão as primeiras posições nas buscas e recomendações do site.
  • Dependendo do país e do domínio onde forem anunciados, o catálogo oferece benefícios de até 23% nas tarifas de venda.

 

Conteúdos

→Como anunciar em catálogo
↳Anunciar diretamente no catálogo versus a partir de um anúncio existente
↳Quais são as diferenças?
↳O que acontece se eu modificar, pausar ou remover meu anúncio de catálogo associado a um anúncio tradicional?
↳É necessário saber mais alguma coisa sobre o gerenciamento dos anúncios de catálogo?
↳É possível anunciar qualquer item em catálogo?
↳O que acontece se, por engano, eu associar um item a um produto errado?
 ↳Etapas para anunciar no catálogo a partir de um anúncio existente
↳Etapas para anunciar no catálogo de forma direta, sem um anúncio associado
→Conferir se um anúncio possa ser escolhido para o catálogo
↳Tag de elegibilidade para itens
↳Elegibilidade de um anúncio existente sem catalog_product_id associado
↳Elegibilidade de um anúncio existente com catalog_product_id associado
↳Considerações
↳Descrição dos campos
→Conferir se vários anúncio são elegíveis para o catálogo com multiget
↳Descrição dos campos
→Filtro de itens por vendedor
→Determinar o produto exato a ser vendido
↳Produtos pai e filho
↳Escolhendo o produto específico para meu anúncio
→Anunciar no catálogo a partir de um anúncio existente
↳Criação automática de publicações de catálogo
→Anúncio diretamente no catálogo: buscador de produtos
→Concorrendo para ganhar as vendas
↳Receba notificações de posts que mudam de status na competição
↳Como conhecer o preço para ganhar
↳Conheça as condições e o preço do item vencedor
↳Como conhecer a relação de publicações para um produto
→Mais sobre anúncios de catálogo
↳Como reconhecer o anúncio de catálogo e o original
↳Como saber a relação entre anúncios associados
↳Como gerenciar as perguntas nos anúncios de catálogo
↳Como gerenciar as orders, visitas, etc.
↳Como gerenciar as vendas dos anúncios de catálogo
↳Ciclo de vida de anúncios associados
↳O que pode ser modificado no anúncio de catálogo

 

Anunciar diretamente no catálogo versus a partir de um anúncio existente

Há duas formas de criar anúncios de catálogo:

  • Criando um anúncio de catálogo a partir de um anúncio tradicional.
  • Anunciando diretamente no catálogo.

 

Quais são as diferenças?

Os anúncios de catálogo criados a partir de um anúncio tradicional compartilham estoque entre si. Ou seja, se através do item MLB1234 criarmos o anúncio de catálogo cujo item é MLB1235, a venda em qualquer um desses dois itens atualizará automaticamente o estoque do outro, pois eles são sincronizados. Se uma venda é cancelada em qualquer um desses itens, a quantidade também retornará automaticamente para o estoque de ambos. Os anúncios associados permitem que o vendedor comece a vender em catálogo enquanto continua vendendo através de seus anúncios tradicionais. Os anúncios que são criados diretamente no catálogo sem estarem associados a um anúncio tradicional, são completamente independentes e não compartilham estoque com nenhum outro anúncio atual.

 

O que acontece se eu modificar, pausar ou remover meu anúncio de catálogo associado a um anúncio tradicional?

Com exceção do estoque, os anúncios de catálogo são itens independentes dos anúncios tradicionais, é possível alterar suas condições de venda e gerenciar seu ciclo de vida de forma independente. Se o anúncio de catálogo for removido, a relação com o anúncio tradicional se perde e para voltar a anunciar em catálogo, é necessário repetir o processo de anunciar em catálogo. Tenha em conta que para desvincular a relação, o estatus do item de catálogo deverá ser “delete”.

 

É necessário saber mais alguma coisa sobre o gerenciamento dos anúncios de catálogo?

Considerando que o conteúdo dos anúncios de catálogo é gerenciado pelo Mercado Livre, os campos editáveis, como título, imagens, descrição e atributos da ficha técnica do recurso/item não podem ser editados nos anúncios de catálogo.

 

Os campos referentes às condições de venda como, por exemplo, o preço continuam sendo gerenciados pelos vendedores. Nas seções a seguir, explicaremos mais sobre os recursos disponíveis para você realizar um gerenciamento eficiente das condições de venda.

 

Não, atualmente os requisitos são:

  • Somente produtos novos (não são permitidos produtos recondicionados ou usados),
  • Todos os vendedores sem discriminação de reputação.
  • No domínio CELLPHONES, só é permitido anunciar telefones celulares desbloqueados (que funcionam com qualquer operadora).

 

Importante:

  • Para poder usar um catalog_product_id, é imprescindível que o vendedor preencha a ficha técnica do item.
  • Se o vendedor incluir um identificador de produto universal no anúncio, isso aumenta as chances de podermos associar seu item a um catalog_product_id.
  • Quando tiver itens sem catalog_product_id associado, você pode realizar a busca dele através do “buscador de produtos”, ele te permitirá identificar o catalog_product_id correto para adicioná-lo no POST no momento de realizar o OPTIN.

Essas condições podem mudar com o tempo e, por conta disso, na seção a seguir você encontrará as ferramentas necessárias para saber se um anúncio pode ser escolhido para catálogo.

 

O que acontece se por engano eu associar um item a um produto errado?

Nos anúncios de catálogo, é extremamente importante que não exista nenhuma discrepância entre o produto de catálogo e a oferta.
Como o conteúdo dos produtos é fornecido pelo Mercado Livre, qualquer discrepância entre o produto descrito e a oferta anunciada pelo vendedor pode resultar em um comprador recebendo algo diferente do esperado.
Caso tenha detectado algum erro, é essencial que finalize a publicação de catálogo, realizando o mesmo fluxo de como finalizar uma publicação tradicional. Em primeira instância, você deve realizar um PUT com status=”closed” e logo após, outro PUT com delete=”true” no item de catálogo para finalizar a publicação.
Tanto o vendedor quanto o integrador podem ser responsáveis por erros no anúncio de catálogo e estão sujeitos a punições que vão desde a queda na reputação até a suspensão da conta.

 

Etapas para anunciar em catálogo a partir de um anúncio existente

  1.  Verificamos que a publicação seja elegível para o catálogo com o recurso /items/{item_id}/catalog_listing_eligibility.
  2.  Dependendo se o ítem conta com um catalog_product_id associado com el recurso /items/{item_id}/catalog_listing_eligibility verificaremos se é elegível ou não.
  3.  Se o item não conta com um catalog_product_id associado, devemos buscar no recurso /products/search o catalog_product_id que coincida exatamente con o producto que correto.
  4.  Comprovamos que a publicação sem catalog_product_id associado seja elegível para o catálogo con o recurso /items/{item_id}/catalog_listing_eligibility?catalog_product_id={catalog_product_id}&variation_id={variation_id}.
  5. Realizamos um POST com o recurso /items/catalog_listings para criar a publicação de catálogo relacionada com uma publicação existente.

 

Etapas para anunciar em catálogo de forma direta, sem um anúncio associado

  1.  Usar o recurso /products/search para identificar o catalog_product_id que corresponda exatamente ao produto a ser vendido.
  2. Criar o JSON pelo recurso /items, incluindo catalog_listing=true e o catalog_product_id validado com o recurso /products/search.
  3.  Usar o recurso /items para criar o anúncio de catálogo de forma direta.

Nas seções a seguir, mostraremos detalhadamente como seguir essas etapas.

 

Importante:
Este recurso estará disponível na Argentina, México e Brasil a partir do dia 14 de agosto.

Como mencionado na seção anterior, neste momento só podem participar de catálogo certos anúncios que atendem alguns requisitos, entre eles: serem novos e do domínio CELLPHONES, os aparelhos devem ser desbloqueados.
Para conferir a possibilidade de um anúncio ser elegível para catálogo em qualquer domínio, você deve usar a API catalog_listing_eligibility. Lembre-se de que a resposta será diferente dependendo do anúncio ter ou não variações.
Além do mais, você pode verificar se uma publicação sem catalog_product_id associado é elegível para publicar em catálogo usando o mesmo recurso catalog_listing_eligibility mais os parâmetros de catalog_product_id e variation_id, dependendo das características do item. Tenha em conta que para identificar o catalog_product_id correto, você deverá seguir os passos correspondentes detalhados na seção buscador de produtos.

 

Tag de elegibilidade para itens

Importante:
Esta funcionalidade estará disponível a partir de 6 de março de 2020 para Argentina, Brasil e Mexico.

Através do recurso search, poderá identificar todos os itens dos vendedores que são elegíveis para catálogo, que ainda não foram publicados, pela tag catalog_listing_eligible. Para consultá-los realize a seguinte chamada:

 

Chamada:

curl -X GET https://api.mercadolibre.com/users/$USER_ID/items/search?tags=catalog_listing_eligible&access_token=$ACCESS_TOKEN

Exemplo:

curl -X GET https://api.mercadolibre.com/users/123456987/items/search?tags=catalog_listing_eligible&access_token=$ACCESS_TOKEN

Resposta curta:

{
    "seller_id": "123456987",
    "query": null,
    "paging": {
        "limit": 50,
        "offset": 0,
        "total": 1
    },
    "results": [
        "MLA123456789"
    ],
    "filters": [],
    "available_filters": [
            ]
}
Nota:
A resposta do search mostrará todos os itens do vendedor com a tag catalog_listing_eligible.

Exemplo de item elegível:

{
  "id": "MLA123456789",
  "site_id": "MLA",
  "title": "Item De Testeo, Por Favor No Ofertar --kc:off",
  "subtitle": null,
  "seller_id": 123456987,
  "category_id": "MLA3530",
  "official_store_id": null,
  "price": 50,
  "base_price": 50,
  "original_price": null,
  "currency_id": "ARS",
  "initial_quantity": 1,
  "available_quantity": 1,
  "sold_quantity": 0,
  "sale_terms": [
  ],
  "buying_mode": "buy_it_now",
  "listing_type_id": "free",
  "start_time": "2020-02-17T16:30:39.000Z",
  "stop_time": "2020-04-17T04:00:00.000Z",
  "condition": "used",
  "permalink": "https://articulo.mercadolibre.com.ar/MLA-839616438-item-de-testeo-por-favor-no-ofertar-kcoff-_JM",
  "thumbnail": "http://mla-s1-p.mlstatic.com/951410-MLA40807113659_022020-I.jpg",
  "secure_thumbnail": "https://mla-s1-p.mlstatic.com/951410-MLA40807113659_022020-I.jpg",
  "pictures": [],
  "video_id": null,
  "descriptions": [
  ],
  "accepts_mercadopago": true,
  "non_mercado_pago_payment_methods": [
  ],
  "shipping": {},
  "international_delivery_mode": "none",
  "seller_address": {},
  "seller_contact": null,
  "location": {
  },
  "geolocation": {},
  "coverage_areas": [
  ],
  "attributes": [],
  "warnings": [
  ],
  "listing_source": "",
  "variations": [
  ],
  "status": "active",
  "sub_status": [
  ],
  "tags": [
    "catalog_listing_eligible",
    "good_quality_picture",
    "test_item",
    "immediate_payment"
  ],
  "warranty": null,
  "catalog_product_id": null,
  "domain_id": "MLA-UNCLASSIFIED_PRODUCTS",
  "parent_item_id": null,
  "differential_pricing": null,
  "deal_ids": [
  ],
  "automatic_relist": false,
  "date_created": "2020-02-17T16:30:40.000Z",
  "last_updated": "2020-02-17T16:34:12.000Z",
  "health": 0.4,
  "catalog_listing": false
}

Elegibilidade de um anúncio existente sem catalog_product_id associado

Exemplo sem variação:

curl -X GET https://api.mercadolibre.com/items/MLA123456788/catalog_listing_eligibility?catalog_product_id=MLA6352027&access_token={ACCESS_TOKEN}

Resposta:

{
   "id": "MLA123456788",
   "site_id": "MLA",
   "domain_id": "MLA-MICROWAVES",
   "status": "READY_FOR_OPTIN",
   "buy_box_eligible": true,
   "variations": []
}

Exemplo com variação:

curl -X GET https://api.mercadolibre.com/items/MLA123456789/catalog_listing_eligibility?catalog_product_id=MLA9452524&variation_id=43278798243&access_token=$ACCESS_TOKEN

Resposta:

{
  "id": "MLA123456789",
  "site_id": "MLA",
  "domain_id": "MLA-CELLPHONES",
  "status": null,
  "buy_box_eligible": null,
  "variations": [
    {
      "id": 43278798243,
      "status": "READY_FOR_OPTIN",
      "buy_box_eligible": true
    }
  ]
}

Caso o item não conte com um catalog_product_id e no recurso de eligibilidade também não seja enviado o parâmetro com um valor de catalog_product_id correto, a resposta informará que o catalog_product_id é “null”.

 

Exemplo sem parámetro:

curl -X GET https://api.mercadolibre.com/items/MLA123456789/catalog_listing_eligibility?access_token={ACCESS_TOKEN}

Resposta:

{
   "id": "MLA123456789",
   "site_id": "MLA",
   "domain_id": "MLA-MICROWAVES",
   "status": "CATALOG_PRODUCT_ID_NULL",
   "buy_box_eligible": false,
   "variations": []
}

Elegibilidade de um anuncio existente com catalog_product_id associado

Os seguintes exemplos mostram como validar a elegibilidade de uma publicação existente para vincular uma nova publicação de catálogo com estoque sincronizado que conte com um catalog_product_id associado.

 

Chamada:

curl -X GET https://api.mercadolibre.com/items/{item_id}/catalog_listing_eligibility?access_token={ACCESS_TOKEN}

Exemplo com variações:

curl -X GET https://api.mercadolibre.com/items/MLA1234/catalog_listing_eligibility?access_token={ACCESS_TOKEN}

Resposta:

{
    "id": "MLA1234",
    "site_id": "MLA",
    "domain_id": "MLA-CELLPHONES",
    "status": null,
    "buy_box_eligible": null,
    "variations": [
        {
            "id": 1312323,
            "status": "READY_FOR_OPTIN",
            "buy_box_eligible": true
        },
        {
            "id": 1312444,
            "status": "READY_FOR_OPTIN",
            "buy_box_eligible": true
        }
    ]
}

Exemplo sem variações

curl -X GET https://api.mercadolibre.com/items/MLB1234/catalog_listing_eligibility?access_token={ACCESS_TOKEN}

Resposta:

{
    "id": "MLB1234",
    "site_id": "MLB",
    "domain_id": "MLB-MICROWAVES",
    "status": "READY_FOR_OPTIN",
    "buy_box_eligible": true,
    "variations": []
}

Considerações

  • Se o item não possuir variações, a elegibilidade será expressada no campo buy_box_eligible de primeiro nível no JSON de resposta e a seção variations estará vazia.
  • Se o item possuir variações, a elegibilidade de cada uma delas será expressada na seção variations, que conterá um array por variação com um campo buy_box_eligible para cada uma delas.

Descrição dos campos:

  • id: ID do anúncio que estamos consultando.
  • site_id: ID do país ao qual o item corresponde.
  • domain_id: ID do domínio ao qual o item corresponde.
  • buy_box_eligible: indica se o item/variação é elegível ou não para participar de catálogo.
  • variations: são todas as variações de um item. Cada uma terá um status associado e um valor para o campo buy_box_eligible.
  • status: define a situação do item tradicional com relação ao catálogo. Os diferentes status podem ser:

Elegível:

  • READY_FOR_OPTIN: o item pode ser anunciado no catálogo.

Não elegíveis:

 

  • ALREADY_OPTED_IN: o item tradicional consultado já possui um item de catálogo associado.
  • CLOSED: o item encontra-se em um status que não pode mais ser vendido.
  • PRODUCT_INACTIVE: o item está associado a um produto que ainda não foi habilitado para o catálogo ou o item ainda não possui um catalog_product_id associado.
  • NOT_ELIGIBLE: existe uma regra de negócio que impede que o item seja elegível para o catálogo.

 

Por exemplo, celular usado, celular bloqueado. Lembre-se de que, se você consultar um item de catálogo que estiver competindo, o status será COMPETING.

 

Conferir se vários anúncio são elegíveis para o catálogo com multiget

Para verificar se várias publicações são elegíveis para o catálogo fazendo uma única chamada, você deve incorporá-las ao parâmetro ids, bem como efetuar a chamada multiget, da seguinte maneira:

 

Chamada:

https://api.mercadolibre.com/multiget/catalog_listing_eligibility?ids=$item_id,$item_id&access_token=$ACCESS_TOKEN

Exemplo:

https://api.mercadolibre.com/multiget/catalog_listing_eligibility?ids=MLA818878419,MLA820167922&access_token=$ACCESS_TOKEN

Resposta:

[
    {
        "code": 200,
        "body": {
            "buy_box_eligible": null,
            "domain_id": "MLA-CELLPHONES",
            "id": "MLA818878419",
            "site_id": "MLA",
            "status": null,
            "variations": [
                {
                    "buy_box_eligible": true,
                    "id": 44612657634,
                    "status": "READY_FOR_OPTIN"
                },
                {
                    "buy_box_eligible": false,
                    "id": 44890704657,
                    "status": "ALREADY_OPTED_IN"
                }
            ]
        }
    },
    {
        "code": 200,
        "body": {
            "buy_box_eligible": null,
            "domain_id": "MLA-CELLPHONES",
            "id": "MLA820167922",
            "site_id": "MLA",
            "status": null,
            "variations": [
                {
                    "buy_box_eligible": true,
                    "id": 44931385066,
                    "status": "READY_FOR_OPTIN"
                },
                {
                    "buy_box_eligible": true,
                    "id": 44931385069,
                    "status": "READY_FOR_OPTIN"
                }
            ]
        }
    }
]

Descrição dos campos

  • code: é o código de status HTTP que retorna a consulta com cada item_id; se não houver erro, ele deve ser 200.
  • body: corpo da mensagem que retorna essa consulta à API de elegibilidade.

Filtro de itens por vendedor

Adicionamos ao recurso de busca de publicações de um vendedor, um filtro que permitirá conhecer as publicações que são de catálogo e aquelas que são as tradicionais. Para isso você deverá passar na busca o parâmetro “catalog_listing” com o valor true ou false, dependendo do que você deseja consultar.
Em primeiro lugar identificamos todos os itens de catálogo de um seller, tenha em conta que você deverá passar o parâmetro de status correspondente caso queira adicionar um filtro como por exemplo status=“active”.

 

Chamada:

curl -X GET https://api.mercadolibre.com/users/{user_id}/items/search?catalog_listing=true&access_token={ACCESS_TOKEN}

Exemplo:

curl -X GET https://api.mercadolibre.com/users/123456789/items/search?catalog_listing=true&access_token={ACCESS_TOKEN}

Resposta resumida de itens que são de catálogo:

{
  "seller_id": "123456789",
  "query": null,
  "paging": {
    "limit": 50,
    "offset": 0,
    "total": 8
  },
  "results": [
    "MLA123456789",
    "MLA234567890",
    "MLA345678912",
    "MLA456789123",
    "MLA567891234",
    "MLA678912345",
    "MLA789123456",
    "MLA891234567"
  ],
  "filters": [
  ],
  "available_filters": [],
  "orders": [],
  "available_orders": []
}

Por outro lado você poderá realizar o mesmo filtro para identificar todos os itens de um seller que não são de catálogo.

 

Chamada:

curl -X GET https://api.mercadolibre.com/users/{user_id}/items/search?catalog_listing=false&access_token={ACCESS_TOKEN}

Exemplo:

curl -X GET https://api.mercadolibre.com/users/123456789/items/search?catalog_listing=false&access_token={ACCESS_TOKEN}

Resposta resumida de itens que não são de catálogo:

{
  "seller_id": "123456789",
  "query": null,
  "paging": {
    "limit": 50,
    "offset": 0,
    "total": 2902
  },
  "results": [
    "MLA987654321",
    "MLA123789456",
    "MLA456789123",
    "MLA132465798",
    "MLA978645312",
    "MLA312645978",
    "MLA654987321",
    "MLA123789654",
      ],
  "filters": [
  ],
  "available_filters": [],
  "orders": [],
  "available_orders": []
}

Determinar o produto exato a ser vendido

Para que um item possa ser anunciado no catálogo e ser comprado, ele deve estar associado a um produto específico o bastante, para que o comprador possa saber exatamente o que está comprando, e para o qual o Mercado Livre tenha criado o conteúdo (produtos com status ”active” no recurso /products/{catalog_product_id})

Importante:
O conteúdo do anúncio de catálogo é fornecido pelo Mercado Livre. Portanto, o vendedor é responsável por conferir que o produto a ser associado coincida com as características específicas mostradas na plataforma.
Se houver alguma diferença entre o que o usuário comprar e o produto associado, é possível que existam reclamações e/ou cancelamentos que vão impactar negativamente na sua reputação e, por conseguinte, será inabilitado para anunciar em catálogo, levando, eventualmente, ao cancelamento da conta.

Produtos pai e filho

Em muitos domínios (não em todos), existem dois níveis de produtos:

  • Produtos pai (“parents“), que reúnem produtos específicos e que não podem ser comprados. Por exemplo: Motorola Moto G6 ⇐ Não tem a capacidade nem a cor especificadas!
  • Produtos filho (“children“) suficientemente especificados para sua compra. Por exemplo: Motorola Moto G6 32GB Índigo escuro.
curl -X GET https://api.mercadolibre.com/products/MLB9652753

Resposta:

{
  "id": "MLB9652753",
  "status": "inactive",
  "domain_id": "MLB-CELLPHONES",
  "permalink": "https://www.mercadolivre.com.br/p/MLB9652753",
  "name": "Motorola Moto G6",
  "buy_box_winner": null,
  "pickers": null,
  "pictures": null,
  "main_features": null,
  "attributes": [],
  "short_description": {},
  "parent_id": "",
  "children_ids": [
    "MLB9652754",
    "MLB9652755",
    "MLB9652756",
    "MLB9652757",
    "MLB9707910",
    "MLB9707911",
    "MLB9707912",
    "MLB9707913"
  ]
}

Exemplo de produto children (específico e pode ser usado para anunciar e comprar, se estiver ativo):

curl -X GET https://api.mercadolibre.com/products/MLB9652754

Resposta:

{
  "id": "MLA9652754",
  "status": "active",
  "domain_id": "MLA-CELLPHONES",
  "permalink": "https://www.mercadolibre.com.ar/p/MLA9652754",
  "name": "Motorola G6 32 GB Índigo oscuro",
  "buy_box_winner": {},
  "pickers": [],
  "pictures": [],
  "main_features": [],
  "attributes": [],
  "short_description": {},
  "parent_id": "MLA9652753",
  "children_ids": [
  ]
}

O que nos interessa em relação ao anúncio é:

  • children_ids
    • Se o campo estiver vazio, trata-se de um produto filho e é específico o bastante para ser anunciado.
    • Se contém IDs de outros produtos, isso quer dizer que o catalog_product_id atual corresponde a um produto pai (não completamente especificado). Para anunciar no catálogo, devemos buscar o produto específico entre seus children_ids.
  • status
    • Para poder criar um anúncio de catálogo, é necessário que o produto tenha status ”active”.
    • Os produtos “parent” nunca terão status ”active”, pois não podem ser comprados.

 

Escolhendo o produto específico para o meu anúncio

Seu anúncio e/ou suas variações elegíveis para catálogo terão um catalog_product_id onde você deverá conferir se é adequado para ser anunciado usando o recurso /products/{catalog_product_id}

Exemplo de “catalog_product_id” em um item:

curl -X GET  https://api.mercadolibre.com/items/MLB123456789?access_token={ACCESS_TOKEN}

Resposta resumida:

{
    "id": "MLB123456789",
    "site_id": "MLB",
    "title": "ITEM DE TESTE",
    "subtitle": null,
    "seller_id": 337011113,
    "category_id": "MLB22195",
    "price": 14330,
    "available_quantity": 50,
    "catalog_product_id": "MLB14793781",
    "domain_id": "MLB-AUTOMOTIVE_TIRES"
}

Na hora de criar um anúncio de catálogo a partir de um anúncio existente elegível, você deve conferir com nosso recurso de Produtos:

  • Se o catalog_product_id corresponder a um produto com status “active”, você pode anunciar no catálogo usando esse catalog_product_id
  • Se o catalog_product_id corresponder a um produto que está com status “inactive”.
    • Se o array children_ids estiver vazio, isso quer dizer que o anúncio ou variação já foi associada ao produto mais específico que temos e este ainda não está pronto para ser anunciado no catálogo, portanto, você não pode criar o anúncio de catálogo até que o produto tenha sido editado pelo Mercado Livre.
    • Se o array children_ids não estiver vazio, você deve procurar entre os produtos filho aquele que corresponder exatamente ao que você estiver vendendo.
  • Se você encontrar um catalog_product_id filho ativo que corresponder exatamente ao que você quer vender, pode usá-lo na etapa seguinte para criar seu anúncio de catálogo.
  • Se você não encontrar seu produto exato entre os catalog_product_id filho, ou se encontrar mas não estiver ativo, você não pode anunciar esse produto no catálogo e deve esperar até que o Mercado Livre crie e edite o produto.

Anunciar no catálogo a partir de um anúncio existente

Importante:
Lembre que este recurso estará disponível na Argentina, México e Brasil.

Após conferir que seu anúncio existente é elegível para o catálogo e tiver obtido o catalog_product_id ativo que corresponde exatamente ao que você está anunciando, deve criar o anúncio de catálogo a partir de um POST no recurso /items/catalog_listings.

Sobre as variações

  • Nos domínios onde atualmente existe catálogo, os anúncios de catálogo não contém variações, pois elas estão associadas a um produto específico. Portanto, se seu anúncio original possuía variações, você terá um anúncio de catálogo para cada uma delas. As informações importantes de suas variações (por exemplo, a cor do item) não serão perdidas, mas estarão refletidas nos atributos do produto de catálogo. No futuro, é possível que existam domínios onde o produto nunca especifique perfeitamente o que é vendido (o tamanho em roupas, por exemplo) e é possível que as variações sejam permitidas. Vamos informar quando isso acontecer.
  • Se seu item contém variações, você deve fazer um POST para cada uma delas, enviando o campo variation_id no corpo do POST.

Exemplo de um item com variações:

curl -X POST https://api.mercadolibre.com/items/catalog_listings?access_token={ACCESS_TOKEN}
{
  "item_id":"MLB1234",
  "variation_id": 4321,
  "catalog_product_id":"MLB9876"
}

Exemplo de um item sem variações:

curl -X POST https://api.mercadolibre.com/items/catalog_listings?access_token={ACCESS_TOKEN}
{
  "item_id":"MLB1234",
  "catalog_product_id":"MLB9876" 
}

Exemplo resumido de resposta para a criação de um item:

Resposta:

{
    "id": "MLB1234",
    "site_id": "MLB",
    "title": "Samsung Galaxy J7 Prime 16 Gb Negro",
    "warranty": null,
    "catalog_product_id": "MLB9876",
    "domain_id": "MLB-CELLPHONES",
    "seller_custom_field": null,
    "parent_item_id": null,
    "differential_pricing": null,
    "deal_ids": [],
    "automatic_relist": false,
    "date_created": "2019-08-02T11:33:31.270Z",
    "last_updated": "2019-08-02T11:33:31.270Z",
    "total_listing_fee": null,
    "health": null,
    "catalog_listing": true,
    "item_relations": [
        {
            "id": "MLB123456789",
            "variation_id": null,
            "stock_relation": 1
        }
    ]
}

Além disso, lembre-se de que:

  • Se o item tiver variações, mas for enviado sem elas, o POST falhará, retornando um erro 400.
  • catalog_product_id é um campo obrigatório no POST, o item possuindo ou não variações.

 

Importante:
A partir de 13 de dezembro de 2019, começaremos a criar publicações de catálogo sobre aqueles que são elegíveis.

Essas publicações do catálogo serão criadas com o status pausado e marcadas com a tag catalog_boost. Os vendedores terão 7 (sete) dias para confirmar que vendem exatamente os produtos aos quais os associamos. Após essa data, ativaremos as publicações automaticamente e perderemos a tag com a qual elas foram reconhecidas.

 

Para conhecer o produto ao qual seu item de catálogo pertence, você pode consultar o recurso /products/{product_id}.

Importante:
Lembre-se de ouvir o feed do item e reconhecer quando novos itens são criados.

 

Se a sua ferramenta não permite que o vendedor confirme que vende exatamente os produtos que associamos, você deverá recomendar o seller acessar a lista de publicações em sua conta do Mercado Livre até que se adapte sua ferramenta.

 

Em seguida, você pode ver como o JSON de um item de catálogo se parece.

 

Exemplo de item de catálogo marcado:

curl -X GET https://api.mercadolibre.com/items/MLA123456789

Resposta:

{
   "id":"MLA123456789",
   "site_id":"MLA",
   "title":"Samsung Galaxy A10 32 Gb Negro 2 Gb Ram",
   "subtitle":null,
   "seller_id":12312345,
   "category_id":"MLA1055",
   "official_store_id":null,
   "price":14498.49,
   "base_price":14498.49,
   "original_price":null,
   "currency_id":"ARS",
   "initial_quantity":1,
   "available_quantity":1,
   "sold_quantity":0,
   "sale_terms":[

   ],
   "buying_mode":"buy_it_now",
   "listing_type_id":"gold_special",
   "start_time":"2020-02-25T13:30:06.000Z",
   "stop_time":"2040-02-20T04:00:00.000Z",
   "condition":"new",
   "permalink":"https://articulo.mercadolibre.com.ar/MLA-840863454-samsung-galaxy-a10-32-gb-negro-2-gb-ram-_JM",
   "thumbnail":"http://mla-s1-p.mlstatic.com/935364-MLA31838804614_082019-I.jpg",
   "secure_thumbnail":"https://mla-s1-p.mlstatic.com/935364-MLA31838804614_082019-I.jpg",
   "pictures":[

   ],
   "video_id":"63vjmsBa3nw",
   "descriptions":[

   ],
   "accepts_mercadopago":true,
   "non_mercado_pago_payment_methods":[

   ],
   "shipping":{

   },
   "international_delivery_mode":"none",
   "seller_address":{

   },
   "seller_contact":null,
   "location":{

   },
   "geolocation":{

   },
   "coverage_areas":[

   ],
   "attributes":[

   ],
   "warnings":[

   ],
   "listing_source":"",
   "variations":[

   ],
   "status":"active",
   "sub_status":[

   ],
   "tags":[
      "brand_verified",
      "extended_warranty_eligible",
      "catalog_boost",
      "good_quality_picture",
      "good_quality_thumbnail",
      "immediate_payment",
      "cart_eligible"
   ],
   "warranty":"Garantía del vendedor: 6 meses",
   "catalog_product_id":"MLA14648964",
   "domain_id":"MLA-CELLPHONES",
   "parent_item_id":null,
   "differential_pricing":null,
   "deal_ids":[

   ],
   "automatic_relist":false,
   "date_created":"2020-02-25T13:30:06.000Z",
   "last_updated":"2020-02-28T16:28:14.000Z",
   "health":0.9,
   "catalog_listing":false
}
Nota:
Você poderá realizar uma busca por seller para identificar os ítems que estejam marcados con a tag utilizando o seguinte recurso.

Exemplo:

curl -X GET https://api.mercadolibre.com/users/1234567/items/search?status=paused&tags=catalog_boost&access_token={ACCESS_TOKEN}

 

Para te orientar e realizar testes, você poderá utilizar um usuario de teste, criar um item que cumpra todas as condições necessárias para que esteja elegível ao catálogo, reconhecer qual é o produto específico ativo em catálogo para associá-lo e realizar o POST no recurso /items/catalog_listings
Observação: A publicação de teste NÃO irá competir em catálogo.
Etapas:

  1. Criar user de teste e o item de teste que não terá um catalog_product_id associado.
  2.  Validar o item criado com o recurso de /products/search qual é o catalog_product_id correto para o item.
  3. Uma vez identificado o catalog_product_id, você poderá verificar a elegibilidade com o recurso /items/{item_id}/catalog_listing_eligibility passando o parâmetro catalog_product_id e a variação dependendo das características do item. Desta forma, será verificado se o item é elegível para catálogo.
  4. Uma vez identificado que o item com o catalog_prodcut_id são elegíveis, o próximo passo é realizar o Optin para terminar de associar o item de teste com um item de catálogo.
  5. Realizamos um POST com o recurso /items/catalog_listings para criar a publicação de catálogo relacionada ao item de teste.

Anúncio diretamente no catálogo: Buscador de produtos

Importante:
Este recurso está disponível na Argentina, México e Brasil.

Para publicar um anúncio diretamente no catálogo, é necessário localizar o catalog_product_id que corresponde exatamente com o produto a ser vendido. Com este recurso, você terá uma sugestão de produtos com base em certos parâmetros de busca.

Importante:
O conteúdo do anúncio de catálogo é fornecido pelo Mercado Livre. Portanto, o vendedor é responsável por conferir que o produto a ser associado corresponda às características específicas mostradas na plataforma.
Se houver alguma diferença entre o que o usuário comprar e o produto associado, é possível que existam reclamações e/ou cancelamentos que vão impactar negativamente na sua reputação e, por isso, será suspenso para anunciar no catálogo, levando, eventualmente, ao cancelamento da conta.

Os parâmetros do buscador de produtos podem ser o código universal ou um conjunto de palavras-chave como, por exemplo, marca e modelo.
Parâmetros:

  • site_id: string que representa o país. Obrigatório.
  • status: pode ser que, embora o produto esteja identificado dentro do nosso catálogo, ainda não seja elegível para ser associado a um anúncio.

-status “active”: retorna os produtos que já podem ser escolhidos para associar a um anúncio.
-status “inactive”: retorna os produtos que ainda não podem ser escolhidos para associar a um anúncio.
Esclarecimento: se este parâmetro não for enviado, por padrão, ele trará todos os resultados, tanto ativos quanto inativos.

  • q: string com palavras-chave de busca. Exemplo: “Celular Samsung Galaxy S8” Obrigatório, caso não seja enviado um product_identifier.
  • product_identifier: string com o código universal do produto. Exemplo: EAN, UPC, ISBN etc. Obrigatório, caso não seja enviada uma cadeia de palavras-chave.
  • domain_id: string com o domínio no qual se quer anunciar (opcional).
  • offset: posição da qual são retornados os resultados da busca (opcional).
  • limit: número de resultados retornados pela busca (opcional).

 

Chamada com parâmetro “q”:

curl -X GET https://api.mercadolibre.com/products/search?status={status_id}&site_id={site_id}&q={q}

Exemplo com parâmetro “q”:

curl -X GET https://api.mercadolibre.com/products/search?status=active&site_id=MLB&q=Samsung%20Galaxy%20S8

Resposta com parâmetro “q”:

{
    "keywords": "Samsung Galaxy S8",
    "paging": {
        "total": 5,
        "limit": 10,
        "offset": 0
    },
    "results": [
        {
            "id": "MLB6408702",
            "status": "active",
            "domain_id": "MLB-CELLPHONES",
            "name": "Samsung Galaxy S8 64 GB Azul-coral",
            "attributes": [
                {
                    "id": "BRAND",
                    "name": "Marca",
                    "value_id": "206",
                    "value_name": "Samsung"
                },
            ],
            "pictures": [
                {
                    "id": "907751-MLA31348023274_072019",
                    "url": "https://mla-s2-p.mlstatic.com/907751-MLA31348023274_072019-F.jpg"
                },
                {
                    "id": "972557-MLA31347859895_072019",
                    "url": "https://mla-s1-p.mlstatic.com/972557-MLA31347859895_072019-F.jpg"
                },
                {
                    "id": "727533-MLA31348023275_072019",
                    "url": "https://mla-s1-p.mlstatic.com/727533-MLA31348023275_072019-F.jpg"
                },
                {
                    "id": "779614-MLA31348110125_072019",
                    "url": "https://mla-s1-p.mlstatic.com/779614-MLA31348110125_072019-F.jpg"
                }
            ]
        }
    ]
}

Chamada com parâmetros “q” e “domain_id”:

curl -X GET https://api.mercadolibre.com/products/search?status={status_id}&site_id={site_id}&q={q}&domain_id={domain_id}

Exemplo com parâmetros “q” e “domain_id”:

curl -X GET https://api.mercadolibre.com/products/search?status=active&site_id=MLB&q=Samsung%20Galaxy%20S8&domain_id=MLA-CELLPHONES

Resposta com parâmetros “q” e “domain_id”:

{
  "q": "Samsung Galaxy S8",
  "domain_id":"MLB-CELLPHONES",
  "paging": {
    "total": 10,
    "offset": 0,
    "limit": 10
  },
  "results": [
    {
      "id": "MLB6408699",
      "status": "active",
      "domain_id": "MLB-CELLPHONES",
      "name": "Samsung Galaxy S8 64 GB Gris orquídea",
      "description": "descripción",
      "attributes": [
        {
          "id": "BRAND",
          "name": "Marca",
          "value_id": "206",
          "value_name": "Samsung"
        }
      ],
      "pictures": [
        {
          "id": "924348-MLB31003000895_062019",
          "url": "https://mlb-s2-p.mlstatic.com/924348-MLB31003000895_062019-F.jpg"
        }
      ]
    }
  ]
}

Chamada com parâmetro “product_identifier”:

curl -X GET https://api.mercadolibre.com/products/search?status={status_id}&site_id={site_id}&product_identifier={product_identifier}

Exemplo com parâmetro “product_identifier”:

curl -X GET https://api.mercadolibre.com/products/search?status=active&site_id=MLB&product_identifier=0123456789

Resposta com parâmetro “product_identifier”:

{ 
  "product_identifier": "0123456789", 
  "paging": {
      "total": 10, 
      "offset": 0, 
      "limit": 10 
   }, 
   "results": [ 
        { 
          "id": "MLB6408699", 
          "status": "active", 
          "domain_id": "MLB-CELLPHONES", 
          "name": "Samsung Galaxy S8 64 GB Gris orquídea", 
          "description": "descripción", 
          "attributes": [
                { 
                   "id": "BRAND", 
                  "name": "Marca", 
                  "value_id": "206", 
                  "value_name": "Samsung" 
                } 
           ], 
         "pictures": [ 
              { 
                 "id": "924348-MLB31003000895_062019", 
                 "url": "https://mla-s2-p.mlstatic.com/924348-MLB31003000895_062019-F.jpg" 
              } 
           ] 
        } 
     ] 
  }

Considerações:

  • Dependendo dos parâmetros usados na busca, haverá como resultado um ou vários produtos como sugestão.
  • Se um product_identifier for usado como parâmetro, só será obtido um produto.
  • Se uma palavra-chave for usada como parâmetro, com ou sem domínio, poderá ser obtido um ou vários produtos relacionados aos valores informados.

 

Criar uma publicação de catálogo de maneira direta

Além de realizar publicações de catálogo com uma publicação original, você também pode criar itens de catálogo sem a necessidade de utilizar um item de marketplace para vincular. Tenha em conta que para criar o item de catálogo você deverá considerar os mesmos requisitos mencionados no É possível publicar qualquer ítem em catálogo.
Importante: Tenah em conta que no momento de realizar o POST é necessário enviar os seguintes valores para que seja criada a publicação de catálogo.

  • “catalog_product_id”: este valor deve ser confirmado com o recurso de search/product.
  • “catalog_listing”: true: é necessário enviar o valor como true para gerar o item de catálogo.

 

Chamada:

curl -X POST \https://api.mercadolibre.com/items?access_token={ACCESS_TOKEN}

Exemplo:

curl -X POST -H "Content-Type: application/json" -d
'{
    "site_id": "MLA",
    "title": "Item de test no ofertar",
    "category_id": "MLA1055",
    "price": 10000000,
    "currency_id": "ARS",
    "available_quantity": 1,
    "buying_mode": "buy_it_now",
    "listing_type_id": "gold_special",
    "pictures": [],
    "attributes": [
        {
            "id": "CARRIER",
            "name": "Compañía telefónica",
            "value_id": "298335",
            "value_name": "Liberado",
            "value_struct": null,
            "attribute_group_id": "OTHERS",
            "attribute_group_name": "Otros"
        },
        {
            "id": "ITEM_CONDITION",
            "name": "Condición del ítem",
            "value_id": "2230284",
            "value_name": "Nuevo",
            "value_struct": null,
            "attribute_group_id": "OTHERS",
            "attribute_group_name": "Otros"
        }
    ],
    "catalog_product_id": "MLA6005934",
    "catalog_listing": true
}'
https://api.mercadolibre.com/items?access_token={ACCESS_TOKEN}

Resposta:

{
    "id": "MLA811894603",
    "site_id": "MLA",
    "title": "Apple iPhone iPhone 3g 8 Gb Negro 128 Mb Ram",
    "subtitle": null,
    "seller_id": 464161506,
    "category_id": "MLA1055",
    "official_store_id": null,
    "price": 10000000,
    "base_price": 10000000,
    "original_price": null,
    "inventory_id": null,
    "currency_id": "ARS",
    "initial_quantity": 1,
    "available_quantity": 1,
    "sold_quantity": 0,
    "sale_terms": [],
    "buying_mode": "buy_it_now",
    "listing_type_id": "gold_special",
    "start_time": "2019-08-29T14:49:42.945Z",
    "historical_start_time": "2019-08-29T14:49:42.945Z",
    "stop_time": "2039-08-24T04:00:00.000Z",
    "end_time": "2039-08-24T04:00:00.000Z",
    "expiration_time": "2019-11-17T14:49:42.987Z",
    "condition": "new",
    "permalink": "http://articulo.mercadolibre.com.ar/MLA-811894603-apple-iphone-iphone-3g-8-gb-negro-128-mb-ram-_JM",
    "pictures": [
        {
            "id": "675782-MLA31138875214_062019",
            "url": "http://mla-s1-p.mlstatic.com/675782-MLA31138875214_062019-O.jpg",
            "secure_url": "https://mla-s1-p.mlstatic.com/675782-MLA31138875214_062019-O.jpg",
            "size": "249x500",
            "max_size": "598x1200",
            "quality": ""
        },
        {
            "id": "915001-MLA31138546867_062019",
            "url": "http://mla-s2-p.mlstatic.com/915001-MLA31138546867_062019-O.jpg",
            "secure_url": "https://mla-s2-p.mlstatic.com/915001-MLA31138546867_062019-O.jpg",
            "size": "250x500",
            "max_size": "600x1200",
            "quality": ""
        },
        {
            "id": "881441-MLA31138332972_062019",
            "url": "http://mla-s2-p.mlstatic.com/881441-MLA31138332972_062019-O.jpg",
            "secure_url": "https://mla-s2-p.mlstatic.com/881441-MLA31138332972_062019-O.jpg",
            "size": "243x500",
            "max_size": "585x1200",
            "quality": ""
        },
        {
            "id": "804666-MLA31139286536_062019",
            "url": "http://mla-s1-p.mlstatic.com/804666-MLA31139286536_062019-O.jpg",
            "secure_url": "https://mla-s1-p.mlstatic.com/804666-MLA31139286536_062019-O.jpg",
            "size": "405x500",
            "max_size": "836x1030",
            "quality": ""
        }
    ],
    "video_id": null,
    "descriptions": [
        {
            "id": "MLA811894603-2265773390"
        }
    ],
    "accepts_mercadopago": true,
    "non_mercado_pago_payment_methods": [],
    "shipping": {
        "mode": "not_specified",
        "local_pick_up": false,
        "free_shipping": false,
        "methods": [],
        "dimensions": null,
        "tags": [],
        "logistic_type": "not_specified",
        "store_pick_up": false
    },
    "international_delivery_mode": "none",
    "seller_address": {
        "id": 1061221617,
        "comment": "",
        "address_line": "Test Address 123",
        "zip_code": "1414",
        "city": {
            "id": "",
            "name": "Palermo"
        },
        "state": {
            "id": "AR-C",
            "name": "Capital Federal"
        },
        "country": {
            "id": "AR",
            "name": "Argentina"
        },
        "latitude": 38.11569,
        "longitude": 13.3614868,
        "search_location": {
            "neighborhood": {
                "id": "TUxBQlBBTDI1MTVa",
                "name": "Palermo"
            },
            "city": {
                "id": "TUxBQ0NBUGZlZG1sYQ",
                "name": "Capital Federal"
            },
            "state": {
                "id": "TUxBUENBUGw3M2E1",
                "name": "Capital Federal"
            }
        }
    },
    "seller_contact": null,
    "location": {},
    "geolocation": {
        "latitude": 38.11569,
        "longitude": 13.3614868
    },
    "coverage_areas": [],
    "attributes": [
        {
            "id": "CARRIER",
            "name": "Compañía telefónica",
            "value_id": "298335",
            "value_name": "Liberado",
            "value_struct": null,
            "attribute_group_id": "OTHERS",
            "attribute_group_name": "Otros"
        },
        {
            "id": "ITEM_CONDITION",
            "name": "Condición del ítem",
            "value_id": "2230284",
            "value_name": "Nuevo",
            "value_struct": null,
            "attribute_group_id": "OTHERS",
            "attribute_group_name": "Otros"
        },
        {
            "id": "BRAND",
            "name": "Marca",
            "value_id": "9344",
            "value_name": "Apple",
            "value_struct": null,
            "attribute_group_id": "OTHERS",
            "attribute_group_name": "Otros"
        },
        {
            "id": "LINE",
            "name": "Línea",
            "value_id": "58993",
            "value_name": "iPhone",
            "value_struct": null,
            "attribute_group_id": "OTHERS",
            "attribute_group_name": "Otros"
        },
        {
            "id": "MODEL",
            "name": "Modelo",
            "value_id": "14605",
            "value_name": "iPhone 3G",
            "value_struct": null,
            "attribute_group_id": "OTHERS",
            "attribute_group_name": "Otros"
        },
        {
            "id": "IS_DUAL_SIM",
            "name": "Es Dual SIM",
            "value_id": "242084",
            "value_name": "No",
            "value_struct": null,
            "attribute_group_id": "OTHERS",
            "attribute_group_name": "Otros"
        },
        {
            "id": "COLOR",
            "name": "Color",
            "value_id": "52049",
            "value_name": "Negro",
            "value_struct": null,
            "attribute_group_id": "OTHERS",
            "attribute_group_name": "Otros"
        },
        {
            "id": "INTERNAL_MEMORY",
            "name": "Memoria interna",
            "value_id": "59566",
            "value_name": "8 GB",
            "value_struct": {
                "number": 8,
                "unit": "GB"
            },
            "attribute_group_id": "OTHERS",
            "attribute_group_name": "Otros"
        },
        {
            "id": "RAM",
            "name": "Memoria RAM",
            "value_id": "366239",
            "value_name": "128 MB",
            "value_struct": {
                "number": 128,
                "unit": "MB"
            },
            "attribute_group_id": "OTHERS",
            "attribute_group_name": "Otros"
        },
        {
            "id": "MAIN_COLOR",
            "name": "Color principal",
            "value_id": "2450295",
            "value_name": "Negro",
            "value_struct": null,
            "attribute_group_id": "OTHERS",
            "attribute_group_name": "Otros"
        },
        {
            "id": "OPERATING_SYSTEM_NAME",
            "name": "Nombre del sistema operativo",
            "value_id": "7404961",
            "value_name": "iOS",
            "value_struct": null,
            "attribute_group_id": "OTHERS",
            "attribute_group_name": "Otros"
        },
        {
            "id": "WITH_IMEI",
            "name": "Con IMEI",
            "value_id": "242085",
            "value_name": "Sí",
            "value_struct": null,
            "attribute_group_id": "OTHERS",
            "attribute_group_name": "Otros"
        }
    ],
    "warnings": [],
    "listing_source": "",
    "variations": [],
    "thumbnail": "http://mla-s1-p.mlstatic.com/675782-MLA31138875214_062019-I.jpg",
    "secure_thumbnail": "https://mla-s1-p.mlstatic.com/675782-MLA31138875214_062019-I.jpg",
    "status": "active",
    "sub_status": [],
    "tags": [
        "immediate_payment",
        "test_item"
    ],
    "warranty": null,
    "catalog_product_id": "MLA6005934",
    "domain_id": "MLA-CELLPHONES",
    "seller_custom_field": null,
    "parent_item_id": null,
    "differential_pricing": null,
    "deal_ids": [],
    "automatic_relist": false,
    "date_created": "2019-08-29T14:49:43.099Z",
    "last_updated": "2019-08-29T14:49:43.099Z",
    "total_listing_fee": null,
    "health": null,
    "catalog_listing": true,
    "item_relations": []
}

 

Concorrendo para ganhar as vendas

Receba notificações de posts que mudam de status na competição

Você pode se inscrever no tópico item competition para começar a receber notificações sobre a mudança de status dos itens do catálogo. Ele permite identificar as modificações no status de competição para vencedor ou vice-versa.

Para visualizar as informações da concorrência e revisar as condições com as que o vendedor está competindo para ganhar a página de produto, deve utilizar o recurso /price_to_win e entender que ações deve tomar.

Saiba mais sobre como receber notificações.

 

Como conhecer o preço para ganhar

As publicações de catálogo concorrem para obter as vendas da página de produto e existe um algoritmo que determina quem será o vencedor nessas vendas, baseado nas características da publicação e do vendedor.
O algoritmo que avalia qual será a publicação vencedora considera principalmente:

  • preço da publicação
  • parcelas sem juros
  • envio full, envio grátis, envio no dia

Observações:

  • Algumas dessas características podem aplicar somente a alguns compradores (exemplo: envio no dia ou desconto de Mercado Pontos). Nesses casos, fazemos o melhor esforço por escolher um vencedor considerando o comprador particular, levando em consideração que características são aplicáveis a ele.
  • Pelo dito acima, apesar de que falemos de “vencedor” de forma unívoca, eventualmente o vendedor poderia estar vencendo em geral, mas não em particular, para certos usuários (ex.: se morarem muito longe e não obteriam nunca o envio no dia).

Para que os vendedores possam concorrer eficientemente, oferecemos um recurso que indica o estado em que está a publicação de catálogo, isso pode variar, pois uma publicação pode ser vencedora, competitiva ou listada. O último estado tem os motivos pelos quais a publicação não concorre.

Chamada:

curl -X GET https://api.mercadolibre.com/items/$ITEM_ID/price_to_win?access_token=$ACCESS_TOKEN

Exemplo de item concorrente:

curl -X GET https://api.mercadolibre.com/items/MLB1234/price_to_win?access_token=$ACCESS_TOKEN

Resposta:

"item_id": "MLA123456789",
    "current_price": 21499.0,
    "currency_id": "ARS",
    "price_to_win": 17600.0,
    "boosts": {
        "fulfillment": false,
        "free_installments": false,
        "free_shipping": true,
        "same_day_shipping": false
    },
    "status": "competing",
    "reason": [],
    "catalog_product_id": "MLA9652755"
}

Exemplo de item vencedor:

curl -X GET https://api.mercadolibre.com/items/MLB123456710/price_to_win?access_token=$ACCESS_TOKEN

Resposta:

{
    "item_id": "MLA123456710",
    "current_price": 20499.0,
    "currency_id": "ARS",
    "price_to_win": 20499.0,
    "boosts": {
        "fulfillment": false,
        "free_installments": true,
        "free_shipping": true,
        "same_day_shipping": false
    },
    "status": "winning",
    "reason": [],
    "catalog_product_id": "MLA9652755"
}

Exemplo de item que não concorre:

curl -X GET https://api.mercadolibre.com/items/MLB123456710/price_to_win?access_token=$ACCESS_TOKEN

Resposta:

{
    "item_id": "MLA123456710",
    "current_price": 68000,
    "currency_id": "ARS",
    "price_to_win": null,
    "boosts": {
        "same_day_shipping": false,
        "fulfillment": false,
        "free_installments": false,
        "free_shipping": true,
        "cross_docking": false,
        "drop_off": true,
        "shipping_quarantine": false
    },
    "status": "listed",
    "reason": [
        "item_paused"
    ]

 

Como ler a resposta:

  • O campo status indica se estamos ganhando para o público geral (poderíamos estar ganhando para segmentos minoritários com os que não aproveitam o envio no dia). Quando estamos ganhando, o valor é winning, quando não estamos ganhando, é competing.
  • O campo boosts indica quais características da nossa publicação estão aportando para as chances de ganhar. As possibilidades são:
    • same_day_shipping: Envios no dia pelo Mercado Envíos.
    • fulfillment: Mercado Envios Full.
    • free_installments: Parcelamento sem juros.
    • free_shipping: Envio sem custo pelo Mercado Envios.
    • shipping_quarantine: Envios com normalidade.
    • shipping_collect: Mercado Envios coleta.
  • O campo price_to_win indica qual é o preço (na moeda atual da publicação) para ser o ganhador. Isto é que, fazendo um PUT ao recurso /itens com o preço sugerido, você garante ser o ganhador.

 

  • O campo reason mostrará informações quando o item não estiver competindo, podendo identificar o motivo pelo qual ele não está fazendo isso.

 

Valores possíveis para reason

Reason Descrição
non_trusted_seller O vendedor não está na lista de permissões de fraude. Não pode competir. Ele aparece nas listagens em segundo plano.
reputation_below_threshold O vendedor não atinge a reputação mínima para ganhar. Não pode competir. Aparece apenas nas listagens.
winner_has_better_reputation O vendedor tem uma reputação que pode competir, mas há um vencedor com uma reputação melhor. No momento, ele aparece apenas nas listagens (caixa amarela com vencedor verde).
manufacturing_time O item possui manufacturing time, aparece apenas nas listagens e não pode vencer porque o vencedor possui estoque imediato.
temporarily_winning_manufacturing_time O item possui manufacturing time, está ganhando temporariamente porque não há concorrentes no mesmo nível de reputação sem MF.
temporarily_competing_manufacturing_time O item tiene manufacturing time, esta compitiendo temporalmente porque no hay competidores en el mismo nivel de reputación sin MF, el winner también tiene MF.
temporarily_winning_best_reputation_available O vendedor não é verde, mas tem uma reputação que pode ganhar e é a melhor oferta disponível. Ele está ganhando temporariamente. Se uma oferta melhor aparecer, pare de ganhar.
temporarily_competing_best_reputation_available O vendedor não é verde, mas é a melhor reputação disponível, está competindo temporariamente. O vencedor também é da mesma reputação. Se um best-seller aparecer, ele será listado apenas novamente.
item_paused O item está em pausa, não pode ser listado.
item_not_opted_in O item não fiz opt in, não pode ser listado ou é um item de teste.

Neste chamado, você deverá utilizar um item_id de uma publicação de catálogo, no caso de não poder fazê-lo, você obterá um código de erro 4XX.
Além disso, existem variáveis como a reputação, que são utilizadas para determinar o ganhador. Contudo, para um bom vendedor, as variáveis acima serão as utilizadas para determinar o ganhador.
Importante: em breve disponibilizaremos um recurso para receber notificações quando o vendedor se transforme em ganhador de um produto.

Conheça as condições e o preço do item vencedor

A tabela de competição permitirá que os vendedores comparem e melhorem as condições do item. Com a nova versão do recurso price_to_win, você pode adicionar via API uma tabela de competição para comparar as condições de um item que está competindo e as do vencedor. Com essa funcionalidade em seu desenvolvimento, os vendedores terão conhecimento de quais condições melhorar para ganhar a página do produto.

Chamada:

curl -X GET https://api.mercadolibre.com/items/$ITEM_ID/price_to_win?siteId=$SITE_ID&version=v2

Exemplo:

curl -X GET https://api.mercadolibre.com/items/MLA123456789/price_to_win?siteId=MLA&version=v2

Resposta:

{
    "item_id": "MLA848886211",
    "current_price": 85990,
    "currency_id": "ARS",
    "price_to_win": 65200,
    "boosts": [
        {
            "id": "same_day_shipping",
            "status": "opportunity",
            "description": "Envíos en el dia por Mercado Envíos"
        },
        {
            "id": "fulfillment",
            "status": "opportunity",
            "description": "Mercado Envíos Full"
        },
        {
            "id": "free_installments",
            "status": "opportunity",
            "description": "Cuotas sin interés"
        },
        {
            "id": "free_shipping",
            "status": "not_boosted",
            "description": "Envíos gratis por Mercado Envíos"
        },
        {
            "id": "shipping_quarantine",
            "status": "boosted",
            "description": "Envío con normalidad"
        },
        {
            "id": "shipping_collect",
            "status": "boosted",
            "description": "Mercado Envíos Colecta"
        }
    ],
    "status": "competing",
    "reason": [],
    "catalog_product_id": "MLA14186099",
    "winner": {
        "item_id": "MLA849174940",
        "price": 76999,
        "currency_id": "ARS",
        "boosts": [
            {
                "id": "same_day_shipping",
                "status": "not_apply",
                "description": "Envíos en el dia por Mercado Envíos"
            },
            {
                "id": "fulfillment",
                "status": "boosted",
                "description": "Mercado Envíos Full"
            },
            {
                "id": "free_installments",
                "status": "boosted",
                "description": "Cuotas sin interés"
            },
            {
                "id": "free_shipping",
                "status": "not_boosted",
                "description": "Envíos gratis por Mercado Envíos"
            },
            {
                "id": "shipping_quarantine",
                "status": "boosted",
                "description": "Envío con normalidad"
            },
            {
                "id": "shipping_collect",
                "status": "opportunity",
                "description": "Mercado Envíos Colecta"
            }
        ]
    }
}

Na nova versão do recurso, além dos campos já conhecidos na versão anterior, adicionamos as informações do item que estamos consultando e as do item que está ganhando (caso o item consultado esteja competindo).

Portanto, primeiro visualizamos o preço e as condições de venda listadas nos boosts, com um status e uma explicação, permitindo comparar rapidamente com a segunda lista que se refere à publicação que está ganhando a página do produto.

Os boosts são aqueles já mencionados nos campos de resposta da versão anterior. Agora, você pode reconhecer o status deles no boost e desenhar uma tabela comparativa de acordo.

Estado dos boost Detalhe
boosted tem a condição de venda e atualmente aplica o aumento.
not_boosted possui a condição de venda, mas não é um boost que aumenta as chances de ganhar.
opportunity não possui condição de venda. Caso aplique, melhoraria as chances de ganhar.
not_apply a condição de vendas não se aplica como um boost ao produto em que o item concorre.
Nota:
Lembre-se de que essas informações permitem comparar rapidamente com a segunda listagem sobre a publicação do item que está ganhando a página do produto.

Conheça a publicação que está ganhando um produto

Usando o recurso de /products/{product_id} , além de conhecer as características e o status do produto, você pode reconhecer a publicação que está ganhando a página do produto com o campo buy_box_winner.

 

Como conhecer a relação de publicações para um produto

Se você precisar conhecer quais são os itens (de todos os vendedores) que concorrem pelas vendas de um produto em particular, tem um recurso que entrega a você essas informações.

Chamada:

curl -X GET https://api.mercadolibre.com/products/{product_id}/items

Exemplo:

curl -X GET https://api.mercadolibre.com/products/MLB6309815/items

Resposta simplificada:

{
  "paging": {
    "total": 7,
    "offset": 0,
    "limit": 100
  },
  "results": [
    {
      "item_id": "MLA824759321",
      "category_id": "MLA1055",
      "seller_id": 90205574,
      "price": 13999,
      "currency_id": "ARS",
      "sold_quantity": 0,
      "available_quantity": 1,
      "installments": {
        "quantity": 1,
        "amount": 13999,
        "rate": 0,
        "currency_id": "ARS"
      },
      "shipping": {
        "mode": "me2",
        "tags": [
          "mandatory_free_shipping"
        ],
        "free_shipping": true,
        "logistic_type": "fulfillment",
        "store_pick_up": false
      },
      "warranty": "Garantía de fábrica: 1 años",
      "condition": "new",
      "sale_terms": [
        {
          "id": "INVOICE",
          "name": "Facturación",
          "value_id": "6891885",
          "value_name": "Factura A",
          "value_struct": null
        },
        {
          "id": "WARRANTY_TYPE",
          "name": "Tipo de garantía",
          "value_id": "2230279",
          "value_name": "Garantía de fábrica",
          "value_struct": null
        },
        {
          "id": "WARRANTY_TIME",
          "name": "Tiempo de garantía",
          "value_id": null,
          "value_name": "1 años",
          "value_struct": {
            "number": 1,
            "unit": "años"
          }
        }
      ],
      "official_store_id": null,
      "original_price": null,
      "listing_type_id": "gold_special",
      "accepts_mercadopago": true,
      "seller_address": {
        "city": {
          "id": "TUxBQ0xBWmI3M2Q3",
          "name": "Santa Fe"
        },
        "state": {
          "id": "TUxBUFNBTmU5Nzk2",
          "name": "Santa Fe"
        },
        "neighborhood": {
          "id": "TUxBQk9UUjQyMjJa",
          "name": "Otros Barrios"
        }
      },
      "international_delivery_mode": "none",
      "tags": [
        "brand_verified",
        "extended_warranty_eligible",
        "good_quality_picture",
        "good_quality_thumbnail",
        "immediate_payment",
        "cart_eligible"
      ],
      "tier": ""
    },
    {},
    {},
    {},
    {},
    {},
    {}
  ]
}

Tenha em conta que em “results” terá os itens que estão competindo para ganhar esse produto.

 

Filtro

O filtro funcionará da mesma forma que no recurso de Search (/sites/{site}/search) onde utilizar os valores de available_filters como parâmetro na URI é possível.

Atualmente, você tem as seguintes opções de filtragem:

Parâmetros Valor Descrição
official_store all Para mostrar apenas produtos com vencedor de Lojas Oficiais.
official_store_id id Para mostrar os produtos vencedores de uma loja oficial.
discount 10-100 Para mostrar os produtos vencedores com desconto maior ou igual a 10%.
price 100-200 Para produtos vencedores com preço entre 100 e 200.
*100 para produtos com vencedor com preço maior ou igual a 100.
*200 para produtos com vencedor com preço menor ou igual a 200.
installments no_interest Para produtos com vencedor com parcelamentos sem juros.
shipping fulfillment Para produtos com vencedor com FBM.
shipping mercadoenvios Para produtos com vencedor sem FBM.
shipping_cost free Para produtos con vencedor com frete grátis.
shipping_time sameday/ nextday Deve ser usado junto com a query param b.buyer_zones, que indica em quais áreas o comprador está localizado.
seller_id id Obter o vencedor user_id

Ejemplo:

curl -X GET https://api.mercadolibre.com/products/MLB6309815/items?shipping_cost=free

Exemplo:

curl -X GET https://api.mercadolibre.com/products/MLB6309815/items?shipping=free

Criar um anúncio de catálogo associado a um anúncio existente significa criar um novo item do recurso /items com uma ID própria e única. Ao ser criado o novo item de catálogo, você receberá notificações, tanto de criação quanto de alteração, como de costume. Exemplo resumido de consulta no anúncio tradicional.

 

Chamada:

curl -X GET https://api.mercadolibre.com/items/{item_id}?access_token={ACCESS_TOKEN}

Exemplo:

curl -X GET https://api.mercadolibre.com/items/MLB1234?access_token={ACCESS_TOKEN}

Resposta:

{ 
  "variations": [ 
     { 
      "id": 36296213011, 
      "price": 50, 
      "attribute_combinations": [
         { 
           "id": "COLOR", 
           "name": "Color", 
           "value_id": "52014", 
           "value_name": "Verde" 
         }, 
         { 
           "id": "SIZE", 
           "name": "Talle", 
           "value_id": null, 
           "value_name": "8 litros" 
        } 
     ], 
     "available_quantity": 2, 
     "sold_quantity": 0, 
     "sale_terms": [], 
     "picture_ids": [ 
        "937728-MLB26910896929_1111111", 
        "911601-MLB26910896930_1111111", 
        "762115-MLB26910896931_1111111", 
        "827037-MLB26910896928_1111111" 
     ], 
    "seller_custom_field": null, 
    "catalog_product_id": null,
    "attributes": [ 
        { 
          "id": "T_SHIRT_SIZE", 
         "name": "Talle de la remera", 
         "value_id": "5727532", 
         "value_name": "6XL" 
       } 
     ], 
    "item_relations": [ 
       { 
         "id": "MLA987654321", 
         "variation_id": null, 
         "stock_relation": 1 
       }
     ]
    } 
  ], 
    "catalog_listing": false, 
    "item_relations": [] 
}

Exemplo resumido de item de catálogo:
Chamada:

curl -X GET https://api.mercadolibre.com/items/{item_id}/?access_token={ACCESS_TOKEN}

Exemplo:

curl -X GET https://api.mercadolibre.com/items/MLB1234?access_token={ACCESS_TOKEN}

Resposta:

{
   "variations": [], 
   "catalog_listing": true, 
   "item_relations": [
        { 
          "id": "MLA1234", 
          "variation_id": 36296213006, 
          "stock_relation": 1 
        }
    ] 
 }

Como reconhecer o anúncio de catálogo e o original

Para entender qual é o anúncio de catálogo e qual é o tradicional, você conta com o campo catalog_listing. no recurso /items. Se o valor for “true”, é um anúncio de catálogo. Se o valor for “false”, é o anúncio tradicional associado. Para ver as informações completas do item, você deve usar o access token.

Como conhecer a relação entre anúncios associados

O campo item_relations no recurso /items (com access token), informará quais anúncios estão associados ao atual. O único dado que será compartilhado nos dois anúncios será o estoque. Por isso, quando o vendedor receber uma venda ou alterar o estoque em um anúncio, ambos serão automaticamente ajustados.
No futuro, pode haver diversos anúncios associados e a relação de diminuição de estoque poderá ser diferente de 1. Leve isso em consideração ao elaborar seu sistema.

As perguntas nos anúncios de catálogo são gerenciadas da mesma forma que nos anúncios tradicionais, porém, elas não estão sincronizadas. Isso quer dizer que as perguntas e respostas que você receber pelos anúncios de catálogo não serão visíveis nos anúncios tradicionais e vice-versa.
No site, quando uma pergunta é feita na página de produto, a consulta fica unicamente associada ao item vencedor desse momento e não é compartilhada com outro item que, em outro momento, possa ser vencedor na página de produto.

 

Como gerenciar as orders, visitas, etc.

As publicações de catálogo são itens como qualquer outro, logo a administração das orders é igual a de uma publicação tradicional, com exceção de que estas orders contarão com a tag catalog para diferenciar as orders tradicionais. Na resposta do recurso /orders, o item_id fará referencia ao produto que tenha sido comprado.
As publicações relacionadas não compartilham nenhuma outra informação a não ser o stock. Por exemplo, as visitas e vendas que estão completamente individuais.
Exemplo resumido de uma order de catálogo:

 

Chamada:

curl -X GET https://api.mercadolibre.com/orders/{order_id}?access_token={ACCESS_TOKEN} 

Exemplo:

curl -X GET https://api.mercadolibre.com/orders/1234567890?access_token={ACCESS_TOKEN} 

Resposta:

{
  "id": 1234567890,
  "date_created": "2019-08-27T23:39:10.000-04:00",
  "date_closed": "2019-08-28T10:46:14.000-04:00",
  "last_updated": "2019-08-28T10:46:14.000-04:00",
  "manufacturing_ending_date": null,
  "feedback": {},
  "mediations": [
  ],
  "comments": null,
  "pack_id": null,
  "pickup_id": null,
  "order_request": {},
  "fulfilled": null,
  "total_amount": 16000,
  "total_amount_with_shipping": 16000,
  "paid_amount": 16000,
  "coupon": {},
  "expiration_date": "2019-09-25T10:46:14.000-04:00",
  "order_items": [
    {
      "item": {
        "id": "MLA123456789",
        "title": "Motorola G6 Plus 64 Gb",
        "category_id": "MLA1055",
        "variation_id": null,
        "seller_custom_field": "MO-CEL-N0011",
        "variation_attributes": [
        ],
        "warranty": "Garantía de fábrica: 12 meses",
        "condition": "new",
        "seller_sku": "MO-CEL-N0011"
      },
      "quantity": 1,
      "unit_price": 16000,
      "full_unit_price": 16000,
      "currency_id": "ARS",
      "manufacturing_days": null
    }
  ],
  "currency_id": "ARS",
  "payments": [],
  "shipping": {},
  "status": "paid",
  "status_detail": null,
  "tags": [
    "catalog",
    "not_delivered",
    "paid"
  ],
  "buyer": {},
  "seller": {},
  "taxes": {
    "amount": null,
    "currency_id": null
  }
}

As vendas das publicações de catálogo são gestionadas da mesma forma que as de publicaciones tradicionais. Isto quer dizer que por cada venda que seja gerada desde un item de catálogo, será criada uma order com a mesma informação que contém uma venda de uma publicação tradicional, com a diferença que iremos identificá-las com a tag de “catalog”. A order terá asociada o item de catálogo. E enviaremos notificações tanto quando for criada como quando houver alguma atualização.

Ciclo de vida de anúncios associados

Se você remover ou pausar uma variação de um item de marketplace relacionada a um item de catálogo, a relação entre os anúncios se perderá, mas o item de catálogo não será desativado. Se você excluir o item de catálogo, o anúncio tradicional continuará ativo.
Os anúncios de catálogo podem ser criados e excluídos sempre que necessário. Os vendedores cujo comportamento de vendas for estável não terão sua capacidade de obter vendas da página de produto impactada pelo histórico de vendas do anúncio.

Condições de venda como preço, forma de envio e a condição poderão ser alteradas. Além disso, elas podem ser diferentes das condições do anúncio original.
Fotos, títulos, descrições e fichas técnicas não poderão ser alterados, porque são informações padronizadas pelo Mercado Livre. A condição do produto também não pode ser modificada.

 

Fonte: https://developers.mercadolivre.com.br/pt_br/o-catalogo-chegou-saiba-como-adaptar-sua-integracao

Matriz de confusão

No campo de aprendizado de máquina e, especificamente, no problema de classificação estatística , uma matriz de confusão , também conhecida como matriz de erros, [6] é um layout de tabela específico que permite a visualização do desempenho de um algoritmo, tipicamente um aprendizado supervisionado (em aprendizado não supervisionado , geralmente é chamado de matriz correspondente ). Cada linha da matriz representa as instâncias em uma classe prevista, enquanto cada coluna representa as instâncias em uma classe real (ou vice-versa). [2] O nome deriva do fato de que é fácil ver se o sistema está confundindo duas classes (ou seja, geralmente classificando incorretamente uma como outra).

É um tipo especial de tabela de contingência , com duas dimensões (“real” e “previsto”) e conjuntos idênticos de “classes” em ambas as dimensões (cada combinação de dimensão e classe é uma variável na tabela de contingência).

Exemplo

Se um sistema de classificação foi treinado para distinguir entre cães e gatos, uma matriz de confusão resumirá os resultados do teste do algoritmo para uma inspeção mais aprofundada. Supondo que uma amostra de 13 animais – 8 gatos e 5 cães – a matriz de confusão resultante possa se parecer com a tabela abaixo:

Classe real
Gato Cachorro
Classe prevista
Gato 5 2
Cachorro 3 3

Nesta matriz de confusão, dos 8 gatos reais, o sistema previu que três eram cães, e dos cinco cães, previu que dois eram gatos. Todas as previsões corretas estão localizadas na diagonal da tabela (destacadas em negrito), portanto é fácil inspecionar visualmente a tabela quanto a erros de previsão, pois eles serão representados por valores fora da diagonal.

Tabela de confusão 

Na análise preditiva , uma tabela de confusão (às vezes também chamada de matriz de confusão ) é uma tabela com duas linhas e duas colunas que relata o número de falsos positivos , falsos negativos , verdadeiros positivos e verdadeiros negativos. Isso permite uma análise mais detalhada do que a mera proporção de classificações corretas (precisão). A precisão não é uma métrica confiável para o desempenho real de um classificador, porque produzirá resultados enganosos se o conjunto de dados for desequilibrado (ou seja, quando o número de observações em diferentes classes varia muito). Por exemplo, se houvesse 95 gatos e apenas 5 cães nos dados, um classificador específico poderia classificar todas as observações como gatos. A precisão geral seria de 95%, mas com mais detalhes o classificador teria uma taxa de reconhecimento de 100% ( sensibilidade ) para a classe de gatos, mas uma taxa de reconhecimento de 0% para a classe de cães. A pontuação F1 é ainda mais confiável nesses casos, e aqui renderia mais de 97,4%, enquanto a informação remove esse viés e gera 0 como a probabilidade de uma decisão informada para qualquer forma de adivinhação (aqui, sempre adivinhando o gato).

De acordo com Davide Chicco e Giuseppe Jurman, a métrica mais informativa para avaliar uma matriz de confusão é o coeficiente de correlação de Matthews (MCC) [5] .

Assumindo a matriz de confusão acima, sua tabela de confusão correspondente, para a classe cat, seria:

Classe real
Gato Não gato
Classe prevista
Gato 5 verdadeiros positivos 2 falsos positivos
Não gato 3 negativos falsos 3 verdadeiros negativos

A tabela final de confusão conteria os valores médios para todas as classes combinadas.

Vamos definir um experimento a partir de instâncias P positivas e N negativas para alguma condição. Os quatro resultados podem ser formulados em uma matriz de confusão 2 × 2 , da seguinte maneira:

Condição verdadeira
População total Condição positiva Condição negativa Prevalência Σ Condição positiva/population População total Precisão (ACC) = Σ Verdadeiro positivo + Σ Verdadeiro negativo/Σ População total

Condição prevista
Condição prevista
positiva
Verdadeiro positivo Falso positivo ,
erro tipo I
Valor preditivo positivo (VPP), Precisão = Σ Verdadeiro positivo/Σ Condição prevista positiva Taxa de descoberta falsa (FDR) = Σ Falso positivo/condition Condição prevista positiva
Condição prevista
negativa
Falso negativo ,
erro tipo II
Verdadeiro negativo Taxa de falsa omissão (FOR) = Σ Falso negativo/Σ Condição prevista negativa Valor preditivo negativo (VPN) = negative Verdadeiro negativo/Σ Condição prevista negativa
Taxa positiva verdadeira (TPR), Rechamada , Sensibilidade , probabilidade de detecção, Potência Σ Verdadeiro positivo/Σ Condição positiva Taxa de falso positivo (FPR), Fallout , probabilidade de alarme falso Σ Falso positivo/Σ Condição negativa Razão de verossimilhança positiva (LR +) TPR/FPR Odds ratio diagnóstico (DOR) LR +/LR− 1 pontuação = 2 · Precisão · Recuperação/Precisão + Recuperação
Taxa de falsos negativos (FNR), taxa de faltas = Σ Falso negativo/Σ Condição positiva Especificidade (RCM), Seletividade, Taxa negativa verdadeira (TNR) Σ Verdadeira negativa/Σ Condição negativa Razão de verossimilhança negativa (LR−) FNR/TNR

Referências

  1. ^ Fawcett, Tom (2006). “Uma introdução à análise ROC” (PDF) . Cartas de reconhecimento de padrão . 27 (8): 861–874. doi : 10.1016 / j.patrec.2005.10.010 .
  2. Salte para:b Poderes, David MW (2011). “Avaliação: da precisão, rechamada e medida F ao ROC, informação, marcação e correlação” (PDF) . Jornal de Tecnologias de Aprendizado de Máquina . 2 (1): 37-63.
  3. ^ Ting, Kai Ming (2011). Enciclopédia de aprendizado de máquina . Springer. ISBN978-0-387-30164-8.
  4. ^ Brooks, Harold; Castanho, Barb; Ebert, Beth; Ferro, Chris; Jolliffe, Ian; Koh, Tieh-Yong; Roebber, Paul; Stephenson, David (26-01- 2015). “Grupo de Trabalho Conjunto WWRP / WGNE sobre Pesquisa de Verificação de Previsão” . Colaboração para a pesquisa australiana sobre clima e clima . Organização Meteorológica Mundial . Recuperado em 17/07/2019 .
  5. Salte para:b Chicco D, Jurman G (janeiro de 2020). “As vantagens do coeficiente de correlação de Matthews (MCC) sobre o escore F1 e a precisão na avaliação da classificação binária” . BMC Genomics . 21 (6) doi : 10.1186 / s12864-019-6413-7 . PMC 6941312 . PMID 31898477 .
  6. ^ Stehman, Stephen V. (1997). “Seleção e interpretação de medidas de precisão de classificação temática”. Sensoriamento Remoto do Ambiente . 62 (1): 77-89. doi : 10.1016 / S0034-4257 (97) 00083-7 .

Fonte: https://en.wikipedia.org/wiki/Confusion_matrix

Design Responsivo para Flutter: Introdução

Às vezes, a configuração muda para um aplicativo em um dispositivo móvel. Talvez um teclado apareça de repente ou o usuário gire o dispositivo. Ou talvez você queira exibir seu aplicativo em dispositivos pequenos e grandes.

De qualquer forma, seu aplicativo precisa responder a essas alterações de layout. Se você usar o Design Responsivo , ele usará.

Neste tutorial do Flutter, você:

  • Crie um aplicativo de bate-papo no Flutter que responda às alterações no layout.
  • Aprenda a usar de vibração MediaQueryLayoutBuilderOrientationBuilderFittedBoxAspectRatiowidgets.
  • Aprenda a lidar com mudanças de orientação.
  • Realize redimensionamento de texto.
  • Restrinja um widget filho em uma coluna.
  • Aprenda sobre a ideia do CustomMultiChildLayoutwidget.
Nota : Este tutorial supõe que você já esteja familiarizado com o básico do desenvolvimento do Flutter. Se você é novo no Flutter, leia o  tutorial Introdução ao Flutter . Você também deve ter conhecimento do uso do Android Studio com Flutter.

O que é Design Responsivo?

O conceito de Design Responsivo tem tudo a ver com o uso de um conjunto de códigos que respondem a várias alterações no layout. Plataformas como os SDKs nativos do iOS e Android resolveram esse problema com “layouts universais”. Os layouts universais respondem a alterações de layout usando restrições e redimensionando elementos automaticamente.

Existem várias razões pelas quais o layout precisa mudar responsavelmente dos desenhos iniciais.

Manipulação de diferentes tipos de dispositivos e tamanhos de tela

Layouts responsivos

Seu aplicativo Flutter pode ser executado em um telefone, tablet, tela de TV ou (quando eles começam a suportá-lo) assistir. Mesmo na categoria de telefones, há uma grande variedade de resoluções e tamanhos de tela diferentes. Você precisa garantir que o layout funcione conforme o planejado para cada tipo de dispositivo e tamanho de tela. Além disso, você pode ter layouts diferentes para cada tipo de dispositivo e tamanho de tela.

Com isso em mente, o Flutter fornece vários widgets e classes para o design responsivo. Você aprenderá sobre alguns deles neste tutorial.

Manipulando Alterações de Estado do Teclado

Sua interface pode ter campos de texto. O teclado aparece quando o usuário começa a interagir com esses campos. Quando esse teclado é exibido, também ocorrem problemas de layout.

O Android lida com isso com alterações na configuração do teclado. O iOS usa notificações internas para alterações de estado do teclado. Mas no Flutter, a Scaffoldclasse lida automaticamente com as alterações de estado do teclado.

Em detalhes, Scaffoldajusta as inserções inferiores para liberar espaço para o teclado. No entanto, você pode desativar esse comportamento definindo a resizeToAvoidBottomInsetpropriedade como false.

Você pode ler mais sobre Scaffolda interação do teclado aqui .

Como lidar com alterações de orientação

Vamos ser sinceros, os usuários podem girar o dispositivo e o fazem com frequência. Você pode desativar a resposta a isso no seu aplicativo, bloqueando-o no modo retrato ou paisagem, mas seu aplicativo não seria tão divertido e poderá ser menos útil em relação à experiência do usuário.

Quando a rotação ocorre no Flutter, MediaQuerypode ajudar a reconstruir seu layout. MaterialAppWidgetsAppjá use MediaQuery. Se você usá-los, o Flutter recria seus widgets em MaterialAppse a orientação mudar.

Você pode ler mais sobre MediaQuery aqui .

Agora que você entende os motivos do Design responsivo, é hora de ver o que os widgets do Flutter podem fazer para ajudar.

Começando

Faça o download do projeto inicial clicando no botão Download de materiais na parte superior ou inferior do tutorial. Em seguida, abra o projeto inicial no Android Studio 3.4 ou posterior. Você também pode usar o VS Code, mas precisará adaptar as instruções abaixo, conforme necessário.

Você deve usar uma versão recente do Flutter, 1.5 ou superior. Certifique-se de obter dependências do Flutter para o projeto, se solicitado pelo Android Studio com a mensagem ‘Packages get’ não foi executada .

Você encontrará que o projeto inicial fornece algumas partes do aplicativo de bate-papo com as quais você trabalhará.

Usando o MediaQuery para decidir o layout

Agora você deve tentar usar MediaQuerypara determinar o layout. Essa é apenas uma das opções que você pode usar para responder às alterações de layout. Você poderá usar as outras opções nas próximas seções.

Vá para o arquivo ChatListPage.dart na pasta lib . Substitua o conteúdo de build(BuildContext context)por:

// 1 
var hasDetailPage =
    MediaQuery.of (context) .orientation == Orientation.landscape;
// 2
Filho Widget;

if (hasDetailPage) {
   // 3
  filho = linha (
    crianças: [
      // 4
      SizedBox (
        largura: 250 ,
        altura: infinito duplo ,
        filho: _buildList (contexto, hasDetailPage),
      ),
      // 5
      Expandido (filho: _buildChat (context, selectedIndex)),
    ],
  );
} mais {
   // 6
  filho = _buildList (contexto, hasDetailPage);
}

andaime de retorno (
  appBar: AppBar (
    title: Text ( "Bate-papo" ),
  ),
  body: SafeArea (
    // 7
    criança: criança,
  ),
);

Com isso, você cria a página de bate-papo usando  MediaQuery. Aqui está o que você fez:

  1. Primeiro, você verifica a orientação de MediaQuery. Se for paisagem, você tem uma página de detalhes.
  2. Segundo, você declara um widget filho para uso posterior.
  3. Em seguida, se você tiver uma página de detalhes, declara o filho como uma linha de widgets.
  4. Para isso, a linha contém a lista de bate-papos como um primeiro item.
  5. Em seguida, o próximo item da linha é a página de bate-papo que mostra a conversa.
  6. Se você não tiver uma página de detalhes, a criança será a lista de bate-papos.
  7. Por fim, você precisa atribuir o widget filho que você criou como filho SafeArea.

Crie e execute o projeto – você deve ver uma tela como esta para retrato:

Retrato da lista de bate-papo

E isso para a paisagem:

Lista de bate-papo com paisagem detalhada

Você notará que o layout é diferente para retrato e paisagem. Você também pode tentar executá-lo em um dispositivo diferente, como um tablet.

Usando widgets no design responsivo

Como mencionado anteriormente, existem outros widgets que atingem o mesmo efeito que MediaQuery. Por exemplo, LayoutBuilderpermite que você faça a mesma coisa. Você verá isso nesta seção.

Além disso, existem outros problemas de layout com o aplicativo de bate-papo. Por exemplo, o tamanho do texto no avatar do usuário não é dimensionado. Você vai consertar isso daqui a pouco.

Usando LayoutBuilder e OrientationBuilder

LayoutBuilderOrientationBuildersão alternativas MediaQuerypara lidar com mudanças de orientação. Hora de ver exatamente como eles funcionam, começando com LayoutBuilder.

Primeiro, abra o ChatListPage.dart , como você fez na seção anterior. Substitua o conteúdo de build(...)por:

andaime de retorno (
  appBar: AppBar (
    title: Text ( "Bate-papo" ),
  ),
  body: SafeArea (
    // 1
    filho: LayoutBuilder (construtor: (construtor, restrições) {
      // 2 
      var hasDetailPage = constraints.maxWidth> 600 ;

      if (hasDetailPage) {
         // 3 
        retorna Row (
          crianças: [
            // 4
            SizedBox (
              largura: 250 ,
              altura: infinito duplo ,
              filho: _buildList (contexto, hasDetailPage),
            ),
            // 5
            Expandido (filho: _buildChat (context, selectedIndex)),
          ],
        );
      } else {
         // 6 
        return _buildList (context, hasDetailPage);
      }
    }),
  ),
);

Com isso, você cria a página de bate-papo novamente, desta vez usando LayoutBuilder. Aqui está o que você fez:

  1. Primeiro, você declara a LayoutBuildercomo filho de SafeArea.
  2. Segundo, você determina se possui uma página de detalhes usando a largura máxima do widget pai. Se for maior que 600, você terá uma página de detalhes.
  3. Em seguida, se você tiver uma página de detalhes, declara filho como uma linha de widgets.
  4. Para isso, a linha contém a lista de bate-papos como um primeiro item.
  5. Em seguida, o próximo item da linha é a página de bate-papo que mostra a conversa.
  6. Por fim, se você não tiver uma página de detalhes, será a lista de bate-papos.

Crie e execute o projeto. Você deve ver a mesma tela nas diferentes orientações da seção anterior.

Se você também quiser tentar OrientationBuilder, substitua as linhas por LayoutBuildere a configuração de hasDetailPagepor:

filho: OrientationBuilder (construtor: (construtor, orientação) {  
   var hasDetailPage = guidance == Orientation.landscape;

Essa pequena alteração tem o mesmo efeito. Em vez de ler a largura do widget pai, você lê a orientação do widget pai no construtor. Se a orientação for paisagem, você terá uma página de detalhes.

Crie e execute o projeto. Você deve ver as mesmas telas de antes. Como você pode ver, cada um desses vários widgets pode resolver o problema de diferentes orientações e tamanhos de tela.

Em seguida, você corrigirá o texto que não está sendo redimensionado no avatar do usuário.

Redimensionamento automático de texto com base no tamanho do widget pai

Como você pode ver na captura de tela da paisagem acima, o texto nas caixas coloridas do usuário não está sendo redimensionado corretamente para preencher a caixa. Você não pode simplesmente aumentar o tamanho da fonte, pois pode passar por cima da caixa. A maneira correta de fazer isso é permitir que o widget seja dimensionado de acordo com o tamanho do widget pai.

O widget Flutter FittedBoxpode resolver esse problema.

Usando FittedBox

Abra AvatarImageView.dart em lib / widgets e verifique o conteúdo de _buildContent(Color textColor). Você pode ver aqui um Textwidget que renderiza as iniciais do usuário. O tamanho da fonte é 14. Coloque o Textwidget FittedBoxcomo abaixo:

// 1 
retorno FittedBox (
   // 2
  fit: BoxFit.contain,
  // 3
  filho: texto (
    iniciais,
    style: TextStyle (cor: textColor, fontSize: 14 ),
  ),
);

Isso faz com que o Textwidget preencha o widget pai e siga as BoxFit.containregras. Passando por cada linha:

  1. Primeiro, você declara a FittedBoxcomo pai do Textwidget.
  2. Segundo, você usa o BoxFit.containajuste para aumentar o tamanho possível sem sair da caixa de widgets.
  3. Por fim, você declara o Textwidget original como filho.

Crie e execute o projeto. Você verá o seguinte na orientação paisagem:

Texto redimensionado em paisagem

Agora você vê que o texto foi redimensionado de acordo. Em geral, você pode usar outros tipos de BoxFit. Você pode ver como cada um deles se comporta na imagem abaixo:

Opções BoxFit

Fornecendo restrições às crianças

Há um botão de anexo de imagem de clipe de papel no seu aplicativo de bate-papo. Isso deve permitir que você selecione imagens de uma galeria. Geralmente, você deseja exibi-lo na visualização de bate-papo para poder continuar vendo a conversa enquanto escolhe uma imagem.

No momento, isso não está sendo exibido. Clique no botão anexar e você verá apenas o seguinte para retrato:

Galeria no retrato inicial

e isso para paisagem:

Galeria na paisagem inicial

Usando o AspectRatio

Você precisa consertar a galeria quebrada. Primeiro, abra o arquivo ConversationPage.dart na pasta lib . Em seguida, procure a linha SquareGallery()com um TODO .

Esse widget não está aparecendo porque é filho Columne não possui informações suficientes para determinar sua própria altura. Portanto, envolva-o em um  AspectRatiowidget para fornecer restrições. Substitua a SquareGallery()linha pelo seguinte:

Proporção da tela(
  aspectRatio: 3 ,
  filho: SquareGallery (),
),

Agora que a galeria está envolvida AspectRatio, ela terá uma restrição que tenta seguir a proporção fornecida. Será três vezes mais largo do que alto. Além disso, AspectRatiotentará encontrar restrições que se encaixem no que você forneceu como proporção, bem como nas restrições pai.

No entanto, se não encontrar essa restrição, fornecerá uma que segue apenas a proporção que você forneceu. Nesse caso, o widget pode estourar.

Crie e execute o projeto. Ao clicar no botão de anexo da imagem, você verá uma tela como esta para retrato:

Retrato final da galeria

e isso para paisagem:

Galeria paisagem final

Parabéns! Agora você corrigiu os problemas de layout no aplicativo. Você pode finalmente responder novamente nos chats! :]

CustomMultiChildLayout

Além dos widgets básicos para o design responsivo, o Flutter também fornece uma maneira de criar widgets por conta própria CustomMultiChildLayout. Agora você verá como usá-lo, mas apenas na teoria. Por CustomMultiChildLayoutser um tópico tão grande, você verá apenas o básico aqui.

Confira o snippet de código abaixo:

CustomMultiChildLayout (
  delegar: delegar,
  filhos: widgets,
)

Aqui você declara um CustomMultiChildLayoutcom um delegado personalizado. O delegado pode ser um objeto de uma classe como o seguinte:

// 1 
classe  RWDelegate  estende  MultiChildLayoutDelegate  {
   // 2 
  @override 
  void performLayout (tamanho do tamanho) {
     // Faça seu layout aqui
  }

  // 3 
  @override 
  bool shouldRelayout (MultiChildLayoutDelegate oldDelegate) => false ;
}

Aqui está o que você fez:

  1. Primeiro, você declara uma subclasse de MultiChildLayoutDelegate.
  2. Segundo, você substitui o performLayoutmétodo. Aqui você precisa fazer o layout dos widgets filhos usando os métodos layoutChildpositionChild.
  3. Por fim, você retorna um booleano de shouldRelayoutse o widget deve executar um layout novamente. Este método deve decidir com base nos parâmetros ou estado do seu próprio widget.

Você pode ler a documentação completa deste widget aqui e do delegado  aqui . Procure um tutorial completo CustomMultiChildLayoutem nossa página Flutter em breve!

Para onde ir a partir daqui?

Você pode baixar o projeto concluído clicando no botão Download de materiais na parte superior ou inferior do tutorial.

Se você estiver interessado, consulte os documentos oficiais dos aplicativos responsivos no Flutter  aqui  e o livro de receitas oficial do design  aqui .

Também existem bons guias sobre como desenvolver aplicativos para vários tamanhos de tela e orientações aqui e aqui .

A equipe do Flutter também fez uma apresentação no Google I / O 2019 sobre UIs adaptáveis ​​no Flutter. Você pode assistir aqui .

Você também pode querer ler sobre as configurações de acessibilidade de texto em cada plataforma.

Espero que você tenha gostado deste tutorial sobre Design Responsivo com Flutter! Se você tiver alguma dúvida ou comentário, participe da discussão no fórum abaixo.

Fonte: https://www.raywenderlich.com/4324124-responsive-design-for-flutter-getting-started

Observador de interseção

Observador de interseção

Rascunho do Editor, 

Esta versão:
https://szager-chromium.github.io/IntersectionObserver/
Última versão publicada:
https://www.w3.org/TR/intersection-observer/
Suíte de teste:
http://w3c-test.org/intersection-observer/
Rastreamento de problemas:
GitHub
Editor:
 ( Google )
Antigo editor:
 ( Google )

Esta é uma iteração V2 proposta da especificação IntersectionObserver. Essa cor de plano de fundo identifica as alterações propostas na V1.


Abstrato

Esta especificação descreve uma API que pode ser usada para entender a visibilidade e a posição dos elementos DOM (“destinos”) em relação a um elemento que contenha ou à viewport de nível superior (“raiz”). A posição é entregue de forma assíncrona e é útil para entender a visibilidade dos elementos e implementar o pré-carregamento e o adiamento do conteúdo do DOM.

Status deste documento

Esta seção descreve o status deste documento no momento de sua publicação. Outros documentos podem substituir este documento. Uma lista das publicações atuais do W3C e a revisão mais recente deste relatório técnico podem ser encontradas no índice de relatórios técnicos do W3C em https://www.w3.org/TR/.

Este documento foi publicado pelo Web Platform Working Group como um rascunho dos editores. Este documento pretende se tornar uma recomendação do W3C.

Comentários e comentários sobre esta especificação são bem-vindos; envie-os para public-webapps@w3.org ( inscrição , arquivos ) [intersection-observer]no início do assunto do seu email.

A publicação como rascunho do editor não implica o endosso da associação ao W3C . Este é um rascunho de documento e pode ser atualizado, substituído ou obsoleto por outros documentos a qualquer momento. Não é apropriado citar este documento como outro trabalho que não esteja em andamento.

Este documento foi produzido por um grupo que opera sob a Política de Patentes do W3C . O W3C mantém uma lista pública de todas as divulgações de patentes feitas em conexão com as entregas do grupo; essa página também inclui instruções para divulgar uma patente. Um indivíduo que tenha conhecimento real de uma patente que acredite conter Reivindicações Essenciais deve divulgar as informações de acordo com a seção 6 da Política de Patentes do W3C .

Este documento é regido pelo Documento de Processo do W3C de 1 de fevereiro de 2018 .

1. Introdução

Os mecanismos tradicionais de cálculo de posição da Web se baseiam em consultas explícitas do estado DOM que são conhecidas por causar recálculo e layout de estilo (caro) e, frequentemente, são uma fonte de sobrecarga de desempenho significativa devido à pesquisa contínua dessas informações.

Um corpo de prática comum evoluiu que depende desses comportamentos, no entanto, incluindo (mas não limitado a):

  • Construção de carregamento pré e adiado personalizado de DOM e dados.
  • Implementando listas de rolagem de alto desempenho vinculadas a dados que carregam e processam subconjuntos de conjuntos de dados. Essas listas são um idioma central de interação móvel.
  • Calculando a visibilidade do elemento. Em particular, as redes de anúncios agora exigem relatórios de “visibilidade” de anúncios para monetizar impressões . Isso levou muitos sites a abusar de manipuladores de rolagem (causando jank on scroll), layout síncrono invocando readbacks (causando trabalho crítico desnecessário em loops rAF) e recorrendo a soluções exóticas baseadas em plug-ins para calcular a “verdadeira” visibilidade do elemento (com todas as informações associadas) sobrecarga da arquitetura do plug-in).

Esses casos de uso têm várias propriedades comuns:

  1. Eles podem ser representados como “consultas” passivas sobre o estado de elementos individuais em relação a algum outro elemento (ou a janela de exibição global).
  2. Eles não impõem requisitos de latência rígida; isto é, a informação pode ser entregue de forma assíncrona (por exemplo, de outro segmento) sem penalidade.
  3. Eles são pouco suportados por quase todas as combinações de recursos existentes da plataforma da Web, exigindo um esforço extraordinário do desenvolvedor, apesar do uso generalizado.

Uma não meta notável são as informações precisas em pixels sobre o que realmente foi exibido (o que pode ser bastante difícil de obter com eficiência em determinadas arquiteturas de navegadores em face de filtros, webgl e outros recursos). Em todos esses cenários, as informações são úteis mesmo quando entregues com um pequeno atraso e sem dados perfeitos de resultados de composição.

A API Intersection Observer soluciona os problemas acima, oferecendo aos desenvolvedores um novo método para consultar de forma assíncrona a posição de um elemento em relação a outros elementos ou à janela de exibição global. A entrega assíncrona elimina a necessidade de consultas caras de DOM e estilo, pesquisa contínua e uso de plug-ins personalizados. Ao eliminar a necessidade desses métodos, permite que os aplicativos reduzam significativamente seus custos de CPU, GPU e energia.

var observador = Novo IntersectionObserver(alterar => {
  para (const mudança do alterar) {
    console.registro(mudança.Tempo);               // Registro de data e hora quando a alteração ocorreu
    console.registro(mudança.rootBounds);         // Área da raiz não cortada
    console.registro(mudança.boundingClientRect); // target.boundingClientRect ()
    console.registro(mudança.intersectionRect);   // boundingClientRect, recortado por seus ancestrais de bloco contendo e cruzado com rootBounds
    console.registro(mudança.intersectionRatio);  // Relação entre a área intersectionRect e a área boundingClientRect
    console.registro(mudança.alvo);             // o elemento Target
  }
} {});

// Observe os eventos de interseção em um elemento de destino específico.
observador.observar(alvo);

// Pare de observar eventos de interseção em um elemento de destino específico.
observador.desobedecer(alvo);

// Pare de observar eventos de limite em todos os elementos de destino.
observador.desconectar();

2. Observador de interseção

A API Intersection Observer permite que os desenvolvedores entendam a visibilidade e a posição dos elementos DOM de destino em relação a uma raiz de interseção .

2.1 The IntersectionObserverCallback

ligue de volta IntersectionObserverCallback = vazio (seqüência<IntersectionObserverEntry> entries, IntersectionObserver observer);

Esse retorno de chamada será chamado quando houver alterações na interseção do alvo com a raiz da interseção , conforme o modelo de processamento .

2.2 A interface IntersectionObserver

IntersectionObserverinterface pode ser usada para observar alterações na interseção de uma raiz de interseção e um ou mais alvos Element .

Um IntersectionObservercom a root Elementpode observar qualquer alvo Element que seja descendente do rootna cadeia de blocos que o contém .

Um IntersectionObserversem root Elementobservará automaticamente interseções com a raiz implícita , e válidos alvos incluem qualquer Elementno contexto de navegação de nível superior , bem como qualquer Elementem quaisquer contextos de navegação aninhados dentro do contexto de navegação de nível superior .

Nota: Em MutationObserver, as MutationObserverInitopções são passadas para observe()enquanto IntersectionObserverestão sendo passadas para o construtor. Isso ocorre porque, para MutationObserver, cada um Nodesendo observado pode ter um conjunto diferente de atributos para filtrar. Pois IntersectionObserver, os desenvolvedores podem optar por usar um único observador para rastrear vários destinos usando o mesmo conjunto de opções; ou eles podem usar um observador diferente para cada destino rastreado.

rootMarginou thresholdvalores para cada destino parecem introduzir mais complexidade sem resolver casos de uso adicionais. Per- observe()opções poderia ser fornecido no futuro, se V2 apresenta uma necessidade para ela.

[Construtor(IntersectionObserverCallback callback, opcional IntersectionObserverInit options), Exposto=Janela] interface IntersectionObserver { somente leitura atributo Elemento? raiz; somente leitura atributo DOMString rootMargin; somente leitura atributo FrozenArray<Duplo> limiares; [proposto] somente leitura atributo grandesdemora;  [proposto] somente leitura atributo boleanotrackVisibility; vazio observar(Elemento target); vazio desobedecer(Elemento target); vazio desconectar(); seqüência<IntersectionObserverEntry> takeRecords(); };
new IntersectionObserver(callback, options)
  1. Que este seja um novo IntersectionObserverobjeto
  2. Defina este[[callback]] slot interno para retorno de chamada .
  3. Defina isso . raiz para opções . raiz .
  4. Tente analisar uma margem raiz das opções . rootMargin . Se uma lista for retornada, defina esse[[rootMargin]] slot interno como esse. Caso contrário, lance uma SyntaxErrorexceção.
  5. Permita que os limites sejam uma lista igual às opções . limiar .
  6. Se qualquer valor nos limites for menor que 0,0 ou maior que 1,0, lance uma RangeErrorexceção.
  7. Classifique os limites em ordem crescente.
  8. Se limiares está vazio, de acréscimo 0de limiares .
  9. Defina isso . limiares para limiares .
  10. Se opções . trackVisibility é true, e opções . atraso não está especificado ou é menor que 100lança uma NotAllowedErrorexceção.
  11. Defina isso . atraso nas opções . atraso .
  12. Defina isso . trackVisibility para opções . trackVisibility .
  13. Devolva isso .
observe(target)
  1. Se alvo é esta é interna [[ObservationTargets]]slot retorno.
  2. Permita que o registro seja um IntersectionObserverRegistrationregistro com:
  3. Anexe o registro ao slot interno do alvo[[RegisteredIntersectionObservers]] .
  4. Adicione -alvo para este ‘s interno [[ObservationTargets]]slot.
  5. Agende uma iteração do loop de evento no root‘s contexto de navegação .
unobserve(target)
  1. Remova o IntersectionObserverRegistrationregistro cuja observerpropriedade é igual a isso do slot interno do destino[[RegisteredIntersectionObservers]] .
  2. Remove -alvo a partir deste ‘s interno [[ObservationTargets]]slot.

Nota: MutationObserver não implementa unobserve(). Para IntersectionObserverunobserve()aborda o caso de uso de carregamento lento. Depois que o alvo se torna visível, ele não precisa ser rastreado. Seria mais trabalhoso para disconnect()todos os destinos e observe()os restantes, ou criar um separado IntersectionObserverpara cada destino .

disconnect()
Para cada alvo em este é interna [[ObservationTargets]]ranhura:

  1. Remova o IntersectionObserverRegistrationregistro cuja observerpropriedade é igual a isso do slot interno do destino[[RegisteredIntersectionObservers]] .
  2. Remove -alvo a partir deste ‘s interno [[ObservationTargets]]slot.
takeRecords()
  1. Vamos fila de ser uma cópia do presente ‘s interno [[QueuedEntries]]slot.
  2. Limpe esse[[QueuedEntries]] slot interno .
  3. Fila de retorno .
root, do tipo Elemento , somente leitura, anulável
A raiz Elementa ser usada para interseção ou nullse o observador usar a raiz implícita .
rootMargin, do tipo DOMString , somente leitura
Compensações aplicadas à caixa delimitadora da raiz da interseção , aumentando ou diminuindo efetivamente a caixa usada para calcular as interseções. Observe que isso rootMarginé aplicado apenas a destinos que pertencem à mesma unidade de contextos de navegação de origem semelhante relacionados à raiz da interseção .

Ao obter, retorne o resultado da serialização dos elementos [[rootMargin]]separados por espaço, onde os comprimentos de pixel serão serializados como o valor numérico seguido de “px” e as porcentagens serializadas como o valor numérico seguido de “%”. Observe que isso não garante que seja idêntico às opções . rootMarginpassado para o IntersectionObserverconstrutor. Se nenhum rootMarginfoi passado para o IntersectionObserverconstrutor, o valor desse atributo é “0px 0px 0px 0px”.

thresholds, do tipo FrozenArray < double >, somente leitura
Uma lista de limites, classificados em ordem numérica crescente, em que cada limite é uma proporção da área de interseção com a área da caixa delimitadora de um destino observado. As notificações para um destino são geradas quando qualquer um dos limites é ultrapassado para esse destino. Se não houver opções . thresholdfoi fornecido ao IntersectionObserverconstrutor, o valor desse atributo será [0].
delay, do tipo long , somente leitura
Um número que indica o atraso mínimo em milissegundos entre as notificações desse observador para um determinado destino.
trackVisibility, do tipo booleano , somente leitura
Um booleano indicando se isso IntersectionObserverrastreará alterações na visibilidade de um destino .

A raiz intersecção para um IntersectionObserveré o valor de seu rootatributo, ou então o de nível superior contexto de navegação do documento nó (referida como a raiz implícita ) se o rootatributo é null.

O retângulo de interseção raiz de um IntersectionObserveré o retângulo que usaremos para verificar os alvos.

Se a raiz da interseção for a raiz implícita ,
é o tamanho da janela de exibição.
Se a raiz da interseção tiver um clipe de estouro,
é a área de conteúdo do elemento .
De outra forma,
é o resultado da execução do getBoundingClientRect()algoritmo na raiz da interseção .

Para qualquer alvo que pertence à mesma unidade de contextos de navegação semelhante relativa à origem como a raiz de intersecção , o retângulo é então expandido de acordo com os deslocamentos no IntersectionObservers’ [[rootMargin]]ranhura de uma maneira semelhante à da CSS margem de propriedade, com os quatro valores indicando o As margens superior, direita, inferior e esquerda, respectivamente, são compensadas por, com comprimentos positivos indicando um deslocamento externo. As porcentagens são resolvidas em relação à largura do retângulo não dilatado.

Nota: rootMargin aplica-se apenas à raiz da interseção . Se um destino Element for cortado por um ancestral que não seja a raiz da interseção , esse recorte não será afetado rootMargin.

Nota: O retângulo de interseção da raiz não é afetado pelo zoom de pitada e reportará a janela de visualização não ajustada , consistente com a intenção do zoom de pitada (para agir como uma lupa e NÃO alterar o layout).

Para analisar uma margem raiz de uma string de entrada marginString , retornando uma lista de comprimentos ou porcentagens de 4 pixels ou falha:

  1. Analise uma lista de valores do componente marginString , armazenando o resultado como tokens .
  2. Remova todos os tokens de espaço em branco dos tokens .
  3. Se o comprimento dos tokens for 0 ou maior que 4, retorne a falha.
  4. Substitua cada token em tokens :
    • Se o token for um token de dimensão de comprimento absoluto , substitua-o por um comprimento de pixel equivalente.
    • Se o token for um <percentage> , substitua-o por uma porcentagem equivalente.
    • Caso contrário, retorne a falha.
  5. Se houver um elemento nos tokens , anexe três duplicatas desse elemento aos tokens . Se houver dois elementos são tokens , anexe uma duplicata de cada elemento aos tokens . Se houver três elementos nos tokens , anexe uma duplicata do segundo elemento aos tokens .
  6. Retornar tokens .

2.3 A interface IntersectionObserverEntry

[Constructor(IntersectionObserverEntryInit intersectionObserverEntryInit)] interface IntersectionObserverEntry { somente leitura atributo DOMHighResTimeStamp Tempo; somente leitura atributo DOMRectReadOnly? rootBounds; somente leitura atributo DOMRectReadOnly boundingClientRect; somente leitura atributo DOMRectReadOnly intersectionRect; somente leitura atributo boleano isIntersecting; [proposto] somente leitura atributo boleanoé visível; somente leitura atributo Duplo intersectionRatio; somente leitura atributo Elemento alvo; }; dicionário IntersectionObserverEntryInit { requeridos DOMHighResTimeStamp time; requeridos DOMRectInit? rootBounds; requeridos DOMRectInit boundingClientRect; requeridos DOMRectInit intersectionRect; requeridos boleano isIntersecting; [proposto] requeridos boleanoisVisible; requeridos Duplo intersectionRatio; requeridos Elemento target; };
boundingClientRect, do tipo DOMRectReadOnly , somente leitura
DOMRectReadOnlyobtido executando o getBoundingClientRect()algoritmo no target.
intersectionRect, do tipo DOMRectReadOnly , somente leitura
boundingClientRect, interceptadas pelas rects de cada targetclipe ancestral (até, mas não incluindo root), interceptadas com o retângulo de interseção raiz . Este valor representa a porção não recortado de targetdentro do rectângulo intersecção raiz .
isIntersecting, do tipo booleano , somente leitura
truese o targetcruzar com o rootfalsede outra forma. Este sinalizador permite distinguir entre IntersectionObserverEntrysinalizar a transição de interseção para não interseção; e uma IntersectionObserverEntrysinalização de uma transição de não interseção para interseção com um retângulo de interseção de área zero (como acontecerá com interseções adjacentes à borda ou quando a boundingClientRectárea tiver zero).
isVisible, do tipo booleano , somente leitura
truese o algoritmo de visibilidade , quando executado target, retornartrue .
intersectionRatio, do tipo double , somente leitura
Se a área boundingClientRectfor diferente de zero, será a proporção da intersectionRectárea para a boundingClientRectárea. Caso contrário, será 1 se isIntersectingfor truee 0 se não.
rootBounds, do tipo DOMRectReadOnly , somente leitura, anulável
Se targetpertencer à mesma unidade de contextos de navegação de origem semelhante relacionados à raiz de interseção , esse será o retângulo de interseção de raiz . Caso contrário, isso será null. Observe que se o destino estiver em um contexto de navegação diferente da raiz da interseção , ele estará em um sistema de coordenadas diferente de boundingClientRectintersectionRect.
target, do tipo Element , somente leitura
Elementinterseção cuja com a raiz da interseção foi alterada.
time, do tipo DOMHighResTimeStamp , somente leitura
O atributo deve retornar um DOMHighResTimeStampque corresponda à hora em que a interseção foi registrada, em relação à origem da hora do objeto global associado à instância IntersectionObserver que gerou a notificação.

2.4 O dicionário IntersectionObserverInit

dicionário IntersectionObserverInit { Elemento? raiz = nulo; DOMString rootMargin= "0px"; (Duplo ou seqüência<Duplo>) limite= 0; [proposto] grandesdemora= 0;  [proposto] boleanotrackVisibility = falso;  };
root, do tipo Elemento , anulável, padronizado comonull
raiz a ser usada para interseção. Se não for fornecido, use a raiz implícita .
rootMargin, do tipo DOMString , padronizado como"0px"
Semelhante à propriedade da margem CSS , essa é uma sequência de 1 a 4 componentes, cada um com comprimento absoluto ou porcentagem.

"5px"                // todas as margens definidas para 5 px
"5px 10px"           // superior e inferior = 5 px, direita e esquerda = 10 px
"-10px 5px 8px"      // superior = -10 px, direita e esquerda = 5 px, inferior = 8 px
"-10px -5px 5px 8px" // superior = -10px, direita = -5px, inferior = 5px, esquerda = 8px
threshold, do tipo (double or sequence<double>), padronizado como0
Lista de limites nos quais acionar retorno de chamada. o retorno de chamada será chamado quando a área de intersectionRect for alterada de maior ou igual a qualquer limite para menor que esse limite e vice-versa.

Os valores limite devem estar no intervalo de [0, 1,0] e representar uma porcentagem da área do retângulo produzida executando o getBoundingClientRect()algoritmo no destino .

Nota: 0.0 é efetivamente “qualquer número diferente de zero de pixels”.

delay, do tipo long , padronizado como0
Um número que especifica o atraso mínimo em milissegundos entre as notificações do observador para um determinado destino.
trackVisibility, do tipo booleano , padronizado comofalse
Um booleano indicando se o observador deve rastrear a visibilidade . Observe que a visibilidade do rastreamento provavelmente será uma operação mais cara que o rastreamento de cruzamentos. Recomenda-se que esta opção seja usada apenas conforme necessário.

3. Modelo de Processamento

Esta seção descreve as etapas que o agente do usuário deve executar ao implementar a API do Intersection Observer .

3.1 Definições de slot interno

3.1.1 Documento

Cada documento tem um sinalizador IntersectionObserverTaskQueued que é inicializado false.

3.1.2 Elemento

Elementobjetos têm um [[RegisteredIntersectionObservers]]slot interno , que é inicializado em uma lista vazia. Esta lista contém IntersectionObserverRegistrationregistros que têm:

  • uma observerpropriedade

segurando um IntersectionObserver,

  • uma previousThresholdIndexpropriedade com um número entre -1 e o comprimento da thresholdspropriedade do observador (inclusive),
  • uma previousIsIntersectingpropriedade segurando um booleano,
  • uma lastUpdateTimepropriedade com um DOMHighResTimeStampvalor ,
  • uma previousIsVisiblepropriedade que possui um valor boolen .

3.1.3 IntersectionObserver

IntersectionObserver Os objetos têm os seguintes slots internos:

  • Um [[QueuedEntries]]slot inicializado para uma lista vazia.
  • Um [[ObservationTargets]]slot inicializado para uma lista vazia.
  • Um [[callback]]slot inicializado por IntersectionObserver(callback, options). inicializado com um DOMHighResTimeStampque corresponde à hora, relativa à origem da hora do objeto global associado ao objeto em que a instância foi criada, menos 100.
  • Um [[rootMargin]]slot que é uma lista de quatro comprimentos ou porcentagens de pixels.

3.2 Algoritmos

3.2.1 Enfileirar uma tarefa de observador de interseção

Para enfileirar uma tarefa de observador de interseção para um documento do documento , execute estas etapas:

  1. Se o sinalizador IntersectionObserverTaskQueued do documento estiver definido como , retorne.true
  2. Defina o sinalizador IntersectionObserverTaskQueued do documento como .true
  3. A fila de uma tarefa ao documento ‘s ciclo de eventos para notificar os observadores de intersecção .

3.2.2 Notificar observadores de interseção

Para notificar observadores de interseção para um documento do documento , execute estas etapas:

  1. Defina o sinalizador IntersectionObserverTaskQueued do documento como .false
  2. Permita que a lista de notificações seja uma lista de todos os IntersectionObservers que rootestão na árvore do documento do DOM .
  3. Para cada observador deIntersectionObserver objetos na lista de notificações , execute estas etapas:
    1. Se o slot interno do observador[[QueuedEntries]] estiver vazio, continue.
    2. Deixe a fila ser uma cópia do slot interno do observador[[QueuedEntries]] .
    3. Limpe o espaço interno do observador[[QueuedEntries]] .
    4. Chame o retorno de chamada com fila como o primeiro argumento e o observador como o segundo argumento e retorne o valor de retorno . Se isso gerar uma exceção, relate a exceção .

3.2.3 Enfileirar um IntersectionObserverEntry

Para enfileirar um IntersectionObserverEntry para um IntersectionObserver observador , dado um documento Document ; DOMHighResTimeStamp tempo ; DOMRectflag de rootBounds , boundingClientRect , intersectionRect e isIntersecting ; e um Element alvo ; execute estas etapas:

  1. Construa um IntersectionObserverEntry, passando no tempo , rootBounds , boundingClientRect , intersectionRect , isIntersecting e target .
  2. Anexe-o ao slot interno do observador[[QueuedEntries]] .
  3. Enfileire uma tarefa de observador de interseção para o documento .

3.2.4 Calcular a interseção de um elemento de destino e a raiz

Para calcular a interseção entre um destino e a raiz de interseção do observador , execute estas etapas:

  1. Seja intersectionRect o resultado da execução do getBoundingClientRect()algoritmo no destino .
  2. Deixe o container ser o bloco que contém o alvo .
  3. Enquanto o contêiner não é a raiz da interseção :
    1. Mapa intersectionRect ao espaço de coordenadas do recipiente .
    2. Se o contêiner estiver com recorte excedente ou uma propriedade de caminho do clipe de css , atualize o intersectionRect aplicando o clipe do contêiner .
    3. Se contêiner for o elemento raiz de um contexto de navegação aninhado , atualize o contêiner para ser o contêiner de contexto de navegação do contêiner e atualize intersectionRect recortando a janela de exibição do contexto de navegação aninhado . Caso contrário, atualize o contêiner para ser o bloco de contêiner que o contém .
  4. Mapa intersectionRect ao espaço de coordenadas da raiz intersecção .
  5. Atualize intersectionRect cruzando-o com o retângulo de interseção raiz .
  6. Mapa intersectionRect ao espaço de coordenadas da janela de exibição do documento que contém o alvo .

3.2.5 Calcule se um Alvo está desclassificado, não transformado, não filtrado e opaco.

Para calcular a visibilidade de um destino , execute estas etapas:

  1. Se o observador ‘s trackVisibilityatributo é false, de retorno true.
  2. Se o destino tiver uma matriz de transformação eficaz que não seja uma tradução 2D ou um aumento proporcional em 2D, retorne false.
  3. Se o alvo , ou qualquer elemento em sua cadeia de blocos que contenha , tiver uma opacidade efetiva diferente de 100%, retorne false.
  4. Se o destino , ou qualquer elemento em sua cadeia de blocos que contenha , tiver algum filtro aplicado, retorne false.
  5. Se a implementação não puder garantir que o destino não esteja completamente ocluído por outro conteúdo da página, retorne false.

Nota: As implementações devem usar o retângulo de estouro de tinta do conteúdo da página ao determinar se um destino está ocluído. Para efeitos de desfoque , que têm extensão teoricamente infinita, a definição de trabalho recomendada para a região de excesso de tinta é a extensão da aproximação padrão de desfoque de caixa tripla de um filtro gaussiano, ou seja ((3 * sqrt(2 * π) / 4) * σ),.

  1. Retorno true.

3.2.6 Calcular a matriz de transformação eficaz de um destino

Para calcular a matriz de transformação efetiva de um destino , execute estas etapas:

  1. Seja matriz a serialização da função de transformação de identidade .
  2. Deixe o recipiente ser o alvo.
  3. Enquanto o contêiner não é a raiz da interseção :
    1. Conjunto de t para recipiente de matriz de transformação .
    2. Defina a matriz como pós-multiplicada pela matriz .
    3. Se contêiner for o elemento raiz de um contexto de navegação aninhado , atualize o contêiner para ser o contêiner de contexto de navegação do contêiner . Caso contrário, atualize o contêiner para ser o bloco de contêiner que o contém .
  4. Matriz de retorno .

3.2.7 Execute as etapas de observação de interseção de atualização

Para executar as etapas de observação de interseção de atualização para um documento do documento com um horário de data e hora , execute estas etapas:

  1. Permita que a lista de observadores seja uma lista de todos os IntersectionObservers que rootestão na árvore do documento do DOM .
  2. Para cada observador na lista de observadores :
    1. Vamos rootBounds ser observador da intersecção retângulo raiz .
    2. Para cada destino no espaço interno do observador[[ObservationTargets]] , processado na mesma ordem em que observe()foi chamado em cada destino :
      1. Permita que o registro seja o IntersectionObserverRegistrationregistro no espaço interno do alvo[[RegisteredIntersectionObservers]] cuja observerpropriedade seja igual ao observador .
      2. Se , pule o processamento adicional para o destino .(time - registration.lastUpdateTime < observer.delay)
      3. Defina o registro . lastUpdateTimeao tempo .
      4. Se a raiz de interseção não for a raiz implícita e o destino não for um descendente da raiz de interseção na cadeia de blocos que o contém , pule o processamento adicional para o destino .
      5. Se a raiz de interseção não for a raiz implícita e o destino não estiver no mesmo documento que a raiz de interseção , pule o processamento adicional para o destino .
      6. Permita que targetRect seja DOMRectReadOnlyobtido executando o getBoundingClientRect()algoritmo no alvo .
      7. Seja intersectionRect o resultado da execução do cálculo do algoritmo de interseção no destino .
      8. Deixe targetArea ser a área de targetRect .
      9. Permita que intersectionArea seja a área de intersectionRect .
      10. Seja isIntersecting be truese targetRect e rootBounds se cruzam ou são adjacentes à borda, mesmo que a interseção tenha zero área (porque rootBounds ou targetRect têm zero área); caso contrário, seja isIntersecting be false.
      11. Se targetArea for diferente de zero, deixe intersectionRatio ser intersectionArea dividido por targetArea .
        Caso contrário, deixe intersectionRatio ser 1se isIntersecting for true ou 0se isIntersecting for false.
      12. Permita que thresholdIndex seja o índice da primeira entrada no observador . thresholdscujo valor é maior que intersectionRatio ou a duração do observador . thresholdsse intersectionRatio for maior ou igual à última entrada no observador . thresholds.
      13. Seja isVisible o resultado da execução do algoritmo de visibilidade no destino .
      14. Se thresholdIndex não for igual ao registro . previousThresholdIndex, ou isIntersecting não é igual a registro . previousIsIntersectingou isVisible não é igual a registro . previousIsVisibleA fila uma IntersectionObserverEntry , passando em observadores , tempo , rootBounds , boundingClientRect , intersectionRect , isIntersecting , isVisible , e alvo .
      15. Atribuir limite para registro de previousThresholdIndexpropriedade.
      16. Atribuir isIntersecting para registro de previousIsIntersectingpropriedade.
      17. Atribuir isVisible para registro de previousIsVisiblepropriedade.

3.3 IntersectionObserver Lifetime

Um IntersectionObserverpermanecerá vivo até que ambas as condições ocorram:

  • Não há referências de script para o observador.
  • O observador não está observando nenhum alvo.

Um IntersectionObservercontinuará observando um alvo até que seja unobserve(target)chamado no alvo ou disconnect()chamado no observador.

3.4 Integrações de especificações externas

3.4.1 Modelo de processamento HTML: loop de eventos

Uma etapa de processamento do Intersection Observer deve ocorrer durante as etapas ” Atualizar a renderização “, após a etapa 9, execute as etapas de renderização em tela cheia e, antes da etapa 10, execute os retornos de chamada do quadro de animação , no Modelo de processamento HTML .

Esta etapa é:

  1. Para cada documento totalmente ativo nos documentos , execute as etapas de observação de interseção de atualização para cada um que esteja na DOMtree desse documento . IntersectionObserverroot

4. Agradecimentos

Agradecimentos especiais a todos os colaboradores por suas contribuições técnicas e sugestões que levaram a melhorias nessa especificação.

Conformidade

Convenções de documentos

Os requisitos de conformidade são expressos com uma combinação de asserções descritivas e terminologia RFC 2119. As palavras-chave “DEVEM”, “NÃO DEVEM”, “NECESSÁRIO”, “DEVEM”, “NÃO DEVEM”, “DEVEM”, “NÃO DEVEM”, “RECOMENDADO”, “PODE” e “OPCIONAL” nas partes normativas deste documento devem ser interpretados conforme descrito na RFC 2119. No entanto, para facilitar a leitura, essas palavras não aparecem em todas as letras maiúsculas nesta especificação.

Todo o texto desta especificação é normativo, exceto as seções explicitamente marcadas como não normativas, exemplos e notas. [RFC2119]

Os exemplos nesta especificação são introduzidos com as palavras “por exemplo” ou são separados do texto normativo com class="example", assim:

Este é um exemplo de exemplo informativo.

As notas informativas começam com a palavra “Nota” e são separadas do texto normativo com class="note", assim:

Note, esta é uma nota informativa.

Algoritmos em Conformidade

Os requisitos expressos no imperativo como parte de algoritmos (como “remover qualquer caractere de espaço inicial” ou “retornar falso e abortar essas etapas”) devem ser interpretados com o significado da palavra-chave (“deve”, “deveria”, ” pode “, etc) usado na introdução do algoritmo.

Os requisitos de conformidade expressos como algoritmos ou etapas específicas podem ser implementados de qualquer maneira, desde que o resultado final seja equivalente. Em particular, os algoritmos definidos nesta especificação devem ser fáceis de entender e não têm desempenho. Os implementadores são incentivados a otimizar.

.

Índice

Termos definidos por esta especificação

Termos definidos por referência

  • [css-box-3] define os seguintes termos:
    • margem
  • [css-syntax-3] define os seguintes termos:
    • analisar uma lista de valores de componentes
  • [css-values-3] define os seguintes termos:
    • <percentagem>
    • comprimento absoluto
    • dimensão
  • [cssom-view-1] define os seguintes termos:
    • getBoundingClientRect ()
  • [DOM] define os seguintes termos:
    • Elemento
    • MutationObserver
    • MutationObserverInit
    • observar (alvo)
  • [geometry-1] define os seguintes termos:
    • DOMRect
    • DOMRectInit
    • DOMRectReadOnly
  • [WebIDL] define os seguintes termos:
    • DOMString
    • Exposto
    • boleano
    • grandes

Referências

Referências normativas

[CSS-BOX-3]
Elika Etemad. Módulo CSS Box Model Level 3 . 9 de agosto de 2018. WD. URL: https://www.w3.org/TR/css-box-3/
[CSS-SYNTAX-3]
Tab Atkins Jr .; Simon Sapin. Módulo de sintaxe CSS nível 3 . 20 de fevereiro de 2014. CR. URL: https://www.w3.org/TR/css-syntax-3/
[CSS-VALUES-3]
Tab Atkins Jr .; Elika Etemad. Módulo CSS de valores e unidades, nível 3 . 14 de agosto de 2018. CR. URL: https://www.w3.org/TR/css-values-3/
[CSSOM-VIEW-1]
Simon Pieters. Módulo de Visualização CSSOM . 17 de março de 2016. WD. URL: https://www.w3.org/TR/cssom-view-1/
[DOM]
Anne van Kesteren. Padrão DOM . Padrão de vida. URL: https://dom.spec.whatwg.org/
[GEOMETRIA-1]
Simon Pieters; Dirk Schulze; Rik Cabanier. Módulo de interfaces de geometria nível 1 . 25 de novembro de 2014. CR. URL: https://www.w3.org/TR/geometry-1/
[RFC2119]
S. Bradner. Palavras-chave para uso em RFCs para indicar níveis de exigência . Março 1997. Best Practice Current. URL: https://tools.ietf.org/html/rfc2119
[WebIDL]
Cameron McCormack; Boris Zbarsky; Tobie Langel. IDL da Web . 15 de dezembro de 2016. ED. URL: https://heycam.github.io/webidl/

Índice IDL

callback IntersectionObserverCallback = void (sequence<IntersectionObserverEntry> entries, IntersectionObserver observer);

[Constructor(IntersectionObserverCallback callback, optional IntersectionObserverInit options),
Exposed=Window]
interface IntersectionObserver {
readonly attribute Element? root;
readonly attribute DOMString rootMargin;
readonly attribute FrozenArray<double> thresholds;
[proposed] readonly attribute long delay;
[proposed] readonly attribute boolean trackVisibility;
void observe(Element target);
void unobserve(Element target);
void disconnect();
sequence<IntersectionObserverEntry> takeRecords();
};

[Constructor(IntersectionObserverEntryInit intersectionObserverEntryInit)]
interface IntersectionObserverEntry {
readonly attribute DOMHighResTimeStamp time;
readonly attribute DOMRectReadOnly? rootBounds;
readonly attribute DOMRectReadOnly boundingClientRect;
readonly attribute DOMRectReadOnly intersectionRect;
readonly attribute boolean isIntersecting;
[proposed] readonly attribute boolean isVisible;
readonly attribute double intersectionRatio;
readonly attribute Element target;
};

dictionary IntersectionObserverEntryInit {
required DOMHighResTimeStamp time;
required DOMRectInit? rootBounds;
required DOMRectInit boundingClientRect;
required DOMRectInit intersectionRect;
required boolean isIntersecting;
[proposed] required boolean isVisible;
required double intersectionRatio;
required Element target;
};

dictionary IntersectionObserverInit {
Element? root = null;
DOMString rootMargin = “0px”;
(double or sequence<double>) threshold = 0;
[proposed] long delay = 0;
[proposed] boolean trackVisibility = false;
};

Fonte:  https://szager-chromium.github.io/IntersectionObserver/

Interface para dados veicular com OpenXC

A biblioteca OpenXC Python (para Python 3.6.7) fornece uma interface para dados do veículo a partir da plataforma OpenXC. A plataforma principal para aplicativos OpenXC é o Android, mas para prototipagem e teste, geralmente é preferível usar um ambiente de baixo custo como o Python durante o desenvolvimento.

Além de uma porta da API da biblioteca do Android, o pacote também contém várias ferramentas de linha de comando para conectar-se ao tradutor CAN e manipular dados do veículo gravados anteriormente.

Devido a alterações no signs.cpp, o openxc-python versão 2.0.0 deve ser usado com o vi-firmware 8.0.0 ou superior.

Para empacotar, execute “setup.py sdist bdist_wheel” para enviar para o pypi, execute “python -m twine upload dist / *” Arquivos de versão:

  • CHANGELOG.rst
  • README.rst
  • openxc / version.py
  • docs / index.rst

 

Fonte: https://github.com/openxc/openxc-python

Como usar triggers Cloud Functions para o Firestore

Ferramentas utilizadas: 

Back end: Firebase Cloud Functions – Versão: 3.0.0

Neste tutorial, exploraremos o Firebase Cloud Functions para executar o código nos servidores Firebase.

Uma das principais dificuldades ao trabalhar com a autenticação baseada em funções é permitir que os usuários administrativos criem ou convidem pessoas para sua equipe.

Se você usar a conta de administrador para criar o novo usuário, o Firebase efetuará logout e login com a nova conta.

Para corrigir isso, usaremos o Firebase Cloud Functions. A ideia é que, em vez de criar a conta, nosso usuário administrador possa armazenar as informações desejadas no banco de dados.

O Cloud Functions lê o banco de dados e, com essas informações, cria a nova conta de usuário e armazena o perfil do usuário no banco de dados.

Configurando funções da nuvem

Se você ainda não ouviu falar sobre o Cloud Functions, o TL; DR é que são funções executadas nos servidores do Firebase.

Você cria a função, carrega-a, ela é executada. O Google cuida de dimensionamento automático, segurança e muito mais para você.

Para começar, a primeira coisa que você precisa fazer é instalar a Firebase CLI, para fazer isso, abra seu terminal e digite:

npm install -g firebase-tools

Depois de instalado, vá em frente e use a CLI para fazer login no Firebase Console com:

firebase login

Ele abrirá uma janela do navegador para você efetuar login. Por fim, vá para a pasta em que você tem seu projeto e inicialize o Cloud Functions com:

firebase init functions

Ele fará algumas perguntas, como selecionar se você deseja usar o TypeScript ou JavaScript, escolher o projeto que será associado ao seu console etc.

Escolha TypeScript, e ele fornecerá o TSLint e ajudará a detectar erros antes que eles aconteçam 🙂

Uma vez feito, ele gerará uma pasta chamada functions, dentro, você encontrará alguns arquivos de configuração, como package.jsonindex.tsarquivo onde escreveremos nossas funções.

Abra o index.tsarquivo e verifique se está dentro:

import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';

import { UserRecord } from 'firebase-functions/lib/providers/auth';
admin.initializeApp();

OBSERVAÇÃO: a inicialização do administrador provavelmente não estará lá; adicione-o você mesmo.

Estamos dizendo às nossas funções da nuvem que queremos usar as funções SDK e o SDK de administrador. Em seguida, estamos usando o SDK de administrador para inicializar nosso aplicativo.

UserRecordobjeto será usado estritamente para fins de digitação, para garantir que nosso projeto use tipos apropriados.

Agora é hora de criar nossa função, mas primeiro, vamos examinar o que precisamos, a função precisa:

  • Leia o Firestore para saber quando adicionamos um novo usuário.
  • Obtenha as informações do usuário.
  • Crie a conta do usuário.
  • Armazene os dados do usuário dentro de uma coleção de perfis de usuário.

Com isso em mente, vamos criar nossa função e realizar o primeiro passo, lendo o Firestore:

exports.createTeamMember = functions.firestore
  .document(`teamProfile/{teamId}/teamMemberList/{newUserId}`)
  .onCreate(async (snap, context) => {});

Estamos usando o functions.firestorepacote para ouvir o documento localizado em:

`teamProfile/{teamId}/teamMemberList/{newUserId}`

Observe que {teamId} e {newUserId} são curingas, portanto, o Functions escutará nesses caminhos dinamicamente, portanto, se você adicionar esses usuários:

`teamProfile/ATeam/teamMemberList/user1`
`teamProfile/BTeam/teamMemberList/user2`
`teamProfile/ATeam/teamMemberList/user3`
`teamProfile/BTeam/teamMemberList/user4`

As funções capturam todos eles. Agora que estamos ouvindo o banco de dados, extrairemos as informações que precisamos usar:

exports.createTeamMember = functions.firestore
  .document(`teamProfile/{teamId}/teamMemberList/{newUserId}`)
  .onCreate(async (snap, context) => {
    const id: string = snap.data().id;
    const email: string = snap.data().email;
    const teamId: string = snap.data().teamId;
  });

Estamos acessando as informações do event.dataEssas são as informações que armazenamos no banco de dados sobre esse usuário .)

Assim que tivermos as informações, o próximo passo seria criar a conta do usuário:

exports.createTeamMember = functions.firestore
  .document(`teamProfile/{teamId}/teamMemberList/{newUserId}`)
  .onCreate(async (snap, context) => {
    const id: string = snap.data().id;
    const email: string = snap.data().email;
    const teamId: string = snap.data().teamId;

    const newUser: UserRecord = await admin.auth().createUser({
      uid: id,
      email: email,
      password: '123456789'
    });
  });

Estamos usando o adminSDK para criar um novo usuário e estamos passando o uid, o emaile o passwordque queremos que o usuário tenha.

Quando tivermos isso, nossa próxima etapa é criar o documento para as informações de perfil deste usuário, para isso vamos usar o adminSDK novamente:

exports.createTeamMember = functions.firestore
  .document(`teamProfile/{teamId}/teamMemberList/{newUserId}`)
  .onCreate(async (snap, context) => {
    const id: string = snap.data().id;
    const email: string = snap.data().email;
    const teamId: string = snap.data().teamId;

    const newUser: UserRecord = await admin.auth().createUser({
      uid: id,
      email: email,
      password: '123456789'
    });

    await admin
      .firestore()
      .doc(`userProfile/${id}`)
      .set({
        email: email,
        id: id,
        teamId: teamId,
        teamAdmin: false
      });

    return newUser;
  });

Essa última função vai para a userProfilecoleção, depois vai um nível mais fundo no documento {userId} e armazena as informações lá.

Estamos dizendo ao Firestore que o usuário não é um administrador, o ID da equipe a que pertence e as informações pessoais do usuário ( email e ID ).

Nossa função está pronta para ser usada, então vá em frente e abra o terminal novamente dentro da pasta do seu projeto e digite:

firebase deploy --only functions

Ele implantará sua Função no Firebase, vá em frente e tente, você pode acessar seu aplicativo e usar a função adicionar usuário que criamos, verifique se a função está sendo acionada, que cria o usuário e cria o perfil no base de dados.

Fonte: https://javebratt.com/firestore-functions/#commento-login-box-container

Dados Raster

Dados rastermatriciais ou bitmap (que significa mapa de bits em inglês) são imagens que contêm a descrição de cada pixel, em oposição aos gráficos vetoriais.

O tratamento de imagens deste tipo requer ferramentas especializadas, geralmente utilizadas em fotografia, pois envolvem cálculos muito complexos, como interpolaçãoálgebra matricial, etc.

Um bitmap pode ser monocromático, em escala de cinza ou colorido. Normalmente os pixels são formados no padrão RGB, do inglês Red, Green, Blue, que utiliza três números inteiros para representar as cores vermelhoverde e azul ou RGBA, quando o formato possui transparência (sendo A o nível de alfa de cada pixel). Para mídias impressas as imagens bitmap ou raster utilizam o modo de cor CMYK (CianoMagentaAmarelo e Preto).

Necessidade de compactação

A cada ponto da imagem exibida na tela ou papel corresponde um pixel desta grade, de forma que a maioria das imagens requer um número muito grande de pixels para ser representada completamente. Por exemplo, uma imagem comum de 800 pixels de largura por 600 de altura necessita de 3 bytes para representar cada pixel (um para cada cor primária RGB) e mais 54 bytes de cabeçalho. Isso totaliza 1.440.054 bytes. Embora a representação de imagens na memória RAM seja feita geralmente em bitmaps, quando se fala em um grande número de imagens armazenadas em discos magnéticos e transmissão de dados via redes surge a necessidade de compressão desses arquivos, para reduzir o espaço ocupado e o tempo de transmissão.

compactação de dados pode ser com perda ou sem perda. Os principais formatos adotados para a compressão de dados na internet são o Compuserve GIF, o JFIF(conhecido por JPEG), e o mais atual e livre o PNG.

 

Fonte: https://pt.wikipedia.org/wiki/Raster

Certificação CTAL

Para participar de um exame do nível avançado, o ISTQB determina que os candidatos possuam experiência prática na área. Assim, para ser considerado apto a realizar estes exames, é necessário que o candidato:

  1. Possua uma Certificação ISTQB Certified Tester, Foundation Level (CTFL) ou seu similar emitido pelo ISEB.
  2. Comprove suas experiências em período integral (8hs diárias) em pelo menos um dos itens abaixo:
    • 2 anos de experiência prática em Teste de Software ou Qualidade em TI.
    • 2 anos dedicados à Pesquisa Acadêmica relacionadas à Qualidade de TI no nível de Pós Graduação, ou como instrutor de cursos ou disciplinas relacionadas à Qualidade de TI.
    • 3 anos de experiência prática em Desenvolvimento de Sistemas, Análise de Sistemas ou Engenharia de Software.

A Qualificação CTAL não expira, sendo necessário obtê-la apenas uma única vez para realizar qualquer exame do nível avançado.

Processo de Qualificação

1) Declaração

Para ser avaliado o candidato deve apresentar uma declaração das empresas ou instituições que atuou, comprovando seu tempo de serviço e as atividades exercidas na função ou cargo ocupado. O candidato deve apresentar um número suficiente de declarações que cubram os requisitos para a Qualificação. Por exemplo, caso o candidato tenha 1 ano e 6 meses na empresa A, e 6 meses na empresa B, ambas atuando em funções exercidas na área de teste de software, ele deve apresentar duas declarações (uma de cada empresa).

Esta declaração deve possuir 6 itens importantes (veja na imagem abaixo), onde na ausência de qualquer um, a qualificação será recusada em primeira análise, e o pagamento da taxa devolvido.

istqb

Declaracao-modelo

Declaracao-exemplo

Fonte:  https://www.bstqb.org.br/qualificacao

Como homologar sua Automação Comercial com o TEF PayGo?

Clique aqui para acessar o passo-a-passo da homologação do TEF PayGo. É simples, rápido e gratuito.

Para verificar a integração Android e Linux, entre em contato conosco por 0800 737 2255, dev@paygo.com.br ou preencha o formulário abaixo

 

Fonte: https://www.paygo.com.br/homologue-2/

VPE – ( Validador de Pagamentos Eletrônicos ) utilizando o Integrador Fiscal – CE

Homologando o Módulo VPE – CE

Ola, Nesse tópico vamos detalhar os passos para realizar testes e homologação utilizando o Módulo VPE (Validador de Pagamentos Eletrônicos) com o Integrador Fiscal no estado do CE.

Embora a SEFAZ CE permitiu a emissão de Cupom Fiscal Eletrônico utilizando apenas o driver MFe (sem a necessidade do uso do Aplicativo Integrador Fiscal), para a integração dos dados de pagamento com cartão – VPE, ainda é necessário a utilização do Integrador Fiscal do Ceará.

Para esse procedimento, segue abaixo como utilizar o Componente ACBrIntegrador para realizar o envio dos dados de pagamento por meio do Integrador Fiscal. Neste caso, estamos utilizando o Demo “SATTest” do Projeto ACBr para os testes, você poderá verificar os fontes desse demo no repositório do ACBr : (..\ACBr\Exemplos\ACBrSAT\ ) ou baixar o demo em: SATTest

Instalar Integrador Fiscal

O Primeiro passo é Instalar o Aplicativo Integrador Fiscal, segue abaixo o tópico sobre como Instalar e configurar o Integrador Fiscal: Instalar Integrador Fiscal

Utilizando o SATTest 

No exemplo do SATTest abaixo, estamos utilizando a conexão direta com a dll do driver MFe, mas a comunicação entre o ACBrIntegrador – (VPE) e o Integrador Fiscal vai funcionar independente desta configuração, basta apenas que o Integrador Fiscal esteja em execução e devidamente configurado na máquina.

Para mais Informações sobre configuração do Driver MFe, veja em: Configurar Driver MFe

Para integração ACBrIntegrador e VPE vá para aba: MFe e veja as quatro opções disponíveis para o Módulo VPE – (“Enviar Pagamento”, “Enviar Status Pagamento”, “Verificar Status Validador”, “Resposta Fiscal”)

Existem duas situações para Integração do Módulo VPE, sendo distintas entre: POS e TEF:

 

Utilizando Integração VPE com Pagamento P.O.S. 

Obs Importante: 

A SEFAZ CE não disponibilizou um Serviço P.O.S. compatível com Integrador Fiscal conforme estava previsto inicialmente. Então a opção “Verificar Status Validador” está disponível apenas para ambiente de homologação, para isso é utilizado o Simulador P.O.S. Ceara: http://simuladorposceara.azurewebsites.net/. Portanto o Serviço “Verificar Status Validador” não é utilizado em Produção.

Passo 1:  EnviarPagamento

Informações a ser enviada neste método:

PagamentoMFe := TEnviarPagamento.Create;
  try
    with PagamentoMFe do
    begin
      Clear;
      ChaveAcessoValidador := '25CFE38D-3B92-46C0-91CA-CFF751A82D3D';                          
      ChaveRequisicao := '26359854-5698-1365-9856-965478231456';                               
      Estabelecimento := '10';                                                                 
      SerialPOS := InputBox('SerialPOS','Informe o Serial do POS','ACBr-'+RandomName(8));      
      CNPJ := edtEmitCNPJ.Text;                                                                
      IcmsBase := 0.23;                                                                        
      ValorTotalVenda := 1530;                                                                 
      HabilitarMultiplosPagamentos := True;                                                    
      HabilitarControleAntiFraude := False;                                                    
      CodigoMoeda := 'BRL';                                                                    
      EmitirCupomNFCE := False;                                                              
      OrigemPagamento := 'Mesa 1234';                                                        
    end;

    ...
  finally
     ...
  end;

Definição sobre Principais Campos:

Chave de Acesso Validador – Esta chave é fixa, está Pré-Definida no Manual Do Integrador Fiscal.

Chave de Requisição – Esta chave deve ser única para cada requisição POS, deve-se gerar um GUID para cada Envio de Pagamento. Esta especificação está descrita no Manual do Integrador.

Estabelecimento –   Como não existe este equipamento POS Integrado conforme previsão inicial, está sendo informado um valor fixo.

SerialPOS –  Como não existe este equipamento POS Integrado conforme previsão inicial, está sendo informado o Numero serial do Equipamento POS utilizado (Independente do equipamento)

(Apenas para efeito de testes no SATTest, estamos utilizando um valor randômico para gerar o Número do Serial).

 

Após o Envio do Pagamento será retornado o “ID do Pagamento”

obs: O ID do pagamento deve ser gravado pela sua aplicação para Identificação do Pagamento e Requisições Posteriores, pode ser obtido pelo método: (RespostaVerificarStatusValidador.CodigoAutorizacao)

Passo 2:  VerificarStatusValidador  (Utilizado apenas em Ambiente de Homologação)

Para Testes em Homologação deve-se utilizar o Site Simulador POS Ceará http://simuladorposceara.azurewebsites.net/ e informar o SerialPOS utilizado no envio, para Simular o Pagamento Efetuado

Após a Confirmação de Pagamento utilizando o Emulador,  deve realizar a chamada do método: VerificarStatusValidador informando o ID Pagamento:

with VerificarStatusValidador do
begin
  Clear;
  ChaveAcessoValidador := '25CFE38D-3B92-46C0-91CA-CFF751A82D3D';                          
  IDFila := StrToIntDef(InputBox('IDPagmento','Informe o ID do Pagamento',''),0);          
  CNPJ:= edtEmitCNPJ.Text;                                                                
end;

Definição sobre os Campos:

Chave de Acesso Validador – Esta chave é fixa, está Pré-Definida no Manual Do Integrador Fiscal.

ID FIla – Este campo se trata do “ID Pagamento” retornado no primeiro método

CNPJ –   CNPJ do Emitente

 

Será obtido como retorno o XML com a simulação da Autorização de Pagamento:

Lembrando que em Produção não é possível realizar o Passo 2, pula direto para o passo 3:

Passo 3:  RespostaFiscal 

Após o Envio do XML de Venda para o MFe ou Integrador (no caso de NFC-e), realiza-se o passo 3, apenas para Vincular o Pagamento com Cartão a um Documento Fiscal, através do método: RespostaFiscal

RespostaFiscal := TRespostaFiscal.Create;
    try
      with RespostaFiscal do
      begin
        Clear;
        ChaveAcessoValidador := '25CFE38D-3B92-46C0-91CA-CFF751A82D3D';                           
        IDFila := StrToIntDef(InputBox('IDPagmento','Informe o ID do Pagamento',''),0);           
        ChaveAcesso := '35170408723218000186599000113100000279731880';                           
        Nsu := '1674068';                                                                        
        NumerodeAprovacao := '123456';                                                             
        Bandeira := 'VISA';                                                                       
        Adquirente := 'STONE';                                                                    
        if Assigned(ACBrSAT1.CFe) and (ACBrSAT1.Extrato= ACBrSATExtratoESCPOS1) then
          ImpressaoFiscal := '<![CDATA['+ACBrSATExtratoESCPOS1.GerarImpressaoFiscalMFe+']]>';     
        NumeroDocumento := '1674068';                                                            
        CNPJ:= edtEmitCNPJ.Text;                                                                  
      end;
      
    finally
      RespostaFiscal.Free;
    end;

Definição sobre Principais Campos:

Chave de Acesso Validador – Esta chave é fixa, está Pré-Definida no Manual Do Integrador Fiscal.

ID FIla – Este campo se trata do “ID Pagamento” retornado no primeiro método

ChaveAcesso –   Refere-se a Chave do CFe de Venda gerado pelo MFe ou Integrador Fiscal (no caso de NFC-e)

NSU –   Fornecido pela Adquirente (Autorizadora de Pagamento) – Como não existe este equipamento POS Integrado conforme previsão inicial, está sendo informado um valor fixo.

NumeroAprovacao –   Código de Autorização de Pagamento Retornado pela Adquirente – Como não existe este equipamento POS Integrado conforme previsão inicial, está sendo informado um valor fixo.

ImpressaoFiscal –   A Intensão futura será passar o Extrato do CFe para impressão no aparelho POS (A Função GerarImpressaoFiscalMFe já gera o Modelo do Cupom a ser impresso)

NumeroDocumento –   Número do Cupom Fiscal Autorizado.

Será obtido o XML Retorno com o Código de Processamento da Resposta Fiscal.

Encerra-se o Processo VPE – utilizando o P.O.S.

 

 

Utilizando Integração VPE com Pagamento TEF

Passo 1:  EnviarStatusPagamento

Informações a ser enviada neste método:

StatusPagamentoMFe := TStatusPagamento.Create;
  try
    with StatusPagamentoMFe do
    begin
      Clear;
      ChaveAcessoValidador := '25CFE38D-3B92-46C0-91CA-CFF751A82D3D';     
      CodigoAutorizacao := '20551';                                       
      Bin := '123456';                                                    
      DonoCartao := 'TESTE';                                              
      DataExpiracao := '01/01';                                           
      InstituicaoFinanceira:= 'STONE';                                    
      Parcelas := 1;                                                      
      CodigoPagamento := '12846';                                         
      ValorPagamento := 1530;                                             
      IDFila := 1674068;                                                  
      Tipo := '1';                                                        
      UltimosQuatroDigitos := 1234;                                       
    end;
   
  finally
    StatusPagamentoMFe.Free;
  end;

Definição sobre Principais Campos:

Chave de Acesso Validador – Esta chave é fixa, está Pré-Definida no Manual Do Integrador Fiscal.

Obs: Para quem utiliza o Componente ACBrTEFD os dados do cartão e de Confirmação de Pagamento, utilizados no pagamento TEF podem ser obtidos
acessando a propriedade ACBrTEFDRespNFCeSAT da Classe de retorno TACBrTEFDResp do Componente ACBrTEFD, automatizando assim o preenchimento destes dados. 

Será obtido o XML Retorno com o Código de Processamento do Status de Pagamento.

 

Passo 2:  RespostaFiscal 

Após o Envio do XML de Venda para o MFe (ou Integrador no caso de NFC-e), realiza o passo 2, apenas para Vincular um Pagamento com Cartão ao Documento Fiscal, através do método: RespostaFiscal

RespostaFiscal := TRespostaFiscal.Create;
    try
      with RespostaFiscal do
      begin
        Clear;
        ChaveAcessoValidador := '25CFE38D-3B92-46C0-91CA-CFF751A82D3D';                           
        IDFila := StrToIntDef(InputBox('IDPagmento','Informe o ID do Pagamento',''),0);           
        ChaveAcesso := '35170408723218000186599000113100000279731880';                           
        Nsu := '1674068';                                                                        
        NumerodeAprovacao := '123456';                                                             
        Bandeira := 'VISA';                                                                       
        Adquirente := 'STONE';                                                                    
        if Assigned(ACBrSAT1.CFe) and (ACBrSAT1.Extrato= ACBrSATExtratoESCPOS1) then
          ImpressaoFiscal := '<![CDATA['+ACBrSATExtratoESCPOS1.GerarImpressaoFiscalMFe+']]>';     
        NumeroDocumento := '1674068';                                                            
        CNPJ:= edtEmitCNPJ.Text;                                                                  
      end;
      
    finally
      RespostaFiscal.Free;
    end;

Definição sobre Principais Campos:

Chave de Acesso Validador – Esta chave é fixa, está Pré-Definida no Manual Do Integrador Fiscal.

ID FIla – Este campo se trata do “ID Pagamento” retornado no primeiro método

ChaveAcesso –   Refere-se a Chave do CFe de Venda gerado pelo MFe ou Integrador Fiscal (no caso de NFC-e)

NSU –   Fornecido pela Adquirente (Autorizadora de Pagamento) – Como não existe este equipamento POS Integrado conforme previsão inicial, está sendo informado um valor fixo.

NumeroAprovacao –   Código de Autorização de Pagamento Retornado pela Adquirente – Como não existe este equipamento POS Integrado conforme previsão inicial, está sendo informado um valor fixo.

ImpressaoFiscal –   A Intensão futura é utilizar no Aparelho POS

NumeroDocumento –   Número do Cupom Fiscal Autorizado.

Será obtido o XML Retorno com o Código de Processamento da Resposta Fiscal.

Encerra o Processo VPE – utilizando o TEF

 

 

Veja Mais detalhes sobre o Fluxo de Venda utilizando POS e TEF em:

https://servicos.sefaz.ce.gov.br/internet/download/projetomfe/FluxoVendaPDVUtilizandoPOS.pdf

https://servicos.sefaz.ce.gov.br/internet/download/projetomfe/FluxoVendaPDVUtilizandoTEF.pdf

Manual Integrador:

http://cfe.sefaz.ce.gov.br/mfe/informacoes/downloads#/

 

Fonte: https://www.projetoacbr.com.br/forum/topic/51588-vpe-validador-de-pagamentos-eletr%C3%B4nicos-utilizando-o-integrador-fiscal-ce/

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

CHECK-LIST DE HOMOLOGAÇÃO CF-e

HOMOLOGAÇÃO

1. PREPARAR AMBIENTE:

1.1 – Se certificar de que tanto a aplicação comercial quanto o integrador estejam fechados.

1.2 – Abrir o integrador

1.3 – Abrir a aplicação comercial pelo integrador

2. VERIFICAÇÃO DADOS POS:

2.1 – Cadastro de POS

Dados do POS:

ID: Valor fornecido pelo usuário, pode ser um número sequencial.

Serial do POS: No ambiente de produção, o valor inserido é o número de série do equipamento.

Descrição: Valor fornecido pelo usuário, pode ser uma forma de identificar o POS.

2.2 – VERIFICAÇÃO CHAVE DE ACESSO AO VALIDADOR.

Esse valor pode ser encontrado no manual do integrador fiscal, página 9. OBSERVAÇÃO: A chave de acesso ao validador é igual nos dois ambientes tanto na homologação quanto na produção.

Chave de acesso Validador: 25CFE38D-3B92-46C0-91CA-CFF751A82D3D

2.3 – VERIFICAÇÃO CHAVE DE REQUISIÇÃO

OBSERVAÇÃO: A chave de requisição é um código gerado a partir do CNPJ do contribuinte mais o CNPJ da adquirente.

3. TESTE DE VENDAS:

3.1 – Fazer uma venda a dinheiro

3.2 – Fazer uma nova venda (a venda deve ser finalizada com duas formas de pagamento, dinheiro e cartão).

3.3 – O AC deve solicitar COD DE AUT, NSU e BANDEIRA, antes de finalizar o cupom.

3.4 – Realizar uma venda com o integrador desligado – Nesse caso aplicação não deve emitir o cupom.

3.6 – Fazer uma nova venda a cartão, logo depois cancelá-la.

4. VERIFICAÇÃO DO BANCO DE DADOS

4.1 – Verificar no banco de dados as seguintes tabelas: ID_pagamentos e ID_respostafiscal

5. ENVIO DE DOCUMENTOS FISCAIS

5.1 – Enviar todos os XML’s gerados no momento da homologação para o e-mail: suporte.mfe@sefaz.ce.gov.br com o assunto “DADOS HOMOLOGAÇÃO + NOME SOFTWARE HOUSE”.

OBS: PARA SER FEITO A HOMOLOGAÇÃO É NECESSÁRIO A DISPONIBILIZAÇÃO DO APLICATIVO DE ACESSO REMOTO ACESEFA.

NO DIA DO AGENDAMENTO, ENTRAR EM CONTATO ATRAVÉS DOS SEGUINTES RAMAIS:

(85) 3108-0283

(85) 3108-0284

(85) 3108-0215

(85) 3108-0216

(85) 3108-0784

(85) 3108-0797

Caso tenha alguma dúvida enviar um e-mail para suporte.mfe@sefaz.ce.gov.br

 

Fonte:

https://www.projetoacbr.com.br/forum/topic/55266-roteiro-e-ou-manual-para-homologa%C3%A7%C3%A3o/

 

https://www.projetoacbr.com.br/forum/topic/51588-vpe-validador-de-pagamentos-eletr%C3%B4nicos-utilizando-o-integrador-fiscal-ce/

 

Linguagem Elixir

Elixir é uma linguagem dinâmica e funcional projetada para a criação de aplicativos escaláveis ​​e de manutenção.

O Elixir aproveita a Erlang VM, conhecida por executar sistemas de baixa latência, distribuídos e tolerantes a falhas, além de ser usada com sucesso no desenvolvimento da Web e no domínio de software incorporado.

Para saber mais sobre o Elixir, consulte nosso guia de introdução e nossa página de aprendizado para outros recursos . Ou continue lendo para obter uma visão geral da plataforma, idioma e ferramentas.

Recursos da plataforma

Escalabilidade

Todo o código Elixir é executado dentro de threads de execução leves (chamados processos) que são isolados e trocam informações por meio de mensagens:

current_process = self()

# Spawn an Elixir process (not an operating system one!)
spawn_link(fn ->
  send(current_process, {:msg, "hello world"})
end)

# Block until the message is received
receive do
  {:msg, contents} -> IO.puts(contents)
end

Devido à sua natureza leve, não é incomum ter centenas de milhares de processos em execução simultaneamente na mesma máquina. O isolamento permite que os processos sejam coletados de maneira independente, reduzindo as pausas em todo o sistema e usando todos os recursos da máquina da maneira mais eficiente possível (escala vertical).

Os processos também podem se comunicar com outros processos em execução em máquinas diferentes na mesma rede. Isso fornece a base para a distribuição, permitindo que os desenvolvedores coordenem o trabalho em vários nós (escala horizontal).

Tolerância ao erro

A verdade inevitável sobre o software em execução na produção é que as coisas vão dar errado . Ainda mais quando levamos em consideração a rede, os sistemas de arquivos e outros recursos de terceiros.

Para lidar com falhas, o Elixir fornece supervisores que descrevem como reiniciar partes do seu sistema quando as coisas dão errado, voltando a um estado inicial conhecido que é garantido que funcione:

children = [
  TCP.Pool,
  {TCP.Acceptor, port: 4040}
]

Supervisor.start_link(children, strategy: :one_for_one)

A combinação de escalabilidade, tolerância a falhas e programação orientada a eventos por meio da passagem de mensagens faz do Elixir uma excelente opção para arquitetura e programação reativa.

Caracteristicas do idioma

Programação funcional

A programação funcional promove um estilo de codificação que ajuda os desenvolvedores a escrever um código curto, conciso e sustentável. Por exemplo, a correspondência de padrões permite que os desenvolvedores destruam facilmente os dados e acessem seu conteúdo:

%User{name: name, age: age} = User.get("John Doe")
name #=> "John Doe"

Quando combinada com guardas, a correspondência de padrões nos permite combinar e declarar condições específicas para que algum código seja executado:

def drive(%User{age: age}) when age >= 16 do
  # Code that drives a car
end

drive(User.get("John Doe"))
#=> Fails if the user is under 16

O Elixir depende muito desses recursos para garantir que seu software esteja funcionando sob as restrições esperadas. E quando não estiver, não se preocupe, os supervisores estão de costas!

Extensibilidade e DSLs

O Elixir foi projetado para ser extensível, permitindo que os desenvolvedores estendam naturalmente a linguagem para domínios específicos, a fim de aumentar sua produtividade.

Como exemplo, vamos escrever um caso de teste simples usando a estrutura de teste do Elixir chamada ExUnit :

defmodule MathTest do
  use ExUnit.Case, async: true

  test "can add two numbers" do
    assert 1 + 1 == 2
  end
end

async: trueopção permite que tests sejam executados em paralelo, usando o maior número possível de núcleos de CPU, enquanto a assertfuncionalidade pode introspectar seu código, fornecendo ótimos relatórios em caso de falhas. Esses recursos são criados usando as macros do Elixir, possibilitando adicionar novas construções como se fizessem parte da própria linguagem.

Recursos de ferramentas

Um ecossistema em crescimento

O Elixir é fornecido com um ótimo conjunto de ferramentas para facilitar o desenvolvimento. O Mix é uma ferramenta de compilação que permite criar facilmente projetos, gerenciar tarefas, executar testes e muito mais:

$ mix new my_app
$ cd my_app
$ mix test
.

Finished in 0.04 seconds (0.04s on load, 0.00s on tests)
1 tests, 0 failures

O Mix também é capaz de gerenciar dependências e se integra ao gerenciador de pacotes Hex , que executa a resolução de dependências, busca pacotes remotos e hospeda documentação para todo o ecossistema.

Desenvolvimento interativo

Ferramentas como o IEx (shell interativo do Elixir) são capazes de alavancar muitos aspectos do idioma e da plataforma para fornecer ferramentas de depuração automáticas, recarga de código, recarga de código e documentação bem formatada:

$ iex
Interactive Elixir - press Ctrl+C to exit (type h() ENTER for help)
iex> h String.trim           # Prints the documentation for function
iex> i "Hello, World"        # Prints information about the given data type
iex> break! String.trim/1    # Sets a breakpoint in the String.trim/1 function
iex> recompile               # Recompiles the current project on the fly

Erlang compatível

O Elixir é executado na VM Erlang, oferecendo aos desenvolvedores acesso completo ao ecossistema da Erlang, usado por empresas como Heroku , WhatsApp , Klarna e muito mais para criar aplicativos distribuídos e tolerantes a falhas. Um programador Elixir pode chamar qualquer função Erlang sem custo de tempo de execução:

iex> :crypto.hash(:md5, "Using crypto from Erlang OTP")
<<192, 223, 75, 115, ...>>

Para saber mais sobre o Elixir, consulte o nosso guia de primeiros passos . Também temos documentação online disponível e um Crash Course para desenvolvedores de Erlang .

Fonte: https://elixir-lang.org/

Use o Firebase Cloud Functions para buscar uma imagem e transformá-la em base64

Publicado pela primeira vez: 14 de novembro de 2019
Atualizado em: 14 de novembro de 2019

Você já manipulou imagens em um servidor?

Esse era um requisito que eu tinha um tempo atrás que não sabia como resolver no momento.

Estávamos trabalhando jsPDFpara criar PDFs de relatórios em um de nossos aplicativos Ionic, mas tivemos um problema: todas as nossas imagens eram armazenadas on-line e você não pode passar um URL jsPDFpara as imagens.

Leva apenas base64, URI de dados e acho que o objeto blob.

Nossa primeira tentativa foi fazer o lado do cliente de transformação base64 e enviar todas essas cadeias para criar o PDF. A questão era que, se tivéssemos mais de 10 imagens, elas começavam a ficar lentas.

Por isso, decidimos mudar esse servidor e criamos uma função de nuvem que a tratava para nós.

Para isso, precisamos de uma função de nuvem que:

  • Escuta o banco de dados quando adicionamos o URL das imagens regulares.
  • Redimensiona essa imagem para não armazenar algo pesado.
  • Transforma para base64.
  • Armazena a sequência base64 no banco de dados.

Com isso em mente, vamos para a codificação, este artigo supõe que você já tenha um projeto e tenha o Cloud Functions inicializado; caso contrário, passe por este artigo primeiro .

Instalando os pacotes que precisamos

A primeira coisa que faremos é instalar os pacotes de que precisamos; no nosso caso, são dois, usamos o requestpacote para buscar a URL da imagem e o sharppacote para redimensioná-la.

npm install request sharp

E, em seguida, importe-os na parte superior do arquivo de funções

var request = require('request').defaults({
  encoding: null
});
const sharp = require('sharp');

Estamos usando encoding: nullpara dizer à solicitação que você deseja um buffer, não uma string. Precisamos desse buffer para criar a string base64.

Criar a função de nuvem

Queremos primeiro criar a função que atende ao banco de dados, com algumas verificações no local. No nosso caso, tínhamos uma coleção de projetos e cada documento tinha uma foto antes e depois necessária para o relatório:

exports.convertImageToPDF = functions.firestore
  .document('projects/{projectId}')
  .onWrite(async (change, context) => {
    // We get the project's ID from the context param.
    // We get the actual project data from the change param, we want to
    // use the .after to signal is the new data we're listening to.
    const projectId = context.params.projectId;
    const currentProject = change.after.data();
  });

Então, queremos verificar se estamos atualizando mais alguma coisa nesse projeto e já temos essa propriedade base64, queremos interromper a função.

exports.convertImageToPDF = functions.firestore
  .document('projects/{projectId}')
  .onWrite(async (change, context) => {
    const projectId = context.params.projectId;
    const currentProject = change.after.data();

    let beforePictureBase64 = currentProject.beforePictureBase64;
    let afterPictureBase64 = currentProject.afterPictureBase64;

    if (beforePictureBase64 && afterPictureBase64) {
      console('Both pictures are here');
      return;
    }
  });

Queremos perguntar, se não há imagem antes ou depois da imagem e convertê-las em base64.

Chamaremos uma função para fazer a transformação, cobriremos isso assim que terminarmos com a função de nuvem que fala com o banco de dados.

exports.convertImageToPDF = functions.firestore
  .document('projects/{projectId}')
  .onWrite(async (change, context) => {
    const projectId = context.params.projectId;
    const currentProject = change.after.data();

    let beforePictureBase64 = currentProject.beforePictureBase64;
    let afterPictureBase64 = currentProject.afterPictureBase64;

    if (beforePictureBase64 && afterPictureBase64) {
      console('Both pictures are here');
      return;
    }

    if (!beforePictureBase64) {
      // currentProject.beforePicture is the online URL of the before picture
      beforePictureBase64 = await toDataURL(currentProject.beforePicture);
    }

    if (!afterPictureBase64) {
      // Same as above but for the after picture
      afterPictureBase64 = await toDataURL(currentProject.afterPicture);
    }

    // If we get to this point and still we have no transformed images,
    // we want to stop the function.
    if (!beforePictureBase64 && !afterPictureBase64) {
      console.log('No pictures here');
      return;
    }

    // And then we want to store the base64 pictures in the same project.

    return admin
      .firestore()
      .doc(`projects/${projectId}`)
      .update({
        beforePictureBase64: beforePictureBase64 || null,
        afterPictureBase64: afterPictureBase64 || null
      });
  });

Agora, vamos falar sobre a toDataURL()função, já que toda a transformação da imagem está acontecendo lá.

Primeiro, precisamos da função de usar o URL on-line como parâmetro e retornar uma Promessa, pois faremos coisas assíncronas.

function toDataURL(url) {
  return new Promise((resolve, reject) => {});
}

Então, vamos usar o requestmódulo para buscar a imagem, se não houver erro e tudo correr bem, fazemos a manipulação da imagem, se algo estiver errado, lançamos o erro.

function toDataURL(url) {
  return new Promise((resolve, reject) => {
    request.get(url, function(error, response, body) {
      if (!error && response.statusCode === 200) {
        // Do the transformation
      } else {
        throw error;
      }
    });
  });
}

Então, redimensionaremos a imagem original, lembre-se: um documento do Firestore tem um limite rígido de 1 MB e uma imagem base64 geralmente é 30% mais pesada que a original.

function toDataURL(url) {
  return new Promise((resolve, reject) => {
    request.get(url, function(error, response, body) {
      if (!error && response.statusCode === 200) {
        return sharp(body)
          .resize(100, 100)
          .toBuffer()
          .then(resizedImage => {
            // Transform to base64
          })
          .catch(err => {
            throw err;
          });
      } else {
        throw error;
      }
    });
  });
}

Estamos usando o sharpmódulo para redimensioná-lo, passando a altura e a largura que queremos para a imagem e, em seguida, certificando-nos de que a resposta também seja um buffer.

E, finalmente, estamos formando nossa string base64:

function toDataURL(url) {
  return new Promise((resolve, reject) => {
    request.get(url, function(error, response, body) {
      if (!error && response.statusCode === 200) {
        return sharp(body)
          .resize(100, 100)
          .toBuffer()
          .then(resizedImage => {
            data =
              'data:' +
              response.headers['content-type'] +
              ';base64,' +
              new Buffer(resizedImage).toString('base64');

            resolve(data);
            return data;
          })
          .catch(err => {
            throw err;
          });
      } else {
        throw error;
      }
    });
  });
}

E é isso, a toDataURL(url)função retornará uma string base64 válida que podemos armazenar no Firestore e usar para a manipulação do pdf 🙂

Deixe-me saber se você tiver algum problema com este, foi uma grande dor para nós, tentamos várias coisas diferentes antes de chegar a isso.

Fonte: https://javebratt.com/cloud-function-image-base64/

Kit de laboratório doméstico de engenharia genética

 

 

 

Descrição do Produto

NOTA: A maneira como podemos oferecer este kit a um preço tão baixo é encontrando as melhores ofertas com nossos parceiros e fabricantes. Isso significa que este kit leva de 1 a 2 meses para ser enviado. Por favor, seja paciente e entenda que estamos fazendo o possível para chegar até você.

Consulte-nos sobre códigos de desconto para nossas aulas on-line com a compra deste kit.

Escolha nossa opção de plano de pagamento no check-out para fazer 4 pagamentos mensais.Veja mais informações aqui .

Este kit inicial do laboratório de bricolage fornece todo o equipamento, reagentes e materiais necessários para começar em biologia molecular e engenharia genética. Além disso, inclui um  kit de genotipagem e suprimentos do nosso  kit DIY CRISPR  para que você possa realizar seus primeiros experimentos! Vem com tutoriais explicando a ciência e como usar o equipamento.

Este kit vem com

  • Máquina de PCR com tampa aquecida
  • Tubos de PCR
  • Um conjunto de 3 novas pipetas de grau laboratorial
  • Pontas de pipeta para cada pipeta
  • Caixa de eletroforese em gel de agarose e molde de gel com pente
  • Rack de tubo
  • Uma fonte de alimentação para executar a eletroforese
  • 2 powerchords
  • Almofada de aquecimento com temperatura controlada para culturas em crescimento
  • 10g Agarose
  • 50g de mistura de tampão TAE (27g de base Tris / 23g de acetato de Tris / 0,5g de EDTA)
  • 5g de sulfato de canamicina
  • 5g de ampicilina de sódio
  • 40g de ágar LB
  • 20g LB Media
  • Manga de 20 placas de Petri
  • Balanças de 0,01g – 200g e balanças
  • Óculos trans-eye-luminator e luz azul
  • 5 x 15mL Tubes
  • 5 x tubos de 50 ml
  • bactérias ativadas por luz pDusk, pDawn
  • pJE202 bactérias brilhantes bioluminescentes geneticamente modificadas
  • 100uL Gel Verde Mancha 10.000x
  • 500uL 5x Taq Master Mix
  • Corante de carregamento de DNA de 200 uL
  • 100uL 100bp DNA Ladder
  • 100uL 1kbp DNA Ladder
  • Kit de Genotipagem
  • Suprimentos do  kit DIY CRISPR
  • Microcentrífuga 10k novíssima

https://www.the-odin.com/genetic-engineering-home-lab-kit/

Jython – A linguagem que mistura Java com Python

Essa linguagem une duas boas ferramentas numa só. 🐍

Introdução

Jython é uma implementação da linguagem Python que gera bytecode para máquinas Java (JVM – Java Virtual Machine). Com ela é possível fazer o desenvolvimento de aplicações híbridas que unem código em Java e Python.

Esta ferramenta é muito útil também para embutir uma linguagem para criação de scripts em aplicações que requerem este tipo de funcionalidade. Também inclui um compilador que converte código fonte Python em Java bytecode, permitindo que programadores Python possam escrever classes que possam ser utilizadas por um programa Java.

Entre suas vantagens, destacam-se:

  • 🐍 – Velocidade de desenvolvimento: Python é uma linguagem de desenvolvimento rápido (RAD – Rapid Application Development).
  • 🐍 – Praticidade: Não é necessário compilar o código Jython para testá-lo. Isto torna a depuração muito mais rápida. Depois de terminado o processo, utiliza-se o compilador Jythonc para compilar o programa, para incluir as bibliotecas do Jython existe a opção do freeze.
  • 🐍 – Tempo de aprendizado: Por ter uma sintaxe simples, limpa e coerente o seu aprendizado é muito fácil.

Instalação

Procedimento no Linux

  • 1. – Instale as dependências Primeiramente você precisará ter o instalados no seu sistema:
  • JDK – Ambiente de desenvolvimento para Java;
  • e o IcedTea – Um software de integração.

Use o gerenciador de pacotes da sua distribuição para instalá-los, exemplo, como instalei aqui no Gentoo:

sudo USE="-cups -alsa" emerge -a dev-java/openjdk-bin dev-java/openjdk-jre-bin

Nesse caso eu rejeitei os módulos: cups e alsa e o icedtea foi instalado automaticamente, pois é uma dependência.

Agora baixe o Jython no endereço: https://sourceforge.net/projects/jython/ . Após baixar extraia o pacote:

Antes crie e entre um diretório, para os arquivos não ficarem espalhados

mkdir ambiente && cd ambiente/
mv ../jython* .
jar xj jython.jar
java -jar jython_installer-*.jar

Após esse último comando, ele abrirá um wizard para você seguir, acompanhe as imagens abaixo:

Jython WizardJython WizardJython Wizard

Nessa 4º imagem ↓ parte você ainda poderia escolhe um diretório personalizado, exemplo de de ~/.config/jython, seria o mais ideal para não poluir sua pasta pessoal.Jython Wizard

Jython WizardJython WizardJython WizardJython WizardJython WizardJython Wizard

Após o finish agora vamos editar o seu vim ~/.bashrc e adicione a seguinte linha:

Nesse caso minha versão e nome do diretório é 2.5.2 , verifique a sua.

PATH="${PATH}:${HOME}/jython2.5.2/bin/"

Depois rode o comando source ~/.bashrc ou feche e abra o terminal para poder que o comando jython seja encontrado.

Criando sua primeira aplicação

Um mini aplicativo que efetua soma de dois números. Crie um arquivo como nome vim soma.py

import javax.swing as libswing 
pnumero = libswing.JOptionPane.showInputDialog("Digite um Numero Inteiro: ") 
snumero = libswing.JOptionPane.showInputDialog("Digite um Numero Inteiro: ") 
soma = int(pnumero) + int(snumero) 
libswing.JOptionPane.showMessageDialog(None, "A soma eh %d " % soma)

Salve e rode da seguinte maneira:

jython soma.py

No Shell irá aparecer as saídas do programa, mas não significa que é um problema, e sim que está enviando os outputs corretamente.

Jython WizardJython Wizard

Perceba que nesse caso eu somei 8 + 8 e o resultado foi o esperado. 😁️

Explicando o código

  • import javax.swing as libswing – Importa a biblioteca do Java.
  • pnumero = libswing.JOptionPane.showInputDialog("Digite um Numero Inteiro: ") – Mostra a primeira caixa de diálogo e armazena o valor na variável pnumero.
  • snumero = libswing.JOptionPane.showInputDialog("Digite um Numero Inteiro: ") – Mostra a segunda caixa de diálogo e armazena o valor na variável snumero.
  • soma = int(pnumero) + int(snumero) – Converte os valores de pnumero e snumero para inteiros e soma os dois armazenando o resultado na variável soma.
  • libswing.JOptionPane.showMessageDialog(None, "A soma eh %d " % soma) – Mostra na tela o resultado da soma, simples não é?

Conclusão

Eu particularmente curti o Jython 🙌️ e vou me aprofundar mais sobre ele e provavelmente haverá mais tutoriais aqui sobre o mesmo. E você ?! Curtiu ?! Conte-nos usando o campo de comentários . Abraços!

 

Fontehttps://terminalroot.com.br/2019/10/jython-a-linguagem-que-mistura-java-com-python.html?utm_source=dlvr.it&utm_medium=facebook

Integração fiscal com equipamentos Bematech

Windows – SAT BEMATECH
http://bematechpartners.com.br/wp01/?page_id=308

Plataforma Fiscal Bematech
http://www.bematechpartners.com.br/wp01/upload-files/downloads/oneapi/DOCUMENTACAO_GERAL/help/APIOne.html#_o_que_é_a_a_apione

Integrando a Plataforma Fiscal através da APIOne.
http://www.bematechpartners.com.br/wp01/upload-files/downloads/oneapi/DOCUMENTACAO_GERAL/help/APIOne.html#_instalação_da_plataforma_fiscal_fiscal_manager

CENTRAL DE DOWNLOADS
http://bematechpartners.com.br/wp01/

Electron JS

 

 

Crie um aplicativo de desktop usando a tecnologia da Web (Javascript, HTML, CSS, Nodejs e mais), escrevendo o código javascript do zero usando o Electron.js como estrutura.

 

 

http://www.faztweb.com/curso/electron-primera-aplicaci%C3%B3n

https://github.com/FaztWeb/electron-products-test/blob/master/src/views/index.html

https://github.com/electron/electron-api-demos

 

http://photonkit.com/

 

 

 

 

Como instalar um servidor web no Raspberry Pi (Apache + PHP + MySQL)

Por que um Raspberry Pi como um servidor web?

Mas por que usar uma raspberry como um servidor web , em vez de usar provedores de serviços especializados em hospedagem na web?

Primeiro, do ponto de vista econômico, você deve saber que os serviços de hospedagem não são gratuitos e que você tem que pagar todos os meses / ano. Ao contrário do framboesa que só precisa de uma conexão . 
Além disso, escolhendo Raspberry, você tem a possibilidade de modificar seus serviços como você deseja (exemplos: o tamanho do disco, a hospedagem do banco de dados, etc.), que geralmente não é o caso de hosts especializados , que geralmente vendem compartilhada hospedagem com baixa capacidade de configuração . 
No entanto, para suportar mais usuários, você deve usar um Raspberry Pi 3 (o Pi 3 pode ser encontrado aqui ), o Raspberry Pi com 1 GB de RAM, em vez do Raspberry tipo B + (512 MB de RAM)

A questão que surge agora é, como fazer um servidor web no Raspeberry Pi ? Instalação do servidor Apache com Raspbian

O que é o Apache?

Primeiro, vamos instalar o Apache, que é o servidor web como tal . 
Quando falamos de um servidor web, geralmente pensamos na máquina, mas esse termo também se refere ao software que permite que a máquina analise solicitações de usuários (em formato http) e retorne o arquivo correspondente à solicitação (Ou um erro se o arquivo não for encontrado ou a consulta for formulada incorretamente). 
Como parte do Apache, é um software sobre o qual falamos .

No momento, o Apache é o servidor web mais utilizado , com cerca de 60% de participação de mercado. O Apache tem sua própria licença, usada por muitos outros projetos. Além disso, o uso maciço do Apache (que se tornou o padrão para servidores da Web), juntamente com sua alta popularidade, levou a uma tremenda abundância de documentação, cursos e outros livros relacionados ao seu uso, e sua segurança, como esta. livro .

Seja para o Raspberry Pi e o Raspbian, ou para uma máquina mais genérica, o Apache é, portanto, uma opção segura , e as habilidades que você poderá adquirir no assunto sempre serão úteis.

Instalação do Apache

Antes de instalar o servidor, verifique se temos uma máquina atualizada. Para fazer isso , devemos ter direitos de administrador , seja por causa do comando sudo.

sudo apt update

sudo apt upgrade

sudo apt update

Quando o Raspberry Pi estiver atualizado, instalaremos o servidor Apache.

sudo apt instalar apache2


A propósito, aproveitamos para dar direitos ao arquivo do apache
para que você possa gerenciar facilmente seus sites. 
Para fazer isso, execute os seguintes comandos:

sudo chown -R pi: www-data / var / www / html / 
chmod sudo-R 770 / var / www / html /

Verifique se o Apache está funcionando

Quando a instalação estiver concluída, podemos testar se o Apache está funcionando corretamente , indo para o endereço do Raspberry. 
Para fazer isso, é necessário tentar acessar o Raspberry a partir da porta 80 (essa porta não será aberta de fora, ela terá que fazer desde o próprio Raspberry). Não se preocupe, é muito fácil. Simplesmente abra o navegador da Web Raspberry e vá para “http://127.0.0.1”. Você deve então receber uma página com uma mensagem como “Funciona! “E muitos outros textos. 
Se você ainda não tem uma GUI no seu Raspbian ou usa o SSH para se conectar ao seu Raspberry, você pode usar o seguinte comando:

wget -O check_apache.html http://127.0.0.1

Este comando salvará o código HTML da página no arquivo “check_apache.html”no diretório atual. 
Então você só tem que ler o arquivo com o comando

cat ./check_apache.html

Se você vir marcado em um local no código “Funciona! É que o Apache está funcionando.

O Apache usa o diretório “/ var / www / html” como a raiz do seu site. Isso significa que quando você chama seu Raspberry na porta 80 (http), o Apache procura o arquivo em “/ var / www / html”. 
Por exemplo, se você chamar o endereço “http://127.0.0.1/example”, o Apache procurará o arquivo “exemplo” no diretório “/ var / www / html”. 
Para adicionar novos arquivos, sites, etc., você precisará adicioná-los a este diretório.

Agora você pode usar seu Raspberry para criar um site em HTML, CSS e JavaScriptinternamente. 
No entanto, você pode querer permitir rapidamente interações entre o site e o usuário . Por exemplo, para permitir que o usuário se registre, etc. Para isso, você precisará do PHP.

Instalação do PHP no seu Raspberry Pi

O que é PHP?

Primeiro de tudo, você deve saber que o PHP é uma linguagem interpretada . E como no caso dos servidores, a sigla PHP pode ter vários significados . De fato, quando falamos sobre PHP, podemos falar sobre o idioma ou o interpretador . 
Aqui, quando falamos sobre a instalação do PHP, isso significa que vamos instalar o interpretador , a fim de usar a linguagem.

O PHP (o idioma desta vez) é usado principalmente para tornar um site dinâmico, isto é, o usuário envia informações para o servidor que retorna os resultados modificados de acordo com essas informações . Por outro lado, um site estático não se adapta às informações fornecidas por um usuário . É salvo como um arquivo de uma vez por todas e sempre entregará o mesmo conteúdo.

O PHP é gratuito e mantido pela PHP Foundation, assim como pelo Zend Enterprise, e várias outras empresas (deve-se notar que Zend também é o autor do famoso framework Zend PHP, amplamente utilizado e reconhecido no mundo dos negócios). .

É uma das linguagens de programação mais utilizadas e é até a mais utilizada para programação web, com cerca de 79% de market share.

Mais uma vez, todas as habilidades que você pode adquirir, no idioma, ou na instalação e configuração do interpretador, sempre serão úteis. Então, só podemos aconselhá-lo a aprender o PHP, que é realmente uma linguagem maravilhosa e muitas vezes subestimada.

Como instalar o PHP

Voltaremos a usar o administrador para instalar o PHP com a linha de comando.

sudo apt instalar php php-mbstring

Saber se o PHP está funcionando

Para saber se o PHP está funcionando corretamente, não é muito complicado, e o método é bastante semelhante ao usado para o Apache .

Você primeiro excluirá o arquivo “index.html” no diretório “/ var / www / html”.

sudo rm /var/www/html/index.html

Em seguida, crie um arquivo “index.php” neste diretório, com esta linha de comando

echo "<? php phpinfo ();?>"> /var/www/html/index.php

A partir daí, a operação é a mesma da verificação do Apache . Você tenta acessar sua página, e você deve ter um resultado próximo a esta imagem (se você não tiver uma interface, use o mesmo método de antes, e procure as palavras “Versão do PHP”).

Capturando um phpinfo de um servidor em Raspbian.

Tabela gerada pelo comando phpinfo em uma framboesa.

Um banco de dados MySQL para o seu servidor

Um DBMS, o  que é isso? Por que o MySQL?

Agora que configuramos o PHP, você provavelmente desejará armazenar informações para uso em seus sites. Para este propósito, os bancos de dados são usados ​​com mais freqüência. 
Vamos, portanto, configurar um DBMS (Database Management System), ou seja, o MySQL.

O MySQL é um DBMS gratuito , poderoso e usado maciçamente (cerca de 56% de participação no mercado de DBMSs gratuitos). Aqui, novamente, o MySQL é tão essencial para o desenvolvimento, seja qual for a linguagem, que você deve aprender e dominar completamente, com este livro, por exemplo .

Como instalar o MySQL

Para fazer isso, vamos instalar o mysql-server e o php-mysql (que servirão como um link entre o php e o mysql)

sudo apt instale o mysql-server php-mysql

Verifique se o MySQL está funcionando corretamente

Para verificar o funcionamento do MySQL, desta vez vamos usar apenas a linha de comando . Para fazer isso, simplesmente nos conectaremos pelo comando:

sudo mysql --user = root

Não excluiremos o usuário root padrão do mysql e criaremos um novo usuário root do mysql, porque o padrão só pode ser usado com a conta root do Linux, e portanto não disponível para os scripts do servidor web e php.

Para fazer isso, uma vez que você se conectar ao MySQL, simplesmente execute esses comandos (substitua passwordpela senha que você quer):

DROP USER 'root' @ 'localhost'; 
CREATE USER 'root' @ 'localhost' IDENTIFICADO POR 'senha'; 
GRANT ALL PRIVILEGES ON *. * TO 'root' @ 'localhost'

Então você agora tem um servidor web, conectado ao PHP e MySQL . Isso é tudo que é preciso.

(Nas suas conexões de nexts, você poderá se conectar ao mysql sem usar o sudo, com o comando mysql --user=root --password=yourmysqlpassword).

Adicionar PHPMyAdmin

A instalação do PHPMyAdmin é absolutamente desnecessária. Nesta instalação, não vamos nos preocupar com nenhuma configuração de segurança especial!

A instalação do PHPMyAdmin é muito rápida e fácil, nós simplesmente temos que usar o gerenciador de pacotes com este comando:

sudo apt instala phpmyadmin

O programa de instalação do PHPMyAdmin fará algumas perguntas. Sobre o dbconfig-commoncomponente, opte por não usá-lo (como já configuramos nosso banco de dados). Sobre o servidor para configurar o PHPMyAdmin para, escolha Apache. E a senha do root é aquela que você definiu para o MySQL.

Você também deve ativar a extensão mysqli usando o comando acima:

sudo phpenmod mysqli 
sudo /etc/init.d/apache2 reiniciar

Verifique se o PHPMyAdmin está funcionando corretamente

Para verificar se o PHPMyAdmin funciona, você simplesmente tentará acessá-lo, usando o endereço do seu Raspberry seguido de / phpmyadmin. Por exemplo, localmente será http://127.0.0.1/phpmyadmin

Se você ainda receber um erro, pode ser porque o PHPMyAdmin foi movido para outro diretório. Neste caso, tente o comando

sudo ln -s / usr / share / phpmyadmin / var / www / html / phpmyadmin

Agora, podemos acessar o PHPMyAdmin do navegador do Raspberry Pi, com o URL: http://127.0.0.1/phpmyadmin

Tornar um servidor acessível a partir da web

Seu servidor da web está pronto. No entanto, você provavelmente não pode acessá-lo da internet . De fato, seria necessário que o seu modem redirecionasse os pedidos para o seu Raspberry, as boas portas. 
Para colocar esses redirecionamentos no lugar, e até mesmo obter um URL, você deve olhar para DynDNS e encaminhamento de porta!

Fonte

https://howtoraspberrypi.com/how-to-install-web-server-raspberry-pi-lamp/

https://stackoverflow.com/questions/39281594/error-1698-28000-access-denied-for-user-rootlocalhost