Hello, everyone, and welcome. This is Melissa Arma with the Stock Swoosh, and today I wanted to talk to you about sizing and consistency and the importance of consistency with sizing. In order to have consistent results with your trading, first of all, you need a winning system. That goes without saying. You have to have a system that has a high win ratio. I do, it's the golden gap. But secondly, even if you're using a system that works, whatever system that happens to be, you have to take consistent risk in your sizing, meaning you can't be up and down all the time like this. In fact, I'd say to people, listen, look at four quarters of the year. If you want to increase your sizing or decrease your sizing, you shouldn't be changing it every day or every week or even every month. I would say you don't even need to trade it, change it every year, okay, even though there's four quarterly earnings seasons, but you could, you could, is what I'm saying. But either way, every trade you take should be of equal or similar size. And again, when you're taking trades, sometimes we're taking them really quickly. This is an estimate. If your risk is $500 and you risk $550, that's not the end of the world. But if your risk is $500 and you end up risking $2,000, well, that's completely wrong. That means that you would have taken four times the risk in one trade that you normally would. Even if the cash is there, it doesn't matter.  You have to have consistent risk per trade, sizing properly the cash risk. Okay, this isn't about the share quantity, because your share quantity will not be the same, especially if you're trading with me because it stops that we take our different on each trade. And the cost of the options too are different on each trade, depending on the cost of the stock. So you have to have consistent risk per cash per trade. The amount that it costs you to take it, that if the trade loses, you will lose, or if the trade wins, you're looking to make again one over one amount. So say you risk $500, you're looking to make $500. That's what I typically go for. Now some trades go more, some trades are slightly less, some trades go to the dream target, but that's neither here nor there. Your risk amount has to be the same or very, very close to it. And if you're not good with math, then you know what, you gotta get a calculator. I've had this calculator for so long. I've had this calculator, I have had this calculator for 30 years. That's pretty crazy. It's a Texas Instrument Calculator that I've had for 30 years. I don't use it that often because I'm really good with math in my head, but I always have it, it's always right here. Sitting right here next to me. And if you don't have the calculator next to you and you're not good with math, you've gotta get one and buy one today. They're dirt cheap, you can get one anywhere, order from Amazon, you can get it by tomorrow or get it same day delivery. And again, sometimes I need to use it, but most of the times I do it in my head, but if you're not good with math, then you need a calculator. You've gotta have it because you really have to be careful with your risk. You wanna have consistent results. Any questions, email me at melissathestockswish.com. Have a great day everyone and good luck.


So Newsweek explains, Russian Foreign Minister Sergei Lavrov has said Russia has no intention of attacking other countries after talks with Ukrainian Foreign Minister Dmitry Kuleba reportedly made no progress on Thursday. Quote, we are not planning to attack other countries, Lavrov said, during remarks delivered in Russian in Antalya, Turkey. We didn't attack Ukraine in the first place, the Russian Foreign Minister said. We just explained a lot of times that the situation has come, that there was a direct threat to the safety and security of the Russian Federation. Uh-huh. Sure. The thing that Russia is currently doing in Ukraine, which is definitely not an attack or an invasion, is purely defensive in measure. This is what every single imperialist invader will say, it'll always be the justification for their imperialist expansionist vision. Oh, well, we had to do this because it was defensive.  And what's interesting is that while he says that we should not believe our lying eyes, Russia is actually intensifying attacks on civilians in Ukraine. As Brett Wilkins of Common Dreams explains, amid new reports Thursday of non-combatants killed and wounded by Russian attacks on Ukrainian civilian infrastructure, human rights advocates joined United Nations officials in expressing their horror and accusing Russia of possible war crimes. BBC reports three people including a child were killed and 17 others were injured Wednesday in a Russian airstrike on a maternity and children's hospital in the besieged southern port city of Maripul, with patients and staff trapped beneath the rubble caused by the attack. People don't understand how it's possible in modern life to bomb a children's hospital, Maripul deputy mayor Sir He or Love told the BBC. People cannot believe that it's true. United Nations Children's Fund Executive Director Catherine Russell said she was horrified by the attack, which if confirmed underscores the horrific toll this war is exacting on Ukraine's children and families. In less than two weeks, at least 37 children have been killed and 50 injured. She continued, while more than 1 million children have fled Ukraine to neighboring countries. Now I want to stress that that report has not been confirmed when it comes to reporting on wars.   So far there's been more than 1400 civilian casualties in the country, 516 killed and 908 injured.  So over a thousand civilian casualties and that number will likely grow. And again, this number is an approximation. But just know that it's bloody. That's the takeaway.  And as Russia seemingly is getting more desperate, they're ramping up their attacks. And now they're doing war crimes, potentially. So the foreign minister of Russia, Sergey Lavrov, is saying we didn't attack Ukraine. What we're doing isn't a war or an invasion. It's a special military operation. You know, they'll they'll coat their militarism and imperialism in Orwellian terms. But we know what this is. We see it for what it is. You can't lie to people in this era where everyone has a smartphone. Everyone has a camera on them. We can see the war now in high definition. So you can't gaslight us anymore. We see what's happening. This is an invasion. It's an act of aggression. It's an illegal war. And if it's proven that these are indeed war crimes being committed deliberately by the Russian government, then people need to be held accountable. I condemn US imperialism, and I absolutely damn sure condemn Russian imperialism as well, especially as I see these reports pouring in about civilian casualties and them targeting civilian infrastructure. It's just it's grotesque and unimaginable, and I really feel so bad for the people of Ukraine. So you know, this is what we're seeing currently. I'm sure there's going to be more reports. I hope that this war ends soon. I'm not necessarily that optimistic given how we keep seeing reports about talks failing. But still, I'm holding out some hope that this will end soon. But this comes down to Vladimir Putin. The onus is on him. He's the person who can choose to end this all right now. He can stop the blood shed and the suffering like that. But he's choosing not to. So the blood is on his hands, and the scary part is that he doesn't care.


Sam here with late in sports cards. I've been five, 20, 23, Panini VIP Gold Packs for Greg M. So again, Greg, you got one, two, three, four, and five. Good luck. Purple Ice, Lamello, 250, 50 of 50. Frank Thomas. Purple Ice, Cal Ricken Jr., Ironman, 13 of 50. And Haley Deegan. Where do you think we should have the size, chairs? That'd be sweet. Matos Buzelis, two, 149. Blue Ice, I agree with that. Quinn Ewers, Rated Prospect. Just signed exclusively with Panini. Blue Ice, Bryce Young, two, 149. Kevin Garnett. And Thickey, what we got here? Ooh, that's cool. Nicola Jokic, two, 199. And how about a gold? Nicola Jokic, seven of 10. Player worn on that one. Congrats on that, Greg. Very nice. Nicola Jokic, seven of 10, gold jersey for the Nuggets. About to do it for your break there, Greg. Thanks again, as always, for your support, buddy. Get him right out to my man.


