';
}
// Same .tc-room skeleton as renderRoomRow (avatar/info/top/bottom) so a group row matches the
// 1:1 rows visually — data-type="group" + data-gid instead of data-cid/data-uid is what the
// click-delegation in renderRooms() switches on. No online/typing indicator (doesn't apply to
// a group), and the avatar is a rounded square instead of a circle as the only visual cue
// distinguishing a group from a person, mirroring common chat-app convention.
function renderGroupRow(group) {
var gid = group.gid;
var name = group.name || '';
var lastMsg = group.lastMessage;
var preview = '';
if (lastMsg) {
preview = parseDisplayText(lastMsg.msm);
if (!preview) {
if (lastMsg.urlima && lastMsg.urlima.indexOf('public://') >= 0) preview = '📷';
else if (lastMsg.urlaudi && lastMsg.urlaudi.indexOf('public://') >= 0) preview = '🎵';
}
if (String(lastMsg.whosend) === String(userId)) preview = 'You: ' + preview;
} else {
preview = 'No messages yet';
}
var timeStr = group.updated ? fmtTime(unixToDbTimestamp(group.updated)) : '';
var unread = group.unreadCount > 0;
var active = activeGid === gid;
return '
';
}
var body = '';
if (msg.urlima === '_loading_') {
body += '
📷 Sending…
';
} else if (msg.urlima && msg.urlima.indexOf('public://') >= 0) {
var src = msg.urlima.replace('public://', FILES_BASE);
body += '';
}
if (msg.urlaudi && msg.urlaudi.indexOf('public://') >= 0) {
var asrc = msg.urlaudi.replace('public://', FILES_BASE);
body += '';
}
if (meta && meta.type === 'loc') {
body += locationLinkHtml(meta.lat, meta.lng);
} else if (!isSalt && text) {
body += '
' + linkifyText(escHtml(text)) + '
';
}
var time = fmtTime(msg.timestamp || '');
return '
'
+ metaHtml + body
+ '' + escHtml(time) + ''
+ '
';
}
// ── Render group messages ────────────────────────────────────────────────────
function renderGroupMessages(gid) {
var msgs = allGroupMsgs[gid] || [];
var $el = $('#tc-msgs');
var order = msgs.slice().reverse();
$el.html(order.map(renderGroupMsg).join(''));
$el.scrollTop($el[0].scrollHeight);
}
// Same shape as renderMsg(), plus a sender-name label on incoming bubbles — unlike a 1:1
// conversation, "not me" doesn't tell you who actually sent it. Reuses the identical
// urlima/urlaudi rendering, so images/audio sent from the Android app (or sendGroupImage()
// here) display correctly. Audio still has no send control in this web widget.
function renderGroupMsg(msg) {
var isMe = String(msg.whosend) === String(userId);
var side = isMe ? 'tc-out' : 'tc-in';
var parsed = parseInlineMeta(msg.msm || '');
var text = parsed.text;
var meta = parsed.meta;
var isSalt = (text.length === 18 && text.indexOf(' ') < 0);
var senderHtml = '';
if (!isMe) {
senderHtml = '
' + escHtml(msg.senderName || msg.whosend) + '
';
}
var metaHtml = '';
if (meta && meta.type === 'fwd') {
metaHtml = '
';
}
// ── Send (opc 11) ────────────────────────────────────────────────────────────
function sendMessage() {
var text = $.trim($('#tc-input').val());
if (!text || !activeCid) return;
$('#tc-input').val('').focus();
isTyping = false;
post({ opc: '11', userid: userId, cid: activeCid, msm: text, fid: '0' })
.then(function (resp) {
if (!resp) return;
var ok = (resp.resp === 3 || resp.resp === '3' ||
resp.resp === 11 || resp.resp === '11');
if (!ok) return;
var msg = {
id: resp.lastmid || String(Date.now()),
whosend: String(userId),
msm: text,
urlima: '',
urlaudi: '',
timestamp: new Date().toISOString().replace('T', ' ').substr(0, 19)
};
if (!allMsgs[activeCid]) allMsgs[activeCid] = [];
allMsgs[activeCid].unshift(msg);
renderMessages(activeCid);
if (socket && socket.connected) {
socket.emit('send-message', {
id: resp.lastmid,
chatId: activeCid,
from: String(userId),
to: String(activeUid),
message: text,
type: 'text'
});
}
});
}
// ── Send group message ───────────────────────────────────────────────────────
// Purely socket-based — group-message-send both persists (tc_group_message, via the
// signaling server) and delivers, unlike 1:1's HTTP-then-socket-notify split. The server
// echoes the message back to the sender too (see group-message-send in signaling-server-2.js),
// so onGroupSocketMessage() is what actually appends it here — no optimistic local insert.
function sendGroupMessage() {
var text = $.trim($('#tc-input').val());
if (!text || !activeGid) return;
if (!socket || !socket.connected) return;
$('#tc-input').val('').focus();
isTyping = false;
socket.emit('group-message-send', {
gid: parseInt(activeGid, 10),
from: userId,
message: text,
type: 'text',
localId: 'web-' + Date.now() + '-' + Math.random().toString(36).substr(2, 8)
});
}
// ── Send group image (group-message-send, type:"image") ─────────────────────
// Unlike 1:1 (HTTP upload then socket notify), groups have no HTTP upload endpoint —
// the server expects the raw file as a base64 string on the same socket event used for
// text (see group-message-send in signaling-server-2.js), and does its own resize/compress
// (sharp, 1024x1024 max, jpeg75) server-side before writing it and echoing "group-message"
// back to every member including the sender. That echo is what onGroupSocketMessage() uses
// to both confirm this optimistic placeholder (matched by localId) and actually display it.
function sendGroupImage(file) {
if (!activeGid) return;
if (!socket || !socket.connected) return;
if (pendingGroupImage) return; // one at a time — button is disabled meanwhile anyway
var gid = activeGid;
var localId = 'web-img-' + Date.now() + '-' + Math.random().toString(36).substr(2, 8);
pendingGroupImage = { gid: gid, localId: localId };
if (!allGroupMsgs[gid]) allGroupMsgs[gid] = [];
allGroupMsgs[gid].unshift({
id: localId, localId: localId, whosend: String(userId), senderName: myName,
msm: '', urlima: '_loading_', urlaudi: '', created: Math.floor(Date.now() / 1000)
});
renderGroupMessages(gid);
$('#tc-img-btn').attr('disabled', 'disabled');
// Safety net — if the server/socket never answers at all (disconnect mid-flight etc.),
// don't leave "Sending…" stuck forever (see the 1:1 image-send bug this mirrors).
var timeoutId = setTimeout(function () { onGroupMessageError({}); }, 20000);
compressImageIfNeeded(file, function (uploadFile) {
var reader = new FileReader();
reader.onload = function () {
clearTimeout(timeoutId);
if (!pendingGroupImage || pendingGroupImage.localId !== localId) return; // already cleared
var base64 = (reader.result || '').split(',')[1] || '';
if (!base64 || !socket || !socket.connected) { onGroupMessageError({}); return; }
socket.emit('group-message-send', {
gid: parseInt(gid, 10),
from: userId,
message: '',
type: 'image',
filedata: base64,
localId: localId
});
};
reader.onerror = function () {
clearTimeout(timeoutId);
onGroupMessageError({});
};
reader.readAsDataURL(uploadFile);
});
}
// Clears whatever group image send is currently in flight — used both for explicit
// "group-message-error" replies (bad file, not a member, rate-limited) and the
// client-side timeout above. Doesn't distinguish by localId: only one send is ever
// in flight at a time (the button is disabled meanwhile), so there's nothing to match.
function onGroupMessageError(data) {
if (!pendingGroupImage) return;
var gid = pendingGroupImage.gid;
var localId = pendingGroupImage.localId;
pendingGroupImage = null;
$('#tc-img-btn').removeAttr('disabled');
if (allGroupMsgs[gid]) {
allGroupMsgs[gid] = allGroupMsgs[gid].filter(function (m) { return m.localId !== localId; });
}
if (activeGid === gid && isOpen) renderGroupMessages(gid);
if (data && data.error) { console.warn('group image send failed:', data.error); }
}
// Resizes/re-encodes as JPEG when a file exceeds COMPRESS_THRESHOLD. Skips GIFs —
// redrawing to canvas would flatten an animated GIF to a single static frame.
// Falls back to the original file untouched if decoding/encoding fails for any reason.
function compressImageIfNeeded(file, callback) {
if (file.size <= COMPRESS_THRESHOLD || file.type === 'image/gif') {
callback(file);
return;
}
var img = new Image();
var url = URL.createObjectURL(file);
img.onload = function () {
URL.revokeObjectURL(url);
var scale = Math.min(1, COMPRESS_MAX_DIM / Math.max(img.width, img.height));
var canvas = document.createElement('canvas');
canvas.width = Math.round(img.width * scale);
canvas.height = Math.round(img.height * scale);
canvas.getContext('2d').drawImage(img, 0, 0, canvas.width, canvas.height);
canvas.toBlob(function (blob) {
callback(blob || file, !!blob);
}, 'image/jpeg', COMPRESS_QUALITY);
};
img.onerror = function () {
URL.revokeObjectURL(url);
callback(file);
};
img.src = url;
}
// ── Send image (opc 11I) ─────────────────────────────────────────────────────
function sendImage(file) {
if (!activeCid) return;
var tempId = '_img_' + Date.now();
if (!allMsgs[activeCid]) allMsgs[activeCid] = [];
allMsgs[activeCid].unshift({
id: tempId, whosend: String(userId), msm: '', urlima: '_loading_',
urlaudi: '', timestamp: new Date().toISOString().replace('T', ' ').substr(0, 19)
});
renderMessages(activeCid);
// .attr()/.removeAttr(), not .prop() — this site's jQuery predates 1.6 (which is
// when .prop() was introduced), and every other call in this file sticks to
// pre-1.6-safe APIs already.
$('#tc-img-btn').attr('disabled', 'disabled');
compressImageIfNeeded(file, function (uploadFile, wasCompressed) {
var form = new FormData();
form.append('opc', '11I');
form.append('userid', String(userId));
form.append('cid', activeCid);
form.append('image', uploadFile, wasCompressed ? 'upload.jpg' : file.name);
fetch(API_URL, { method: 'POST', body: form })
.then(function (r) { return r.ok ? r.json() : null; })
.then(function (resp) {
allMsgs[activeCid] = allMsgs[activeCid].filter(function (m) { return m.id !== tempId; });
if (resp && (resp.resp === 3 || resp.resp === '3') && resp.urlima) {
var msg = {
id: resp.lastmid || String(Date.now()),
whosend: String(userId),
msm: '',
urlima: resp.urlima,
urlaudi: '',
timestamp: new Date().toISOString().replace('T', ' ').substr(0, 19)
};
allMsgs[activeCid].unshift(msg);
if (socket && socket.connected) {
socket.emit('send-message', {
id: resp.lastmid,
chatId: activeCid,
from: String(userId),
to: String(activeUid),
message: '',
urlima: resp.urlima,
type: 'image'
});
}
}
renderMessages(activeCid);
})
.catch(function () {
allMsgs[activeCid] = allMsgs[activeCid].filter(function (m) { return m.id !== tempId; });
renderMessages(activeCid);
})
.then(function () { $('#tc-img-btn').removeAttr('disabled'); });
});
}
// ── Inline meta parser ────────────────────────────────────────────────────────
function parseInlineMeta(raw) {
if (!raw) return { text: '', meta: null };
if (raw.substr(0, FWD_MARKER.length) === FWD_MARKER) {
var end = raw.indexOf(META_ETX);
if (end < 0) return { text: raw, meta: null };
var sender = raw.substring(FWD_MARKER.length, end);
return { text: raw.substring(end + 1), meta: { type: 'fwd', sender: sender } };
}
if (raw.substr(0, REPLY_MARKER.length) === REPLY_MARKER) {
var rend = raw.indexOf(META_ETX);
if (rend < 0) return { text: raw, meta: null };
var parts = raw.substring(REPLY_MARKER.length, rend);
var sep = parts.indexOf(META_SEP);
var rsender = sep >= 0 ? parts.substring(0, sep) : parts;
var orig = sep >= 0 ? parts.substring(sep + 1) : '';
return { text: raw.substring(rend + 1), meta: { type: 'reply', sender: rsender, orig: orig } };
}
// Shared location — same "lat" + META_SEP + "lng" encoding the Android app writes
// (see LOC_MARKER / sendLocationMessage() in ActivityChat.java). No trailing text.
if (raw.substr(0, LOC_MARKER.length) === LOC_MARKER) {
var lend = raw.indexOf(META_ETX);
if (lend < 0) return { text: raw, meta: null };
var coords = raw.substring(LOC_MARKER.length, lend);
var lsep = coords.indexOf(META_SEP);
var lat = lsep >= 0 ? coords.substring(0, lsep) : coords;
var lng = lsep >= 0 ? coords.substring(lsep + 1) : '';
return { text: raw.substring(lend + 1), meta: { type: 'loc', lat: lat, lng: lng } };
}
return { text: raw, meta: null };
}
function parseDisplayText(msm) {
var p = parseInlineMeta(msm || '');
var t = p.text;
if (p.meta && p.meta.type === 'loc') return '📍 ' + LOC_LABEL;
if (t.length === 18 && t.indexOf(' ') < 0) return '';
return (p.meta ? (p.meta.type === 'fwd' ? '↪ ' : '↩ ') : '') + t;
}
// ── Badge & notifications ─────────────────────────────────────────────────────
function updateBadge() {
var n = Object.keys(unreadCids).length;
Object.keys(allGroups).forEach(function (k) {
if (allGroups[k].unreadCount > 0) n++;
});
var $b = $('#tc-badge');
if (n > 0) { $b.text(n).removeClass('tc-hidden'); }
else { $b.addClass('tc-hidden'); }
}
function showNotif(title, body) {
if (!('Notification' in window)) return;
if (Notification.permission === 'granted') {
new Notification(title, {
body: body || '',
icon: 'https://www.taleoi.com/sites/default/files/taleoi.ico'
});
} else if (Notification.permission === 'default') {
Notification.requestPermission();
}
}
// ── HTTP ──────────────────────────────────────────────────────────────────────
function post(params) {
var form = new FormData();
Object.keys(params).forEach(function (k) { form.append(k, String(params[k])); });
return fetch(API_URL, { method: 'POST', body: form })
.then(function (r) { return r.ok ? r.json() : null; })
.catch(function () { return null; });
}
// ── Helpers ───────────────────────────────────────────────────────────────────
// Group timestamps (tc_group.updated, tc_group_message.created) are unix seconds, unlike
// 1:1's "YYYY-MM-DD HH:MM:SS" strings — converts to that same shape (local time) so both can
// share fmtTime() and the plain string comparison renderRooms() sorts by.
// Formatted with UTC getters, not local — fmtTime() (below) always treats this
// "YYYY-MM-DD HH:MM:SS" shape as UTC (appending 'Z' before parsing), matching the raw
// DB timestamp strings 1:1 chat passes it directly. Using local getters here would hand
// fmtTime() an already-local time it then re-shifts by the viewer's UTC offset again.
function unixToDbTimestamp(unixSec) {
if (!unixSec) return '0';
var d = new Date(unixSec * 1000);
function pad(n) { return (n < 10 ? '0' : '') + n; }
return d.getUTCFullYear() + '-' + pad(d.getUTCMonth() + 1) + '-' + pad(d.getUTCDate()) + ' '
+ pad(d.getUTCHours()) + ':' + pad(d.getUTCMinutes()) + ':' + pad(d.getUTCSeconds());
}
function fmtTime(ts) {
if (!ts) return '';
// DB timestamps are plain "YYYY-MM-DD HH:MM:SS" in UTC (MySQL TIMESTAMP column).
// Without a trailing 'Z', the JS Date parser treats a date-TIME string (unlike a
// date-only string) as local time, not UTC — silently shifting displayed times by
// the viewer's UTC offset. The 'Z' forces correct UTC interpretation.
var d = new Date(ts.replace(' ', 'T') + 'Z');
if (isNaN(d.getTime())) return '';
var now = new Date();
if (d.toDateString() === now.toDateString()) {
return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
}
return (d.getMonth() + 1) + '/' + d.getDate();
}
function escHtml(s) {
return String(s == null ? '' : s)
.replace(/&/g, '&').replace(//g, '>')
.replace(/"/g, '"').replace(/'/g, ''');
}
function escAttr(s) { return escHtml(s); }
// Wraps http(s) URLs in a message's already-escaped text with clickable links. Must run
// AFTER escHtml() — matching against the escaped string is safe since escaping never
// introduces whitespace inside a URL run, and the entities it does introduce (e.g. "&"
// for a literal "&" in a query string) are exactly what a browser expects inside an href
// attribute anyway. target="_blank" + rel="noopener noreferrer" so following a link never
// navigates away from (or exposes window.opener to) the page the chat widget is floating on.
function linkifyText(escapedText) {
return escapedText.replace(/https?:\/\/[^\s<]+/g, function (url) {
var trail = '';
var m = url.match(/[.,!?:;)\]}'"]+$/);
if (m) { trail = m[0]; url = url.slice(0, -trail.length); }
if (!url) return trail;
return '' + url + '' + trail;
});
}
// A shared location (LOC_MARKER — see parseInlineMeta()) renders as a tappable card
// linking to Google Maps, matching how the Android app opens a geo: intent for the
// same coordinates. Uses an https:// maps URL instead since geo: isn't reliably
// clickable in desktop browsers.
function locationLinkHtml(lat, lng) {
var mapUrl = 'https://www.google.com/maps?q=' + encodeURIComponent(lat) + ',' + encodeURIComponent(lng);
return ''
+ '📍 ' + escHtml(LOC_LABEL) + '';
}
})(jQuery);
br| Page 67 | taleoi.com
O mesatenista João David, 13 anos, da federação Amazonense de tênis de mesa, visitou o projeto "Transformando Vidas” em Benjamin Constant.
O projeto é de iniciativa do amigo, Valter Rocha de Lima (Boby) que é professor de tênis de mesa e i...read more
O mesatenista João David, 13 anos, da federação Amazonense de tênis de mesa, visitou o projeto "Transformando Vidas” em Benjamin Constant.
O projeto é de iniciativa do amigo, Valter Rocha de Lima (Boby) que é professor de tênis de mesa e iniciou as ações para incentivar a modalidade esportiva e tirar crianças e jovens das ruas.
As ações são realizadas no CETI BC e está precisando de doações para continuar o projeto. Você pode colaborar, doando raquetes, bolas, rede e mais…
PM apreende R$18 milhões em droga em São Gabriel da Cachoeira
A Polícia Militar do Amazonas (PMAM), por meio da 2ª Companhia Independente de Polícia Militar (CIPM), apreendeu 836 quilos de entorpecentes, no município de São Gabriel da Cacho...read more
PM apreende R$18 milhões em droga em São Gabriel da Cachoeira
A Polícia Militar do Amazonas (PMAM), por meio da 2ª Companhia Independente de Polícia Militar (CIPM), apreendeu 836 quilos de entorpecentes, no município de São Gabriel da Cachoeira (a 852 quilômetros da capital). Os produtos ilícitos localizados, na noite de quarta-feira (08/11), foram avaliados em aproximadamente R$18 milhões.
De acordo com o relatório da ocorrência policial, as equipes localizaram a droga em São Gabriel da Cachoeira, por volta das 20h. Os policiais receberam denúncia anônima relatando que um micro-ônibus, com diversos tabletes de drogas, estaria embarcando em uma balsa, no Porto de Camanaus, com destino a Manaus.
Já no local, os policiais militares encontraram 661 tabletes de entorpecentes, sendo 580 de maconha e 81 de pasta base de cocaína.
O caso foi conduzido à 9ª Delegacia Regional de Polícia Civil, de São Gabriel da Cachoeira.
Esta foi a quinta ocorrência, neste ano, com drogas apreendidas em São Gabriel da Cachoeira. No mês passado, a Polícia Civil localizou duas cargas de drogas em portos de Manaus provenientes do município. Na maior ocorrência registrada este ano, uma operação policial envolvendo diversos órgãos de segurança pública apreendeu 1,4 toneladas de drogas no rio Marié, que faz a fronteira entre o município e Santa Isabel do Rio Negro.
Via: Segundo a Segundo
Fonte consultada/ Fronteira TV
A Prefeitura de Tabatinga, através do Programa Bolsa Família, reforça a importância do combate ao câncer de próstata. Uma palestra informativa sobre saúde masculina, incentivando hábitos saudáveis e a realização do exame de próstata foi ministrada...read more
A Prefeitura de Tabatinga, através do Programa Bolsa Família, reforça a importância do combate ao câncer de próstata. Uma palestra informativa sobre saúde masculina, incentivando hábitos saudáveis e a realização do exame de próstata foi ministrada por profissionais da Secretaria Municipal de Saúde e Assistência Social. Juntos, cuidamos da saúde e bem-estar dos homens tabatinguenses! 🩺🔬💙
PMAM aprende mochila com entorpecente no porto de santo Antônio do Içá
Durante a inspeção nas embarcações que estavam ancoradas, constatou-se uma mochila de cor vermelha contendo tabletes de substância tipo maconha. Apesar das revistas, o p...read more
PMAM aprende mochila com entorpecente no porto de santo Antônio do Içá
Durante a inspeção nas embarcações que estavam ancoradas, constatou-se uma mochila de cor vermelha contendo tabletes de substância tipo maconha. Apesar das revistas, o proprietário da mochila não foi identificado.
A Polícia Militar do Amazonas (PMAM) por meio da 3.ª Companhia de Polícia Militar (CPM), manhã de terça-feira (07/11) apreenderam uma mochila contendo entorpecente, no porto do município de Santo Antônio do Içá.
Os policiais receberam denúncia anônima via linha direta, informando a chegada de uma embarcação transportando entorpecente no porto do município.
Durante a inspeção nas embarcações que estavam ancoradas, constatou-se uma mochila de cor vermelha contendo tabletes de substância tipo maconha. Apesar das revistas, o proprietário da mochila não foi identificado.
Diante disso o material apreendido foi levado para o 53º Distrito Integrado de Polícia (Dip) para os procedimentos cabíveis.
O deputado federal Átila Lins, através de uma emenda parlamentar, viabilizou a construção de um novo Ginásio Poliesportivo em Tabatinga, no valor de R$4.500.000,00.
Em breve, as obras do ginásio começarão e a juventude tabatinguense terá um...read more
O deputado federal Átila Lins, através de uma emenda parlamentar, viabilizou a construção de um novo Ginásio Poliesportivo em Tabatinga, no valor de R$4.500.000,00.
Em breve, as obras do ginásio começarão e a juventude tabatinguense terá uma praça de esportes digna de suas tradições. A capacidade do ginásio será de 5.000 pessoas.
21 casais participam de casamento comunitário na igreja Matriz
Fronteira TV ( Facebook)
A cerimônia foi organizada pela Pastoral da Família e foi realizada no último sábado (04), na igreja Catedral N. Sra. do Perpétuo Socorro.
Foram 21 casais que aceitaram o sacramento do matrimônio e disseram Sim no altar. Outros casais deci...read more
A cerimônia foi organizada pela Pastoral da Família e foi realizada no último sábado (04), na igreja Catedral N. Sra. do Perpétuo Socorro.
Foram 21 casais que aceitaram o sacramento do matrimônio e disseram Sim no altar. Outros casais decidiram realizar nos próximos dias, cerimônias em outras comunidades.
No total, são quase 30.
Por: Pascom Paróquia Santos Anjos
Fonte: Fronteira TV - Facebook
Operação conjunta apreendida mais de uma tonelada de cocaína
Polícia Federal-PF Facebook
🚨🤜🤛🚢 A Polícia Federal e a @receita_federal em operação conjunta, realizaram uma varredura em um navio atracado no Porto de Vitória/ES, onde apreenderam mais de uma tonelada de cocaína.
👮♂️👊 Mais de 50 policiais dos dois órgãos participar...read more
🚨🤜🤛🚢 A Polícia Federal e a @receita_federal em operação conjunta, realizaram uma varredura em um navio atracado no Porto de Vitória/ES, onde apreenderam mais de uma tonelada de cocaína.
👮♂️👊 Mais de 50 policiais dos dois órgãos participaram da operação, com o apoio de 14 cães farejadores.
Forças se reúnem para discutir atuação nos aeroportos e fronteiras nacionais
Polícia Federal- PF / Facebook
Forças de segurança e defesa se reúnem para discutir atuação nos portos, aeroportos e fronteiras nacionais.
Representantes da PF e @prfoficial , @exercito_oficial , @fab_oficial , @marinhaoficial e @receita_federal se reuniram para alinham...read more
Forças de segurança e defesa se reúnem para discutir atuação nos portos, aeroportos e fronteiras nacionais.
Representantes da PF e @prfoficial , @exercito_oficial , @fab_oficial , @marinhaoficial e @receita_federal se reuniram para alinhamento de ações, em prol do fortalecimento do combate ao crime organizado, tráfico de armas e drogas, contrabando e descaminho e outros delitos transfronteiriços.
Operação para combater e comercialização ilícita de produtos
Polícia Federal - PF
🚨 👊 A Polícia Federal em atuação conjunta com a @receita_federal deflagrou, nesta quarta-feira (08), a Operação Lex Mercatoria, para combater esquema de importação e comercialização ilícita de produtos no Ceará.
🚨 👊 A Polícia Federal em atuação conjunta com a @receita_federal deflagrou, nesta quarta-feira (08), a Operação Lex Mercatoria, para combater esquema de importação e comercialização ilícita de produtos no Ceará.
👮♂️🤜🤛 Na ação, 105 policiais federais e 10 auditores da Receita Federal cumpriram 23 mandados de busca e apreensão.