Subversion Repositories SmartDukaan

Rev

Rev 29905 | Rev 29917 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
27391 tejbeer 1
package com.spice.profitmandi.web.controller;
2
 
29900 amit.gupta 3
import java.awt.image.BufferedImage;
27876 amit.gupta 4
import java.io.ByteArrayInputStream;
29900 amit.gupta 5
import java.io.File;
6
import java.io.FileNotFoundException;
27876 amit.gupta 7
import java.io.InputStream;
29900 amit.gupta 8
import java.time.Instant;
27876 amit.gupta 9
import java.time.LocalDate;
27391 tejbeer 10
import java.time.LocalDateTime;
27876 amit.gupta 11
import java.time.YearMonth;
27391 tejbeer 12
import java.util.ArrayList;
27876 amit.gupta 13
import java.util.Arrays;
14
import java.util.Collection;
15
import java.util.Comparator;
29900 amit.gupta 16
import java.util.HashMap;
27391 tejbeer 17
import java.util.List;
18
import java.util.Map;
19
import java.util.Set;
20
import java.util.stream.Collectors;
21
 
29900 amit.gupta 22
import javax.imageio.ImageIO;
27391 tejbeer 23
import javax.servlet.http.HttpServletRequest;
24
import javax.transaction.Transactional;
25
 
29900 amit.gupta 26
import org.apache.commons.io.FileUtils;
27876 amit.gupta 27
import org.apache.commons.io.output.ByteArrayOutputStream;
27391 tejbeer 28
import org.apache.logging.log4j.LogManager;
29
import org.apache.logging.log4j.Logger;
29900 amit.gupta 30
import org.apache.velocity.app.VelocityEngine;
27391 tejbeer 31
import org.springframework.beans.factory.annotation.Autowired;
29809 amit.gupta 32
import org.springframework.cache.CacheManager;
27876 amit.gupta 33
import org.springframework.core.io.InputStreamResource;
34
import org.springframework.http.HttpHeaders;
35
import org.springframework.http.HttpStatus;
36
import org.springframework.http.ResponseEntity;
27391 tejbeer 37
import org.springframework.stereotype.Controller;
38
import org.springframework.ui.Model;
29900 amit.gupta 39
import org.springframework.ui.velocity.VelocityEngineUtils;
27876 amit.gupta 40
import org.springframework.web.bind.annotation.PathVariable;
29682 amit.gupta 41
import org.springframework.web.bind.annotation.PostMapping;
27391 tejbeer 42
import org.springframework.web.bind.annotation.RequestBody;
43
import org.springframework.web.bind.annotation.RequestMapping;
44
import org.springframework.web.bind.annotation.RequestMethod;
45
import org.springframework.web.bind.annotation.RequestParam;
29682 amit.gupta 46
import org.springframework.web.bind.annotation.RequestPart;
47
import org.springframework.web.multipart.MultipartFile;
29900 amit.gupta 48
import org.xhtmlrenderer.simple.Graphics2DRenderer;
27391 tejbeer 49
 
