Page 2 of 3

Story told by an entrepreneur of becoming %1 (Part 1 Story)

The original post is in quora How can one become part of the 1%? where an entrepreneur told his story of making %1 three times and the last time he has been transformed to one who deeply believes in his value and pursuit. The story and lessons inspired me so much that I want to share it here. The post is devided into 3 parts and here is the first part that narrates his up and down along with his enlightment.

Quora is full of questions along these lines, “I am fifteen, I would like to be a multi-millionaire when I am thirty.” Or “I want to be a billionaire when I am at XXX age”, and so on. I get a chuckle whenever I see these kind of questions. (I am 24 years old. I want to be a billionaire by the time I’m 60. What should I do? )

What people really should be asking is that “I want to be rich, what kind of crap and how much of it will I have to take to get there?”

In my case I have done it three times thus far. But there is no short cuts, so unless you find a magical way to win the next lotto, there is no get rich quick scheme here.

There are some real bitter counter to other posts on this topic, most are along the lines of how lucky someone was and so on. The younger, poorer me, or the outsider looking might have agreed with a lot of those sentiments. But having gone through it a few times, I feel like I have a better perspective now. After all, I was desperately poor a few times myself.

I came to US along with my parents as a teenager from mainland China back in the mid 1980s, a time no one gave a fuck about China. Even among the Chinese here in Seattle, we were considered 3rd class citizens behind other Chinese, namely American born ones, Chinese from Taiwan and so on. We had no skills, no money, no connections, but we had our physical labor we could sell. My parents were college professors from China with no language ability and zero business sense. So, no, you can’t accuse me of having some kind of head start in business. They were utterly useless and had no concept of money in this new capitalistic society. They had to work as housekeepers and janitors, starting fresh from the bottom in their 50s. So yes, I want to say a gentle fuck you to all those whiners about how some of the 1% had all the advantages. The only advantages I had was I had my four limbs in tact, and chip on my shoulder.

My first job was at the local Safeway for the simple reason McDonalds turned me down due to my poor English skills. I was sixteen, having just arrived three months prior. I worked my ass off, always looking forward to weekends, holidays, and any overtime shifts if possible so I can earn more. I biked to work in the rain (Seattle rains a shit load), snow, ice, sometimes not getting home until 2am in the morning, and I still had homework to do. I finished 4 years of high school course in 2 years so I can graduate on time with my age group (my high school in US didn’t accept credits from China). I did not want to stay in high school until I was twenty. So I had extra course load too. During this time I worked as many as three jobs at a time. Moonlighting as a clerk at the neighborhood 7-Elevens, got abused at call centers, participated in focus groups, sold plasma to the local blood bank. Pretty much anything I could do to earn extra money. I simply couldn’t understand how kids in my high school could afford to drive cars to school, cars of their own! Needless to say I did not participate in any of the after school activities, nor did I make any friends. I was this nerdy looking Asian dude who wore cheap Kmart and thrift shop clothes who excelled at math (fill in your stereotypes) on campus. I worked, and worked some more. So for those of you who complained that you have to make ends meet to work extra hours and take on extra jobs, I understand exactly how it goes, but you will not get any sympathy from me because the entire time I kept telling myself this is all just temporary. There is no way I won’t get out of the hell hole if I worked hard.

Two years into my Safeway clerk job I moved out of the house because I met my first girlfriend, my parents didn’t approve. I was eighteen. Faced with the prospect of having to make more money to support myself, saving for college, I looked for anything that would pay more for a high schooler. The only thing that paid more than $5.25 an hour was selling.

Like a lot of men, I like gadgets. I was fascinated by cameras. Growing up poor in China meant virtually no one had a camera of any kind. It was a very expensive hobby. I would hang out at a camera stores in Bellevue so I can fondle some of these amazing machines. To my surprise a lot of the clerks knew far less than I did about the equipments they were selling. This made me realize I could probably do their jobs better. So I asked their managers for a sales job. But none would hire me because my English was still not so great, of course I didn’t have any sales experience. The classic chicken or egg thing. I knew I had to get sales experience somehow.

I saw this flyer from Cutco ( Kitchen knives, block sets, utensils) promising that I could make $9 an hour. As it turned out, it was all about door to door sales. Undaunted, I bought the starter knife set and started selling. I found a directory of all the Chinese engineers in Seattle that worked for Boeing and started dialing away. I would make up stories about how showing them knives was for a school marketing project, and assumed they all knew my uncle who also worked at Boeing. Most assumed a high school kid would just be harmless, and some might have vaguely remembered my uncle’s name, but few would turn me down for a house call. This taught me a lesson, if you don’t ask, you won’t receive. I even went so far to ask my uncle to drop me off at some of those “friends” houses so I could do my sales demo. Of course not everyone bought, but the few who did still reminds me to this day just how good those knives were! The company is still around, I saw Costco carrying their knives!

Having had this sales experience in one summer, I used it on my resume and got a job selling cameras in the local camera store. But even this first sales job didn’t come easy. I had to offer to work for free for one month just so I could get in. I told the manager if I didn’t sell as much as he expected by the end of the month, I wouldn’t get the job. I went from Cameras West (now out of business) to Silos (gone too), to Video Only (Don’t Be Sorry… Shop Video Only!). I was always nearly the top sales guy everywhere I went because I spent all of my spare time learning about all the products I was selling. During my off days, I would go visit other electronic stores to learn about the product they were selling. I would linger around other salespeople to listen in on their sales pitches to learn. I hung out at magazine racks at Tower Books to read about product reviews. I simply wanted to know more about what I am doing than the next guy. I learned from early on that solution selling worked. I went from making $5.25 an hour to making $40,000 plus a year in two years. I was twenty.