The Navy recently released an enhanced carrier presence plan detailing potential changes to deployment and maintenance schedules. Now the Navy wants your input to help shape the plan. This plan is going to do a couple of things for us. It's going to allow us to deploy you, train you in a much more predictable fashion. So you'll do two shorter deployments of seven months each during the course of a training cycle. So you'll be at sea a little bit longer than you are now, but it'll be on a much more predictable, stable schedule. It's also going to allow us to provide better training and maintenance availabilities for the ships in a carrier strike group over the course of that cycle. The way it's been working now is the deployments are advertised as seven or eight months and then sometimes they go a little bit longer due to surge requirements overseas. Well if we can do this plan effectively and we don't think we're going to get there until probably fiscal year 15, the funding is still being worked out. But if when we can do this effectively, it'll allow us to surge essentially from the scene. Kirby also reiterated that although this plan has not been initiated yet, Navy officials are confident that if it is, it would provide a better model for ship maintenance and added predictability for sailors and their families. There's a lot more to come out on this. Again, a lot of things still have to be worked out, including the funding for it. But this is a plan that we believe is going to give the Navy a far greater ability to respond to command and commander requirements over there while giving you and your families much more stability back here at home. Your voice counts. You can make a difference. Go to the Navy blog at navylive.dodlive.mil or the Navy Facebook page at facebook.com slash US Navy to offer your suggestions. From the Defense Media Activity, I'm Petty Officer Amara Timberlake.


Good morning, John. I would like to do for you a historic re-enactment of the moment when I read the title of your video from last week. What a lovely day. I am not currently experiencing any sources of broad anxiety. Lets go see if John's uploaded his video. Heeeeeeeeeeeee! I'm fine now. I mean, how does this all end? It ends in death, John. You give me a whole word for it that I forgot. It's gonna bug me, so I'm gonna text you. What's the word for the philosophical word? For death and talking about death that you use sometimes? I mean, the translation algorithms are getting so good now. You know, he'll write back. He knows what I mean. First of all, survey results say people are cool with us taking three weeks of vacation. I don't know how I'm going to do that. I'm not really set up for that in my mind. There being space for flexibility. I don't know if that's good for me. I need to know exactly what I have to do. So I think that I'm going to schedule my vacation days like very far in advance to not give myself the possibility that like, oh, maybe it's going to be this week if I don't have any good ideas. No, I need the pressure. John, I think it's interesting that you were like, how do we get a little bit of vacation? Whereas I have spent the last three weeks being like, I think I need to upload a video about donuts on Hank's channel. What about the FDA's new nutritional label requirements? I think I need to weigh in on that.  But it's the whole human apocalypse, not just individual death. Eschatological anxiety is fear of apocalyptic events. But that stands. How is this going to end? You know, it will eventually. But I have a lot more to talk about today. For example, the fact that I have just left this hammer that I hit a router with on the floor for that long. I have a problem with tidying up. Does anyone want this hammer? I'm going to hide it in the bushes by the Big Dipper Ice Cream Shop. And if you come by, it'll be there. Okay. John, I'm almost done signing pieces of paper. And the pieces of paper they gave me for the UK editions of my book were different and had a weird cool stop motion effect when I sped up the video. Each page is a little bit different and the curls faded and out. And at one point, one of them blinks. Whoever at Orion, which is my UK publisher, thought of that. That's amazing. And I did not expect that to work that well when you told me that you were doing it. I was like, yeah, probably won't look as, but it looks so cool.  I also, John, have an audiobook narrator. I almost wish that I had been less involved because it gave me so much anxiety. They were all so good, all of the people we had to choose from. But ultimately, it was very subjective. It was the person when I was listening to it. I felt like I was listening to April gave me those goosebumps, made me feel like the person I created was talking to me, which was both like beautiful and emotional, but also like a little upsetting and like kind of uncanny. But the narrator of my audiobook, there's actually two of them. The main one is Kristen See. She was in Oranges in the New Black. The blacklist, House of Cards. The other narrator of my audiobook. So there is, at a point in the book, a switching of perspectives for one chapter. And I will be doing that chapter. And so I feel very good about this happening, and I cannot wait to start getting into the weeds of getting the audiobook made. And John, finally to cap off this video, the comments that people left on your video after you said this. What do you get out of Vlogbrothers videos? We're just so, like, life-giving to me. I'll know forever that if I need a little lift me up, a little kick me in the pants, I can go to the comments of that video and just read a little bit. So thanks, John. And thanks everybody who left those comments. It means a huge amount. John, I'll see you on Tuesday.


Hey, welcome back to Magic Orthodoxy, my name is David and this is the Deck Review. Hey, today we're going to look at the Magic Con decks from 2012 and Dan and Dave. What is Magic Con? I'll tell you. Magic Con is a conference for those who are serious about the art of magic and where those in attendance, they then share ideas, insight, and they just have a common experience of working together towards the advancement of the art form of cardistry and magic. Now, Dan and Dave, they would say that it's their mission to advance the art of magic. So Magic Con then provides this platform for some of Magic's smartest thinkers, their greatest visionaries, and top performers. Plus, not to mention those presentations, there's behind-the-scenes stuff, there's art, there's science. Anything that has to do with the technology of magic is at Magic Con. The Magic Con 2012 conference was in San Diego, California on April 12th through the 15th. Like I said, it is the premier conference for magicians. And if you'd like to learn more, you can visit magic-con.org. The front of the tuck case, of course, says Magic Con and has the five-pointed star. And you're also going to have another little five-pointed star right there on the tuck flap. On the bottom, there's some ad copy about Magic Con and Dan and Dave. And the back design is a glimpse of what the back design of the cards looks like. That is pretty much it for the tuck case. Let's take a look at these cards. These cards were, of course, printed from the United States Playing Card Company and they do come on their retail stock. They do have air-cushion finish and a modern emboss. And if you'd like to learn more about stock cut or finish, you can click the link below in the description. The back design of these cards is a five-pointed star amidst a kaleidoscope of color and a nice thick white border. Magic Con so far has always included the star icon as its symbol. With this deck, you're going to get two extras. You're going to get a Dan and Dave ad card, as well as an ad card that tells you a little bit about Magic Con. Courts in this deck are somewhat standard. They have had most of their color removed except for a tiny little hint of purple. They've also had their borders removed and then the entire image has been blown up just a smidge. The pips and indice cards are going to look completely standard to you. However, the coloring is a little different. The red in this deck is almost kind of like a light, light, light magenta. I won't say pink because that's just too girly. But it is a soft color, which is nice. And then the black cards almost look black, but they're actually a very real dark, deep shade of purple. All right, so that is my review of the Magic Con 2012 deck from Dan and Dave. As always, recommend that you like this video just so other people can find it faster. We also recommend that you subscribe to this channel just to stay up to date on the latest cards and card magic. Now, if you want to follow me on social media, you can. I'm at Facebook.com slash mentor Barthacy Twitter.com slash mentor Barthacy and Instagram.com slash Magic underscore orthoboxy. Thanks. Bye