50
import com.google.gson.Gson;
29900 amit.gupta 51
import com.jcraft.jsch.ChannelSftp;
52
import com.jcraft.jsch.JSch;
53
import com.jcraft.jsch.JSchException;
54
import com.jcraft.jsch.Session;
55
import com.jcraft.jsch.SftpATTRS;
56
import com.jcraft.jsch.SftpException;
57
import com.spice.profitmandi.common.enumuration.MessageType;
27391 tejbeer 58
import com.spice.profitmandi.common.exception.ProfitMandiBusinessException;
59
import com.spice.profitmandi.common.model.CustomRetailer;
27876 amit.gupta 60
import com.spice.profitmandi.common.model.ProfitMandiConstants;
29900 amit.gupta 61
import com.spice.profitmandi.common.model.SendNotificationModel;
27876 amit.gupta 62
import com.spice.profitmandi.common.util.FileUtil;
29904 amit.gupta 63
import com.spice.profitmandi.common.util.FormattingUtils;
27876 amit.gupta 64
import com.spice.profitmandi.common.web.util.ResponseSender;
27391 tejbeer 65
import com.spice.profitmandi.dao.entity.catalog.Offer;
66
import com.spice.profitmandi.dao.entity.fofo.PartnerType;
67
import com.spice.profitmandi.dao.enumuration.catalog.ItemCriteriaType;
68
import com.spice.profitmandi.dao.model.CreateOfferRequest;
27876 amit.gupta 69
import com.spice.profitmandi.dao.model.OfferRowModel;
27391 tejbeer 70
import com.spice.profitmandi.dao.repository.catalog.ItemRepository;
71
import com.spice.profitmandi.dao.repository.catalog.OfferMarginRepository;
72
import com.spice.profitmandi.dao.repository.catalog.OfferPartnerRepository;
73
import com.spice.profitmandi.dao.repository.catalog.OfferRepository;
74
import com.spice.profitmandi.dao.repository.dtr.FofoStoreRepository;
75
import com.spice.profitmandi.dao.repository.dtr.Mongo;
76
import com.spice.profitmandi.dao.repository.fofo.PartnerTypeChangeService;
29900 amit.gupta 77
import com.spice.profitmandi.service.NotificationService;
29785 amit.gupta 78
import com.spice.profitmandi.service.authentication.RoleManager;
27876 amit.gupta 79
import com.spice.profitmandi.service.offers.OfferService;
27391 tejbeer 80
import com.spice.profitmandi.service.user.RetailerService;
81
import com.spice.profitmandi.web.model.LoginDetails;
82
import com.spice.profitmandi.web.util.CookiesProcessor;
83
import com.spice.profitmandi.web.util.MVCResponseSender;
84
 