My job at Video Only also gave me a small taste of entrepreneurism. Peter Edwards, the owner of Video Only instituted a margin based commission system for salespeople. We would all get a computer printout of the “costs” of all the items for sell along with the displayed price on the floor. The salespeople get to decide what the item actually gets sold at between those two data points. By the end of the month, the higher the profit margin of ones overall sales, the higher the commission payout. I loved the freedom this gave me and it taught me how to do deals on the fly. I would later on copy some of this approach with my own employees.

This was also the same time I got really interested in business and finance. I spent most of my “entertainment” money on books. I never partied, I saved whatever money I could so I can buy my first piece of real estate so I can avoid paying rent. I bought my first condo at twenty-one. Since I worked in retail sales and got pretty good at it, it quickly made me realize most the people I was working with were twice my age or older, and I was already doing better than them. The thought of spending the rest of my life on the sales floor made me looking further ahead. If I was going to be doing sales, the only way to “scale” was to move merchandise with much bigger dollar value or speed. So the idea of being a stockbroker or a real estate agent seemed appealing. I got a real estate license but found the pace too slow and boring. So stock and bonds sales it was. But being a minority with no connections (rich friends and family you can immediately bring to the firm) was not so appealing to most hiring managers, not to mention the fact I had yet to graduate from college.

I kept cold calling, pestering the local branch managers of various brokerage houses. Since Seattle is three hours behind NYSE opening time, it meant most brokers show up to work around 6AM. So I would camp out at the lobbies at brokers offices at 5AM in the morning, hoping to improve my odds of intercepting the decision makers. This went on day after day for more than three months. Eventually it paid off, I finally got hired at Prudential Securities by Paul Wonnacott in their Seattle branch. This is the first time I have actually encounter the 1%. Despite the fact stock brokerage was really just a sales job, I tried to learn and absorb everything I could. Finance, accounting, deal structure, annual reports, research reports, most of these were Greek to me but no matter. I read and read some more. I also got interested in technical analysis for stock trading. The early Bloomberg terminal became my best friend. I couldn’t believe how much information I was able to find on this orange tinted screen. In a few years I was making six figures, or by early 1990s standards, I was in the 1% myself. I was proud but also hated my job. I hated the conflict of selling products loaded with fees or promoting stocks that we “knew” the firm had a vested interest in. After all, it was all about selling and not actually figuring out how to make trades and investments. I wanted out and started looking for a reason.

By 1996, freshly married and sick of my job, I noticed online brokers starting to flourish. Considering the fact I was charging clients $110 a trade to trade 100 shares of Microsoft, the online brokers were charging $20 a trade, I thought my business as a broker was going to be toast. Besides, at $20 a trade, it was cheaper than the $50 a trade the firm charged employees. I finally saw the chance to leave and trade for myself.

I quit my job by late spring of 1996, but all I had was about $20,000 liquid cash to trade. The first 6 months was a disaster, I lost nearly all of my $20,000 on stocks like Ascend, Shiva and a host of other bygone tech stocks. I had to drastically scale down my lifestyle and asked myself if I was really serious. In order to trade out of my hole, I needed more capital. I maxed out all of my credit cards for cash advances. Fortunately, the market turned and I recovered my losses and some. When all said and done, I had $50,000 to trade. But I knew I needed a plan to make it. I set a goal of making at least $100,000 a year to justify what I was doing. That meant making at least 200% a year from my then $50,000 stake. It seemed almost impossible.

After some calculation and observing what I did wrong I came up with a simple plan. It would be impossible to look for stocks that can double or triple in a year without major downside, these kind of stocks are volatile. But there are plenty of stocks that moves more than a few percentage points a day, if I can capture just a chunk of those movements I didn’t need to hold stocks overnight. Since there are more than 200 trading days a year, it meant 100,000/200=500, or roughly 1% return a day on my $50,000 stake. This was entirely doable. The key would be to contain my losses. For those of you who knows trading, this is day trading in its essence. And off I went. By the end of 1996 I was up more than $100,000, I reached my goal.

I know it sounded easy, but it wasn’t. This was during a time when I was dealing with slow dial-up 14.4 modems (it drops in the middle of trading day all the time), multiple CRT monitors crammed up in a small room while running multiple servers, temperature routinely ran up to well over 100 degrees, but I didn’t care. I was a man possessed, sleeping on 3-4 hours a day while pouring thousands of charts daily, surfing message boards, reading floods and floods of news, gossips trying to gain any kind of edge. It was a daily battle of my own internal greed vs. fear, but I was loving it because I felt I could conquer the market (famous last words for sure).

A year later I made more than $500,000 and never looked back. Yes, I was back in the 1%. And this is also where things got crazy. Since day trading only occupied a few hours in the morning (Seattle is 3 hours behind NYSE time), and I was done usually by 10AM, I had plenty of time on my hands. I started shopping out of boredom. I bought multiple cars, houses, my expenses quickly got out of control. Pretty soon I was feeling like a slave to my purchases. The monthly fixed cost to my lifestyle was $50,000-100,000. For a day trader starting fresh everyday, I started to feel like I had to make certain amount just to stay afloat. I was not even thirty at the time. My mood was no longer upbeat, I was angry at myself and took out on people around me. I was this raging asshole because I was so full of myself yet I couldn’t figure out why I was so unhappy. I heard this line from someone, “having money merely unmask the real person”, in my case, it unmasked a terrible individual. Despite the fact I reached my goal I had nothing but an empty feeling inside.

I had to find a way to scale my trading to pay for my now lavish lifestyle. So I went back to do what I hated, namely going after other rich people to raise funds for my hedge fund. I wasn’t particularly good at networking (hard to do when you are an obvious asshole), the fund got started with a very small pool of $10,000,000, a good chunk from myself. I struggled to trade under the nagging of limited partners, I hated it. I felt like I was being watched all the time, my trading suffered. I could no longer do the same style of trade I was used to, the returns lagged and I started to feel really depressed. I went through a couple of years of depression, spending days doing nothing but staying home and browsing online. My marriage suffered. I blamed my spouse and her extended family for being greedy and always wanting more from me. Even the arrival of my son didn’t cheer me up.