So what does that mean as if you invested $50,000 five years back, today your $50,000 would have already become $100,000 inside your CPF. Which is way better than your unit trust of course.  Do you want to double your investment portfolio and generate 100% return for your CPF in the next 5 years? Do you want to grow your CPF safely and consistently regardless of the market direction? If yes, then keep on watching. Hey everyone, this is Chloe or Kylie and welcome back to my channel. The only one place for you to learn about stocks, investing as well as options. If it's the first time that you come into my channel, remember to hit that subscribe and like button and hit that notification bell so that you will not miss out my future investment sharing. And early comes up is also appreciated because it will tell YouTube algorithm that you find this video helpful and it will push out to more people to inspire them to start investing safely. Today I decide to dedicate this video particularly to people living in Singapore as we all have some of our money locked up with the government in the form of CPF. But don't go away even though you are not living in Singapore because the content that I'll be sharing with you will be very very useful and it's regardless which country are you currently living in. With this simple strategy, you can generate 15 to sometimes even 20% return year on year as long as you stop taking action. But before that, I just want to say that whatever I'm going to share is not an investment advice. You should make sure you do your due diligence before making any investment decision. What I'm going to share is basically my own personal experience as well as what I'm going to do with my own personal portfolio so that it can really give you some insight into what you can do as well for your CPF investment. Now when it comes to CPF, most people living in Singapore tend to just live it with the government as it can give them a guaranteed 2.5% return. Although 2.5% guaranteed return is better than putting your money in a bank, it will not be sufficient given the rising cost of medical expenses as well as the rising cost of living as well. So if you want to make sure that you start growing your CPF and get your dream home within the shortest time possible, you gotta start investing. In fact, I have some friends that half of their house mortgage is basically paid off by their investment through CPF and that's why this is something that's very very doable for you as well. To invest your CPF, there are certain prerequisites that you need to fulfill. Firstly, you must have $20,000 in your OWL account and secondly, you must be 18 years old and you should not be discharged of bankruptcy before. Once you fulfill that, you can start investing your CPF and here are my recommended ways to do so. The first way is to invest in Singapore listed companies such as the Logo Banks, including your UOB, OCBC or DBS. It's very important to note that when it comes to investing in individual companies, you really want to make sure you understand this company by studying its finances and I personally invested in all 3 banks as well because last year during COVID-19, when the stock market crashed, it really gave me a very very good entry point to buy all these banks. In fact, ever since then, UOB as well as OCBC has increased more than 30% and for DBS, it actually has increased to more than 50%. The reason why I decided to invest in local banks last year was because firstly, these 3 companies are very very stable companies and secondly, they have actually dropped to a price that is so attractive, giving me more than 5% in terms of dividend yield. Although the bank prices have climbed up quite significantly as compared to last year, they are still giving about 3% in terms of dividend yield even at the current price which is not too bad. So if your CPF investment objective is to collect dividends, investing in Logo Banks can be a good option for you. However, if your objective is to grow your CPF much quickly, then here comes my second option. In fact, this is my preferred way of investing my CPF as well. That is, none other than investing in the US index, S&P 500 which can give you a very very safe 10-13% return year on year. If you see how S&P 500 has performed over the years, regardless how many financial crises we have encountered or how many pandemics we had before, the market just kept on going up and up due to inflation as well as economic development. In fact, just for the past 5 years, the S&P 500 has actually gone up more than 100% giving you a very decent annualized return of more than 15% year on year.  Which is way better than your unique trust of course. So the question is, how do we invest in S&P 500 using our CPF? The truth is, you can't. You must be wondering, Chloe, are you kidding me? Why are you telling me something that I can't invest in the first place? Chill guys, chill. Investing is all about being chill and make money peacefully because I haven't completed my sentence yet. You can't exactly buy S&P 500 ETF directly using your CPF because the government just doesn't allow it. However, you can invest in unique trust that basically buys into funds that tracks the S&P 500 index. Wait, before you show me and talk about Chloe, why are you telling us to invest in unique trust that charges expenses fees again and again? Chill guys, chill. Most people invest in unique trust and the reason why they don't make money in fact some of them even lose money after years is because indeed, unique trust that you buy from your banks or your insurance, they tend to charge you a lot of fees. Sorry bankers or insurance agents, if you are watching right now, I am telling the truth. So it actually really frustrates me when people just keep on buying unique trust or investment link plans without even bothering to invest on their own which they can do so much better. But guys, this unique trust that I am going to share with you right now is not the typical unique trust that you know of because this fund charges very very minimal fees. The fund is called Infinity US 500 Stop Index Fund and you can see that the expense ratio which is the management fee is only 0.7% which is way lower than most of the unique trust recommended by your bankers or insurance agents. Besides, when you are investing into this fund, what the fund manager does is basically just buy into the current S&P 500 holdings and that's why you can see that in terms of the holding, both of them are very very similar in nature and because the fund manager doesn't need to do much to be creative to give you a higher return and that's why they charge you very very minimal fee because they just need to track the index and obviously there's also no better way to invest your CPF than to buy into an index that has a long track record of growth. So how exactly can we buy into this Infinity 500 using our CPF? Simple. All you need to do is to buy True and Taoist which is a fintech platform that allows you to invest your CPF money as or as cash in fact as of January 2020 and Taoist is the only platform in Singapore that allows you to actually use your CPF money to buy into Infinity 500 fund and on top of that it actually can help me to buy into this fund automatically every single month so that it can do dollar cost averaging without worrying too much about how the market is going up or down because if you are not good, you cannot time the market and that's why why bother timing the market? Just keep on buying every single month to compound your wealth and later on I'm going to share with you how can you actually set up automatically for yourself just like how I do for my CPF investment portfolio. Before I navigate through the and Taoist platform with you, I just want to say that I do not invest my cash True and Taoist because I know I can definitely make better use of my cash using options which is a very powerful vehicle that I have been personally using for years to compound my return way better. So if you want to learn about my secret option strategy which is called Kuditaiji, a very unique Japanese technique that can help you to compound your $50000 into a million dollar in about 10 years time then make sure you check out the video over here. So now I am going into the end our platform so that you can see how you can set up step by step and start investing your CPF. Before that definitely you do need to open an end ours account so all you need to do is go down to the link below okay to open your account and you actually will get a $20 free credit when you actually invest your first $1000 so all you need to do is to create an account if you haven't and just click this create account and you just log in create using your email address and everything so I personally have already created so I'm just going to log in right now. So as you can see immediately what is my portfolio return because I only started investing my CPF True and Taoist just last month and that's why right now you can see there's certain losses about 3% but I really don't care so much because once again when I talk about this dollar cost averaging it's about long term and long term the US economy is going to grow further as well do you agree and that is why you don't have to be afraid of short term volatility. In fact right now with the reason pullback I actually want to fund my account even more I really just want to make sure I captivate the current great opportunity that the market is giving me so today in fact I want to transact another $15,000 of my CPF and invest True and Taoist to the Infinity 500 so how can you do that if it's the first time of you logging in make sure you just click over here under invest all right and right now what I can do is under invest make a one time or recurring investment I'm just going to click it so what I need to do is I click add new goal right and very importantly over here instead of a selected advice portfolio which this is something that I don't suggest you to do you just really just build your own fund through the US of infinity 500 so what I can do right now okay over here I will just choose this choose this under fund smart all right and you can you can see that you can use CPFOA as well as well as SRS if you have all right so I'm just going to choose CPFOA and you can see fund smart 2 and I will just rename it fund smart SP 500 so that you will understand that I am investing in infinity 500 all right so what I can do is it's a mid to long term kind of investing and I'm selecting CPFOA all right so you can talk about your risk loss tolerance should be quite high all right because actually the risk is very low but you just make sure that you write it high so that they are willing to let you invest so right now you just scroll down a little bit can you see that over here there's lion global infinity us 500 stock index okay all you need to do is to click this you check this all right and then you confirm by SMS all right so what is our fund selection you want to make sure you find this 500 you just click in 500 here just click infinity us 500 and 100% because our 100% of my portfolio of our investment portfolio in CPF I will use this to invest 100% into this fund that's what it means all right so after that what is my investment amount actually right now I want to invest another $15,000 because I really just want to make sure I use I use this chance to invest more average is about 8.29% with annual fees 0.7% really cheap as compared to investing in any other funds or ETF and and long term you are going to make money in my very safe manner all right so and roughly you can see what is your return is going to be like if you just continue to do dollar cost averaging like I mentioned earlier and now you can see the top 10 holdings all right which is similar to S&P 500 because basically this fund just tracks the index which is exactly what I want I don't want this fund to be too creative and invest in something that I don't have confidence in and in fact this is the top 500 companies in the US very stable and they are going to continue to grow all right and that's how you can see Apple, Microsoft, Amazon, Tesla, it's all inside Google it's inside which is I'm happy right you can even see sector allocation 24% it's in technology and then financial services including your banks like JP Morgan, Bank of America is about 13 to 14% there's healthcare as well so you can see that it's a very diversified portfolio so this is what I really like about investing our CPF in a very safe manner and as you can see the annual fee is only 0.7% and if you use my referral code right now you actually get $20 discount from your management fee which I think is great and you can see all time it has been just keep on going up and up and this is basically S&P 500 return if you invested since like 10 years ago it's like close to 300% return so which is very good now all I need to do is confirm by SMS okay both created no further action so you can see that it will automatically draw funds from your CPF OA account to execute this so it will take about four to five days and later on you will see your portfolio start to have this amount of money invested and you'll be able to track your portfolio performance okay all you need to do is go back to your dashboard and you can see that right now it's underpending okay if you want to cancel it for sure you can but definitely I will not this is a great chance all right and you can see that I just started this like last month yeah so because I just got to know about this last month from a very good friend as well as my investment mentor Pete and he's the one who actually shared with me this and I really want to share with all of you so that you can start taking action the right way and right now I just want to share with you how can you set up recurring investment to do dollar cost averaging so you go back to invest again and you can see that over here under invest you can actually make recurring investment so what I can do is right now uh under the thing that I have already created just now so what you can do is over here I just click back and I just want to make sure I set up recurring investment every single month to do dollar cost averaging so you can click recurring can you see that all right and you can select every one day of the month so I just want to set it okay so you can set 500 up to you you can set thousand dollars up to you and yeah then just continue some confirmed by sms you are able to set up recurring investment into your uh infinity 500 funds as well that's it you are good to go congratulations to taking your first step and start investing your cpf safely and profitably one more tip before you go this strategy for it to work you really must adopt a long-term investing horizon and that is why you should not expect a lot of profits within the next few days or even the next few months however with patience your portfolio will definitely grow because with time that's where the compounding effect actually happens if you still remember just now I talk about I use my cash to invest using options to accelerate my return and if this is something that you want to learn for yourself as well make sure join me in my upcoming options foundation class where I'll be sharing with you three powerful options strategy for you to profit regardless of the market condition all you need to do is to click on the link below and register your free webinar so do you want to kickstart your cpf investment journey if yes leave it in the comment section below and let me know what do you intend to invest with your cpf and if you find this video helpful remember to like as well as share it to more of your friends so that more people can be inspired to start investing the safe way lastly remember to subscribe to my telegram because I constantly share about my investment updates over there as well with that happy investing and I will see you next time mother likes you bye bye


