Files
pds/app/Http/Controllers/PdfController.php
dhanabalan 36e51ad6cb
Some checks failed
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (push) Successful in 10s
Scan for leaked secrets using Kingfisher / kingfisher-secrets-scan (pull_request) Successful in 11s
Gemini PR Review / review (pull_request) Failing after 24s
Laravel Larastan / larastan (pull_request) Failing after 2m12s
Laravel Pint / pint (pull_request) Failing after 2m26s
Enhanced storeProcessOrderData method with improved validation and error handling for plant code, item code, coil number, order quantity, received quantity, SFG number, machine ID, and created by
2025-11-26 19:48:52 +05:30

879 lines
30 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\GrMaster;
use App\Models\Item;
use App\Models\Plant;
use App\Models\ProcessOrder;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Response;
use Illuminate\Support\Facades\Storage;
use Str;
class PdfController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
{
//
}
public function updateGR(Request $request)
{
$expectedUser = env('API_AUTH_USER');
$expectedPw = env('API_AUTH_PW');
$header_auth = $request->header('Authorization');
$expectedToken = $expectedUser.':'.$expectedPw;
if ('Bearer '.$expectedToken != $header_auth) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => 'Invalid authorization token!',
], 403);
}
$data = $request->all();
if ($data['plant_code'] == null || $data['plant_code'] == '') {
// return response("ERROR: Please provide a valid plant code.", 400)
// ->header('Content-Type', 'text/plain');
return response()->json([
'status_code' => 'ERROR',
'status_description' => "Plant code can't be empty!",
], 400);
} elseif (Str::length($data['plant_code']) < 4 || ! is_numeric($data['plant_code']) || ! preg_match('/^[1-9]\d{3,}$/', $data['plant_code'])) {// !ctype_digit($data['plant_code'])
return response()->json([
'status_code' => 'ERROR',
'status_description' => 'Invalid plant code found!',
], 400);
}
$plant = Plant::where('code', $data['plant_code'])->first();
if (! $plant) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => 'Plant not found!',
], 400);
}
$plantId = $plant->id;
if ($data['gr_number'] == null || $data['gr_number'] == '') {
return response()->json([
'status_code' => 'ERROR',
'status_description' => "GR Number can't be empty!",
], 400);
}
$grExists = GRMaster::where('plant_id', $plantId)
->where('gr_number', $data['gr_number'])
->first();
if (! $grExists) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => "GR Number {$data['gr_number']} not found for plant {$data['plant_code']}!",
], 404);
}
$scannedBy = $data['scanned_by'] ?? null;
if ($scannedBy == '' || $scannedBy == null) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => "Scanned by can't be empty!",
], 400);
}
$user = User::where('name', $data['scanned_by'])
->first();
if (! $user) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => "'{$data['scanned_by']}' user not found!",
], 404);
}
$itemCodes = array_column($data['item_codes'], 'item_code');
$duplicateItemCodes = array_unique(array_diff_assoc($itemCodes, array_unique($itemCodes)));
if (count($duplicateItemCodes) > 0) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => 'Duplicate item codes found in request!',
'duplicate_item_codes' => array_values($duplicateItemCodes),
], 400);
}
$allSerials = [];
foreach ($data['item_codes'] as $item) {
if (! isset($item['serial_numbers']) || ! is_array($item['serial_numbers'])) {
continue;
}
foreach ($item['serial_numbers'] as $serial) {
$allSerials[] = $serial;
}
}
$duplicateSerials = array_unique(array_diff_assoc($allSerials, array_unique($allSerials)));
if (count($duplicateSerials) > 0) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => 'Duplicate serial numbers found in request!',
'duplicate_serial_numbers' => array_values($duplicateSerials),
], 400);
}
$invalidLengthItemCodes = [];
foreach ($data['item_codes'] as $item) {
$itemCode = $item['item_code'] ?? null;
// Skip if item code is missing
if (! $itemCode) {
continue;
}
// Check if item code is less than 6 digits or not numeric
if (strlen($itemCode) < 6 || ! ctype_digit($itemCode)) {
$invalidLengthItemCodes[] = $itemCode;
}
}
if (count($invalidLengthItemCodes) > 0) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => 'Some item codes are invalid: must be at least 6 digits!',
'invalid_item_codes' => array_values($invalidLengthItemCodes),
], 400);
}
$invalidItemCodes = [];
$invalidPlantItems = [];
foreach ($data['item_codes'] as $item) {
$itemCode = $item['item_code'] ?? null;
if (! $itemCode) {
$invalidItemCodes[] = '(missing)';
continue;
}
$itemObj = Item::where('code', $itemCode)->first();
if (! $itemObj) {
$invalidItemCodes[] = $itemCode;
continue;
}
$itemPlant = Item::where('plant_id', $plantId)
->where('code', $itemCode)->first();
if (! $itemPlant) {
$invalidPlantItems[] = $itemCode;
}
}
if (count($invalidItemCodes) > 0 || count($invalidPlantItems) > 0) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => 'Some item codes are invalid!',
'not_found_items' => array_values($invalidItemCodes),
'not_in_plant' => array_values($invalidPlantItems),
], 400);
}
$missingSerialsByItem = [];
foreach ($data['item_codes'] as $item) {
$itemCode = $item['item_code'];
$serialNumbers = $item['serial_numbers'];
// Get the item id
$itemObj = Item::where('plant_id', $plantId)
->where('code', $itemCode)
->first();
if (! $itemObj) {
continue;
}
$itemId = $itemObj->id;
$foundSerials = GRMaster::where('plant_id', $plantId)
->where('gr_number', $data['gr_number'])
->where('item_id', $itemId)
->whereIn('serial_number', $serialNumbers)
->pluck('serial_number')
->toArray();
$missingSerials = array_diff($serialNumbers, $foundSerials);
if (count($missingSerials) > 0) {
$missingSerialsByItem[$itemCode] = array_values($missingSerials);
}
}
if (count($missingSerialsByItem) > 0) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => 'Some serial numbers not found in DB for given plant, GR number, and item!',
'missing_serials' => $missingSerialsByItem,
], 400);
}
$alreadyCompleted = [];
foreach ($data['item_codes'] as $item) {
$itemCode = $item['item_code'];
$serialNumbers = $item['serial_numbers'];
$itemId = Item::where('code', $itemCode)->value('id');
foreach ($serialNumbers as $serial) {
$gr = GRMaster::where('plant_id', $plantId)
->where('item_id', $itemId)
->where('gr_number', $data['gr_number'])
->where('serial_number', $serial)
->first();
if (! $gr) {
continue;
}
if ($gr->status == 'Completed') {
$alreadyCompleted[] = $serial;
}
}
}
if (! empty($alreadyCompleted)) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => 'Below serial numbers are already completed',
'serial_numbers' => $alreadyCompleted,
], 400);
}
// {
// $itemCode = $item['item_code'];
// $serialNumbers = $item['serial_numbers'];
// $itemObj = Item::where('code', $itemCode)->first();
// if (!$itemObj) {
// return response()->json([
// 'status_code' => 'ERROR',
// 'status_description' => "Item code: $itemCode not found"
// ], 400);
// }
// $itemPlant = Item::where('plant_id', $plantId)
// ->where('code', $itemCode)->first();
// if (!$itemPlant) {
// return response()->json([
// 'status_code' => 'ERROR',
// 'status_description' => "Item code: $itemCode not found for the plant: $data[plant_code]"
// ], 400);
// }
// $itemId = $itemObj->id;
// // Update all serial numbers for this item
// GRMaster::where('plant_id', $plantId)
// ->where('item_id', $itemId)
// ->where('gr_number', $data['gr_number'])
// ->whereIn('serial_number', $serialNumbers)
// ->update(['created_by' => $scannedBy]);
// }
foreach ($data['item_codes'] as $item) {
$itemCode = $item['item_code'];
$serialNumbers = $item['serial_numbers'];
$itemId = Item::where('code', $itemCode)->value('id');
GRMaster::where('plant_id', $plantId)
->where('item_id', $itemId)
->where('gr_number', $data['gr_number'])
->whereIn('serial_number', $serialNumbers)
->update(['created_by' => $scannedBy, 'status' => 'Completed']);
}
return response()->json([
'status_code' => 'SUCCESS',
'status_description' => 'Serial numbers updated successfully!',
], 200);
}
/**
* Store a newly created resource in storage.
*/
public function getPdf(Request $request)
{
// Validate input
// $request->validate([
// 'filename' => 'required|string',
// ]);
$expectedUser = env('API_AUTH_USER');
$expectedPw = env('API_AUTH_PW');
$header_auth = $request->header('Authorization');
$expectedToken = $expectedUser.':'.$expectedPw;
if ('Bearer '.$expectedToken != $header_auth) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => 'Invalid authorization token!',
], 403);
}
$filename = $request->header('process-order');
if (! $filename) {
return response()->json(['error' => 'Missing file-name header'], 400);
}
$filename = basename($filename);
// Ensure the file has .pdf extension
if (! str_ends_with(strtolower($filename), '.pdf')) {
$filename .= '.pdf';
}
$filePath = 'uploads/ProcessOrder/'.$filename;
if (! Storage::disk('local')->exists($filePath)) {
return response()->json(['error' => 'File not found'], 404);
}
$file = Storage::disk('local')->get($filePath);
$mimeType = Storage::disk('local')->mimeType($filePath);
return Response::make($file, 200, [
'Content-Type' => $mimeType,
'Content-Disposition' => 'inline; filename="'.$filename.'"',
]);
}
public function getGRPdf(Request $request)
{
// Validate input
// $request->validate([
// 'filename' => 'required|string',
// ]);
$expectedUser = env('API_AUTH_USER');
$expectedPw = env('API_AUTH_PW');
$header_auth = $request->header('Authorization');
$expectedToken = $expectedUser.':'.$expectedPw;
if ('Bearer '.$expectedToken != $header_auth) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => 'Invalid authorization token!',
], 403);
}
$filename = $request->header('gr-number');
if (! $filename) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => 'Gr Number cannot be empty!',
], 403);
// return response()->json(['error' => 'Missing file-name header'], 400);
}
$filename = basename($filename);
// Ensure the file has .pdf extension
if (! str_ends_with(strtolower($filename), '.pdf')) {
$filename .= '.pdf';
}
$filePath = 'uploads/GRNumber/'.$filename;
if (! Storage::disk('local')->exists($filePath)) {
// return response()->json(['error' => 'File not found'], 404);
return response()->json([
'status_code' => 'ERROR',
'status_description' => 'Pdf File not found for the provided GrNumber!',
], 403);
}
$file = Storage::disk('local')->get($filePath);
$mimeType = Storage::disk('local')->mimeType($filePath);
return Response::make($file, 200, [
'Content-Type' => $mimeType,
'Content-Disposition' => 'inline; filename="'.$filename.'"',
]);
}
public function getGRSerial(Request $request)
{
$expectedUser = env('API_AUTH_USER');
$expectedPw = env('API_AUTH_PW');
$header_auth = $request->header('Authorization');
$expectedToken = $expectedUser.':'.$expectedPw;
if ('Bearer '.$expectedToken != $header_auth) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => 'Invalid authorization token!',
], 403);
}
$plantCode = $request->header('plant-code');
$grNumber = $request->header('gr-number');
if (! $plantCode) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => "Plant Code value can't be empty",
], 404);
} elseif (! $grNumber) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => 'GR Number cannot be empty!',
], 403);
}
$plant = Plant::where('code', $plantCode)->first();
$plantId = $plant->id;
if (! $plant) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => "Plant Code '{$plantCode}' not found!",
], 404);
}
$grExist = GRMaster::where('gr_number', $grNumber)->first();
if (! $grExist) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => 'GR Number not found',
], 404);
}
$grExists = GRMaster::where('plant_id', $plantId)
->where('gr_number', $grNumber)
->first();
if (! $grExists) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => 'GR Number not found for this plant!',
], 404);
}
$grRecords = GrMaster::where('plant_id', $plantId)
->where('gr_number', $grNumber)
->get(['serial_number', 'item_id']);
if (empty($grRecords)) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => 'No serial numbers found for the given GR number!',
], 404);
}
// return response()->json([
// 'serial_numbers' => $serialNumbers
// ], 200);
// $itemId = $grRecords->first()->item_id;
// $itemCode = $itemId ? optional(Item::find($itemId))->code : null;
// $serialNumbers = $grRecords->pluck('serial_number')->toArray();
// return response()->json([
// 'item_code' => $itemCode,
// 'serial_numbers' => $serialNumbers
// ], 200);
$itemIds = $grRecords->pluck('item_id')->unique()->filter();
$items = Item::whereIn('id', $itemIds)->pluck('code', 'id');
$result = $grRecords->groupBy('item_id')->map(function ($group, $itemId) use ($items) {
return [
'item_code' => $items[$itemId] ?? null,
'serial_numbers' => $group->pluck('serial_number')->toArray(),
];
})->values(); // remove keys
return response()->json($result, 200);
}
public function getProcessOrderData(Request $request)
{
$expectedUser = env('API_AUTH_USER');
$expectedPw = env('API_AUTH_PW');
$header_auth = $request->header('Authorization');
$expectedToken = $expectedUser.':'.$expectedPw;
if ('Bearer '.$expectedToken != $header_auth) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => 'Invalid authorization token!',
], 403);
}
$plantCode = $request->header('plant-code');
$processOrder = $request->header('process-order');
if (! $plantCode) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => "Plant Code value can't be empty",
], 404);
} elseif (! $processOrder) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => 'Process Order cannot be empty!',
], 403);
}
$plant = Plant::where('code', $plantCode)->first();
$plantId = $plant->id;
if (! $plant) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => "Plant Code '{$plantCode}' not found!",
], 404);
}
$processOrderExist = ProcessOrder::where('process_order', $processOrder)->first();
if (! $processOrderExist) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => 'Process order not found',
], 404);
}
$proOrdAgPlant = ProcessOrder::where('plant_id', $plantId)
->where('process_order', $processOrder)
->first();
if (! $proOrdAgPlant) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => 'Process order not found for this plant!',
], 404);
}
$item = $proOrdAgPlant->item;
$processOrderRecords = ProcessOrder::with('item')
->where('plant_id', $plant->id)
->where('process_order', $processOrder)
->get();
$lastRecord = ProcessOrder::with('item')
->where('plant_id', $plant->id)
->where('process_order', $processOrder)
->orderBy('id', 'desc')
->first();
$totalReceivedQty = $processOrderRecords->sum('received_quantity');
// $lastRecord = $processOrderRecords->first();
$item = $lastRecord->item;
if ($totalReceivedQty == $proOrdAgPlant->order_quantity) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => "Process order '{$processOrder}' for plant '{$plantCode}' has already reached its order quantity.",
], 400);
}
// if ($totalReceivedQty > $proOrdAgPlant->order_quantity) {
// return response()->json([
// 'status_code' => 'ERROR',
// 'status_description' => "Process order '{$processOrder}' for plant '{$plantCode}' received quantity is more than its order quantity."
// ], 400);
// }
return response()->json([
'item_code' => $item?->code ?? '',
'description' => $item?->description ?? '',
// 'coil_number' => $proOrdAgPlant->coil_number ?? "",
// 'order_quantity' => (string)$proOrdAgPlant->order_quantity ?? "",
'coil_number' => $lastRecord->coil_number ?? '',
'order_quantity' => (string) $lastRecord->order_quantity ?? '',
'received_quantity' => (string) $totalReceivedQty ?? '',
]);
}
public function storeProcessOrderData(Request $request)
{
$expectedUser = env('API_AUTH_USER');
$expectedPw = env('API_AUTH_PW');
$headerAuth = $request->header('Authorization');
$expectedToken = 'Bearer '.$expectedUser.':'.$expectedPw;
if ($headerAuth !== $expectedToken) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => 'Invalid authorization token!',
], 403);
}
Log::info('Process Order POST API called >>', ['request_data' => $request->all()]);
$plantCode = $request->header('plant-code');
$processOrder = $request->header('process-order');
if ($plantCode == null || $plantCode == '' || ! $plantCode) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => "Plant code can't be empty!",
], 400);
} elseif (! is_numeric($plantCode) || Str::length($plantCode) < 4 || ! preg_match('/^[1-9]\d{3,}$/', $plantCode)) { // !ctype_digit($data['plant_code'])
return response()->json([
'status_code' => 'ERROR',
'status_description' => 'Invalid plant code found!',
], 400);
}
if (! $processOrder) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => 'Process-order are required!',
], 400);
}
$plant = Plant::where('code', $plantCode)->first();
if (! $plant) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => "Plant code '{$plantCode}' not found!",
], 404);
}
$plantId = $plant->id;
$data = $request->all();
$itemCode = $data['item_code'] ?? '';
$coilNo = $data['coil_number'] ?? '';
$orderQty = $data['order_quantity'] ?? 0;
$receivedQty = $data['received_quantity'] ?? 0;
$sfgNo = $data['sfg_number'] ?? '';
$machineId = $data['machine_id'] ?? '';
$createdBy = $data['created_by'] ?? '';
// $validated = $request->validate([
// 'item_code' => 'nullable|integer',
// 'coil_number' => 'nullable|string',
// 'order_quantity' => 'nullable|integer',
// 'received_quantity' => 'nullable|numeric',
// 'sfg_number' => 'nullable|string',
// 'machine_id' => 'nullable|string',
// 'created_by' => 'nullable|string',
// ]);
if ($itemCode == null || $itemCode == '' || ! $itemCode) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => "Item code can't be empty!",
], 404);
} elseif (Str::length($itemCode) < 6) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => 'Item code should contain minimum 6 digits!',
], 404);
} elseif (! ctype_alnum($itemCode)) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => 'Item code should contain only alpha-numeric values!',
], 404);
}
if ($coilNo == null || $coilNo == '') {
return response()->json([
'status_code' => 'ERROR',
'status_description' => "Coil number can't be empty!",
], 404);
} elseif (! is_numeric($coilNo) || Str::length($coilNo) <= 0 || ! preg_match('/^\d{1,}$/', $coilNo)) { // !ctype_digit($data['plant_code'])
return response()->json([
'status_code' => 'ERROR',
'status_description' => 'Invalid coil number found!',
], 404);
}
if ($sfgNo == null || $sfgNo == '' || ! $sfgNo) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => "SFG number can't be empty!",
], 404);
}
if ($machineId == null || $machineId == '' || ! $machineId) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => "Machine ID can't be empty!",
], 404);
}
if ($createdBy == null || $createdBy == '' || ! $createdBy) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => "User name can't be empty!",
], 404);
} elseif ($createdBy == 'jothi') {
$createdBy = 'Admin';
}
$user = User::where('name', $createdBy)->first();
$userPlant = User::where('name', $createdBy)->where('plant_id', $plantId)->first();
if (! $user) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => "User name '{$createdBy}' not found!",
], 403);
} elseif (! $userPlant && ! $user->hasRole('Super Admin')) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => "User name '{$createdBy}' not found for the plant code '{$plantCode}'!",
], 403);
} elseif (! $user->hasRole('Super Admin') && ! $user->hasRole('Process Employee') && ! $user->hasRole('Process Supervisor')) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => 'User does not have rights!',
], 403);
}
$item = Item::where('code', $itemCode)->first();
if (! $item) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => "Item code '{$itemCode}' not found!",
], 404);
}
$itemPlant = Item::where('code', $itemCode)
->where('plant_id', $plantId)
->first();
if (! $itemPlant) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => "Item code '{$itemCode}' not found for the plant code '{$plantCode}'!",
], 404);
}
$itemId = $itemPlant->id;
$existing = ProcessOrder::where('plant_id', $plantId)
->where('process_order', $processOrder)
->where('item_id', '!=', $itemId)
->first();
if ($existing) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => "Process order '{$processOrder}' already has item_code '{$existing->item->code}' for the plant code '{$plantCode}'!",
], 409);
}
$existing = ProcessOrder::where('plant_id', $plantId)
->where('process_order', $processOrder)
->where('coil_number', $coilNo)
->first();
if ($existing) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => "Process order '{$processOrder}' with coil number '{$coilNo}' already exist for the plant code '{$plantCode}'!",
], 409);
}
$alreadyReceived = ProcessOrder::where('plant_id', $plantId)
->where('process_order', $processOrder)
->where('item_id', $itemId)
->sum('received_quantity');
if ($orderQty == 0) {
$orderQty = ProcessOrder::where('plant_id', $plantId)
->where('process_order', $processOrder)
->where('item_id', $itemId)
->value('order_quantity') ?? 0;
}
$total = $alreadyReceived + $receivedQty;
if ($total > $orderQty) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => "Received quantity should not exceed order quantity! Order Qty = {$orderQty}, Already Received Qty = {$alreadyReceived}, Trying to Insert Qty = {$receivedQty}",
], 404);
}
try {
ProcessOrder::Create(
[
'plant_id' => $plantId,
'process_order' => $processOrder,
'item_id' => $itemId,
'coil_number' => $coilNo,
'order_quantity' => $orderQty,
'received_quantity' => $receivedQty,
'sfg_number' => $sfgNo,
'machine_name' => $machineId,
'created_by' => $createdBy,
]
);
return response()->json([
'status_code' => 'SUCCESS',
'status_description' => 'Record Inserted Successfully',
]);
} catch (\Exception $e) {
return response()->json([
'status_code' => 'ERROR',
'status_description' => $e->getMessage(),
], 500);
}
}
/**
* Display the specified resource.
*/
public function show(string $id)
{
//
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, string $id)
{
//
}
/**
* Remove the specified resource from storage.
*/
public function destroy(string $id)
{
//
}
}