Due to my underperformance, people started to pull money out. It compounded to me starting to trade recklessly. I no longer had my old discipline of risk management, it simply went from one Hail Mary trade to another. By 2003 I was insolvent. I burned through all of my capital while still stuck to multiple homes and other obligations. I gave my wife the bad news and she spent days crying. I thought my life was over. I tried to kill myself.

Looking back, those were pretty dark times. I was completely alone with no one to talk to. Since I alienated everyone around me for a long time, it was now up to me to pick up the pieces. I still remember quickly packing up our belongings from my “mansion” to move into one of our much smaller rental properties one night so the neighbors couldn’t see me leaving. I felt so ashamed and desperate. The mansion had a mortgage, I let it slide into foreclosure, and for the next several years I had to learn how to dodge calls from debt collectors.

Eventually I came to the conclusion that hiding, feeling sorry for myself wasn’t going to solve my problems, I had to get up and look for something constructive to work on. By now we had to depend on my wife’s income to support us. Gone are the days of $1M plus a year income, say hello to $70,000. Also gone are all the fancy cars, unnecessary spending and vacations. My mental attitude started to get hardened again. It was time for me to get out of the house and work. I joined a tech startup in 2004 as head of sales, after all, I could still sell.

The startup had no real funding, it was started with less than $50,000 seed by the founders. When I joined, there were all of only two founders left. It had no real customers since it had no revenue. We worked out of a warehouse in Southcenter, an industrial area south of Seattle. It was actually worse than a garage, the constant noise of trucks coming and going made it difficult to even conduct phone calls. Whenever a customer or a prospect asked about the noise, I would jokingly tell them our business was booming since they can obviously hear all the commotion from the loading. I devised a plan to generate revenue anyway we could. I went around the country on sales calls, traveled to China almost monthly dealing with vendors and partners. Since there was only three of us, I did sales, business development, accounting, finance and marketing.

Chronically short of cash we were constantly juggling between which bills to pay first. We tried outsourcing part of development to China, then India, shuffling between different vendors, chasing after deliquent customers constantly. It was stressful and exhilarating at the same time. I had to learn all kinds of new skills on the fly. I went through silly books like “The Portable MBA”, “Dummies” series of books on using Quickbooks, accounting, finance and so on. I felt like a fraud most of the time because so many things I was doing was new to me. But what choice did we have? In retrospect, a lot of the things we did were absolutely correct, at least based on the The Lean Startup: How Today’s Entrepreneurs Use Continuous Innovation to Create Radically Successful Businesses: Eric Ries: 9780307887894: Books

In our first year we had revenue of $500,000, the next year we got to $2M. It was during this time I took over as the CEO since I came up with the plan and direction, generated all the sales. The business grew to $3M by 2007 and we thought we should be able to raise venture capital. Unfortunately no one in Seattle bought our story. All three of us are older when compared to the twenty something startup guys. None of us had a computer science background, as a CEO, I was the least presentable. A college dropout without any experience in the tech space. Despite the revenue, we were unfundable. The VCs in Seattle are about as WASP as they come, but they did point out flaws in our business. One of questions the VCs asked over and over again at the time was: what unfair competitive advantage did we possess. I could never give them a straight answer because we didn’t have any differentiating IP, but even if we did, it wouldn’t have mattered. In was only in hindsight now that the real answer was that we had heart.

It was during this fund raising process I really felt insulted. We would present to “Angel” investors, which often times made of people who got lucky to be some of the earlier employees of successful companies such as Microsoft and Google, or they retired as wealthy corporate executives, doctors and so on. Most never ever ran a business in their lives, most carried this entitled arrogance. One of the investment groups is ZINO Society, we presented while they were wining and dining away as a social club, I really felt like cheap entertainment on the stage. I vowed that if I ever make it big, I will do everything I can to change how startup guys are treated, we are not in medieval society with overlords anymore!

We were raising funds to find a way out of old business model, which is to develop technology to sell to OEMs (basically companies with their own brands and products). Our customer would package our technology and sell it as if it is their own. We discovered over time that we were getting $50-60 per license for our product, when it is all said and done, the end customer actually pays anywhere from $1,000-10,000. Sensing the old business model was running into a dead end, we felt we needed a change. Despite not being able to raise VC funding, we decided to pivot by 2008. This meant building out the rest of the product features and market it directly to the end customers. In business jargons, we want to climb the value chain. What it also means is that we are no longer competing against companies doing $50-100M sales, but billion dollar companies instead. This would require us building a comprehensive suite of products, integrate it with enterprise grade hardware, be responsible to deploy, service and support the product. It is utter insanity if I tried to convince investors that a dinky little company with no prior experience, no direct relationships with large accounts dare to pull it off.

Our timing was horrible. Walking away from $3M a year business while trying to build a new one with little funding was more wishful thinking than anything. We also had a dozen employees to feed. The founders and I never took a salary because we needed to reinvest all the cash back into the business. This was a real stressful time. My marriage went down the toilet. Not earning an income from me for 5 years changed the dynamics of my marriage. I was no longer the “man” of the house.

The world nearly came to an end by 2009. I had no income, the pivot wasn’t going well because new business didn’t pick up fast enough to offset the lost revenue from the old business. The market and the economy came to a halt. Something has got to give, as it turned out, it was me. Adding insults to injury, our largest customer owed us a pile of money, instead of paying, they decided to find an angle to sue us. It was such a shock and totally out of the blue, my partners and employees were in denial for several months. We tried to dodge the subpoenas, tried to reach out to the customer to try and resolve the issues, but it was clear this is the dirty business tactic they decided to employ to get out from paying nearly a million dollars they owed us. I thought I had read and experienced enough with some of the unsavory aspect of business, but this was a new low. You couldn’t help but feel the unjust and get all raged inside. With the lopsided liability from the lawsuit and dwindling prospects of the old business, it would have been really easy to simply fold and shut down the business, and we did entertain that prospect. But I simply couldn’t let this stand. I am a fighter, I will not go down without a fight. We counter-sued.