Today, I'll be talking how we can search for a lot of different languages on your mobile phone very efficiently. And I think I was just introduced, but to reiterate again, I was from NUSCS 2018, so my junior back just graduated. I'm currently an iOS engineer in labs, and you can reach me at this email address. So without much further ado, I will talk about what are the things that I will go through today. So three very quick things. I would introduce you to the full tech search in SQLite, which is a very powerful tool. And after that, we will go on to try to build our own advanced tech search engine, like going beyond what the scope of conventional search engines will do. And finally, at the end, I will give you some tips and tricks in engineering search user experiences. So the first question might come to you is that why do we want to search on mobile devices, right? So increasingly, security and privacy is becoming a larger problem nowadays. A lot of messaging apps now are having end-to-end encryption, and a lot of people prefer whatever they store to be on the device themselves. And also, it will allow you to do whatever functions you have when the user is offline, or just because he's offline, you can get much faster results than if it were to be online. And also, just because we can. Nowadays, phones are so much more powerful. The iPhone 11 was just released, and the new A13 chip is very, very powerful. So with this, I'm working on this product in SQLite C Talk, and it's a messaging app. And so that's why all of these things come into question into our product. Just a small disclaimer, so most of the results I presented today will be like results from my own research, my own firsthand research, and of course, it would not be the best way of doing things if you have better way, feel free to reach out to me or suggest in the Q&A. And most of the ideas I present in this type will be universal, but I'm using Apple's standard library to give you some examples because they are very complete and it's very useful for you to build mobile applications. But of course, all of these things are generalizable to Android because in C, we also have Android team or web team. So all of these features that I will be talking about today has already been presented with our Android team and our web team. Yeah. Okay, so let's go straight into SQLite. And I know that in the US, people don't really talk about SQL a lot. If you only do like the very basic SQL module, this is what all they teach you inside the module. Basically, just do a SQL query, select from this table with a light query with the percentage match on both ends, which allow you to search for everything that matches this particular query. But this is very, very slow and inflexible. So starting from version 3.24, SQLite actually has this feature called full text search, and the latest version is FTS5. So what is full text search? So full text search, as the name implies, it allows you to search for a piece of text in the large document. And a lot of features come out of the box in SQLite, FTS5. There is full text search, of course. There are custom tokenizers to handle different language. What tokenizers are I will talk about later on. And it has a very simple syntax. So let's say if you want to create a table, that has FTS5 by default, you can just call this very simple create command code, create virtual table message using FTS5. And you can specify your custom tokenizer down there. And the searching for the text syntax is also very simple. You can just select from message where content match. And as you can see down here, this is the asterisk, means that this search for a prefix of full. So everything that starts with full will be returned as a result. And there are many, many other kind of syntax that you can search for prefix, you can search for plus. Both of these has to appear in the same, or they near each other, like a near query. So it's very, very powerful, or n or not. So the FTS5 syntax is really, really, really powerful. And there are a lot of other nice things that come out of the box as well. For example, they come with a suite of default tokenizers. So what are tokenizers? Tokenizers are just functions that process your text and turn them into searchable entities. So for example, FTS5 comes with SCPorter and Unicode 6.1. So for ASCII, basically it's very simple. You just convert everything to ASCII, like let's say in French or in some other languages they have those funny signs on top. It will already be removed. Or for Porter, they will try to stem, so some of you who have done information retrieval or some machine learning algorithm, you might know Porter Stammer. So let's say convenience can match convenience or inconvenient or it's just a stemming of the word. And Unicode of course is to handle a lot of other languages out there. And there are some other utility functions, like for example, highlight. You can select highlight where content matched this thing. And on top of the results that is returned to you, it also surround the search result with whatever things you specify in the query. So let's say I put in like an XML tag of HL for highlight and then the results that return to me will contain all of the matched queries surrounded by the text. So it's very, very, very useful. However, today is not a ceremony about FTS5. So we will just talk about its benefits and also trade-offs. So what are problems with FTS5? So first thing first, I'm an iOS developer and the default SQL-like version that's shipped with iOS is does not support FTS5. So we need to add a custom version on top of that. And the other problem is that the only data type that is allowed is text. So if you go back to a few slides here, in the create virtual table, if you see, if you know the SQL syntax, usually you have to specify what is a data type, like an integer or string. But over here, we are not allowed to specify anything. Why? Because the only supported data type is text. So sometimes if you want to sort by timestamp or sort by some other arbitrary ranking, it can be very, very difficult to do so. And other language, for example, let's say the default Unicode 6.1 tokenizer, surprising that does not support Chinese or Japanese because most of these things, let's say here I have Ni Hao, Shijie. And then if I search for Shijie, it actually doesn't give me anything down here, no much found. But if I search for Ni Hao, it actually gives me the result. Why? Because it actually search for the prefix over here and because there's no space between these Chinese characters. So it recognizes this thing as one entire word. Yeah. So that's why it doesn't work. And for Vietnamese as well, like Xin Chao Tazer, there are some characters that, for example, this one, when it translates, this one, it will not match this one because the E with the cap on top does not match with this E. But however in Vietnamese, we usually consider these two as usual when we try to, as similar when we try to search for these things. So it is not very powerful. Yeah. So here are the challenges that we face in having FTS5. But it doesn't stop us there. There are a lot of cool things that we can do on top of FTS5. But before I talk about how we address the challenges, let's go into tokenizing a little bit more. So okay, why is tokenizing? I only went through briefly, but tokenizing, let's say, how many tokens are there in this text? Can anyone tell me in this particular text how many tokens are there? So yes, it's nine. So each one of these one is a token. How about this one? It's actually eight because the my token in the is token is repeated twice. So each of these one will regard them as similar. Yeah, because when we tokenize this string, we only mark what are the tokens that are present in this world and then where they are. So how do we split this thing in tokens? Do we simply do this? You just split by a regular expression of string. So as all things goes, it's not so simple. So let's dig deeper into the problem. So what is a string? Has anyone been taught in school what a string is? Can anyone tell me what a string is? Actually, that's a smart answer, yeah. But because the real answer is that depends on which programming language or framework we are talking about, they have a very different set of definitions about string. So let's take a look at this string, okay? So what's the length of this string over here? And if you ask a lot of different language, they will give you, each of them will give you a different answer. So let me just fire up a very simple demo over here. Wait, this one is, and then I need to drag this thing over. Okay, cool. This is too dark. Anyway, I just, so let's just ask node, okay? So let's just open node and we paste, I'll just go back to my slides and copy that. Yeah, sure. I increase the font size when I go back to the terminal. Whoops. Sorry guys, I'm trying to search for the text. Let's increase the font size a little bit. Is it being enough for everyone? Okay, let's try this one. Okay, when the moment I paste into the terminal you see something fishy going on. So if I ask what is the length of this string, it will tell me 17, yeah, for this string. And I wrote a very simple C program, string.length.c. That just print out this thing.  Yeah, so very simple program, right? Declare a string, print the length, and then I just execute it, string.length. Yeah, it will return me 31. Yeah, so very funny. Let's look at Java, okay? Let's look at Java, string.length. Okay, 17. Same as our friend, node. So final thing is Swift. So what does Swift say? So I just increase here, font size a bit. And Swift says seven. Yeah, which is the correct answer if you look at it from a human perspective. There are one, two, three, four, five, six characters in this token. So let's go back to our slides. Yeah. So each of this language will give us a very, very different answer for each of this one. And for us, just nice, Swift gives us the correct answer and I will base on this thing for the rest of this talk. So why seven and why other languages return different results? It's because Swift characters are grapheme clusters. So this is a very loaded term, but to think about it, a grapheme cluster is just basically a human perceived character. Yeah, for other languages, they might use UTFAs encoding and then they will count some code points and for C, they will count a number of bytes. So it will give you a different result. Yeah. So let's go in to try to decompose this string. Ni hao, wu jia maing, wu, tokenai jing, gu, gai, suki desu. Ya, lu, blu, jia, zheng, Swift. So there are four languages in this text. First is Chinese, is Latin, there's Japanese, and there's Russian. So let's talk about how we can tokenize this thing. So for Chinese tokens and for, there's one character for token and there are no space between them. For Latin-based languages like English and Russian or Cyrillic in general, they will have multiple characters for token and they will mostly separated by spaces or punctuations, whereas Japanese token, so this is an alphabet called katakana, which says tokenizing, which is a borrowed word from English. So actually this one should ideally be considered one single token. However, for the rest of the tokens like gasuki desu, it should be either kanji or hiragana, it should be treated as sim to Chinese. So at this point in time, you might ask me why do we support so many languages, right? So it's just because we are in a very unique region here, we're in Southeast Asia and we have a lot of different languages around the region. It's not like in US where you can just get away with one single language. So let's talk about how we are going to tokenize this thing. So this is just a brief outline. I will go through with you later. But, and this strategy will not work with all languages. It only worked for the languages I just showed you in the previous slide. Yeah, so the first step is to separate potentially single character tokens from the rest. And you can look at this very loaded regular expression. Basically it will check for all Chinese, Japanese and Korean characters in the text. And this regular expression is very, very powerful. Basically just, yeah, just check all these characters that belong in the Han, the Hiragana, Katakana or Hangul group inside of the Unicode blocks. And in each of these token will be captured as one. Whereas for the rest, we'll trip or die critics, convert to lowercase or uppercase depending on your preference and split by whether they are letter. So this is very loaded. Let's go through them one by one. So first one, let's split out all the things that are Chinese or Japanese or Korean. So each one of these will be marked out and we'll regard each one of them as one token. So that's all good. For the rest, let's trip or die critics. So what are die critics? So if you look at this is Vietnamese text and it is a French text and you have like those squiddling marks on top or below. Yeah, so basically stripping or die critics meaning removing all of them. Yeah. And the next step is to convert them to lowercase, uppercase. It depends on your preference. Over here I use lowercase. And so finally we have to split by whether they are letter or not. So why can't we simply split by spaces and punctuations? Why? It's because space and punctuation is too general, right? In different language, they have different spaces and different punctuations. For example, the Japanese space is different from the English space and the Japanese comma is different from the English comma. But even if we know all the sets of spaces and punctuations we still shouldn't split by spaces or punctuations. Why? Because of emoji. Yeah. So even if you split by space or punctuation, you'll see the la and the smiley face will be considered as one token. So basically we have to go through each character and ask them are you a letter or not?  If you're not, then we'll go. Yeah. And in Apple standard library, you will have a very powerful function called East Letter. It was just recently introduced, which is very powerful. So even if you ask it for Arabic characters or like Russian characters, it will just tell you yes is a character. But for any other things, it will say no. So that's why I really like working with iOS libraries because of that. Yeah. So let's talk about how we can bring this tokenizing behavior into FTS5 in SQLite. So SQLite support this thing called custom tokenizer where we can put in a custom function into SQLite and tell us, hey, don't use your BDFopt behavior, use this one instead. Yeah. And it's actually a C API. So you can see like all the const jar and everything down there is very low level. Here, there's a constructor, destructor and the tokenizer. You don't have to care about all these things. The most important thing you have to care about is the tokenizer function. So if you see over here, yeah. So this one is the full text that is passed in into you. And then this is the, all the charges number of characters. And here is the callback function that you're supposed to call in FTS5 to tell them, hey, this is the token. So the callback function takes in the string. Let's tell him, okay, this is one token. This is the length of it. What is the position in the original string? And what is the end position in the original string? So you just call this function in terms and then you can tokenize your text by yourself. However, the SQLite is in C API. So for Android, you can use GNI. And for Swift and Objective-C, actually Swift and Objective-C can interface with calls, with C calls natively. So we don't really have a problem. But in my app, we actually use this framework, GRDB, which abstract a lot of these things out to very nice Swift functions that we can call. Yeah, so if you ever need to do this thing in your own project, you can look at GRDB. And last thing we want to talk about is the sorting of the text type because sometimes, actually most of the time, the virtual table is of text type and we cannot sort them fast enough. So what can we do? So in FTS5, we have an extra feature called the external content table. And what it does is that it links your FTS5 virtual table with an ordinary SQL table, yeah. And you can see here that you can create two tables together and then you link them together using triggers. So every time you add one column to the external content table, it will also be indexed inside the FTS5 table. And they are linked together by this unique default column called row ID. So this one is not what we create, but it is created for us by default for SQLite. So these two things is how they know that hey, these two columns are the same, yeah. So having this external content table, you can finally query for your results. So this is usually what people will do. They will select from the external content table. It will join on the message table and where the row ID are equal and we will search for the content where the content match the query. However, this is very, very slow. This is around 0.3 seconds for 100,000 matches of the query. That is very slow by our app standard. Imagine having to stop for one second before you receive your results. So actually there's a better way of doing this. You have to force the index of the table. So here we're trying to sort all the messages using timestamp because I want the latest message to be on top and the very old message should be below. So to force the index, you can just say index by this thing and it's automatically three times faster, yeah. So why is this so? In SQLite or in any other SQL language, you have this thing called the query plan and you can pass in explain query plan followed by your query to ask it, hey, how are you going to perform this query? And it will tell you what a step it goes through to perform this query. So if you look at no index forcing the query plan, it will scan the message table first, which is the virtual table. After scanning it, it will try to find everything that have the same row ID and then it will construct a temporary B3 in memory to order the string. So it's very, very slow. However, if you force index, it will sort on the external table first and then it will do a sub query on the message table and then it will return out the result and that's why it is so much faster. In our research, we also do other optimizations, but we found out to be slower than this one. So that's why we didn't do it. Yeah. So yes, that's a lot of information about SQLite. I hope you remember this. If you don't, just talk to me sometimes if you want. Okay, let's move on to the second section of today, building a custom search engine. And what are the challenges that we face in Sitot that prompt us to build this custom search engine in words? Because first thing, all the messages are securely stored on the device only and all the messages are wiped on our server as soon as they're delivered to all the intended recipients. So that's why we can only do all these sort of things on the device. And a few months ago, there came a new feature called Global Search in Sitot. So what Global Search means is that it matches everything within the app. You can search for messages, you can search for contacts, you can search for groups for everyone, it matches everything. And the second requirements tells us that we have to highlight all the partial matches. Let's say if I search for V, then only the V will be highlighted, not VU. Yeah, it's actually harder than it sounds. And there are different matching strategies for single and multiple token queries. Like for example, if you type in one single token, let's say VU, then it will match as a substring. But if you say like ANG VU, like two tokens, it will only match by prefix. Don't ask me why, ask my project manager. Yeah. So very weird requirements. And down the line there, okay, let's just talk about this first. So basically if you, okay, it's a little bit small, but here is ANG. And for the single token case, it will match substring. And for the multiple token case, it will match only the prefix. Yeah. And, okay, let's skip the details. Let's go. And a very big feature that came out just two months ago, I think, was pin-in search. So what is pin-in search? In other C offices, there are colleagues who put the Chinese name only in the app. And other colleagues in the same office, they don't speak Chinese. So there's no way they know how to pronounce this people's name. Even they know like, hey, this guy is blah, blah, blah, but they don't know which Chinese character it is. So one of the features that was requested was that we given a pin-in pattern search for the corresponding Chinese name. As you can see here, my colleague, okay, every name or my colleague's name to some weird characters, but it is Lachi Chensang. And then if you say Chensang, it will like flesh out this guy. Yeah. So this is one of the requirements. And it is not as simple as it looks. But let's explore how we can address this problem, okay? So in Swift, we have this very cool API called Applying Transform. And basically it is available in the default library. You can just apply transform mandarin to Latin and you convert this Chinese string to the Latin text. And later on, you can strip the diacritics as well. And then it will turn it into a very intelligible string down here. For Android, you can use this library called Tiny Pin-in. That's what our Android guys in the company is using. Yeah. So switching transformation can work very well for other cases as well. Like you can, you know, transform other languages as well, just as a site. And from here on, it will get a little bit technical. So bear with me for a while. So inside our search, we define a object called the token. So like I said, each token object will represent a unique token in the original string alongside with all the alternate representations of the token. So what are the alternate representations? So for example, let's say this Swift code, but you can understand it, I hope. Yeah, so I have a struct called token. I have a string which is the original representation. I have all the alternate forms of the token. And for each of the alternate forms, we match it. This is the dictionary. It matches with a match type. So it can either partially map to a string or wholly match the string. And for example, here I have this big token. And this is a English text. So it will partially match another string. For example, big will match bigger and ambiguous. But here, for example, here's a Chinese token. It's called ta. So ta, when you translate it to here, you shouldn't make it a substring search. Yeah, you should only match this token wholly. You shouldn't match it as a substring. Because imagine you type in some Chinese character and it matches some English guy's name. So that's why we don't do it. We define it in such behavior. Currently, the way that we do it in our app is very dumb.  So it's a very naive token matching algorithm. So why do I talk about this? We are talking about efficient matching right now. So I'll talk more about how we can improve this case later on in the slides. But let's just move on to solve this problem in its entirety first. So the next step with the problem with the current tokenization is that if you write the Pinyin without spaces, there's no way we can know where we can split the Chinese characters. For example, last time I have a friend named Yan Gen. But a lot of people call him Yang-en.  And for the search as well, for example, if this is a query, it cannot split. It doesn't know where to split the token so that it can match up with the text string. So here was one of the biggest problems that we have when we try to build this feature. So what I will pre-order is this thing called reverse prefix Pinyin matching. So now the text becomes a pattern. We reverse the roles of the two entities we're talking about. So let's say if you're trying to match Lajie Shen Chang with this text, then we'll turn it around. This one becomes a query and this one will become the text. So all this thing here is just a steps but I will explain to you one by one. Okay, so let's say this is now our text and this is our query. We'll turn the first character into the Latin form first and we found out that the prefix of these two match. So we chop up this one and we recursively match it down to the last character. And when we end up into our base case, which is when the query string is with empty, then we know that it is a match. Yeah, so this is how we do our reverse prefix Pinyin matching. And similar to the previous one, it is very, very inefficient because let's say you have N text to match, each text has K, Chinese token and each string matching is OM as best. The best you can do is OM. Then it's OM times K, which is very, very inefficient. So there are a few improvement strategies we have in mind but as with all software engineering products, I have to ask my manager, I have to ask my product manager whether I have time to do all these things.  It's like, no, we have other more important features. So here are just some suggestions. So first thing is that we build a tree, a tri-e that points each token to each of the nodes. So every time you fire up the search, you will do the indexing in the background. Basically, we point, we make a graph or like a tri-e that points each of the token to the intended matching participant, yeah, like the users inside the chat. So here, when you type in the query, you just walk through the tree and then it will point to all of the matching candidates. So this is one, but it's very space-consuming because the space is exponential if, yeah, on a very large database of user names, yeah. So another strategy is just to dump all of this into a SQLite database and let the database does it work. So yeah, this is one of the improvement strategies that we had. There are a few drawbacks to these strategies of doing things, though. So bear in mind that sometimes if you want, you want to translate characters with different pronunciations that you cannot do it. So if you put this string into Swift, it will say Le Bochi, which is wrong. This thing should be Le Bochi, yeah. So that's one of the drawbacks. And another drawback is that it will assume Japanese names as Chinese names. So for example, my favorite character is Conan, Detective Conan, if you watch, is Shinichi Kuro. But then in Chinese, it's Kong Teng Shin-Yi, yeah. So it's a different name, yeah. And also it will, difficult to perform well on Japanese name with multiple pronunciations. For example, this one on the left is Yamada, but on the right is Tanaka. So the character over there, the window character can be pronounced as ta or ta depending on where it is in the string. So yeah, the best way is actually do not assume the pronunciations and tell the users to put in the actual like name there or an alternative Latin name into the database if possible. But otherwise it's a very fun and challenging problem that we come up. So yeah, it can, it can be really fun to do sometimes. All right, so with all of this, all n times m some k algorithms, why not we try to improve our performance? So performance over here in school, you talk about a lot about like O n and how we can make it like as linear as possible, make it O one as possible. But however, engineering is very different. So engineering, we are more concerned with UX, like how users perceive our search performance. It's not how the search is done actually in the code sometimes. So let's explore a few expectations that user might have when they perform a search operation. So first thing is that users nowadays are spoiled by speed and accuracy of Google. So they will expect the results to be among the top five of the return results very, very fast. And sometimes people would like to change the query over going to the next page. For example, if you cannot find what you need, you actually want to type in a different query. You actually don't scroll, scroll, scroll, find your next page or maybe I'm just different. And most people would not go beyond page two. So there's a popular saying somewhere, say everything that lives on page two is dead. No one goes there, no one goes to page two. So these are a few expectations of search that we have observed. And actually these are actually good for us because we can return our results early. If the users only expect the first top five to 10 results to be the best results, then we can always return them first. And then even if other results are required by the users, we always perform all these things in the background and report them later as the users scroll down lazily. Yeah, so that is how we can improve on this thing. Sorry. Let's talk about more aspects of UX of search. So in search, when the user first enters, we need to show something like an initial state for an app like CTOG like us. We have to tell users, okay, what you can search for, right? So we usually show some illustration there and say, hey, these are the things you can look for. And search has to be very responsive, meaning that the moment that you type your query, the users expect your results to return within zero point. For us, we base our research result on 0.5, 0.5 seconds. Yeah, so we also have to indicate whether there are more results. Like for example, if there are more results at the bottom or we are still trying to load for results or empty state, like if we cannot find anything, we need to show them that we cannot find anything. So I will introduce to you this thing called paginated search state. This is not anything that is specific, but you can implement this in any language. It's just a general idea of how I want to show you guys what we do in our app to improve our search result. So basically we keep an array of the current results that we have right now. We have a Boolean flag saying whether we have more results. Well, Boolean flag to say whether we are performing a search. And we have only one function called fetch more results. Yeah. And basically when you execute this one, whatever your search operation might be, it will try to execute that. And wherever there's a result, it will report immediately to the main UI. So basically instead of walking through all the end entries of the text, you can just walk through until you find the first five entries in the text and then you can report them on the main queue. And then you can perform the rest of the search operations in background and report them when you are done with it. So these are very, very technical. I guess I shall not go through them. So yeah, that's it for today. I hope I didn't go through all these things very, very fast. But now it's time for Q&A. So if you have any questions, I can address to you right now. So let's go back there. So talking about the FTS5, so FTS5 is actually very, very efficient already. The problem with this thing is that on top of the search results, we also want to sort them by a certain criteria. In this case, in my messaging app, I want to sort the messages by the timestamp. So because the timestamp is a text, I need to turn it into integer somehow. And that's why I need the external table. The improvement was very simple. Like I only forced the index on this thing. But actually that's a good question because we tried a lot of different strategies. So I can show you another one that we have in here. So this is different slides that I have from my own company search. Because I've been giving this talk for a lot of times. But yeah, so in here, if you can see that, we, when we try to improve on all of this thing, right, we don't just poke around in the dark. We actually look at this thing called the query plan. So you can say, you can input into your SQL console, explain query plan of all this thing and it will tell you like how it's going to do your search. And then you try to look at its strategies. Okay, this one is trying to scan this table first. It's trying to match itself against the other table and then it construct the temporary B3. So this one is notorious because when you try to build B3 or like a sorting tree in memory, it is very, very slow. So we are trying to eliminate this step. How is, we can base itself on the index. So basically the table already had another index that we had beforehand. So when you try to sort the table using the index first, it will not actually touch the temporary B3 to build. Yeah, there is weight. So we actually tried to improve this thing a lot more. Not just, is this, okay, I'm just moving this thing over. Sorry, open this one, move this thing over. Okay, so this is another talk that I gave in my own internal company a long time ago. And we explored another strategy. So, this thing, yeah, this question is taking a bit long. I'm really sorry about that. We have this thing called the, okay, so this is forcing the index. We have another thing called using, we tried to prefix the timestamp with zero. So we tried to cheat it a little bit. You know, all the text, okay, let's try not to use the external table. Let's just append zeros to our timestamp so that now your string sorting is not integer sorting anymore, you're sorting by like string. So you compare each of the character and then if the character is less than that, then it will sort. But this one is also very slow. So yeah, we didn't want to do this. So we explored this new feature in the FTS5 called auxiliary function. Basically, it is used to, traditionally it's used to read how well a query fits certain text. But we can define our custom auxiliary function inside SQL using a C API. And I actually use this thing to turn it into, to use timestamp. So basically, I will just turn the text into UN32 and then I will just bind us in the max because I want the latest message to be on top. So that's why I need to reverse the function. Yeah, and in my initial trials, it is very fast. It's 0.04 seconds. Why? It's because there's only one single query plan which is scan the table. And at first it seems like a miracle. Like this is actually our first prototype. But however we realized later on is that our test database is flawed because when I generated the test database I actually generated them batch by batch. Like when I generated 500,000 messages I actually only generate like 1,000 messages at once. So all of them have the same timestamp. And this becomes a problem because actually each of the timestamp value is only calculated once. So by this method, we've wrongly accused this function or wrongly recognized this function as being very fast. But actually it just has less things to calculate compared to the other methods. But turns out when we create a new test database with strictly increasing timestamp, the forcing index actually works much faster than this one. So after our research, we found out that the forcing the index on the table. But OK, to come back to the question in general, just look at the query plan.  Any other question? I can speak Vietnamese. I mean, great. No, that's a thing. I can speak English. I speak a little bit from French. Je ne parle un peu français. And I speak Russian. Yeah, I can only speak a little bit Russian. I can speak Japanese. I can speak Chinese. I can speak Chinese. I don't know which one. But people, yeah, so I don't know. I cannot count. Actually it's a good thing because when it comes to all these languages, I need to know how they are indexed. So in our company, we actually have Thai customer as well. And no one in our office is Thai. We don't know whether our search on the Thai language is correct or not. But so far, we have not heard complaints from Thai people. So I think it's OK. Just nice to have a new Indian guy. And then we also have a Pakistani guy who happens to know Greek. So basically, currently our search algorithm can work on most of these languages. OK. Yes. So sometimes we will ignore the accent. But when it comes to that, it depends on the user expectation of the search as well. Yeah. So in this particular region, the language that we deal with, we try to strip out the diacritics. But in some other language, when you strip the diacritics, it actually means a very different thing than it is intended to be. So in CTOC, our app, we actually strip out everything so it can return wrong results for that matter. But I think it really depends on your user base. Because if you want to support a lot of different languages, for example, you are building an app in the Europe, for example. And you want to support all those European languages, then you might need a lot of different edge cases to deal with. Over here, just nice in this particular region, we found a set of minimal algorithms to process this text such that we can search them correctly. So I say it's a case by case basis. Yes? So this is more like an engineering term, actually, because this is a protocol. So whatever you're trying to do, you just confirm this protocol. How you return the result is up to you. So in this presented search state, OK, sorry. I need to show this slide on the other side. In this particular search state, we only care about the current state of the search, whereas how you arrive at this search is totally based on you. So it doesn't talk about the accuracy of the search, actually. This one just tells you that if you have a very accurate search algorithms, you can just make use of this framework so that when you first found your first five results, you can just return them immediately. And then you can try to search more for more. I didn't go through this part very in details, because to go through this thing might take quite a long time. If you want to know more about this thing, you can talk to me after the talk. I hope that answered your question. Any more questions? No? OK, so thank you very much for coming today. By the way, just a shameless plug. C is always hiring for interns or whatever. So just come out to me if you want. We need more of you. My team is entirely NUS, by the way.