85
@Controller
86
@Transactional(rollbackOn = Throwable.class)
87
public class OfferController {
88
	private static final Logger LOGGER = LogManager.getLogger(OfferController.class);
89
	@Autowired
90
	private OfferRepository offerRepository;
91
 
92
	@Autowired
93
	private OfferMarginRepository offerMarginRepository;
94
 
95
	@Autowired
96
	private FofoStoreRepository fofoStoreRepository;
97
 
98
	@Autowired
27876 amit.gupta 99
	private ResponseSender responseSender;
100
 
101
	@Autowired
27391 tejbeer 102
	private OfferPartnerRepository offerPartnerRepository;
103
 
29900 amit.gupta 104
	private static final String IMAGE_REMOTE_DIR = "/var/www/dtrdashboard/uploads/campaigns/";
105
	private static final String IMAGE_STATIC_SERVER_URL = "https://images.smartdukaan.com/uploads/campaigns";
106
 
27391 tejbeer 107
	@Autowired
108
	private ItemRepository itemRepository;
109
 
110
	@Autowired
111
	private MVCResponseSender mvcResponseSender;
112
 
113
	@Autowired
114
	private Gson gson;
115
 
116
	@Autowired
117
	private RetailerService retailerService;
118
 
119
	@Autowired
120
	private Mongo mongoClient;
121
 
122
	@Autowired
29900 amit.gupta 123
	private NotificationService notificationService;
124
 
125
	@Autowired
27391 tejbeer 126
	private CookiesProcessor cookiesProcessor;
127
 
128
	@Autowired
27876 amit.gupta 129
	private OfferService offerService;
29900 amit.gupta 130
 
29809 amit.gupta 131
	@Autowired
132
	private CacheManager thirtyMinsTimeOutCacheManager;
29900 amit.gupta 133
 
29855 amit.gupta 134
	@Autowired
135
	private CacheManager oneDayCacheManager;
27876 amit.gupta 136
 
137
	@Autowired
27391 tejbeer 138
	private PartnerTypeChangeService partnerTypeChangeService;
139
 
140
	@RequestMapping(value = "/getCreateOffer", method = RequestMethod.GET)
141
	public String getCreateOffer(HttpServletRequest request, Model model) throws ProfitMandiBusinessException {
142
		LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
143
		List<Integer> fofoIds = fofoStoreRepository.selectActiveStores().stream().map(x -> x.getId())
144
				.collect(Collectors.toList());
145
 
27876 amit.gupta 146
		Set<String> brands = mongoClient.getMongoBrands(loginDetails.getFofoId(), null, 3).stream()
147
				.map(x -> (String) x.get("name")).collect(Collectors.toSet());
27391 tejbeer 148
 
149
		Map<Integer, CustomRetailer> customRetailersMap = retailerService.getFofoRetailers(fofoIds);
150
 
151
		model.addAttribute("customRetailersMap", customRetailersMap);
152
		model.addAttribute("itemCriteriaType", ItemCriteriaType.values());
153
		model.addAttribute("brands", brands);
154
		model.addAttribute("partnerCategories", PartnerType.values());
27876 amit.gupta 155
		model.addAttribute("warehouseRegion", ProfitMandiConstants.WAREHOUSE_MAP);
27391 tejbeer 156
		return "scheme_offer";
157
 
158
	}
159
 
160
	@RequestMapping(value = "/createOffer", method = RequestMethod.POST)
161
	public String createOffer(HttpServletRequest request, @RequestBody CreateOfferRequest createOfferRequest,
162
			Model model) throws Exception {
27876 amit.gupta 163
		LOGGER.info("createOfferRequest [{}]", createOfferRequest);
164
		offerService.addOfferService(createOfferRequest);
29809 amit.gupta 165
		thirtyMinsTimeOutCacheManager.getCache("allOffers").evict(YearMonth.now());
27391 tejbeer 166
		model.addAttribute("response", mvcResponseSender.createResponseString(true));
167
		return "response";
168
 
169
	}
170
 
27876 amit.gupta 171
	@RequestMapping(value = "/offers/published", method = RequestMethod.GET)
172
	public String getPublishedOffers(HttpServletRequest request, @RequestParam int fofoId, Model model)
27391 tejbeer 173
			throws Exception {
27876 amit.gupta 174
		LOGGER.info("Published");
175
		offerService.getPublishedOffers(fofoId, YearMonth.from(LocalDateTime.now()));
176
		return "scheme_offer/published";
27391 tejbeer 177
 
27876 amit.gupta 178
	}
27391 tejbeer 179
 
27876 amit.gupta 180
	@RequestMapping(value = "/offer/active/{offerId}", method = RequestMethod.GET)
29909 amit.gupta 181
	public String activateOffer(HttpServletRequest request, @PathVariable int offerId, Model model, @RequestParam(defaultValue = "true") boolean active)
27876 amit.gupta 182
			throws ProfitMandiBusinessException, Exception {
183
		Offer offer = offerRepository.selectById(offerId);
29909 amit.gupta 184
		boolean alreadyActive = offer.isActive();
185
		if(alreadyActive != active) {
186
			offer.setActive(active);
29900 amit.gupta 187
			oneDayCacheManager.getCache("catalog.published_yearmonth").evict(YearMonth.now());
188
		}
29909 amit.gupta 189
		if(active && !alreadyActive) {
190
			this.sendNotification(offer);
191
		}
27876 amit.gupta 192
		model.addAttribute("response", mvcResponseSender.createResponseString(true));
193
		return "response";
29900 amit.gupta 194
		//CreateOfferRequest createOfferRequest = offerService.getCreateOfferRequest(offer);
195
		//model.addAttribute("offer", createOfferRequest);
196
		//return "offer_margin_detail_partner2";
27876 amit.gupta 197
	}
27391 tejbeer 198
 
29900 amit.gupta 199
	@Autowired
200
	private com.spice.profitmandi.dao.repository.dtr.UserRepository dtrUserRepository;
201
 
202
	private void sendNotification(Offer offer) throws Exception {
203
		String fileName = "offer-" + offer.getId() + ".png";
204
		CreateOfferRequest createOfferRequest = offerService.getCreateOfferRequest(offer);
205
		SendNotificationModel sendNotificationModel = new SendNotificationModel();
206
		sendNotificationModel.setCampaignName("SchemeOffer");
207
		sendNotificationModel.setTitle(offer.getName());
29905 amit.gupta 208
		sendNotificationModel.setMessage(createOfferRequest.getSchemeType().name() + " of select models, " 
209
		+ FormattingUtils.formatDateMonth(offer.getStartDate()) + " to " + FormattingUtils.formatDateMonth(offer.getEndDate()));
29900 amit.gupta 210
		sendNotificationModel.setType("url");
211
		sendNotificationModel.setImageUrl(IMAGE_STATIC_SERVER_URL + "/" + "image" + LocalDate.now() + "/" + fileName);
212
		sendNotificationModel.setUrl("https://app.smartdukaan.com/pages/home/notifications");
213
		sendNotificationModel.setExpiresat(LocalDateTime.now().plusDays(1));
214
		sendNotificationModel.setMessageType(MessageType.scheme);
215
		Map<Integer, Map<Integer, Long>> partnerWiseMap = null;
216
		Map<Integer, List<Offer>> offersMap = offerRepository.selectAllPublishedMapByPartner(YearMonth.now());
217
		List<Integer> fofoIds = offersMap.entrySet().stream().filter(x -> x.getValue().contains(offer))
218
				.map(x -> x.getKey()).collect(Collectors.toList());
219
		sendNotificationModel.setFofoIds(fofoIds);
220
		Map<String, InputStream> fileStreamsMap = new HashMap<>();
221
		List<Integer> dtrIds = dtrUserRepository
222
				.selectAllByEmailIds(Arrays.asList("tarun.verma@smartdukaan.com", "amit.gupta@shop2020.in"))
223
				.stream().map(x->x.getId()).collect(Collectors.toList());
224
		sendNotificationModel.setUserIds(dtrIds);
225
		notificationService.sendNotification(sendNotificationModel);
226
		try {
227
			Map<String, Object> model = new HashMap<>();
228
			model.put("offer", createOfferRequest);
229
			String htmlContent=this.getContentFromTemplate("offer_margin_detail_partner.vm", model);
230
			LOGGER.info("this.getContentFromTemplate {}", htmlContent);
231
			fileStreamsMap.put(fileName, this.getImageBuffer(htmlContent));
232
			this.uploadFile(fileStreamsMap);
233
		} catch (Exception e) {
234
			e.printStackTrace();
235
		}
236
 
237
	}
238
 
239
	private InputStream	asInputStream(BufferedImage bi) throws Exception {
240
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
241
		ImageIO.write(bi, "png", baos);
242
		return new ByteArrayInputStream(baos.toByteArray());
243
 
244
	}
245
 
246
	private ChannelSftp setupJsch() throws JSchException {
247
		JSch jsch = new JSch();
248
		Session jschSession = jsch.getSession("root", "192.168.179.131");
249
		//Session jschSession = jsch.getSession("root", "173.255.254.24");
250
		LOGGER.info("getClass().getResource(\"id_rsa\") {}", getClass().getClassLoader().getResource("id_rsa").getPath());
251
		jsch.addIdentity(getClass().getClassLoader().getResource("id_rsa").getPath());
252
		//jschSession.setPassword("spic@2015static0");
253
		jschSession.setConfig("StrictHostKeyChecking", "no");
254
		jschSession.connect();
255
		return (ChannelSftp) jschSession.openChannel("sftp");
256
	}
257
 
258
	private void fileUpload(ChannelSftp channelSftp, Map<String, InputStream> streamsFileMap, String destinationPath)
259
			throws SftpException, FileNotFoundException {
260
 
261
		channelSftp.cd(destinationPath);
262
		String folderName = "image" + LocalDate.now();
263
 
264
		channelSftp.cd(destinationPath);
265
		SftpATTRS attrs = null;
266
 
267
		// check if the directory is already existing
268
		try {
269
			attrs = channelSftp.stat(folderName);
270
		} catch (Exception e) {
271
			System.out.println(destinationPath + "/" + folderName + " not found");
272
		}
273
 
274
		// else create a directory
275
		if (attrs == null) {
276
			channelSftp.mkdir(folderName);
277
			channelSftp.chmod(0755, ".");
278
		}
279
		channelSftp.cd(folderName);
280
 
281
		for (Map.Entry<String, InputStream> streamsFileEntry : streamsFileMap.entrySet()) {
282
			channelSftp.put(streamsFileEntry.getValue(), streamsFileEntry.getKey(), ChannelSftp.OVERWRITE);
283
		}
284
 
285
	}
286
 
287
	private void uploadFile(Map<String, InputStream> fileStreamsMap) throws Exception {
288
		ChannelSftp channelSftp = setupJsch();
289
		channelSftp.connect();
290
		this.fileUpload(channelSftp, fileStreamsMap, IMAGE_REMOTE_DIR + "");
291
		channelSftp.exit();
292
	}
293
 
294
	private InputStream getImageBuffer (String html) throws Exception {
295
		String fileName = "/tmp/" + Instant.now().toEpochMilli();
296
		FileUtils.writeStringToFile(new File(fileName), html, "UTF-8");
297
		return this.asInputStream(Graphics2DRenderer.renderToImageAutoSize("file:" + fileName, 500));
298
	}
299
 
300
	@Autowired
301
	VelocityEngine velocityEngine;
302
 
303
	private String getContentFromTemplate(String template, Map<String, Object> model) {
304
		StringBuffer content = new StringBuffer();
305
		try {
306
			content.append(VelocityEngineUtils.mergeTemplateIntoString(velocityEngine, template, model));
307
		} catch (Exception e) {
308
			e.printStackTrace();
309
		}
310
		return content.toString();
311
	}
312
 
27876 amit.gupta 313
	@RequestMapping(value = "/offerHistory", method = RequestMethod.GET)
314
	public String getPaginatedOffers(HttpServletRequest request, @RequestParam YearMonth yearMonth, Model model)
315
			throws ProfitMandiBusinessException {
27391 tejbeer 316
 
29900 amit.gupta 317
		List<CreateOfferRequest> publishedOffers = offerService.getAllOffers(yearMonth).values().stream()
318
				.sorted(Comparator.comparing(CreateOfferRequest::getId).reversed()).collect(Collectors.toList());
27876 amit.gupta 319
		model.addAttribute("offers", publishedOffers);
320
		model.addAttribute("yearMonth", yearMonth);
27391 tejbeer 321
 
322
		return "offer_history";
323
	}
324
 
27876 amit.gupta 325
	@RequestMapping(value = "/offer-details", method = RequestMethod.GET)
326
	public String schemeDetails(HttpServletRequest request, @RequestParam int offerId, Model model)
27391 tejbeer 327
			throws ProfitMandiBusinessException {
29839 amit.gupta 328
		CreateOfferRequest createOfferRequest = offerService.getOffer(0, offerId);
27391 tejbeer 329
 
27876 amit.gupta 330
		model.addAttribute("offer", createOfferRequest);
331
		return "offer-details";
27391 tejbeer 332
	}
333
 
27876 amit.gupta 334
	@RequestMapping(value = "/offerDownload", method = RequestMethod.GET)
335
	public ResponseEntity<?> dowloadOfferSummary(HttpServletRequest request, @RequestParam int offerId, Model model)
336
			throws Exception {
337
		List<List<?>> listOfRows = new ArrayList<>();
338
		final HttpHeaders headers = new HttpHeaders();
339
		headers.set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
340
		headers.set("Content-disposition", "inline; filename=offer-" + offerId + ".csv");
29785 amit.gupta 341
		CreateOfferRequest createOfferRequest = offerService.getOffer(0, offerId);
27876 amit.gupta 342
		Collection<OfferRowModel> offerRowModels = offerRepository.getOfferRows(createOfferRequest);
27391 tejbeer 343
 
27876 amit.gupta 344
		for (OfferRowModel offerRowModel : offerRowModels) {
345
			CustomRetailer customRetailer = retailerService.getFofoRetailer(offerRowModel.getFofoId());
346
			listOfRows.add(Arrays.asList(createOfferRequest.getId(), createOfferRequest.getName(),
347
					createOfferRequest.getTargetType(), createOfferRequest.getSchemeType(),
348
					createOfferRequest.getBrandShareTerms(), createOfferRequest.getSellinPercentage(),
349
					createOfferRequest.getPartnerCriteriaString(), createOfferRequest.getItemCriteriaString(),
350
					createOfferRequest.getStartDate(), createOfferRequest.getEndDate(),
351
					createOfferRequest.getCreatedOn(), customRetailer.getPartnerId(), customRetailer.getBusinessName(),
352
					customRetailer.getCode(), offerRowModel.getTotalSale(), offerRowModel.getEligibleSale(),
353
					offerRowModel.getAchievedTarget(), offerRowModel.getNextTarget(), offerRowModel.getEligibleSaleDp(),
354
					offerRowModel.getTotalPurchaseValue(), offerRowModel.getCurrentPayoutTarget(),
355
					offerRowModel.getPayoutTargetAchieved(), offerRowModel.getAmountType(),
356
					offerRowModel.getPayoutValue(), offerRowModel.getPayoutValueDp(), offerRowModel.getFinalPayout(),
357
					String.join(", ", offerRowModel.getPendingImeis())));
27391 tejbeer 358
		}
27876 amit.gupta 359
		ByteArrayOutputStream baos = FileUtil.getCSVByteStream(
360
				Arrays.asList("Id", "Name", "Target Type", "Scheme Type", "Brand %", "Sellin %", "Partner Criteria",
361
						"Item Criteria", "Start", "End", "Created", "Partner Id", "Partner Name", "Partner Code",
362
						"Total Sale", "Eligible Sale", "Achieved Target", "Next Target", "Eligible Sale DP",
363
						"Total Purchase DP", "Current Payout Target", "Payout Target Achieved", "Payout Amount Type",
364
						"Payout Value", "Payout Value DP", "Amount to be credited", "IMEIs pending for Activation"
365
				// "Payout Sale Qty", "Activated Value", "Activated Qty",
366
				), listOfRows);
367
		final InputStream inputStream = new ByteArrayInputStream(baos.toByteArray());
368
		final InputStreamResource inputStreamResource = new InputStreamResource(inputStream);
369
		return new ResponseEntity<>(inputStreamResource, headers, HttpStatus.OK);
27391 tejbeer 370
	}
29900 amit.gupta 371
 
27876 amit.gupta 372
	@RequestMapping(value = "/offerById", method = RequestMethod.GET)
373
	public String offerById(HttpServletRequest request, int offerId, Model model) throws ProfitMandiBusinessException {
27391 tejbeer 374
		Offer offer = offerRepository.selectById(offerId);
375
 
376
		model.addAttribute("offer", offer);
377
 
27876 amit.gupta 378
		return "offer-edit";
27391 tejbeer 379
 
380
	}
29900 amit.gupta 381
 
29675 amit.gupta 382
	@RequestMapping(value = "/published-offers/{yearMonth}", method = RequestMethod.GET)
29900 amit.gupta 383
	public String publishedOffersOnMonthBefore(HttpServletRequest request, @PathVariable int yearMonth, Model model)
384
			throws ProfitMandiBusinessException {
29675 amit.gupta 385
		LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
386
		int fofoId = loginDetails.getFofoId();
29900 amit.gupta 387
		List<CreateOfferRequest> createOffers = offerService.getPublishedOffers(fofoId,
388
				YearMonth.from(LocalDate.now()).minusMonths(yearMonth));
389
 
29675 amit.gupta 390
		model.addAttribute("publishedOffers", createOffers);
29900 amit.gupta 391
 
29675 amit.gupta 392
		return "published-offers";
393
	}
29900 amit.gupta 394
 
29682 amit.gupta 395
	@PostMapping(value = "/offers/upload")
396
	public String uploadOffers(HttpServletRequest request, @RequestPart("file") MultipartFile targetFile, Model model)
397
			throws Exception {
398
		offerService.createOffers(targetFile.getInputStream());
399
		model.addAttribute("response", true);
400
		return "response";
401
	}
29900 amit.gupta 402
 
29785 amit.gupta 403
	@Autowired
404
	RoleManager roleManager;
27391 tejbeer 405
 
27876 amit.gupta 406
	@RequestMapping(value = "/getOfferMargins", method = RequestMethod.GET)
407
	public String getOfferMargins(HttpServletRequest request,
408
			@RequestParam(name = "offerId", defaultValue = "0") int offerId, Model model) throws Exception {
409
		LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
29785 amit.gupta 410
		boolean isAdmin = roleManager.isAdmin(loginDetails.getRoleIds());
29900 amit.gupta 411
		CreateOfferRequest createOfferRequest = offerService.getOffer(isAdmin ? 0 : loginDetails.getFofoId(), offerId);
412
 
27876 amit.gupta 413
		model.addAttribute("offer", createOfferRequest);
27391 tejbeer 414
 
27876 amit.gupta 415
		return "offer_margin_detail_partner";
27391 tejbeer 416
 
417
	}
418
 
27895 amit.gupta 419
}