 Okey, hari ini saya akan bercakap tentang menulis SGE QL PASER Jadi, sedikit tentang diri saya, nama saya Zion Saya dari Singapura, jadi website saya Zion.sg Saya sekarang bekerja sebagai pembangunan perniagaan dan juga belajar bagaimana membuat aplikasi mobil Jadi, ini adalah pengalaman klien saya Jadi, menggunakan jawa untuk Android dan Switch untuk iOS Jadi, ke atas yang terbaik Jadi, apa adalah SGE QL? Jadi, untuk menjawab itu, biar rancangan kita beritahu anda mengenai video ini Sarah dapat sekarang melihat apa yang dia beli Sarah hanya perlu mempunyai pilihan pakaian Buka aplikasi mempunyai pakaian QR Pastikan pakaian yang betul dan mempunyai pakaian yang betul Semuanya yang Sarah dan Hawkin perlu buat sekarang adalah periksa pakaian yang telah digunakan dan telah makan malam Tengok lagi SGE QR dan membuat pakaian pakaian yang telah digunakan Jangan lupa mempunyai pakaian Okey Jangan lupa pakaian yang terbaik Saya mengambil pakaian yang terbaik daripada website dari Sid Lee Ia cuma untuk menunjukkan pakaian yang berbeda yang berbeda yang kita ada sekarang Jadi Pada masa ini, jika pakaian Pada masa ini, jika pakaian adalah seseorang yang membeli makanan atau pakaian yang telah digunakan Jadi, jika pakaian ingin mendukung banyak pakaian Jadi pakaian Periksa, Hawkin memiliki pingan, pengguna, BAL, PTA, BOL, visa dan BAL Mereka mahu memasak Pena keaikinan di pakaian mereka Dan pakaian yang CarСТOR adalah sangat kecil Anda tidak dapat memalukan banyak perkara saya Anda mempunyai pakaian kelo Anda mempunyai pakaian, pakaian dan kekaran Jadi sebenarnya, tidak ada yang terdapat untuk memasak semua pakaian keaikinan ini Jadi, seorang keadaan langsung mengambil pakaan mempunyai今日は tidak memunyai mereka pada satu kekaraan keaikinan dan ia dimana kita dapat SGQR, ini lebih besar, saya tidak pasti di mana anda dapat lihat di sini. Ya, sebaiknya bukan 10 QR kode, anda sebenarnya mempunyai 1 QR kode, dan di atas poster di bawah ini, anda akan menunjukkan apakah penggunaan penggunaan yang penggunaan sebenarnya mendukung. Sekarang anda dapat mempunyai, sehingga penggunaan penggunaan dapat berdiri ke sekitar 25 penggunaan, tetapi mereka tidak dapat menunjukkan semua mereka. Kerana bagi contoh penggunaan, mungkin mereka hanya menunjukkan penggunaan dengan penggunaan kode dan penggunaan alih. Jadi anda dapat menggunakan SGQR dengan Banking App untuk menggunakan SGQR. Tetapi anda tidak akan menunjukkan penggunaan kerana penggunaan tidak menunjukkan penggunaan dengan SGQR, seperti itu. Jadi, penggunaan kecil. Okey, tidak mengapa. Resolusi. Biar saya menggunakan resolusi saya. Okey, mari kita cuba lagi. Okey, tidak mengapa, ia berlaku. Okey, mari kita balik. Okey, tidak mengapa, saya menggunakan kegunaan berlaku. Jadi, hari ini saya berfikir saya akan menunjukkan ke 4 saksi. First is introduction which I have just gone through. Second is specification. I am going to go through specification. Third, I am going to go through the code that I wrote to read and analyze SGQR. And fourth part will be live demo. So, first part, the SGQR or Singapore Quick Response Code for long is actually based on the EMV QR code specification for payment systems, Merchant Presented Mode. Because this QR code is presented by the merchant. It is actually found on this website. If you go to this website, actually it is from the MES website. It is written also. So, you get this PDF found. Very nice. So, if you scroll through everything, it is 47 pages. Okey, I am going to go straight to the data organization part. For the purposes of this talk, I am going to use sample SGQR code that I generated. So, basically, this is the QR code. And then if you scan it, you see it's all this contents. You find that it's not encrypted. You can actually read the test inside over there. Okey. So, SGQR actually consists of data objects. Each data object has 3 fields. The ID is coded as a 2-digit numeric value with a value ranging from 00 to 99. Okey, quite obvious. The length is also coded as a 2-digit numeric value. Okey, a value ranging from 01 to 99. And the value field has a minimum length of 1 character and a maximum length of 99 characters. So, the length part. Okey, the length part over here, this determines how long the value is. If this one says 0.5, so I will read 5 characters for the value field. Okey. For those who just came in, I'm going to use this sample SGQR code as for my talk. These are the contents. Okey. This is the same contents of SGQR broken up into data objects. Every single color denotes a different data object. So, the red one is one data object. The green is another data object. The long blue one is another data object. The long green one is another data object. The blue is another one. Green is another one. Blue is another one. Green is another one. Blue is another one. And last of all, the red one. Okey. Let's look at the first data object. 0000201. So, if you break it up, ID is 00. Length is 02. Value is 01. Length is 02. That means I will actually read the next two characters after it, which is 01. Okey. What is ID00? So, if you look at the PDF for MAS website, ID00 is a payload form indicator. Okey. And the first data object must always have ID00. That's it. Okey. Value is always one for now. They never detect any other values. So, the first data object is always ID00. Now, let's look at the last one. The last one, which is this 630457B3. We break it up. The first two digits or characters is always the ID. ID63. The next two digits, which is 404, means the length of the value. So, that means I'll read the next four characters for the value. So, in this case, the value is 57B3. So, ID63 according to this PDF is basically the chat sum. The CLC. Let me see. Over here. Okey. This is the CLC. Now, and SGQL code consists of data objects and templates. Okey. A template itself can contain data objects and also nested templates. So, let's see what it means. Just now we had SGQL. So, this is the third SGQL. Let me refresh your memory. Remember this long blue color one. So, now we are focusing on this long blue color data object. Okey. In this case, the first two characters is 26. Okey. And if you look at the PDF Merchant Account Information 02-51. So, if the ID is 26, it falls below here. So, it is the Merchant Account Information Template. Why is the length? The length is 81. The worst in italics. And the value is this long value over here. Same thing. It consists of many data objects. So, let's break it up by color again. Red, green, blue, green, blue. So, let's look at the first one. So, remember this ID 26 is a data object by itself. But it is a template. ID 26 is a template. So, their long value can be broken up into more data objects. So, the first data object 0011 SG.com.net. We break it up. The first two characters is 00, ID 00. Now, the ID is not unique. It depends on our context. If it is in a root template in the root, like I say, 26. Okay? So, 26 in this aspect is in the top level, the root level. So, we look at 26 under the root data object. But now this 00 the ID, the context is under template 26. So, we need to look at template 26, which is page 34. Okay, 33. Okay. When your ID is 02 to 51, so in this case, it's ID 26. 00 in this case is no longer payment, payload format indicator. 00 means globally you need identifier. So, what your ID means depends on the context it is in. It is your ID under the root data object or is it under a template. So, let me show you just now the 00 which is on page 19 or page 20. In this case, if it is under the root of a QR code, 00 means payload format indicator. But if it is under a template, 26. Okay? It means globally you need identifier. Okay. That is the specifications. So, right now, I'm going to go to the parser code. In case you cannot remember this link, okay? Or you what you can do is go to my website xion.sg you click on github and you look for sgqlparser which is over here. Okay, I've written this as a PHP library. So, actually, you can install it via Composer. Composer require. It has some tests which I'll go through later. So, first thing I want to go through is how do I store the configuration? This whole PDF channel, right? How do I put it in my PHP library? So, I've done it using PHP arrays because that's the most natural for configuration using PHP. You notice that actually I have JSON and PHP. They are the same. Just in case someone wants to use JSON for their JavaScript project is there. So, I'll provide it in two formats. Okay, let's look at the PHP configuration. I've stored the specifications as an array. The array has just three keys. First one is root data objects by ID. So, just now remember we saw this payload format indicator. ID is 00 payload format indicator. So, over here root data objects by ID I'll store it by the ID 00 The name is payload format indicator and I'll put some command. This command is for the PDF as well. Okay, and just now 26. Let's look at 26. Okay, 26. The name is merchant account information. Blah, blah, blah template reserve for additional payment networks is template equals to true. The configuration as I mentioned has three keys. First one is root data objects by ID. This one. The second one is templates by ID which is this one. Templates by ID. So, instead of dumping the whole set of nested information in the root data objects by ID I've chosen to split it up. So, that's easier for me to change staff next time. I'll explain later. So, for 26 which is over here 26. Okay, users info template equals to true. So, what will happen? I will read from the third key of the configuration which is this. This info template. Okay, remember just now we saw on page 34 or page 33. So, over here we find that oh, for ID 26 ID 00 means globally unique identifier. So, this are what I call info templates. So, in this case you find that simply ID 00 name is globally unique identifier. And from 01 all the way to 99 it's actually payment system specific. The reason why okay, I put this in the key by itself and I use users information template equals true. Imagine I have to duplicate all the information up there into every of these 26 to 51 and later 80 to 99. You'll bloat up my configuration array by lot. So, this is how I what I do to actually string my configuration array. Things that let's say if next time the info template let's say 99. Okay, if 99 if 99 is change okay, then I only need to change one place which is over here. I don't need to I don't need to change for 26 all the way to 99. Okay, that's the configuration. Now for the source code there's only one one class which is the parcel class. You'll notice that actually I've listed a lot of constants because it's what I want to refer to it. If I spell the constant wrongly the interpreter will actually complain to me that we are past error, syntax error. But if I spell string wrongly okay, I won't see any error. I might not see any error. So that's why I decided to use constants to refer to the keys in the configuration array. So first up let's look at the constructor. Okay, so after I allow the passing of a separate alternative set of specifications if the developer wishes to do so. If not, you'll just read from the one that's provided which is this file that I gave just now. Okay. There is only one public method which is pass and I'll just pass in the contents of the QR code. Remember the long string just now? I'll just pass it in. So passing consists of two actions. First is separate data objects. Okay. MC. So first is to break out the QR code into the individual data objects. The second part would be to actually analyze each data object. So first I extract data objects. Okay. Over here. Then later on I have for analyze data object. So now I go through a trial run a sample of passing the QR code. Okay. Let's take a look at this. I'll just copy this. I'll just look through the first three. Okay. So let's look at extract data objects. The test is actually passing and the specifications. In the beginning no specification is passing. If no specification is passing I will refer to this one. Root data objects by ID which is this whole chunk over here. Okay. This whole chunk over here. So I'll start from the first character which is index. Then I'll just extract the ID. The ID is basically the first two characters. So basically I'm looking at this part. So ID goes to 00 and then the length of this data object is actually 2. And the value is the value is actually 1. And then the index is actually forwarded to the next one over here. So the next round we go through a loop you will start with the second data object. You will start with the rest of the QR code. So what I will do with this information is I will call this. What's the ID? ID is 00. I will skip the quotation marks for speed. The value is 01. How for the specs? Initially the specs is referring to root data objects by ID. So I'll passing this whole chunk and analyze data object by actually passing specs 00. So basically I taking this part and I passing in. Okay. Now we will go to When to sleep and then over hit. Okay. Okay dah. Okay. Okay. I have a backup projector just in case. Okay. Okay. Okay. Now we are at this part where the first data object is extracted the first data object and now it's going to analyze it. So I'm going to call this analyze data object ID 02 value 01 and this is specification that is going to pass in. So now let's look at the analyze single data object function. So first thing does the specs belong to a template? No. Root ID 00 is not a template. Okay. The suspect use info template. So we look at this just now. Okay. Is template is equals to force. It's not specified. So it's force. So it is does and there is no users info template key. So it is it does not user info template. So basically skip. So right now the result okay. This will be resolve resolving of the data object. So the value will basically be this ID is 00 name is payload form indicator. The length is 2. Ya 2 and the value 01 and the command is this one shall be the first data object in the QR code. Okay. And when this is passed back. Okay. Is it a template? Okay. It's not a template. So just skip. So return the result. So return the result. Basically it is appended to an array of arrays. So your final result is actually this. Okay. So this is the first part. Now let's look at now I will skip the second data object. I will go straight into the third data object because this is a template. So it's a slightly more complicated. So we skip. So now we are here. Okay. Let me open a new window. Now we are interested in this. So now ID is equal to 26. The length is the next 2 characters which is 81. And the value is this long string over here. So same thing. I've extracted the third data object. Now I'm going to analyze it. So I'm going to call this. So what's ID? ID is 26. The length is 81. And the value is I'm not going to type it out. Okay. And the specs this time now remember originally the specs come from the root data object by ID which is over here. So now you're passing specs 26 which is over here, 26. Okay. I'm going to copy this holding here. Okay. Now let's look at the function analyze single data object. So first part. Okay. Does the specs belong to a template? That means it's template equals to true. If yes, get a template information data object if any. So let's look at this. So right now in the function in the function self this is the specs. Okay. Let me just formatting nicely. Okay. Look at the signature. The signature actually passing the specs. So right now this is the status of the specs. It's template equals to true. So I will go to my configuration. I will go to templates by ID. Templates by ID. And I will just copy this one. This array. I'll copy the whole array and merge it. Okay. It's over here. Array merge. So I'll actually get it from templates by ID. I'll merge it. So now this is the state of my specs. Okay. I added one more users info template equals to true. Now next part. Does the specs use the info template? If yes, populate char data objects with it. So I will add a new key data objects by ID and then I populate it with the info template. So I will have a new key data objects by ID and am I going to get this information from? Go back to my configuration info template. This is the info template. I am not going to copy everything. I'll just copy up to true. Actually it goes all the way to 99. Okay. It goes all the way to goes all the way to 99. Let me see. Ya. Okay. Goes all the way to 99. So zero zero in this case you see globally you need identifier. So now what is my next step? My next step is actually to pass this data object which is this one. I'm still at this level. I'm still at this level. So my result is over here. I should just copy. Ya. Okay. What is the ID this time? I am right now at this level. I'm still at this level. Okay. So my ID right now is 26. What is the name? Bo. Merchant account information. And what's the length? The length is 81. And the value is this funny long staff over here. Okay. And the command I'm going to just skip. So that is the current data object for ID 26. Now the next part. Pass data object further if it is a template. If it is a template then I will set the result data objects and I will call extract data objects but this time around I'll pass in the value. I don't pass in the whole original QR code and I will actually pass in the specs not from the root data objects or passing from the data objects by ID. Okay. So let me copy this part. So what's going to happen is I'm going to have a new key called data objects and the result is actually going to be extract data objects. Or passing this whole value. This whole value over here. And how about the specs? Our specs are actually passing from here. Remember this data objects by ID? I will actually passing this one. Previously previously it was passing in from it was passing in from root data objects over here. Okay. It was passing in from root data objects but now I don't passing that. So let's look at the last part. So now I'm going to pretend that this is the new QR code that this is a new test. So I'm going to break it out again. ID 0 length 11 value is the next 11 characters. So let's count on 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11. Okay. And what am I going to do? I'm right now in this function okay. I'm right now in this loop. Okay. Now we are we are extracting the data objects for the third data object not for the original whole entire QR code. Okay. So we are going to do this thing. 0, 0, which we have seen just now. Now this time around the specs where is it going to come from? Is it going to come from the root data objects by ID? No. Because just now we passing this which is basically referring to this part. Okay. This part. Data objects by the we passing this as a new specs. The new specifications. So basically it is this one. Specs ID 0, 0. So basically right now I just going to passing this one. Okay. And now I going to go into analyze data object which is over here. Does the specs belong to a template? No. Does it use an info template? No. So resolve data object because like this. So the ID is 0, 0. The name is globally unique identifier. The length is 11. The value is edge.com.net and I going to skip the command. So this whole part this whole part where is it going to go to? So you return to the previous call over here at the bottom or at the bottom it is going to come here. Okay. It is going to come here. This is the first part. ID 0, 0. Globally you need identifier. Later on there will be some more 0, 1, 2, 3 and so on and so forth. So Kion doing this internal recursion. And this whole chunk where is it going to go to? This is for the third data object. Okay. So it is going to go to the first part. Okay. So your final result is you are going to get an array. Inside each array you have an array describing each data object. So this first array is the first data object. It is a payload form indicator. Then bla bla bla second data object then third data object. This is the one this is the array describing the third data object. Okay. It is ID 26. Merchant account information. Lamp 81. It is long value. And it consists of nested data object. So the first one is SG.com.net. So it actually can go it can actually go to two levels two levels deep. Okay. Now the boring part is over. I got to go through the demo. Okay. Let me see. Okay. Where is the demo? Um Let me show you the website first. Uh Now same thing if you go to the repo besides the code sgqlpasser as per MES monetary authority of Singapore the demo the link is here. Okay. So I'm going to go to this link. Okay. Let's see where it works. Okay. Hello. Okay. Um this uses the PHP Passer library in the back end to pass it. But how about this? Hello. These are camera thing. I didn't code it myself. Okay. That's the beauty of open source. I went to find some JavaScript library. Right. They actually can access the camera as well as pass the QR code. Okay. So it saves me the trouble and the amazing thing is this hello can actually work on your desktop if you open it up on your iPhone Safari browser if you open it up on your Android phone Chrome browser it works as well you can actually access the camera and scan the QR code so you just need to go to this website on your phone and then you can actually use it to scan QR codes and try if you look at a source code for this website blah blah blah blah blah blah and it's over here. Okay. I put some comments the QR code scanner Let me see. Okay. QR code scanner It's actually from githout.com slash instant scan. I put some notes over here on on some changes that I did and basically this is the code for the hello the camera and then scan the QR code So for this library it can actually detect that your device have two cameras so normally phone at front camera and back camera so I put it on auto detect so let's see if I load this website on my phone right you will use the second camera which is usually the back camera Okay. Let me see. I have some sample sgql over here So the story goes that actually I found out about this then but I didn't want to go all over Singapore go and see which are the hocker stores so actually I first read about this sgql on the channel news Asia article Okay and I try scanning the QR code in the article and it actually work so actually I could get a content so at first I use pen and pen and paper to manually pass it oh first two characters then next two characters then account 11 characters then slowly slowly then I decided I must write program to do it right so what I going to do now hmm see whether I can beat this bigger no okay this responsive okay I going to take a picture of this QR code then I going to point take at the website so you see on the website so basically passion gadgets so recently I send my electric unicycle the blue thing over here for repair so at the counter I notice they are using sgql but the only payment they allow for sgql is basically grab pay okay so I going to take a picture of this first okay so oh sorry I need to point the okay so sgql code pass so I just point the QR code at the webcam right so you pass it so these are the contents of the QR code you can use any QR code reader app to actually read the QR code and you get the same contents okay so let's look at what's the result now this is the result from the PHP parser code that I went through review just now it returns the PHP array but for nice pretty printing I encode it into JSON so that it reads nicely so the QR code let's see whether I can make it bigger the first one as I said is always id00 okay id00 the length to value 1 okay let's look at the sgql okay 00 02 01 the second one usually okay is the point of initiation method id01 the length is always 02 and the value is either 11 or 12 11 bermaksud this QR code will always can be reused so most likely it's the same QR code probably there's a merchant bank account value of 12 is used when a new QR code is used for each transaction for example let's say it contains an invoice number or it's generated on the fly it has a transaction amount so it will generate a new QR code for each transaction in this case the sgql will have a value of 12 for id01 merchant account information starts from 26 to 51 so basically they are using template 26 to 51 to capture the payment provider so the first one is great right so this is the value blah blah blah this is a template result additional payment networks so this is a template id26 I went through just now it is a template so it breaks down into further data objects id00 the globally unique identifier is com.grab so basically this is grabs unique identifier how about this thing the value this is most likely the merchant's account ID with grab when I first release this as you clear someone some stranger email me so can you write sgql generator I say yes and no there are many libraries out there that can generate a ql code they are not very easy there are many oposals library out there I know how the format of sgql looks like but the thing is I do not have the merchant account ID for each of the payment providers okay first thing I may not know what is this this may be some other value second thing I can collect enough ql code to determine okay actually this is the merchant ID but unless I am the merchant and I tell you even probably the chicken rice hawker wouldn't know his account ID with grab only grab would know the chicken rice hawker wouldn't bother about it so in this case I told the person no because I don't have access to all this information so let's look at some other information ID 51 also the merchant account template this is usually sgql itself sg.sgql now look at this I have no idea what is this okay but it is past this is so only sgql I will actually understand what it stands for okay but I can guess that this is 15 September 2018 because that's the date that sgql launch transaction currency 702 so this is this is why I've included the comments in the configuration or else you wouldn't understand what this means so basically this 702 is a 3-digit representation of the currency according to ISO 4217 USD is 840 SINGDOLLAR is 702 country code sg merchant name passion gadgets and the merchant city is actually Singapore and the CRC chat sign shall be the last data object in the QR code and the chat sign is calculated according to something that I don't understand so I'm not going to bother explaining it so basically it's a chat sign so it's a 4 character chat sign so let's look at the other demo this is QQ rice amokyo I was talking about this with my colleague and my colleague say I sold one at QQ rice so I took my colleague to a handmade photo so this is interesting because it does not support NETS it supports early pay B pay which is about honest B and fake pay so same thing I'm going to take a picture hello try again this is a new one because you can see you can see QQ rice over here so I'm going to skip the rest so first part okay it's the ID26 and then over here you have honest B and under the honest B you have MIT, GE6, blah blah blah blah so most ID this is a virtual ID for honest B so it supports honest B so it's using ID26 then later on later on you have ID27 also virtual account information and this now who is using it this time round fake pay is using it okay and how does fake pay have a unique ID for its merches is using a website myfake.com slash qr slash 1066 so if I visit this on the website I'll probably see some information about QQ rice on fake pay so third one early pay ID26 ID27 ID28 so right now ID28 this is the whole value because it's a template so you'll be broken up into more data objects so same thing ID00 globally you need identifier values come to early pay and same thing you also like to use website to denote the merchant ID and ID51 so stay use for HQR and let me see and QQ rice okay let me see okay the last one is the most interesting so how many of you are using pay now I have started using pay now so pay now is basically a grimoire amount of the banks right so let's say if we go for lunch then I pay I pay for the lunch so you are paying back your copy right so you can use you can use your banking app you open it up you key my phone number other day I say you show this phone number belongs to Zion so pay me 350 enter you will be paid to my bank account that's easy another way is I use my phone banking app to generate a pay now QR code you scan it and then you pay using you scan it using your banking app and then you pay for it so pay now so all the banks in Singapore support it I generated this HQR sample that means it doesn't contain any information about me okay this one is a special one because it contains a transaction amount and a nested template ID under template ID 62 remember I say that the nested can go out to two levels deep so now this one will show what it means let me take a photo okay let me just reload a page okay this is the last demo okay same thing 00 payload format indicator point of initiation method point of initiation method the one that we're interested in is ID 26 okay ID 26 so merchant account information this is a whole land the globally unique identifier is SG.PayNow payment network specific ID 0Y, value of 0 I have no idea what that means okay probably if you collect enough pay now QR codes you can't figure out but until now I don't know okay data object number 2 under template ID 26 this is a phone number obviously I detail it out okay so this is a phone number now ID 03 same thing value of 0 again I have no idea what it means because pay now never release their tell us how they use SG QR number 4 2018 October 30th this is the expiry date that I put for my pay now code so when I generate the pay now code using my POSB banking app I can actually specify when is expiry date so this is expiry date okay transaction amount $1,234.56 so if you scan the QR code basically you'll be paying me that much now this is a very special value the comment is shall not be included if the app should prong user enter the amount to be paid if I use my banking app to scan this QR code I will see the amount on my screen $1,234.56 and I won't be able to change it I won't be able to change it versus if if I didn't have the transaction amount in my QR code when I scan the QR code like I say I scan the chicken rice hawker that will fear for me to pay $3.50 so this value will determine whether the amount is fixed whether the user can change the amount in the QR code okay, merchant name basically it will be my name so if you are actually it will be Zion if I generate the pay now QR code and the most interesting is actually $62 ID $62 is an additional data field template it is a template so it can be broken up into data objects so the first data object so one is the build number so the value is can be an invoice number now the interesting part is actually ID $50 under template $62 ID $50 it is a template by itself or so so this value can be broken up into further data objects okay so you have a template inside a template inside under the group template so that is the purpose of showing this QR code okay and that's it really it's a one hour talk I know it's very long hopefully it's interesting so to reiterate if you want to find it can go to Zino SG you can go to Github portfolio and then under repositories you can just search for SGQR over here so under here you get source code as well as the link to the demo so actually what you can do is you can load the demo page on your phone and then let's say tomorrow when you go to South Fukuoka you see one SGQR point the camera point the website this website at the SGQR and then you pass it and tell you the information behind the SGQR and that's all thank you very much and okay