With legal and business troubles piling, I got divorced, laid off most of my staff. With my divorce finalized, I was back down to $20,000 in the bank. But I had to fund payroll. I was also kicked out of my former home. Not wanting to spend money on rent, I moved into the office broom closet with an air mattress (the picture below was taken using a fisheye lens, a lens with a normal angle of view couldn’t capture the whole tiny space. My head was against the other end of the room).

To make matters worse, we were late on our office lease, got cut off from our vendors and owed the bank a pile of money. The legal bills were piling up fast. It felt impossible. I finally hit bottom again. I was broke and homeless.

There were days when my then 6 year old son came to visit me in the office, knowing full well that I lived out of the office broom closet, yet the little boy never displayed any shame or embarrassment, it was as if he knew I can work my way out it. How could I possibly not be motivated if my little boy is unfazed?!! Of course we couldn’t help but turn a bad situation into something fun, so we would bounce up and down on the air mattress just goofing off.

Living out a tiny space with a few possessions makes one realize just little material things matters, I felt like a child again, my head was clear and uncluttered. My employees knew I was living out of the broom closet but no one talked about it, life and business went on as if nothing is going on, even though the whole financial system was in a train wreck. I kept telling everyone day after day just hang in there. In business, success is all about survival. We have to do anything we can to just not die!

It was obviously a dire situation in my life and business at the time, but the funny thing is that I wasn’t sad or angry. I actually found my situation comical. I had always bragged to others that I came from nothing and I wouldn’t be afraid to go back to nothing. I got my wish, now what? I knew I couldn’t stay in the broom closet for too long, it was against the building code. My gym membership (where I took shower everyday) was going to be cancelled because it was a family membership from my ex’s workplace. I had to get back to trading again.

The irony of starting with $20,000 to trade didn’t escape me. This was 2009, a time with extreme market volatility. It was great for a day trader, but I had to be extremely careful not to get stuck. The overnight risk was tremendously high. Fortunately I still had some of my old trading moves, pretty soon I was making enough to make some of the payroll and hang on to my key employees. I renegotiated with our landlord, banks and suppliers to allow us to float a bit longer. I intuitively knew at the time that the worst recession of more than fifty year was going to wipe out a lot of our competitors. All we had to do was to stay alive. I needed to do anything possible to do just that.

It was during this same period I helped out a tech support guy from a competitor of ours. Let’s call him Joe. Joe was recently laid off, his home was foreclosed and the entire family with three teenage kids had to move back in with the grandparents. I sensed the same burning desire in this guy to succeed after his financial failures. I offered Joe a job in sales instead of tech support. We worked together on the company’s sales efforts by going after some of old accounts he supported at his prior job, we managed to poach a few this way. It gave us much needed confirmation that we were on the right track.

By early 2010 I was able to move out of our office broom closet, I turned $20,000 trading stake into $250,000. It gave the company much needed breathing room to survive. The legal fight was also over. The old customer was able to get away with paying the bulk of what they owed us, and we were out of personal liabilities. This same unsavory “customer” eventually went out of business a couple of years later because they lacked the key technology we used to provide to them. But most importantly, I believe it was their unethical business practices that eventually caught up with them. Talk about karma!

In 2010 we were also able to land our first big customer with our newly pivoted product. The large customer has far flung operations all over the world (it is a household name), so the obvious question for them was how this little company with now only 6 employees can support them. I went back to something I learned from getting my first sales job, namely offering them something that is very difficult to do for free as a trial. We integrated our product with their legacy vendor’s product while adding a software layer to allow easier, scalable workflow while saving the customer money. This took us a few months worth of sweat labor, but at the end we were able to deliver something a competitor nearly 100X our size couldn’t deliver. To service and support the customer, we outsourced the deployment and installation while managing the entire logistical process to ensure a superior customer experience. To go one step better, we wrote an entire management suite to monitor their operations and the health of our product to make sure all failures and bugs flow back to us immediately, so we can proactively fix the problems even before the customer is aware of any issues. The picture below is an example what a typical site for our customer looks like, now multiply this by up to a few thousand, and you can imagine the mess we have to manage 🙂

​The bottomline, making sure the customer always interact with our product in the best possible light. We finished the year with $1M in new sales.

With the success of hiring guys like Joe, I wanted to model our company after guys just like him and me, underdogs with attitude. Half of the company are development staff, people from all over the world. We have Russians, Romanians, Indians, Chinese, Latvians, Germans, Italians, and so on. We also have people with non computer science background who learned in unconventional ways too. Folks with majors in geography, math, and even an ex-fisherman. The sales and support staff are equally diverse, most do not have advanced degrees, some with serious family problems and personal failures in the past. But they all know we are in it together. This tight knit group has push the business ahead much better than I could have imagined.

Four years later, the economy has recovered and so have I. My company did $20M in sales in the past 12 months and we are on pace to do $50M next year. Much of this had to do with the effort of tech support turned sales guy Joe. From a starting salary of $40,000 back in 2010, Joe made $750,000 last year and he will bank more than $3M this year from sales commissions. In early 2015, Joe took care of all the bad debts from his past and bought his family a nice horse ranch right outside of Seattle with cash (no one would finance him still). The day he bought his house, we sat in the office conference room with a check for his new home, we looked at each other and nearly cried. We understood each other for the shared journey we both went through. Some day Joe should be telling his own story on Quora.

With gross margin in the 80% range and plenty of cash in the bank I paid myself $1M. The business is probably worth 2-3X sales in private market value, so anywhere between $100-150M as of this writing. I am pretty confident it will be able to do $300M in sales in a few years due to our backlog. So the number of $1B is entirely possible. It is probably safe to say that I am firmly back in the 1% again. I hope to stay there this time.

