Advertisement
Guest User

Untitled

a guest
Mar 2nd, 2016
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 23.01 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include "storage_mgr.h"
  4. #include "dberror.h"
  5. #include <sys/stat.h>
  6.  
  7. void initStorageManager (void) {
  8.  
  9. }
  10.  
  11. /************************************************************
  12. * manipulating page files *
  13. ************************************************************/
  14.  
  15.  
  16. /*******************************************************************
  17. * NAME : RC createPageFile (char *fileName)
  18. *
  19. * DESCRIPTION : Create a new page file fileName. The initial size is one page.
  20. * This method fills this single page with '\0' bytes.
  21. *
  22. * PARAMETERS:
  23. * char * fileName Name of the file to be created
  24. *
  25. * RETURN :
  26. * Type: RC Returned code:
  27. * Values: RC_OK file created successfully
  28. *
  29. * AUTHOR :
  30. * Adrian Tirados <atirados@hawk.iit.edu>
  31. *
  32. * HISTORY :
  33. * DATE WHO DETAIL
  34. * ----------- --------------------------------------- ---------------------------------
  35. * 2016-02-01 Adrian Tirados <atirados@hawk.iit.edu> Initialization
  36. * 2016-02-06 Adrian Tirados <atirados@hawk.iit.edu> Added comments and header comment
  37. *
  38. *******************************************************************/
  39. RC createPageFile (char *fileName) {
  40. // Open a new file for writing
  41. FILE *pageFile = fopen(fileName, "wb");
  42.  
  43. // Allocate one PAGE_SIZE space in memory and fill with \0 characters
  44. char *buffer = (char *) calloc(PAGE_SIZE, sizeof(char));
  45.  
  46. // Write the buffer of zeroes to into the file
  47. fwrite (buffer, sizeof(char), PAGE_SIZE, pageFile);
  48.  
  49. // Free memory and close
  50. free(buffer);
  51. fclose(pageFile);
  52.  
  53. return RC_OK;
  54. }
  55.  
  56. /*******************************************************************
  57. * NAME : RC openPageFile (char *fileName, SM_FileHandle *fHandle)
  58. *
  59. * DESCRIPTION : Opens an existing page file. If opening the file is successful,
  60. * then the fields of this file handle should be initialized with
  61. * the information about the opened file.
  62. *
  63. * PARAMETERS:
  64. * char * fileName Name of the file to be created
  65. * SM_Filehandle * fHandle An existing file handle
  66. *
  67. * RETURN :
  68. * Type: RC Returned code:
  69. * Values: RC_OK file created successfully
  70. * RC_FILE_NOT_FOUND file does not exist
  71. *
  72. * AUTHOR :
  73. * Adrian Tirados <atirados@hawk.iit.edu>
  74. *
  75. * HISTORY :
  76. * DATE WHO DETAIL
  77. * ----------- --------------------------------------- ---------------------------------
  78. * 2016-02-01 Adrian Tirados <atirados@hawk.iit.edu> Initialization
  79. * 2016-02-06 Adrian Tirados <atirados@hawk.iit.edu> Added comments and header comment
  80. *
  81. *******************************************************************/
  82. RC openPageFile (char *fileName, SM_FileHandle *fHandle) {
  83. // Open an existing file for both reading and writing
  84. FILE *pageFile = fopen(fileName, "rb+");
  85.  
  86. // Check if file exists
  87. if (pageFile == NULL) {
  88. return RC_FILE_NOT_FOUND;
  89. } else {
  90. // Calculate size of the file
  91. struct stat st;
  92. stat(fileName, &st);
  93. int size = st.st_size;
  94.  
  95. // Obtain number of pages
  96. int nPages = (int) size / PAGE_SIZE;
  97.  
  98. // Initialize fields of file handle
  99. fHandle->fileName = fileName;
  100. fHandle->totalNumPages = nPages;
  101. fHandle->curPagePos = 0;
  102. fHandle->mgmtInfo = pageFile;
  103. }
  104. return RC_OK;
  105. }
  106.  
  107. /*******************************************************************
  108. * NAME : closePageFile (SM_FileHandle *fHandle)
  109. *
  110. * DESCRIPTION : Close page file which already opened stored information in fHandle.
  111. * If closing the file is successful, then return RC_OK,
  112. * else return error.
  113. *
  114. * PARAMETERS
  115. * SM_Filehandle * fHandle An existing file handle
  116. *
  117. * RETURN :
  118. * Type: RC Returned code:
  119. * Values: RC_OK file created successfully
  120. * RC_FILE_NOT_FOUND file does not exist
  121. *
  122. * AUTHOR :
  123. * Patipat Duangchalomnin <pduangchalomnin@hawk.iit.edu>
  124. *
  125. * HISTORY :
  126. * DATE WHO DETAIL
  127. * ----------- ----------------------------------------------------- ---------------------------------
  128. * 2016-02-01 Patipat Duangchalomnin <pduangchalomnin@hawk.iit.edu> Initialization
  129. * 2016-02-06 Patipat Duangchalomnin <pduangchalomnin@hawk.iit.edu> Added comments and header comment
  130. *
  131. *******************************************************************/
  132. RC closePageFile (SM_FileHandle *fHandle) {
  133.  
  134. //Check and close file return error if any
  135. int close = fclose(fHandle->mgmtInfo);
  136. if (close == 0)
  137. {
  138. return RC_OK;
  139. }
  140. else
  141. {
  142. return RC_FILE_NOT_FOUND;
  143. }
  144. }
  145.  
  146. /*******************************************************************
  147. * NAME : RC destroyPageFile (char *fileName)
  148. *
  149. * DESCRIPTION : Destroys an existing page file.
  150. *
  151. * PARAMETERS:
  152. * char * fileName Name of the file to be created
  153. *
  154. * RETURN :
  155. * Type: RC Returned code:
  156. * Values: RC_OK file destroyed successfully
  157. * RC_FILE_NOT_FOUND file does not exist
  158. *
  159. * AUTHOR :
  160. * Adrian Tirados <atirados@hawk.iit.edu>
  161. *
  162. * HISTORY :
  163. * DATE WHO DETAIL
  164. * ----------- --------------------------------------- ---------------------------------
  165. * 2016-02-01 Adrian Tirados <atirados@hawk.iit.edu> Initialization
  166. * 2016-02-06 Adrian Tirados <atirados@hawk.iit.edu> Added comments and header comment
  167. *
  168. *******************************************************************/
  169. RC destroyPageFile (char *fileName) {
  170. // Check if file is removed successfully
  171. int removed = remove(fileName);
  172. if (removed == 0) {
  173. return RC_OK;
  174. } else {
  175. return RC_FILE_NOT_FOUND;
  176. }
  177. }
  178.  
  179. /*******************************************************************
  180. * NAME : readBlock (int pageNum, SM_FileHandle *fHandle, SM_PageHandle memPage)
  181. *
  182. * DESCRIPTION : Seek into specific page and perform read page in to memory if it valid
  183. *
  184. * PARAMETERS
  185. * int pageNum The pageNumth block needed to be read
  186. * SM_Filehandle * fHandle An existing file handle
  187. * SM_PageHandle memPage Memory which wanted to load data into
  188. *
  189. * RETURN :
  190. * Type: RC Returned code:
  191. * Values: RC_OK file created successfully
  192. * RC_READ_NON_EXISTING_PAGE page file does not exist
  193. *
  194. * AUTHOR :
  195. * Patipat Duangchalomnin <pduangchalomnin@hawk.iit.edu>
  196. *
  197. * HISTORY :
  198. * DATE WHO DETAIL
  199. * ----------- ----------------------------------------------------- ---------------------------------
  200. * 2016-02-01 Patipat Duangchalomnin <pduangchalomnin@hawk.iit.edu> Initialization
  201. * 2016-02-06 Patipat Duangchalomnin <pduangchalomnin@hawk.iit.edu> Add missing fseek
  202. * 2016-02-06 Patipat Duangchalomnin <pduangchalomnin@hawk.iit.edu> Added comments and header comment
  203. * 2016-02-08 Adrian Tirados <atirados@hawk.iit.edu> Added check for opened file
  204. *
  205. *******************************************************************/
  206. RC readBlock (int pageNum, SM_FileHandle *fHandle, SM_PageHandle memPage) {
  207. int pageFirstByte = pageNum * PAGE_SIZE * sizeof(char);
  208.  
  209. // Check if file is opened
  210. if (fHandle->mgmtInfo == NULL) {
  211. return RC_FILE_NOT_FOUND;
  212. }
  213. //Check if page does exist
  214. if (0 > pageNum || fHandle->totalNumPages < pageNum)
  215. {
  216. printf("FLAG1!!\n");
  217. return RC_READ_NON_EXISTING_PAGE;
  218. }
  219. else
  220. {
  221. //Read and write block to memPage (Expected number of element read should be return)
  222. if(fseek(fHandle->mgmtInfo, pageFirstByte, SEEK_SET) != 0) {
  223. printf("FLAG2!!\n");
  224. return RC_READ_NON_EXISTING_PAGE;
  225. }
  226.  
  227. unsigned long size = fread(memPage, sizeof(char), PAGE_SIZE, fHandle->mgmtInfo);
  228.  
  229. if (size == PAGE_SIZE)
  230. {
  231. //Set current page position
  232. fHandle->curPagePos = pageNum;
  233. return RC_OK;
  234. }
  235. else
  236. {
  237. printf("FLAG3!!\n");
  238. printf("%zu\n", size);
  239. printf("%d\n", pageNum);
  240. return RC_READ_NON_EXISTING_PAGE;
  241. }
  242. }
  243. }
  244.  
  245. /*******************************************************************
  246. * NAME : int getBlockPos (SM_FileHandle *fHandle)
  247. *
  248. * DESCRIPTION : Return the current page position in a file.
  249. *
  250. * PARAMETERS:
  251. * SM_Filehandle * fHandle An existing file handle
  252. *
  253. * RETURN :
  254. * Type: int Current page position
  255. *
  256. * AUTHOR :
  257. * Adrian Tirados <atirados@hawk.iit.edu>
  258. *
  259. * HISTORY :
  260. * DATE WHO DETAIL
  261. * ----------- --------------------------------------- ---------------------------------
  262. * 2016-02-02 Adrian Tirados <atirados@hawk.iit.edu> Initialization
  263. * 2016-02-06 Adrian Tirados <atirados@hawk.iit.edu> Added comments and header comment
  264. *
  265. *******************************************************************/
  266. int getBlockPos (SM_FileHandle *fHandle) {
  267. // Get the current page from the file handle information
  268. return fHandle->curPagePos;
  269. }
  270.  
  271. /*******************************************************************
  272. * NAME : RC readFirstBlock (SM_FileHandle *fHandle, SM_PageHandle memPage)
  273. *
  274. * DESCRIPTION : Read the first page in a file.
  275. *
  276. * PARAMETERS:
  277. * SM_Filehandle * fHandle An existing file handle
  278. * SM_PageHandle memPage Pointer to an area in memory storing the data of a page
  279. *
  280. * RETURN :
  281. * Type: RC Returned code:
  282. * Values: RC_OK file read successfully
  283. * RC_READ_NON_EXISTING_PAGE page does not exist
  284. *
  285. * AUTHOR :
  286. * Adrian Tirados <atirados@hawk.iit.edu>
  287. *
  288. * HISTORY :
  289. * DATE WHO DETAIL
  290. * ----------- --------------------------------------- ---------------------------------
  291. * 2016-02-02 Adrian Tirados <atirados@hawk.iit.edu> Initialization
  292. * 2016-02-06 Adrian Tirados <atirados@hawk.iit.edu> Added comments and header comment
  293. *
  294. *******************************************************************/
  295. RC readFirstBlock (SM_FileHandle *fHandle, SM_PageHandle memPage) {
  296. // Call readBlock to read page '0' and return its RC
  297. return readBlock(0, fHandle, memPage);
  298. }
  299.  
  300. /*******************************************************************
  301. * NAME : RC readPreviousBlock (SM_FileHandle *fHandle, SM_PageHandle memPage)
  302. *
  303. * DESCRIPTION : Read the previous page to the current position in a file.
  304. *
  305. * PARAMETERS:
  306. * SM_Filehandle * fHandle An existing file handle
  307. * SM_PageHandle memPage Pointer to an area in memory storing the data of a page
  308. *
  309. * RETURN :
  310. * Type: RC Returned code:
  311. * Values: RC_OK file read successfully
  312. * RC_READ_NON_EXISTING_PAGE page does not exist
  313. *
  314. * AUTHOR :
  315. * Adrian Tirados <atirados@hawk.iit.edu>
  316. *
  317. * HISTORY :
  318. * DATE WHO DETAIL
  319. * ----------- --------------------------------------- ---------------------------------
  320. * 2016-02-02 Adrian Tirados <atirados@hawk.iit.edu> Initialization
  321. * 2016-02-06 Adrian Tirados <atirados@hawk.iit.edu> Added comments and header comment
  322. *
  323. *******************************************************************/
  324. RC readPreviousBlock (SM_FileHandle *fHandle, SM_PageHandle memPage) {
  325. // Calculate previous page
  326. int previousBlock = fHandle->curPagePos - 1;
  327.  
  328. // Call readBlock to read previousBlock and return its RC
  329. return readBlock(previousBlock, fHandle, memPage);
  330. }
  331.  
  332. /*******************************************************************
  333. * NAME : RC readCurrentBlock (SM_FileHandle *fHandle, SM_PageHandle memPage)
  334. *
  335. * DESCRIPTION : Read the current page in a file.
  336. *
  337. * PARAMETERS:
  338. * SM_Filehandle * fHandle An existing file handle
  339. * SM_PageHandle memPage Pointer to an area in memory storing the data of a page
  340. *
  341. * RETURN :
  342. * Type: RC Returned code:
  343. * Values: RC_OK file read successfully
  344. * RC_READ_NON_EXISTING_PAGE page does not exist
  345. *
  346. * AUTHOR :
  347. * Adrian Tirados <atirados@hawk.iit.edu>
  348. *
  349. * HISTORY :
  350. * DATE WHO DETAIL
  351. * ----------- --------------------------------------- ---------------------------------
  352. * 2016-02-02 Adrian Tirados <atirados@hawk.iit.edu> Initialization
  353. * 2016-02-06 Adrian Tirados <atirados@hawk.iit.edu> Added comments and header comment
  354. *
  355. *******************************************************************/
  356. RC readCurrentBlock (SM_FileHandle *fHandle, SM_PageHandle memPage) {
  357. // Call readBlock to read current page and return its RC
  358. return readBlock(fHandle->curPagePos, fHandle, memPage);
  359. }
  360.  
  361. /*******************************************************************
  362. * NAME : RC readNextBlock (SM_FileHandle *fHandle, SM_PageHandle memPage)
  363. *
  364. * DESCRIPTION : Read the next page to the current position page in a file.
  365. *
  366. * PARAMETERS:
  367. * SM_Filehandle * fHandle An existing file handle
  368. * SM_PageHandle memPage Pointer to an area in memory storing the data of a page
  369. *
  370. * RETURN :
  371. * Type: RC Returned code:
  372. * Values: RC_OK file read successfully
  373. * RC_READ_NON_EXISTING_PAGE page does not exist
  374. *
  375. * AUTHOR :
  376. * Adrian Tirados <atirados@hawk.iit.edu>
  377. *
  378. * HISTORY :
  379. * DATE WHO DETAIL
  380. * ----------- --------------------------------------- ---------------------------------
  381. * 2016-02-02 Adrian Tirados <atirados@hawk.iit.edu> Initialization
  382. * 2016-02-06 Adrian Tirados <atirados@hawk.iit.edu> Added comments and header comment
  383. *
  384. *******************************************************************/
  385. RC readNextBlock (SM_FileHandle *fHandle, SM_PageHandle memPage) {
  386. // Calculate next page
  387. int nextBlock = fHandle->curPagePos + 1;
  388.  
  389. // Call readBlock to read nextBlock and return its RC
  390. return readBlock(nextBlock, fHandle, memPage);
  391. }
  392.  
  393. /*******************************************************************
  394. * NAME : RC readLastBlock (SM_FileHandle *fHandle, SM_PageHandle memPage)
  395. *
  396. * DESCRIPTION : Read the last page in a file.
  397. *
  398. * PARAMETERS:
  399. * SM_Filehandle * fHandle An existing file handle
  400. * SM_PageHandle memPage Pointer to an area in memory storing the data of a page
  401. *
  402. * RETURN :
  403. * Type: RC Returned code:
  404. * Values: RC_OK file read successfully
  405. * RC_READ_NON_EXISTING_PAGE page does not exist
  406. *
  407. * AUTHOR :
  408. * Adrian Tirados <atirados@hawk.iit.edu>
  409. *
  410. * HISTORY :
  411. * DATE WHO DETAIL
  412. * ----------- --------------------------------------- ---------------------------------
  413. * 2016-02-02 Adrian Tirados <atirados@hawk.iit.edu> Initialization
  414. * 2016-02-06 Adrian Tirados <atirados@hawk.iit.edu> Added comments and header comment
  415. *
  416. *******************************************************************/
  417. RC readLastBlock (SM_FileHandle *fHandle, SM_PageHandle memPage) {
  418. // Call readBlock to read last page (totalNumPages) and return its RC
  419. int lastBlock = fHandle->totalNumPages-1;
  420. return readBlock(lastBlock, fHandle, memPage);
  421. }
  422.  
  423. /************************************************************
  424. * writing blocks to a page file *
  425. ************************************************************/
  426.  
  427. /*******************************************************************
  428. * NAME : RC writeBlock (int pageNum, SM_FileHandle *fHandle, SM_PageHandle memPage)
  429. *
  430. * DESCRIPTION : Write a page to disk using an absolute position.
  431. *
  432. * PARAMETERS:
  433. * int pageNum The pageNumth block that the method writes
  434. * SM_Filehandle * fHandle An existing file handle
  435. * SM_PageHandle memPage Pointer to an area in memory storing the data of a page
  436. *
  437. * RETURN :
  438. * Type: RC Returned code:
  439. * Values: RC_OK file write successfully
  440. * RC_WRITE_FAILED failed to write
  441. *
  442. * AUTHOR :
  443. * Yung Chi Shih <yshih2@hawk.iit.edu>
  444. *
  445. * HISTORY :
  446. * DATE WHO DETAIL
  447. * ----------- --------------------------------------- ---------------------------------
  448. * 2016-02-08 Yung Chi Shih <yshih2@hawk.iit.edu> Initialization
  449. * 2016-02-08 Yung Chi Shih <yshih2@hawk.iit.edu> Added comments and header comment
  450. * 2016-02-08 Adrian Tirados <atirados@hawk.iit.edu> Fixed return code after running test
  451. *
  452. *******************************************************************/
  453. RC writeBlock (int pageNum, SM_FileHandle *fHandle, SM_PageHandle memPage) {
  454.  
  455. //check if the pageNumth block that the method writes is not less than 0
  456. if (0 > pageNum || fHandle->totalNumPages < pageNum)
  457. return RC_WRITE_FAILED;
  458.  
  459. //sets the file pointer point to a structure that contains information about the file
  460. FILE *pageFile = fHandle->mgmtInfo;
  461.  
  462. //declares the number of bytes to offset
  463. long int offset = pageNum * PAGE_SIZE;
  464.  
  465. //sets the file position of the stream to beginning of file
  466. fseek(pageFile, offset, SEEK_SET);
  467.  
  468. //check if the write is successful
  469. if (fwrite(memPage, sizeof(char), PAGE_SIZE, pageFile) != PAGE_SIZE) {
  470. return RC_WRITE_FAILED;
  471. } else {
  472. fHandle->curPagePos = pageNum;
  473. return RC_OK;
  474. }
  475. }
  476.  
  477. /*******************************************************************
  478. * NAME : RC writeCurrentBlock (SM_FileHandle *fHandle, SM_PageHandle memPage)
  479. *
  480. * DESCRIPTION : Write the current page in a file.
  481. *
  482. * PARAMETERS:
  483. * SM_Filehandle * fHandle An existing file handle
  484. * SM_PageHandle memPage Pointer to an area in memory storing the data of a page
  485. *
  486. * RETURN :
  487. * Type: RC Returned code:
  488. * Values: RC_OK file write successfully
  489. * RC_WRITE_FAILED failed to write
  490. *
  491. * AUTHOR :
  492. * Yung Chi Shih <yshih2@hawk.iit.edu>
  493. *
  494. * HISTORY :
  495. * DATE WHO DETAIL
  496. * ----------- --------------------------------------- ---------------------------------
  497. * 2016-02-07 Yung Chi Shih <yshih2@hawk.iit.edu> Initialization
  498. * 2016-02-07 Yung Chi Shih <yshih2@hawk.iit.edu> Added comments and header comment
  499. *
  500. *******************************************************************/
  501. RC writeCurrentBlock (SM_FileHandle *fHandle, SM_PageHandle memPage) {
  502. // Call writeBlock to write current page and return its RC
  503. return writeBlock(fHandle->curPagePos, fHandle, memPage);
  504. }
  505.  
  506. /*******************************************************************
  507. * NAME : RC appendEmptyBlock (SM_FileHandle *fHandle, SM_PageHandle memPage)
  508. *
  509. * DESCRIPTION : Append a new page at the end of the file
  510. *
  511. * PARAMETERS:
  512. * SM_Filehandle * fHandle An existing file handle
  513. *
  514. * RETURN :
  515. * Type: RC Returned code:
  516. * Values: RC_WRITE_FAILED failed to write
  517. *
  518. *
  519. * AUTHOR :
  520. * Yung Chi Shih <yshih2@hawk.iit.edu>
  521. *
  522. * HISTORY :
  523. * DATE WHO DETAIL
  524. * ----------- --------------------------------------- ---------------------------------
  525. * 2016-02-02 Yung Chi Shih <yshih2@hawk.iit.edu> Initialization
  526. * 2016-02-07 Yung Chi Shih <yshih2@hawk.iit.edu> Added comments and header comment
  527. * 2016-02-08 Yung Chi Shih <yshih2@hawk.iit.edu> Added file pointer declaration
  528. *
  529. *******************************************************************/
  530. RC appendEmptyBlock (SM_FileHandle *fHandle) {
  531.  
  532. //sets the file pointer point to a structure that contains information about the file
  533. FILE *pageFile = fHandle->mgmtInfo;
  534.  
  535. char *buffer = (char *) calloc(PAGE_SIZE, sizeof(char));
  536.  
  537.  
  538. struct stat st;
  539. stat(fHandle->fileName, &st);
  540. int size = st.st_size;
  541.  
  542. //writes data
  543. fwrite (buffer, sizeof(char), PAGE_SIZE, pageFile);
  544.  
  545. stat(fHandle->fileName, &st);
  546. int newSize = st.st_size;
  547.  
  548. //check if a new block of size PAGE_SIZE is appeneded
  549. if (size + PAGE_SIZE != newSize) {
  550. free(buffer);
  551. return RC_WRITE_FAILED;
  552. }
  553.  
  554. free(buffer);
  555.  
  556. //increments the total number of pages
  557. fHandle->totalNumPages++;
  558. fHandle->curPagePos++;
  559. return RC_OK;
  560. }
  561.  
  562. /*******************************************************************
  563. * NAME : RC ensureCapacity (int numberOfPages, SM_FileHandle *fHandle)
  564. *
  565. * DESCRIPTION : Increase page size of file to equal numberOfPages if it is less than numberOfPages.
  566. *
  567. * PARAMETERS:
  568. * SM_Filehandle * fHandle An existing file handle
  569. *
  570. * RETURN :
  571. * Type: RC Returned code:
  572. * Values: RC_OK file page size is equal to or more than numberOfPages
  573. *
  574. *
  575. * AUTHOR :
  576. * Arpita Rathore <arathore@hawk.iit.edu>
  577. *
  578. * HISTORY :
  579. * DATE WHO DETAIL
  580. * ----------- --------------------------------------- ---------------------------------
  581. * 2016-02-04 Arpita Rathore <arathore@hawk.iit.edu> Initialization
  582. * 2016-02-07 Arpita Rathore <arathore@hawk.iit.edu> Added comments and header comment
  583. *
  584. *******************************************************************/
  585. RC ensureCapacity (int numberOfPages, SM_FileHandle *fHandle) {
  586.  
  587. //check if the file page size is less than numberOfPages
  588. if (fHandle->totalNumPages < numberOfPages) {
  589. //call appendEmptyBlock to append an empty page, check again if size is still less than numberOfPages, continue appending a page until size is equal to numberOfPages
  590. do {
  591. appendEmptyBlock(fHandle);
  592. } while (fHandle->totalNumPages < numberOfPages);
  593. //file page size is equal to or more than numberOfPages, appending is not needed
  594. }
  595. return RC_OK;
  596. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement