/dot_cardpeek_dir/scripts/emv.lua

http://cardpeek.googlecode.com/ · Lua · 618 lines · 580 code · 8 blank · 30 comment · 2 complexity · 5b393a722ef6cd0a8c169f7e942a0ddd MD5 · raw file

  1. --
  2. -- This file is part of Cardpeek, the smartcard reader utility.
  3. --
  4. -- Copyright 2009-2012 by 'L1L1'
  5. --
  6. -- Cardpeek is free software: you can redistribute it and/or modify
  7. -- it under the terms of the GNU General Public License as published by
  8. -- the Free Software Foundation, either version 3 of the License, or
  9. -- (at your option) any later version.
  10. --
  11. -- Cardpeek is distributed in the hope that it will be useful,
  12. -- but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. -- GNU General Public License for more details.
  15. --
  16. -- You should have received a copy of the GNU General Public License
  17. -- along with Cardpeek. If not, see <http://www.gnu.org/licenses/>.
  18. --
  19. -- History:
  20. -- Aug 07 2010: Corrected bug in GPO command.
  21. -- Aug 08 2010: Corrected bug in AFL data processing
  22. -- Mar 27 2011: Added CVM patch from Adam Laurie.
  23. -- Jan 23 2012: Added UK Post Office Card Account in AID list from Tyson Key.
  24. require('lib.tlv')
  25. require('lib.strict')
  26. --------------------------------------------------------------------------
  27. -- GLOBAL EMV CARD COMMANDS extending general lib.apdu
  28. --------------------------------------------------------------------------
  29. function card.get_processing_options(pdol)
  30. local command;
  31. if pdol and #pdol>0 then
  32. command = bytes.new(8,"80 A8 00 00",#pdol+2,0x83,#pdol,pdol)
  33. else
  34. command = bytes.new(8,"80 A8 00 00 02 83 00")
  35. end
  36. return card.send(command)
  37. end
  38. -- override card.get_data() for EMV
  39. function card.get_data(data)
  40. local command = bytes.new(8,"80 CA",bit.AND(bit.SHR(data,8),0xFF),bit.AND(data,0xFF),0)
  41. return card.send(command)
  42. end
  43. -- ------------------------------------------------------------------------
  44. -- EMV
  45. -- ------------------------------------------------------------------------
  46. TRANSACTION_TYPE = {
  47. [0]="Purchase",
  48. [1]="Cash"
  49. }
  50. function ui_parse_transaction_type(node,cc)
  51. local tt = TRANSACTION_TYPE[cc[0]]
  52. if tt == nil then
  53. return tostring(cc)
  54. end
  55. ui.tree_set_value(node,cc)
  56. ui.tree_set_alt_value(node,tt)
  57. return true
  58. end
  59. function ui_parse_CVM(node,data)
  60. local i
  61. local left
  62. local right
  63. local leftstring
  64. local rightstring
  65. local subnode
  66. local out
  67. subnode = ui.tree_add_node(node,"item","X",nil,4)
  68. ui.tree_set_value(subnode,bytes.sub(data,0,3))
  69. subnode = ui.tree_add_node(node,"item","Y",nil,4)
  70. ui.tree_set_value(subnode,bytes.sub(data,4,7))
  71. for i= 4,(#data/2)-1 do
  72. subnode = ui.tree_add_node(node,"item","CVM",i-3,2)
  73. ui.tree_set_value(subnode,bytes.sub(data,i*2,i*2+1))
  74. left = data[i*2]
  75. right = data[i*2+1]
  76. if bit.AND(left,0x40) == 0x40 then
  77. out = "Apply succeeding CV rule if this rule is unsuccessful: "
  78. else
  79. out = "Fail cardholder verification if this CVM is unsuccessful: "
  80. end
  81. if CVM_REFERENCE_BYTE1[bit.AND(left,0xBF)] == nil then
  82. leftstring = string.format("Unknown (%02X)",left)
  83. else
  84. leftstring = CVM_REFERENCE_BYTE1[bit.AND(left,0xBF)]
  85. end
  86. if CVM_REFERENCE_BYTE2[right] == nil then
  87. rightstring = string.format("Unknown (%02X)",right)
  88. else
  89. rightstring = CVM_REFERENCE_BYTE2[right]
  90. end
  91. out = out .. leftstring .. " - " .. rightstring
  92. ui.tree_set_alt_value(subnode,out)
  93. end
  94. ui.tree_set_value(node,data)
  95. return true
  96. end
  97. CVM_REFERENCE_BYTE1 = {
  98. [0x00] = "Fail CVM processing",
  99. [0x01] = "Plaintext PIN verification performed by ICC",
  100. [0x02] = "Enciphered PIN verified online",
  101. [0x03] = "Plaintext PIN verification performed by ICC and signature (paper)",
  102. [0x04] = "Enciphered PIN verification performed by ICC",
  103. [0x05] = "Enciphered PIN verification performed by ICC and signature (paper)",
  104. [0x1E] = "Signature (paper)",
  105. [0x1F] = "No CVM Required",
  106. }
  107. CVM_REFERENCE_BYTE2 = {
  108. [0x00] = "Always",
  109. [0x01] = "If unattended cash",
  110. [0x02] = "If not attended cash and not manual cash and not purchase with cashback",
  111. [0x03] = "If terminal supports the CVM",
  112. [0x04] = "If manual cash",
  113. [0x05] = "If purchase with cashback",
  114. [0x06] = "If transaction is in the application currency and is under X value",
  115. [0x07] = "If transaction is in the application currency and is over X value",
  116. [0x08] = "If transaction is in the application currency and is under Y value",
  117. [0x09] = "If transaction is in the application currency and is over Y value"
  118. }
  119. EMV_REFERENCE = {
  120. ['5D'] = {"Directory Definition File (DDF) Name" },
  121. ['70'] = {"Application Data File (ADF)" },
  122. ['80'] = {"Response Message Template Format 1" },
  123. ['82'] = {"Application Interchange Profile (AIP)" },
  124. ['87'] = {"Application Priority Indicator" },
  125. ['88'] = {"Short File Identifier (SFI)" },
  126. ['8C'] = {"Card Risk Management Data Object List 1 (CDOL1)" },
  127. ['8D'] = {"Card Risk Management Data Object List 2 (CDOL2)" },
  128. ['8E'] = {"Cardholder Verification Method (CVM) List", ui_parse_CVM },
  129. ['8F'] = {"Certificate Authority Public Key Index (PKI)" },
  130. ['90'] = {"Issuer PK Certificate" },
  131. ['91'] = {"Issuer Authentication Data" },
  132. ['92'] = {"Issuer PK Remainder" },
  133. ['93'] = {"Signed Static Application Data" },
  134. ['94'] = {"Application File Locator (AFL)" },
  135. ['95'] = {"Terminal Verification Results (TVR)" },
  136. ['97'] = {"Transaction Certificate Data Object List (TDOL)" },
  137. ['9A'] = {"Transaction Date", ui_parse_YYMMDD },
  138. ['9C'] = {"Transaction Type", ui_parse_transaction_type },
  139. ['A5'] = {"FCI Proprietary Template" },
  140. ['9F02'] = {"Amount, Authorized" },
  141. ['9F03'] = {"Amount, Other" },
  142. ['9F05'] = {"Application Discretionary Data" },
  143. ['9F07'] = {"Application Usage Control" },
  144. ['9F08'] = {"Application Version Number" },
  145. ['9F0B'] = {"Cardholder Name - Extended" },
  146. ['9F0D'] = {"Issuer Action Code - Default" },
  147. ['9F0E'] = {"Issuer Action Code - Denial" },
  148. ['9F0F'] = {"Issuer Action Code - Online" },
  149. ['9F10'] = {"Issuer Application Data" },
  150. ['9F11'] = {"Issuer Code Table Index" },
  151. ['9F12'] = {"Application Preferred Name" },
  152. ['9F13'] = {"Last Online ATC Register" },
  153. ['9F14'] = {"Lower Consecutive Offline Limit (Terminal Check)" },
  154. ['9F17'] = {"PIN Try Counter", ui_parse_number },
  155. ['9F19'] = {"Dynamic Data Authentication Data Object List (DDOL)" },
  156. ['9F1A'] = {"Terminal Country Code", ui_parse_country_code },
  157. ['9F1F'] = {"Track 1 Discretionary Data", ui_parse_printable },
  158. ['9F23'] = {"Upper Consecutive Offline Limit (Terminal Check)" },
  159. ['9F26'] = {"Application Cryptogram (AC)" },
  160. ['9F27'] = {"Cryptogram Information Data" },
  161. ['9F2D'] = {"ICC PIN Encipherment Public Key Certificate" },
  162. ['9F2E'] = {"ICC PIN Encipherment Public Key Exponent" },
  163. ['9F2F'] = {"ICC PIN Encipherment Public Key Remainder" },
  164. ['9F32'] = {"Issuer PK Exponent" },
  165. ['9F36'] = {"Application Transaction Counter (ATC)" },
  166. ['9F38'] = {"Processing Options Data Object List (PDOL)" },
  167. ['9F42'] = {"Application Currency Code" },
  168. ['9F44'] = {"Application Currency Exponent" },
  169. ['9F45'] = {"Data Authentication Code" },
  170. ['9F46'] = {"ICC Public Key Certificate" },
  171. ['9F47'] = {"ICC Public Key Exponent" },
  172. ['9F48'] = {"ICC Public Key Remainder" },
  173. ['9F4A'] = {"Static Data Authentication Tag List" },
  174. ['9F4B'] = {"Signed Dynamic Application Data" },
  175. ['9F4C'] = {"Integrated Circuit Card (ICC) Dynamic Number" },
  176. ['9F4F'] = {"Log Fromat" },
  177. ['9F51'] = {"Application Currency Code" },
  178. ['9F52'] = {"Card Verification Results (CVR)" },
  179. ['9F53'] = {"Consecutive Transaction Limit (International)" },
  180. ['9F54'] = {"Cumulative Total Transaction Amount Limit" },
  181. ['9F55'] = {"Geographic Indicator" },
  182. ['9F56'] = {"Issuer Authentication Indicator" },
  183. ['9F57'] = {"Issuer Country Code" },
  184. ['9F58'] = {"Lower Consecutive Offline Limit (Card Check)" },
  185. ['9F59'] = {"Upper Consecutive Offline Limit (Card Check)" },
  186. ['9F5A'] = {"Issuer URL2" },
  187. ['9F5C'] = {"Cumulative Total Transaction Amount Upper Limit" },
  188. ['9F72'] = {"Consecutive Transaction Limit (International - Country)" },
  189. ['9F73'] = {"Currency Conversion Factor" },
  190. ['9F74'] = {"VLP Issuer Authorization Code" },
  191. ['9F75'] = {"Cumulative Total Transaction Amount Limit - Dual Currency" },
  192. ['9F76'] = {"Secondary Application Currency Code" },
  193. ['9F77'] = {"VLP Funds Limit" },
  194. ['9F78'] = {"VLP Single Transaction Limit" },
  195. ['9F79'] = {"VLP Available Funds" },
  196. ['9F7F'] = {"Card Production Life Cycle (CPLC) History File Identifiers" },
  197. ['BF0C'] = {"FCI Issuer Discretionary Data" }
  198. }
  199. function emv_parse(cardenv,tlv)
  200. tlv_parse(cardenv,tlv,EMV_REFERENCE)
  201. end
  202. PSE = "#315041592E5359532E4444463031"
  203. AID_LIST = {
  204. "#A0000000421010",
  205. "#A0000000422010",
  206. "#A0000000031010",
  207. "#A0000000032010",
  208. "#A0000000041010",
  209. "#A0000000042010",
  210. "#A00000006900", -- FR Moneo
  211. "#A0000001850002", -- UK Post Office Card Account card
  212. }
  213. EXTRA_DATA = { 0x9F36, 0x9F13, 0x9F17, 0x9F4D, 0x9F4F }
  214. function emv_process_pse(cardenv)
  215. local sw, resp
  216. local APP
  217. local ref
  218. local sfi
  219. local FILE
  220. local rec
  221. local REC
  222. local RECORD
  223. local aid
  224. local warm_atr
  225. sw, resp = card.select(PSE)
  226. -- Could it be a french card ?
  227. if sw == 0x6E00 then
  228. local ATR
  229. card.warm_reset()
  230. warm_atr = card.last_atr()
  231. ATR = ui.tree_add_node(cardenv, "block", "ATR", "warm", #warm_atr)
  232. ui.tree_set_value(ATR,warm_atr)
  233. sw, resp = card.select(PSE)
  234. end
  235. if sw ~= 0x9000 then
  236. log.print(log.INFO,"No PSE")
  237. return false
  238. end
  239. -- Construct tree
  240. APP = ui.tree_add_node(cardenv,"application","application",PSE)
  241. emv_parse(APP,resp)
  242. ref = ui.tree_find_node(APP,nil,"88")
  243. if (ref) then
  244. sfi = ui.tree_get_value(ref)
  245. FILE = ui.tree_add_node(APP,"file","file",sfi[0])
  246. rec = 1
  247. AID_LIST = {}
  248. repeat
  249. sw,resp = card.read_record(sfi[0],rec)
  250. if sw == 0x9000 then
  251. RECORD = ui.tree_add_node(FILE,"record","record",tostring(rec))
  252. emv_parse(RECORD,resp)
  253. aid = tostring(ui.tree_get_value(ui.tree_find_node(RECORD,nil,"4F")))
  254. table.insert(AID_LIST,"#"..aid)
  255. rec = rec + 1
  256. end
  257. until sw ~= 0x9000
  258. else
  259. log.print(log.WARNING,"SFI indicator (tag 88) not found in PSE")
  260. end
  261. return true
  262. end
  263. function visa_process_application_logs(application, log_sfi, log_max)
  264. local sw, resp
  265. local LOG_FILE
  266. local LOG_DATA
  267. local LOG_FORMAT
  268. local REC
  269. local log_recno
  270. LOG_FILE = ui.tree_add_node(application,"file","file",tostring(log_sfi),nil)
  271. LOG_DATA = ui.tree_add_node(LOG_FILE,"item","log data")
  272. log.print(log.INFO,string.format("Reading LOG SFI %i",log_sfi))
  273. for log_recno =1,log_max do
  274. sw,resp = card.read_record(log_sfi, log_recno)
  275. if sw ~= 0x9000 then
  276. log.print(log.WARNING,"Read log record failed")
  277. break
  278. else
  279. REC = ui.tree_add_node(LOG_DATA,"record","record",log_recno,#resp)
  280. ui.tree_set_value(REC,resp)
  281. end
  282. end
  283. end
  284. function emv_process_application_logs(application, log_sfi, log_max)
  285. local log_format
  286. local log_tag
  287. local log_items = { }
  288. local sw, resp
  289. local tag
  290. local tag_name
  291. local tag_func
  292. local len
  293. local i
  294. local item
  295. local item_pos
  296. local LOG_FILE
  297. local LOG_DATA
  298. local LOG_FORMAT
  299. local REC
  300. local ITEM
  301. local ITEM_AMOUNT
  302. local log_recno
  303. local data
  304. local currency_code, currency_name, currency_digits
  305. LOG_FILE = ui.tree_add_node(application,"file","file",log_sfi)
  306. LOG_FORMAT = ui.tree_add_node(LOG_FILE,"item","log format")
  307. LOG_DATA = ui.tree_add_node(LOG_FILE,"item","log data")
  308. sw, log_format = card.get_data(0x9F4F)
  309. if sw ~=0x9000 then
  310. log.print(log.ERROR,"Failed to get log format information, transaction logs won't be analyzed")
  311. return false
  312. end
  313. log_tag, log_format = asn1.split(log_format)
  314. i = 1
  315. item = ""
  316. ui.tree_set_value(LOG_FORMAT,log_format);
  317. while log_format
  318. do
  319. tag, log_format = asn1.split_tag(log_format)
  320. len, log_format = asn1.split_length(log_format)
  321. tag_name, tag_func = tlv_tag_info(tag,EMV_REFERENCE,0);
  322. log_items[i]= { tag, len, tag_name, tag_func }
  323. i = i+1
  324. item = item .. string.format("%X[%d] ", tag, len);
  325. end
  326. ui.tree_set_alt_value(LOG_FORMAT,item);
  327. log.print(log.INFO,string.format("Reading LOG SFI %i",log_sfi))
  328. for log_recno =1,log_max do
  329. sw,resp = card.read_record(log_sfi,log_recno)
  330. if sw ~= 0x9000 then
  331. log.print(log.WARNING,"Read log record failed")
  332. break
  333. else
  334. REC = ui.tree_add_node(LOG_DATA,"record","record",log_recno,#resp)
  335. item_pos = 0
  336. ITEM_AMOUNT = nil
  337. currency_digits = 0
  338. for i=1,#log_items do
  339. if log_items[i][3] then
  340. ITEM = ui.tree_add_node(REC,"item",log_items[i][3],nil,log_items[i][2])
  341. else
  342. ITEM = ui.tree_add_node(REC,"item",string.format("tag %X",log_items[i][1]),nil,log_items[i][2])
  343. end
  344. data = bytes.sub(resp,item_pos,item_pos+log_items[i][2]-1)
  345. ui.tree_set_value(ITEM,data)
  346. if log_items[i][1]==0x9F02 then
  347. ITEM_AMOUNT=ITEM
  348. elseif log_items[i][1]==0x5F2A then
  349. currency_code = tonumber(tostring(data))
  350. currency_name = iso_currency_code_name(currency_code)
  351. currency_digits = iso_currency_code_digits(currency_code)
  352. ui.tree_set_alt_value(ITEM,currency_name)
  353. elseif log_items[i][4] then
  354. log_items[i][4](ITEM,data)
  355. end
  356. item_pos = item_pos + log_items[i][2]
  357. end
  358. if ITEM_AMOUNT then
  359. ui.tree_set_alt_value(ITEM_AMOUNT,string.format("%.2f",tostring(ui.tree_get_value(ITEM_AMOUNT))/(10^currency_digits)))
  360. end
  361. end
  362. end
  363. end
  364. function emv_process_application(cardenv,aid)
  365. local sw, resp
  366. local APP
  367. local ref
  368. local GPO
  369. local pdol
  370. local AFL
  371. local LOG
  372. local extra
  373. local j -- counter
  374. local logformat
  375. log.print(log.INFO,"Processing application "..aid)
  376. -- Select AID
  377. sw,resp = card.select(aid)
  378. if sw ~=0x9000 then
  379. return false
  380. end
  381. -- Process 'File Control Infomation' and get PDOL
  382. APP = ui.tree_add_node(cardenv,"application","application",aid)
  383. emv_parse(APP,resp)
  384. ref = ui.tree_find_node(APP,nil,"9F38")
  385. if (ref) then
  386. pdol = ui.tree_get_value(ref)
  387. else
  388. pdol = nil;
  389. end
  390. -- find LOG INFO
  391. logformat=nil
  392. ref = ui.tree_find_node(APP,nil,"9F4D")
  393. -- I've seen this on some cards :
  394. if ref==nil then
  395. -- proprietary style ?
  396. ref = ui.tree_find_node(APP,nil,"DF60")
  397. logformat = "VISA"
  398. else
  399. logformat = "EMV"
  400. end
  401. if ref then
  402. LOG = ui.tree_get_value(ref)
  403. else
  404. sw, resp = card.get_data(0x9F4D)
  405. if sw==0x9000 then
  406. LOG = tostring(resp)
  407. logformat = "EMV"
  408. else
  409. sw, resp = card.get_data(0xDF60)
  410. if sw==0x9000 then
  411. LOG = tostring(resp)
  412. logformat = "VISA"
  413. else
  414. logformat = nil
  415. LOG = nil
  416. end
  417. end
  418. end
  419. if logformat then
  420. log.print(log.INFO,"Found "..logformat.." transaction log indicator")
  421. else
  422. log.print(log.INFO,"No transaction log indicator")
  423. end
  424. if ui.question("Issue a GET PROCESSING OPTIONS command?",{"Yes","No"})==1 then
  425. -- Get processing options
  426. log.print(log.INFO,"Attempting GPO")
  427. sw,resp = card.get_processing_options(pdol)
  428. if sw ~=0x9000 then
  429. if pdol then
  430. -- try empty GPO just in case the card is blocking some stuff
  431. log.print(log.WARNING,
  432. string.format("GPO with data failed with code %X, retrying GPO without data",sw))
  433. sw,resp = card.get_processing_options(nil)
  434. end
  435. if sw ~=0x9000 then
  436. log.print(log.ERROR,"GPO Failed")
  437. return false
  438. end
  439. end
  440. GPO = ui.tree_add_node(APP,"item","processing_options");
  441. emv_parse(GPO,resp)
  442. -- find AFL
  443. ref = ui.tree_find_node(GPO,nil,"80")
  444. AFL = ui.tree_get_value(ref)
  445. if AFL then
  446. -- Read all the application data
  447. for i=2,#AFL-1,4 do
  448. local sfi
  449. local rec
  450. log.print(log.INFO,string.format("Reading SFI %i",bit.SHR(AFL[i],3)))
  451. sfi = ui.tree_add_node(APP,"file","file",bit.SHR(AFL[i],3))
  452. for j=AFL[i+1],AFL[i+2] do
  453. log.print(log.INFO,string.format("Reading record %i",j))
  454. sw,resp = card.read_record(bit.SHR(AFL[i],3),j)
  455. if sw ~= 0x9000 then
  456. log.print(log.ERROR,"Read record failed")
  457. else
  458. rec = ui.tree_add_node(sfi,"record","record",j)
  459. emv_parse(rec,resp)
  460. end
  461. end -- for
  462. end -- for
  463. else
  464. log.print(log.LOG_WARNING,"No AFL (Application File Locator) found in GPO data.")
  465. end -- AFL
  466. end -- GPO
  467. -- Read logs if they exist
  468. if logformat=="EMV" then
  469. emv_process_application_logs(APP,LOG[0],LOG[1])
  470. elseif logformat=="VISA" then
  471. visa_process_application_logs(APP,LOG[0],LOG[1])
  472. end
  473. -- Read extra data
  474. extra = ui.tree_add_node(APP,"block","extra emv data")
  475. for j=1,#EXTRA_DATA do
  476. sw,resp = card.get_data(EXTRA_DATA[j])
  477. if sw == 0x9000 then
  478. emv_parse(extra,resp)
  479. end
  480. end
  481. return true
  482. end
  483. CPLC_DATA =
  484. {
  485. { "IC Fabricator", 2, 0 } ,
  486. { "IC Type", 2, 0 },
  487. { "Operating System Provider Identifier", 2 },
  488. { "Operating System Release Date", 2 },
  489. { "Operating System Release Level", 2 },
  490. { "IC Fabrication Date", 2 },
  491. { "IC Serial Number", 4 },
  492. { "IC Batch Identifier", 2 },
  493. { "IC ModuleFabricator", 2 },
  494. { "IC ModulePackaging Date", 2 },
  495. { "ICC Manufacturer", 2 },
  496. { "IC Embedding Date", 2 },
  497. { "Prepersonalizer Identifier", 2 },
  498. { "Prepersonalization Date", 2 },
  499. { "Prepersonalization Equipment", 4 },
  500. { "Personalizer Identifier", 2 },
  501. { "Personalization Date", 2 },
  502. { "Personalization Equipment", 4 },
  503. }
  504. function emv_process_cplc(cardenv)
  505. local sw, resp
  506. local CPLC
  507. local cplc_data
  508. local cplc_tag
  509. local i
  510. local pos
  511. local ref2
  512. log.print(log.INFO,"Processing CPLC data")
  513. sw,resp = card.get_data(0x9F7F)
  514. if sw == 0x9000 then
  515. cplc_tag, cplc_data = asn1.split(resp)
  516. CPLC = ui.tree_add_node(cardenv,"block","cpcl data","9F7F",#cplc_data)
  517. ui.tree_set_value(CPLC,cplc_data)
  518. pos = 0
  519. for i=1,#CPLC_DATA do
  520. ref2 = ui.tree_add_node(CPLC,
  521. "item",
  522. CPLC_DATA[i][1],
  523. pos);
  524. ui.tree_set_value(ref2,bytes.sub(cplc_data,pos,pos+CPLC_DATA[i][2]-1))
  525. pos = pos + CPLC_DATA[i][2]
  526. end
  527. end
  528. end
  529. -- PROCESSING
  530. if card.connect() then
  531. local mycard = card.tree_startup("EMV")
  532. emv_process_pse(mycard)
  533. card.warm_reset()
  534. for i=1,#AID_LIST
  535. do
  536. -- print(AID_LIST[i])
  537. emv_process_application(mycard,AID_LIST[i])
  538. card.warm_reset()
  539. end
  540. emv_process_cplc(mycard)
  541. card.disconnect()
  542. else
  543. ui.question("No card detected in reader",{"OK"})
  544. end