Merge branch 'main' of bitbucket.org:jubilian/nhance_partner_be

This commit is contained in:
VENKATESHWARAN 2026-06-09 10:18:26 +05:30
commit 471a2ce86b
7 changed files with 427 additions and 58 deletions

1
.gitignore vendored
View File

@ -16,6 +16,7 @@
/writable/uploads/enquiry/rc/*
/writable/uploads/quotation/*
/writable/uploads/policy/policy_pdf/*
/writable/uploads/policy/policy_md/*
/writable/uploads/policy/policy_payment_receipt/*

View File

@ -151,6 +151,7 @@ $routes->group('api', ['filter' => ["jwtAuth:1,2,3,4,agent","appSignature"] ], f
$routes->get('claim/ClaimList', 'ClaimController::ClaimList');
$routes->get('claim/getClaimById', 'ClaimController::getClaimById');
$routes->get('claim/downloadClaimFile', 'ClaimController::downloadClaimFile');
$routes->get('claim/deleteClaim', 'ClaimController::deleteClaim');
$routes->post('claim/createClaim', 'ClaimController::createClaim');
$routes->post('claim/updateClaim', 'ClaimController::updateClaim');

View File

@ -351,6 +351,63 @@ class ClaimController extends ResourceController
}
}
/**
* Soft delete claim by id (sets is_active = 0).
* Also soft deletes related claim files.
*/
public function deleteClaim()
{
try {
$claimId = $this->request->getGet('id');
if (empty($claimId)) {
return $this->respond(['status' => 'failed', 'code' => 400, 'data' => 'id is required'], 400);
}
$claim = $this->ClaimModel
->where('id', (int) $claimId)
->where('is_active', 1)
->first();
if (!$claim) {
return $this->respond(['status' => 'failed', 'code' => 404, 'data' => 'Claim not found'], 404);
}
$updatedBy = $this->request->getGet('updated_by');
$this->db->transStart();
$this->ClaimModel->update((int) $claimId, [
'is_active' => 0,
'updated_by' => $updatedBy ?? null,
]);
$this->ClaimFilesModel
->where('claim_id', (int) $claimId)
->where('is_active', 1)
->set([
'is_active' => 0,
'updated_by' => $updatedBy ?? null,
])
->update();
if ($this->db->transStatus() === false) {
$this->db->transRollback();
return $this->respond(['status' => 'failed', 'code' => 500, 'data' => 'Failed to delete claim'], 500);
}
$this->db->transComplete();
return $this->respond([
'status' => 'success',
'code' => 200,
'data' => 'Claim deleted successfully',
], 200);
} catch (\Exception $e) {
return $this->respond(['status' => 'failed', 'code' => 500, 'data' => $e->getMessage()], 500);
}
}
/**
* Fetch a single claim by primary id with related lookups and file preview URLs.
* Used to populate the edit form when the user clicks the edit button on a row.

View File

@ -694,6 +694,14 @@ class PolicyController extends ResourceController
}
}
public function readFile()
{
$readDoc = $this->checkPolicyDoc(15862);
dd($readDoc);
}
public function readFileAndCalculateCommission(array $data)
{
$policyId = $data['policy_id'];
@ -702,6 +710,8 @@ class PolicyController extends ResourceController
$readDoc = $this->checkPolicyDoc($policyId);
if($readDoc['status'] == 'success')
{
@ -807,7 +817,7 @@ class PolicyController extends ResourceController
try
{
helper('policy_pdf_helper');
// Replace with your actual Gemini API key
$apiKey = getenv('GEMINI_API_KEY');
@ -819,33 +829,57 @@ class PolicyController extends ResourceController
$record = $this->PolicyModel->find((int)$policyId);
$uploadedPath = WRITEPATH . 'uploads/policy/policy_pdf/';
$filePath = $uploadedPath.$record['policy_pdf_file_name'];
// dd($filePath);
// Check if the file exists
if (!file_exists($filePath)) {
log_message('info',"Error: File not found at {$filePath}");
$mdUploadedPath = WRITEPATH . 'uploads/policy/policy_md/';
$pdfFilePath = $uploadedPath . $record['policy_pdf_file_name'];
$mdFileName = preg_replace('/\.pdf$/i', '.md', $record['policy_pdf_file_name']);
$mdFilePath = $mdUploadedPath . $mdFileName;
if (!file_exists($pdfFilePath)) {
log_message('info',"Error: File not found at {$pdfFilePath}");
if($return == true)
{
return $this->respond(['status'=>"failed", 'message'=> "File not found at {$filePath}"], 200);
return $this->respond(['status'=>"failed", 'message'=> "File not found at {$pdfFilePath}"], 200);
}else{
return ['status'=>"failed", 'message'=> "File not found at {$filePath}"];
return ['status'=>"failed", 'message'=> "File not found at {$pdfFilePath}"];
}
}
$markdownResult = convert_policy_pdf_to_markdown($pdfFilePath);
if ($markdownResult['status'] !== 'success') {
log_message('info', 'Policy PDF to markdown conversion failed: ' . $markdownResult['message']);
if ($return == true) {
return $this->respond(['status' => 'failed', 'message' => $markdownResult['message']], 200);
}
return ['status' => 'failed', 'message' => $markdownResult['message']];
}
if (!file_exists($mdFilePath)) {
log_message('info',"Error: Markdown file not found at {$mdFilePath}");
if($return == true)
{
return $this->respond(['status'=>"failed", 'message'=> "Markdown file not found at {$mdFilePath}"], 200);
}else{
return ['status'=>"failed", 'message'=> "Markdown file not found at {$mdFilePath}"];
}
}
$filePath = $mdFilePath;
// Get the file's MIME type using the finfo extension
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_file($finfo, $filePath);
finfo_close($finfo);
// Define supported inline MIME types
$supportedInlineMimeTypes = ['application/pdf','text/csv'];
// Gemini inline supports text/plain reliably for markdown files
if (!in_array($mimeType, ['text/plain', 'text/markdown', 'text/x-markdown'], true)) {
$mimeType = 'text/plain';
}
// Read the file content and encode it to Base64
$fileContent = file_get_contents($filePath);
$base64Content = base64_encode($fileContent);
// The prompt you want to send to the model
// $prompt = "give me a json with emp data like name,age,dob,mobile and email. only json not any explanations";
$prompt = "Read the following motor policy pdf document and convert into JSON format as sample specified. Give me only JSON,not any explanations.while pick up premium break up give own damage, third party ,personal accident and taxes as mentioned in JSON format.Notes:vehicle_type should be like Two Wheeler,Four Feeler,Good Vehicle,Bus, Tractor,Commercial Vehicle.rto_state_code is first two char of reg_no and rto_city_code 3rd & 4th char of reg_no and it should be two digit numeric code. Any date should be in mysql date format";
// Define supported inline MIME types
$supportedInlineMimeTypes = ['application/pdf', 'text/csv', 'text/plain', 'text/markdown', 'text/x-markdown'];
$prompt = "Read the following motor policy document and convert into JSON format as sample specified. Give me only JSON,not any explanations.while pick up premium break up give own damage, third party ,personal accident and taxes as mentioned in JSON format.Notes:vehicle_type should be like Two Wheeler,Four Feeler,Good Vehicle,Bus, Tractor,Commercial Vehicle.rto_state_code is first two char of reg_no and rto_city_code 3rd & 4th char of reg_no and it should be two digit numeric code. Any date should be in mysql date format.(note : while fetching TP premium do not add PA AMOUNT)";
$prompt .= '"{\"policy\":{\"intermediary_name\":\"\",\"policy_number\":\"\",\"issue_date\":\"\",\"period\":{\"start\":\"\",\"end\":\"\"},\"insurer\":\"\",\"previous_policy_number\":\"\"},\"insured\":{\"name\":\"\",\"father_name\":\"\",\"address\":[\"\"],\"mobile\":\"\",\"id_proofs\":{\"aadhaar\":\"\",\"pan\":\"\"}},\"vehicle\":{\"reg_no\":\"\",\"rto_state_code\":\"\",\"rto_city_code\":\"\",\"weight\":\"\",\"fuel_type\":\"\",\"date_of_registration\":\"\",\"year_of_manufacture\":\"\",\"engine_no\":\"\",\"chassis_no\":\"\",\"make\":\"\",\"model\":\"\",\"year\":\"\",\"cubic_capacity\":\"\",\"vehicle_type\":\"\"},\"rto\":\"\",\"premium\":{\"tp\":0,\"od\":0,\"pa\":0,\"taxes\":{\"cgst\":\"\",\"sgst\":\"\",\"igst\":\"\"},\"total\":0,\"in_words\":\"\"},\"endorsements\":[{\"code\":\"\",\"desc\":\"\"}]}"';
$payloadPart = null;
@ -854,10 +888,21 @@ class PolicyController extends ResourceController
$text_part = [
"text" => $prompt
];
// Conditionally handle the file upload based on MIME type
if (in_array($mimeType, $supportedInlineMimeTypes)) {
// Handle PDF as inline data
// Read saved markdown file from policy_md directory
$fileContent = file_get_contents($filePath);
if ($fileContent === false || trim($fileContent) === '') {
log_message('info', "Markdown file is empty at {$filePath}");
if ($return == true) {
return $this->respond(['status' => 'failed', 'message' => "Markdown file is empty at {$filePath}"], 200);
}
return ['status' => 'failed', 'message' => "Markdown file is empty at {$filePath}"];
}
$base64Content = base64_encode($fileContent);
$payloadPart = [
"inlineData" => [
@ -872,33 +917,15 @@ class PolicyController extends ResourceController
$payloadPart
]
];
}
// else {
// // Handle Excel/CSV using the Files API
// // echo "Detected unsupported inline MIME type ({$mimeType}). Uploading via Files API...\n";
// $fileInfo = $this->uploadFileToGemini($filePath, $apiKey); // Pass apiKey
// // print_r($fileInfo);
// // The file part, using the URI from the Files API upload
// $file_part = [
// "fileData" => [
// "fileUri" => $fileInfo['uri'],
// "mimeType" => $fileInfo['mimeType']
// ]
// ];
// // The full content array, containing both parts
// $content_parts = [
// "parts" => [
// $text_part,
// $file_part
// ]
// ];
// }
} else {
log_message('info', "Unsupported inline MIME type ({$mimeType}) for markdown file.");
if($return == true)
{
return $this->respond(['status'=>"failed", 'message'=> "Unsupported inline MIME type ({$mimeType})"], 200);
}else{
return ['status'=>"failed", 'message'=> "Unsupported inline MIME type ({$mimeType})"];
}
}
// The final JSON payload
$data = [
@ -1814,7 +1841,7 @@ class PolicyController extends ResourceController
. 'ins.short_name AS insurer_short_name, ipti.insurance_plan_type AS insurance_plan_type, '
. 'pp.policy_number AS policy_no, pp.premium_amount AS premium, '
. 'pp.commission_amount, pp.insured_name, pe.reg_no, pp.weight, pp.fuel_type, '
. 'pp.vehicle_type, pp.issued_date'
. 'pp.vehicle_type, pp.issued_date, pp.od, pp.tp, pp.pa, pp.cgst, pp.sgst, pp.igst'
);
$builder->select(
'COALESCE((SELECT GROUP_CONCAT(piu.utr_no ORDER BY piu.id SEPARATOR ", ") '
@ -1982,9 +2009,10 @@ class PolicyController extends ResourceController
'Q3' => 'A+B (NET)',
'R3' => 'S.TAX',
'S3' => 'TOTAL',
'T3' => "PAYMENT MODE",
'U3' => 'UTR NO',
'V3' => 'UTR DATE',
'T3' => 'PAYOUT',
'U3' => "PAYMENT MODE",
'V3' => 'UTR NO',
'W3' => 'UTR DATE',
];
$headerNumberCols = ['A', 'O', 'P', 'Q', 'R', 'S', 'I'];
@ -2008,8 +2036,17 @@ class PolicyController extends ResourceController
$fuelType = $row['fuel_type'] ?? '';
$vehicleType = $row['vehicle_type'] ?? '';
$weight = $row['weight'] ?? '';
$commissionAmt = (float) ($row['commission_amount'] ?? 0);
$commissionAmt = (float) ($row['commission_amount'] ?? 0); // payout amount
$premium = (float) ($row['premium'] ?? 0);
$od = (float) ($row['od'] ?? 0);
$tp = (float) ($row['tp'] ?? 0);
$pa = (float) ($row['pa'] ?? 0);
$cgst = (float) ($row['cgst'] ?? 0);
$sgst = (float) ($row['sgst'] ?? 0);
$igst = (float) ($row['igst'] ?? 0);
$tpWithPa = $tp + $pa;
$netAmount = $od + $tp + $pa;
$serviceTax = $cgst + $sgst + $igst;
$utrNo = $row['utr_no'] ?? '';
$utrDate = $row['utr_date'] ?? '';
$payoutStatus = ($row['received_or_not'] ?? '') === 'yes' ? 'LINK' : 'PENDING';
@ -2029,14 +2066,15 @@ class PolicyController extends ResourceController
'L' => isset($row['issued_date']) ? date('d-m-Y', strtotime($row['issued_date'])) : '',
'M' => '', // Company / insurer add to query if available
'N' => '', // Make & Variant add if available
'O' => 0, // A (OD) extend query if split premium available
'P' => $premium, // B (TP) using full premium; adjust if split
'Q' => $premium, // A+B Net
'R' => 0, // S.TAX add if available
'S' => $commissionAmt, // Commission as TOTAL
'T' => $payoutStatus,
'U' => $utrNo,
'V' => $utrDate,
'O' => $od, // A (OD) => od
'P' => $tpWithPa, // B (TP) => tp+pa
'Q' => $netAmount, // A+B Net => od+tp+pa
'R' => $serviceTax, // S.TAX => cgst+igst+sgst
'S' => $premium, // TOTAL => premium amount
'T' => $commissionAmt, // PAYOUT => payout amount
'U' => $payoutStatus,
'V' => $utrNo,
'W' => $utrDate,
];
$dataNumberCols = ['A', 'I', 'O', 'P', 'Q', 'R', 'S'];

View File

@ -0,0 +1,196 @@
<?php
if (!function_exists('policy_md_upload_path')) {
/**
* Full path to the saved markdown file for a policy PDF file name.
*/
function policy_md_upload_path(string $pdfFileName): string
{
$mdFileName = preg_replace('/\.pdf$/i', '.md', $pdfFileName);
if ($mdFileName === $pdfFileName) {
$mdFileName .= '.md';
}
return WRITEPATH . 'uploads/policy/policy_md/' . $mdFileName;
}
}
if (!function_exists('policy_pdf_md_path')) {
/**
* Resolve markdown path using the same base name as the PDF file.
* e.g. 1764999905_abc.pdf -> policy_md/1764999905_abc.md
*/
function policy_pdf_md_path(string $pdfPath): string
{
return policy_md_upload_path(basename($pdfPath));
}
}
if (!function_exists('policy_md_is_valid')) {
/**
* Validate that markdown content looks like extracted policy text.
*/
function policy_md_is_valid(string $content): bool
{
$content = trim($content);
if ($content === '' || strlen($content) < 500) {
return false;
}
$errorMarkers = [
'pdftotext:',
'GLIBCXX_',
'CXXABI_',
'no version information available',
];
foreach ($errorMarkers as $marker) {
if (stripos($content, $marker) !== false) {
return false;
}
}
return true;
}
}
if (!function_exists('policy_pdf_extract_text')) {
/**
* Extract plain text from a PDF using pdftotext (poppler).
* Uses a clean environment so LAMPP lib paths do not break pdftotext.
*/
function policy_pdf_extract_text(string $pdfPath): string
{
$pdftotext = getenv('PDFTOTEXT_BIN') ?: '/usr/bin/pdftotext';
if (!is_executable($pdftotext) && $pdftotext === '/usr/bin/pdftotext') {
$which = trim((string) shell_exec('command -v pdftotext 2>/dev/null'));
if ($which !== '') {
$pdftotext = $which;
}
}
$command = sprintf(
'env -i PATH=/usr/bin:/bin LD_LIBRARY_PATH= %s -layout %s - 2>&1',
escapeshellcmd($pdftotext),
escapeshellarg($pdfPath)
);
$text = shell_exec($command);
if (!is_string($text)) {
return '';
}
$text = trim($text);
if (!policy_md_is_valid($text)) {
log_message('error', 'PDF text extraction failed or returned invalid content for: ' . $pdfPath);
return '';
}
return $text;
}
}
if (!function_exists('convert_policy_pdf_to_markdown')) {
/**
* Convert a policy PDF to markdown, save to policy_md/, then read back from disk.
*
* @return array{status: string, message: string, content?: string, md_path?: string, md_file_name?: string}
*/
function convert_policy_pdf_to_markdown(string $pdfPath, bool $forceRefresh = false): array
{
if (!is_file($pdfPath)) {
return [
'status' => 'failed',
'message' => "PDF file not found at {$pdfPath}",
];
}
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_file($finfo, $pdfPath);
finfo_close($finfo);
if ($mimeType !== 'application/pdf') {
return [
'status' => 'failed',
'message' => "Unsupported file type ({$mimeType}). Only PDF is supported.",
];
}
$mdPath = policy_pdf_md_path($pdfPath);
$mdFileName = basename($mdPath);
$mdDir = dirname($mdPath);
if (!is_dir($mdDir) && !mkdir($mdDir, 0777, true) && !is_dir($mdDir)) {
return [
'status' => 'failed',
'message' => "Unable to create markdown directory at {$mdDir}",
];
}
if (!$forceRefresh && is_file($mdPath) && filemtime($mdPath) >= filemtime($pdfPath)) {
$cached = file_get_contents($mdPath);
if ($cached !== false && policy_md_is_valid($cached)) {
log_message('info', "Using cached policy markdown: {$mdPath}");
return [
'status' => 'success',
'message' => 'Cached markdown loaded from disk',
'content' => $cached,
'md_path' => $mdPath,
'md_file_name' => $mdFileName,
];
}
if ($cached !== false) {
log_message('info', "Invalid cached markdown detected, reconverting: {$mdPath}");
@unlink($mdPath);
}
}
$extractedText = policy_pdf_extract_text($pdfPath);
if ($extractedText === '') {
return [
'status' => 'failed',
'message' => 'PDF text extraction failed. The file may be scanned, image-based, or pdftotext is unavailable on the server.',
];
}
$markdown = "# Motor Policy Document\n\n" . $extractedText;
if (file_put_contents($mdPath, $markdown) === false) {
return [
'status' => 'failed',
'message' => "Failed to write markdown file at {$mdPath}",
];
}
$savedContent = file_get_contents($mdPath);
if ($savedContent === false || !policy_md_is_valid($savedContent)) {
@unlink($mdPath);
return [
'status' => 'failed',
'message' => 'Saved markdown file is invalid after conversion',
];
}
log_message('info', "Policy PDF converted to markdown: {$mdPath}");
return [
'status' => 'success',
'message' => 'PDF converted to markdown and saved to disk',
'content' => $savedContent,
'md_path' => $mdPath,
'md_file_name' => $mdFileName,
];
}
}