ME-Mydoc 3.7 Released!

ME-Mydoc 3.7 has several attractive features.

Import Code from a directory
import code 1

import code 2

import code 3

Enhanced full text search and Chinese now supported

Note preview in main window

Recently visited items

Read desire, rate and series for Ebook and custom search

Fast search in tag view component

Auto filling certain fields when adding an Ebook by clipboard content detection

Java RSA encrypt and decrypt using generated key pair

The code demo generates RSA key pair and persists it to local file using Java specific object serialization format. The demo then restores private/public key objects by de-serializing from files it just created. Further, the public key is used to encrypt a clear text and the private key to decrypt.

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.nio.charset.StandardCharsets;

 * RSA encryption/decryption util.
public class RSAUtil {

    private RSAPublicKey pubkey;
    private RSAPrivateKey prikey;

    public RSAUtil(RSAPrivateKey prikey, RSAPublicKey pubkey) {
        this.prikey = prikey;
        this.pubkey = pubkey;

    public byte[] encrypt(byte[] bytes) throws BadPaddingException, IllegalBlockSizeException,
            InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, pubkey);
        return cipher.doFinal(bytes);

    public byte[] decrypt(byte[] bytes) throws NoSuchPaddingException, NoSuchAlgorithmException,
            InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, prikey);
        return cipher.doFinal(bytes);

    public static RSAUtil loadKeys(String privateKeyFile, String publicKeyFile) throws Exception {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(privateKeyFile));
        RSAPrivateKey privateKey = (RSAPrivateKey) ois.readObject();

        ois = new ObjectInputStream(new FileInputStream(publicKeyFile));
        RSAPublicKey publicKey = (RSAPublicKey) ois.readObject();
        return new RSAUtil(privateKey, publicKey);

    public static void genRSAKeyPair(String privateKeyFile, String publicKeyFile) {
        try {
            CertAndKeyGen keyPair = new CertAndKeyGen("RSA", "SHA1WithRSA", null);

            RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivateKey();

            RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublicKey();

            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(privateKeyFile));

            oos = new ObjectOutputStream(new FileOutputStream(publicKeyFile));

        } catch (Exception ex) {

    public static void main(String[] args) throws Exception {
        String clearText = "this is the text";
        genRSAKeyPair("privatekey", "publickey");
        RSAUtil rsaUtil = loadKeys("privatekey", "publickey");
        byte[] encryptedBytes = rsaUtil.encrypt(clearText.getBytes(StandardCharsets.UTF_8));
        String decryptedText = new String(rsaUtil.decrypt(encryptedBytes), StandardCharsets.UTF_8);

Java symmetric encryption decryption demo

In symmetric cryptograph, there are padding mode and blocking cipher that have restrictions on input byte length. SymmetricCryptoUtil in this demo adopts AES/CFB8/NoPadding mode that accepts any input without byte length restriction. In the Java main method, a string is first encrypted as byte array and then decrypted to string again without any loss.

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;

 * Symmetric key encryption/decryption util.
public class SymmetricCryptoUtil {

    private String secretKey = "18345678800knarf";
    private String iv = "S23r87I090qYer9z";
    private static final String CIPHER_MODE = "AES/CFB8/NoPadding";

    private SecretKey keySpec;
    private IvParameterSpec ivSpec;

    public SymmetricCryptoUtil() {
        try {
            keySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "AES");
            ivSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
        } catch (Exception e) {

    public byte[] encrypt(byte[] bytes) throws BadPaddingException, IllegalBlockSizeException,
            InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException {
        Cipher cipher = Cipher.getInstance(CIPHER_MODE);
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
        return cipher.doFinal(bytes);

    public byte[] decrypt(byte[] bytes) throws NoSuchPaddingException, NoSuchAlgorithmException,
            InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException {
        Cipher cipher = Cipher.getInstance(CIPHER_MODE);
        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
        return cipher.doFinal(bytes);

    public static void main(String[] args) throws Exception {
        String clearText = "this is the text";
        SymmetricCryptoUtil cryptoUtil = new SymmetricCryptoUtil();
        byte[] encryptedBytes = cryptoUtil.encrypt(clearText.getBytes(StandardCharsets.UTF_8));
        String decryptedText = new String(cryptoUtil.decrypt(encryptedBytes), StandardCharsets.UTF_8);

Spring boot project with bean loading info

Download source code

The spring boot demo project is taken from spring boot guide. We can build the project with either gradle or maven.
gradle build
mvn package
In addition to the spring boot project in its official tutorial, I configured debug info because sometimes, we are confused about bean loading status, such as what beans are loaded and in what sequence. We can pass debug level info in command line such as

java -jar build/libs/gs-spring-boot-0.1.0.jar --debug
or having a file with following content

debug=true  # When the debug mode is enabled, a selection of core loggers (embedded container, Hibernate and Spring) are configured to output more information. Enabling the debug mode does not configure your application log all messages with DEBUG level.
logging.level.root=DEBUG  # more comprehensive debug level

Reference @ Spring boot logging.

Bean loading report and log are partly extracted as follows


Positive matches:

AuditAutoConfiguration.AuditEventRepositoryConfiguration matched
- @ConditionalOnMissingBean (types: org.springframework.boot.actuate.audit.AuditEventRepository; SearchStrategy: all) found no beans (OnBeanCondition)

DispatcherServletAutoConfiguration matched
- @ConditionalOnClass classes found: org.springframework.web.servlet.DispatcherServlet (OnClassCondition)
- found web application StandardServletEnvironment (OnWebApplicationCondition)

DispatcherServletAutoConfiguration.DispatcherServletConfiguration matched
- @ConditionalOnClass classes found: javax.servlet.ServletRegistration (OnClassCondition)
- no ServletRegistrationBean found (DispatcherServletAutoConfiguration.DefaultDispatcherServletCondition)
2016-02-18 20:43:52.124  INFO 9431 --- [           main]  : Starting beans in phase 0
2016-02-18 20:43:52.127 DEBUG 9431 --- [           main] o.s.b.a.e.jmx.EndpointMBeanExporter      : Located managed bean 'requestMappingEndpoint': registering with JMX server as MBean [org.springframework.boot:type=Endpoint,name=requestMappingEndpoint]
2016-02-18 20:43:52.189 DEBUG 9431 --- [           main] o.s.b.a.e.jmx.EndpointMBeanExporter      : Located managed bean 'environmentEndpoint': registering with JMX server as MBean [org.springframework.boot:type=Endpoint,name=environmentEndpoint]
2016-02-18 20:43:52.201 DEBUG 9431 --- [           main] o.s.b.a.e.jmx.EndpointMBeanExporter      : Located managed bean 'healthEndpoint': registering with JMX server as MBean [org.springframework.boot:type=Endpoint,name=healthEndpoint]

Apriori (Java)

Algorithm Origin: Coursera: Mining of Massive Datasets
Code at GitHub Apriori

Apriori is algorithm for frequent item set mining. For example, given a item set where each line indicates a set of item.

1 2 4
1 3 4
1 4 5 6
1 2 3 4
2 3
4 5 6

The data given above has 7 item sets, the first one being items numbered 1, 2 and 4. Suppose we want to find all item sets having appearance of more than two, Apriori offers an iterative approach. First, Apriori computes all items having more than (or equal) appearance of two. And each later round result sets of length one more than current matched sets are computed.
For the example above, output of each round is listed below

Round 1
Round 2
1, 2,
1, 3,
1, 4,
2, 3,
2, 4,
3, 4,
4, 5,
4, 6,
5, 6,
Round 3
1, 2, 4,
1, 3, 4,
4, 5, 6,

In round 3, 3 item sets, (1, 2, 4), (1, 3, 4) and (4, 5, 6) are found to be appear equal or more than two in input data, which can be comfirmed manually.
The core part of Apriori for each iteration is join, filter algorithms. I implemented them without optimization but sketched its spirit.
I am diving into join algorithm a little bit.

Join takes in a set of tuples of length n. It first permutes all combinations of any two tuples. Let’s say tuple A and tuple B in consideration, if they differ in only 1 item, then tuple C of length n+1 is constructed and tuple C should contain all elements of A and B. For instance, tuple A = (1, 3, 4) and tuple B = (2, 3, 4), because A and B has only one different element so tuple C of length 4 can be constructed, C = (1, 2, 3, 4). However, the candidate tuple C must meet another criteria that all its low order tuples must be in current matched set. That is (1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4) must in current matched set.

TF-IDF (Java)

Algorithm Origin: Coursera: Mining of Massive Datasets
Code at GitHub TF-IDF

TF-IDF Concept

TF-IDF, short for term frequency–inverse document frequency, that is intended to reflect how important a word is to a document in a collection. Based on TF-IDF, it would be convenient to compute document similarity or automated document abstraction.

The intuition is that

  1. The more often a word appears in a doc, the more importance it is than other words. This is term frequency part of TF-IDF.
  2. But not all words are created equal. We need to weigh each word by inverse document frequency which gives common words low weight.

TF-IDF Formula

There are several variants of TF and IDF formula in Wikipedia TF-IDF. In this article and Java code, we adopted TF to be
`tf(t,d) = f_(t,d) / |d|`, where `f_(t,d)` is number of term `t` in doc `d`, `|d|` is total number of terms in doc `d`.
`idf(t, D) = log(1 + N / n_t)`, where `N` is number of all docs and `n_t` is number of docs containing term `t`.
`tfidf(t,d,D) = tf(t,d) * idf(t,D)`

Justification of IDF

The probability that a given document `d` contains a term `t` as
`P(t|d)=|{d in D:t in d}|/N`
So define idf as
`idf=-log*P(t|d) = log N/|{d in D:t in d}|`


public class TF_IDF {

    int numOfWords;
    double[] idfVector;
    double[][] tfIdfMatrix;
    double[][] tfMatrix;
    String[] wordVector;
    int docLength[];

    public TF_IDF(String[] docs) {
        // STEP 1, scan all words and count the number of different words
        // mapWordToIdx maps word to its vector index
        HashMap<String, Integer> mapWordToIdx = new HashMap<>();
        int nextIdx = 0;
        for (String doc : docs) {
            for (String word : doc.split(" ")) {
                if (!mapWordToIdx.containsKey(word)) {
                    mapWordToIdx.put(word, nextIdx);

        numOfWords = mapWordToIdx.size();

        // STEP 2, create word vector where wordVector[i] is the actual word
        wordVector = new String[numOfWords];
        for (String word : mapWordToIdx.keySet()) {
            int wordIdx = mapWordToIdx.get(word);
            wordVector[wordIdx] = word;

        // STEP 3, create doc word vector where docCountVector[i] is number of
        // docs containing word of index i
        // and doc length vector
        int[] docCountVector = new int[numOfWords];
        docLength = new int[docs.length];
        // lastDocWordVector is auxilary vector keeping track of last doc index
        // containing the word
        int[] lastDocWordVector = new int[numOfWords];
        for (int wordIdx = 0; wordIdx < numOfWords; wordIdx++) {
            lastDocWordVector[wordIdx] = -1;
        for (int docIdx = 0; docIdx < docs.length; docIdx++) {
            String doc = docs[docIdx];
            String[] words = doc.split(" ");
            for (String word : words) {
                docLength[docIdx] = words.length;
                int wordIdx = mapWordToIdx.get(word);
                if (lastDocWordVector[wordIdx] < docIdx) {
                    lastDocWordVector[wordIdx] = docIdx;

        // STEP 4, compute IDF vector based on docCountVector
        idfVector = new double[numOfWords];
        for (int wordIdx = 0; wordIdx < numOfWords; wordIdx++) {
            idfVector[wordIdx] = Math.log10(1 + (double) docs.length / (docCountVector[wordIdx]));

        // STEP 5, compute term frequency matrix, tfMatrix[docIdx][wordIdx]
        tfMatrix = new double[docs.length][];
        for (int docIdx = 0; docIdx < docs.length; docIdx++) {
            tfMatrix[docIdx] = new double[numOfWords];
        for (int docIdx = 0; docIdx < docs.length; docIdx++) {
            String doc = docs[docIdx];
            for (String word : doc.split(" ")) {
                int wordIdx = mapWordToIdx.get(word);
                tfMatrix[docIdx][wordIdx] = tfMatrix[docIdx][wordIdx] + 1;
        // normalize idfMatrix by deviding corresponding doc length
        for (int docIdx = 0; docIdx < docs.length; docIdx++) {
            for (int wordIdx = 0; wordIdx < numOfWords; wordIdx++) {
                tfMatrix[docIdx][wordIdx] = tfMatrix[docIdx][wordIdx] / docLength[docIdx];

        // STEP 6, compute final TF-IDF matrix
        // tfIdfMatrix[docIdx][wordIdx] = tfMatrix[docIdx][wordIdx] * idfVector[wordIdx]
        tfIdfMatrix = new double[docs.length][];
        for (int docIdx = 0; docIdx < docs.length; docIdx++) {
            tfIdfMatrix[docIdx] = new double[numOfWords];

        for (int docIdx = 0; docIdx < docs.length; docIdx++) {
            for (int wordIdx = 0; wordIdx < numOfWords; wordIdx++) {
                tfIdfMatrix[docIdx][wordIdx] = tfMatrix[docIdx][wordIdx] * idfVector[wordIdx];


    public double[][] getTF_IDFMatrix() {
        return tfIdfMatrix;

    public String[] getWordVector() {
        return wordVector;


The test case is taken from Wikipedia TF-IDF where
d1 = “this is a a sample” and d2=”this is another another example example example”
Result of sorted TF-IDF values for d2 are
[example, this, is, another]
[0.20448053773699817, 0.13632035849133212, 0.043004285094854454, 0.043004285094854454]

Minhashing (Java)

Algorithm Origin: Coursera: Mining of Massive Datasets week 2
Code is at GitHub Minhashing

Jaccard Similarity of Two Sets

Let `A` and `B` are two sets, the Jaccard similarity is
`J(A,B) = |A nn B|/|A uu B|`

For example, 4 sets illustrated below

Element S1 S2 S3 S4
a 1 0 0 1
b 0 0 1 0
c 0 1 0 1
d 1 0 1 1
e 0 0 1 0

`J(S_1, S_3) = |{d}|/|{a, b, d, e}| = 1/4`

Minhashing and Jaccard Similarity

Because each set may have millions of possible items, computing exact Jaccard similarity would be huge effort. Hence, if there would be a much shorter vector for each set, the estimated Jaccard similarity could be significantly simplified.
We select a random permutation of items and define minhash for that permutation to be the first item that exists in the set. For the example above, a randomly generated permutation h is selected to be b,e,a,d,c, then `h(S_1)=a`.

Minhashing and Jaccard Similarity

The probability that the minhash function for a random permutation of rows produces the same value for two sets equals the Jaccard similarity of those sets.
How to interpret this? Let’s see all permutations of `S_2` and `S_4` in the example above. The items involved in `S_2` and `S_4` are a, c and d.

Element S2 S4
a 0 1
c 1 1
d 0 1

All permutations are

Permutation h `h(S_2) = h(S_4)` ?
adc false
acd false
cad true
cda true
dac false
dca false

`P(h(S_2)=h(S_4))` is 1/3, which is also Jaccard similarity.

Computing Minhash Signatures from Multiple Hash Functions

The actual minhashing signature is computed using some approximations.
1. Sample several permutations but not full permutations.
2. Use a hash function to simulate each permutation. The hash function may map some pairs of integers to the same bucket and
leave other buckets unfilled. However, the difference is unimportant as long as there are not too many collisions. (Illustrated in implementation although I have not figured out mathematical correctness of this).

public Minhashing(int[][] sets, Function<Integer, Integer>[] hashs) {
    int setNumber = sets.length;
    // use Integer[] so that infinity can be represented by null
    sig = new Integer[setNumber][];
    for (int i = 0; i < setNumber; i++) {
        sig[i] = new Integer[hashs.length];

    // for each row index value
    for (int i = 0; i < sets[0].length; i++) {
        // calc hash vector 
        int[] hashVector = new int[hashs.length];
        for (int hashIdx = 0; hashIdx < hashs.length; hashIdx++) {
            hashVector[hashIdx] = hashs[hashIdx].apply(i);

        // for each set signature vector
        for (int setIdx = 0; setIdx < setNumber; setIdx++) {
            for (int hashIdx = 0; hashIdx < hashs.length; hashIdx++) {
                if (sets[setIdx][i] != 0) {
                    if (sig[setIdx][hashIdx] == null || sig[setIdx][hashIdx] > hashVector[hashIdx]) {
                        sig[setIdx][hashIdx] = hashVector[hashIdx];

The running result of the example, with `h_1=(x+1) mod 5` and `h_2=(3*x+1) mod 5` is

S1 S2 S3 S4
h1 1 3 0 1
h2 0 2 0 0

KMP (Java)

The KMP (Knuth-Morris-Pratt) string match algorithm is implemented according to Wikipedia KMP. Code @ github

KMP Table

  1. T[i] means how many chars till i-th char (exclusively) match char sequence of W[0], W[1], …
  2. if T[i] > 0, it also means W[i] corresponds to W[T[i]]
  3. T[0] is always -1, meaning it’s starting element.
  4. T[1] is always 0 because it does not make sense only T[0] is considered.

For example, for the following W, pos 6, AB is char sequence ending with W[5] that matches W[0], W[1], so T[6]=2

i 0 1 2 3 4 5 6
W[i] A B C D A B D
T[i] -1 0 0 0 0 1 2

Another example is

i 0 1 2 3 4 5 6 7
W[i] A B C A B A B C
T[i] -1 0 0 0 1 2 1 2

Construct KMP Table

Code implemented according to Wikipedia pseudocode

  • pos: index into T to compute T[pos]. Actually only need to compare W[pos-1] with W[cnd]
  • cnd: candidate index into T where W[cnd-1], W[cnd-2],…, have been matched.
  • case 1: W[pos-1]==W[cnd], the substring continues. Increment pos to compute next.
  • case 2: W[pos-1]!=W[cnd] but cnd>0. It indicates that although W[pos-1] mismatches with W[cnd] but W[cnd] is end of sub sequence of W[0], W[1], …, W[T[cnd]], so we fall back cnd to T[cnd] to try luck again.
  • case 3: cnd=0, W[pos-1] does not even match W[0], T[pos] is thus 0.
table = new int[strNeedle.length()];
table[0] = -1;
table[1] = 0;
int pos = 2;
int cnd = 0;
while (pos < strNeedle.length()) {
    if (strNeedle.charAt(pos - 1) == strNeedle.charAt(cnd)) {
        // case 1: the substring continues
        table[pos] = cnd;
    } else if (cnd > 0) {
        // case 2: it doesn't, but we can fall back
        cnd = table[cnd];
    } else {
        // case 3: we have run out of candidates.  Note cnd = 0
        table[pos] = 0;

Match Algorithm

Code implemented according to Wikipedia pseudocode

  • m: starting index into strHayStack where a matching sequence begins
  • i: index into strNeedle. Compare strNeedle[i] with strHayStack[m+i]
  • case 1: strNeedle[i]==strHayStack[m+i]
  • case 2: strNeedle[i]!=strHayStack[m+i], reposition starting index m to fall back
  • case 3: table[i]==0, already strNeedle[0] and mismatch, next m
public int match(String strHayStack) {
    int m = 0;
    int i = 0;
    while (m + i < strHayStack.length()) {
        if (strNeedle.charAt(i) == strHayStack.charAt(m + i)) {
            // case 1: the substring continues
            if (i == strNeedle.length() - 1) {
                return m;
        } else {
            if (table[i] > -1) {
                // case 2: fall back to shorter prefix
                m = m + i - table[i];
                i = table[i];
            } else {
                // case 3: mismatch and table[i]==0
                i = 0;
                m = m + 1;
    return -1;

Batch Gradient Descent of Linear Regression (Python)

Originated from Coursera Machine Learning, week 2.
Code at


Vector `X=[1, x_1, x_2, x_3, …, x_n]` is input data

Linear hypothesis is

`h_theta(x) = theta_0 + theta_1(x_1) + theta_2(x_2) + … + theta_n(x_n)`

Define cost function to be


The task is to find `theta` that minimizes `J`
Gradient descent method is to find converged `theta` iteratively.
The partial derivative of `J(theta)` is `1/(2m)Sigma_(i=1)^m(h_theta(x^((i)))-y^((i)))*x_(j)^((i))`

Therefore, iteration equation is
`theta_j=theta_j – alpha*1/(2m)Sigma_(i=1)^m(h_theta(x^((i)))-y^((i)))*x_(j)^((i))`

Feature Scaling

Get every feature into approximately [-1, 1] range.
`x_i = (x_i-mu_i)/ delta_i` where `mu_i` is mean of `i`-th feature and `delta_i` is standard deviation of `i`-th feature.

Python Code

import numpy as np

class GradientDescent:
    "Batch Gradient Descent method of linear regression"
    alpha = 0.01
    step = 100

    def __init__(self, alpha=0.01, step=100):
        self.alpha = alpha
        self.step = step

    def distance(self, v1, v2):
        v = v1 - v2
        v = v * v
        return np.sum(v)

    def h(self, X, theta):
        n = len(theta)
        return, X)

    def cost(self, X):
        c = np.sum(X*X)
        m = len(X)
        c = 1.0/(2*m) * c
        return c

    def featureNormalize(self, X):
        "Get every feature into approximately [-1, 1] range."
        featureN = len(X)
        mu = np.mean(X[0:featureN + 1], axis=1, dtype=np.float64)
        sigma = np.std(X[0:featureN + 1], axis=1, dtype=np.float64)
        X_norm = X
        for i in range(featureN):
            X_norm[i] = (X[i]-mu[i])/sigma[i]
        return X_norm, mu, sigma

    def iterate(self, data, toNormalize=False):
        m = len(data)
        data = np.transpose(data)
        featureN = len(data) - 1
        Y = data[featureN]  # shape 1 * m
        X = data[0:featureN]  # shape N * m
        if toNormalize:
            X, mu, sigma = self.featureNormalize(X)
        X = np.vstack((np.ones(m), X))  # shape (N+1) * m

        theta = np.zeros(featureN + 1, dtype=np.float64)

        for iter in range(self.step):
            theta_temp = np.zeros(featureN + 1, dtype=np.float64)
            V = self.h(X, theta)
            V = V - Y
            costValue = self.cost(V)

            for i in range(featureN+1):
                theta_temp[i] = np.sum(V * X[i])
            theta_temp *= self.alpha / m
            theta_temp = theta - theta_temp
            # dist = distance(theta, theta_temp)
            theta = theta_temp
        return theta

The result running the code above with test data (in homework of course Machine Learning) is
ex1data1.txt: `theta=[-3.63029144, 1.16636235]`
ex1data2.txt: `theta=[ 338658.2492493, 103322.82942954, -474.74249522]`

Page 2 of 3

Powered by WordPress & Theme by Anders Norén