View File

@ -7,5 +7,5 @@ class StaffAttendanceModel extends Model
protected $table = 'partner_staff_attendance';
protected $primaryKey = 'id';
protected $returnType = 'array';
protected $allowedFields = ['staff_id', 'login_datetime', 'logout_datetime'];
protected $allowedFields = ['staff_id', 'login_datetime', 'logout_datetime', 'manager_id'];
}

76
ca.pem Normal file
View File

@ -0,0 +1,76 @@
-----BEGIN CERTIFICATE-----
MIIEADCCAuigAwIBAgIQB/57HSuaqUkLaasdjxUdPjANBgkqhkiG9w0BAQsFADCB
mDELMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIElu
Yy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTEwLwYDVQQDDChB
bWF6b24gUkRTIGFwLXNvdXRoLTEgUm9vdCBDQSBSU0EyMDQ4IEcxMRAwDgYDVQQH
DAdTZWF0dGxlMCAXDTIxMDUxOTE3NDAzNFoYDzIwNjEwNTE5MTg0MDM0WjCBmDEL
MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x
EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTEwLwYDVQQDDChBbWF6
b24gUkRTIGFwLXNvdXRoLTEgUm9vdCBDQSBSU0EyMDQ4IEcxMRAwDgYDVQQHDAdT
ZWF0dGxlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtbkaoVsUS76o
TgLFmcnaB8cswBk1M3Bf4IVRcwWT3a1HeJSnaJUqWHCJ+u3ip/zGVOYl0gN1MgBb
MuQRIJiB95zGVcIa6HZtx00VezDTr3jgGWRHmRjNVCCHGmxOZWvJjsIE1xavT/1j
QYV/ph4EZEIZ/qPq7e3rHohJaHDe23Z7QM9kbyqp2hANG2JtU/iUhCxqgqUHNozV
Zd0l5K6KnltZQoBhhekKgyiHqdTrH8fWajYl5seD71bs0Axowb+Oh0rwmrws3Db2
Dh+oc2PwREnjHeca9/1C6J2vhY+V0LGaJmnnIuOANrslx2+bgMlyhf9j0Bv8AwSi
dSWsobOhNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQb7vJT
VciLN72yJGhaRKLn6Krn2TAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQAD
ggEBAAxEj8N9GslReAQnNOBpGl8SLgCMTejQ6AW/bapQvzxrZrfVOZOYwp/5oV0f
9S1jcGysDM+DrmfUJNzWxq2Y586R94WtpH4UpJDGqZp+FuOVJL313te4609kopzO
lDdmd+8z61+0Au93wB1rMiEfnIMkOEyt7D2eTFJfJRKNmnPrd8RjimRDlFgcLWJA
3E8wca67Lz/G0eAeLhRHIXv429y8RRXDtKNNz0wA2RwURWIxyPjn1fHjA9SPDkeW
E1Bq7gZj+tBnrqz+ra3yjZ2blss6Ds3/uRY6NYqseFTZWmQWT7FolZEnT9vMUitW
I0VynUbShVpGf6946e0vgaaKw20=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIICrjCCAjWgAwIBAgIQGKVv+5VuzEZEBzJ+bVfx2zAKBggqhkjOPQQDAzCBlzEL
MAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x
EzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdBbWF6
b24gUkRTIGFwLXNvdXRoLTEgUm9vdCBDQSBFQ0MzODQgRzExEDAOBgNVBAcMB1Nl
YXR0bGUwIBcNMjEwNTE5MTc1MDU5WhgPMjEyMTA1MTkxODUwNTlaMIGXMQswCQYD
VQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEG
A1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExMDAuBgNVBAMMJ0FtYXpvbiBS
RFMgYXAtc291dGgtMSBSb290IENBIEVDQzM4NCBHMTEQMA4GA1UEBwwHU2VhdHRs
ZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABMqdLJ0tZF/DGFZTKZDrGRJZID8ivC2I
JRCYTWweZKCKSCAzoiuGGHzJhr5RlLHQf/QgmFcgXsdmO2n3CggzhA4tOD9Ip7Lk
P05eHd2UPInyPCHRgmGjGb0Z+RdQ6zkitKNCMEAwDwYDVR0TAQH/BAUwAwEB/zAd
BgNVHQ4EFgQUC1yhRgVqU5bR8cGzOUCIxRpl4EYwDgYDVR0PAQH/BAQDAgGGMAoG
CCqGSM49BAMDA2cAMGQCMG0c/zLGECRPzGKJvYCkpFTCUvdP4J74YP0v/dPvKojL
t/BrR1Tg4xlfhaib7hPc7wIwFvgqHes20CubQnZmswbTKLUrgSUW4/lcKFpouFd2
t2/ewfi/0VhkeUW+IiHhOMdU
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
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
Em4Hy3A=
-----END CERTIFICATE-----