Food Rolodex

I should have listened to my gut and my brain. On hindsight there were so many obvious signs that it’s a bad idea and a bad business relationship. But my heart wanted to really make it work.

My heart can go take a bench break.

So back in October 2013, my soon-to-be Troublesome Business Partner (TBP) convinced me and the soon-to-be Amiable Business Partner (ABP) of forming a company. The business: to have an app where people can browse food items of an eatery place, be it a cafe or restaurant or anything in between.

My instincts and gut feeling told me that was a bad idea. My brain figured out that there’s no real business. The app users must be able to use the service for free. For that kind of service, fremium would drive people away unless there’s something compelling. During the late quarter of 2013, there were already food related services (FoodPanda was one of them I think. We’ll get to that in a future post). That idea alone was not enough of a business model.

Social media was so rampant that just being able to browse food items of an eatery place was laughably ignorable.

Profit would have to come from the eateries themselves, cafes and restaurants and whatnot paying us money to list their business in our app. Or from advertisements and sponsors. As a newcomer in the arena, I did not see how we could compete since we had no competitive advantage.

But ABP agreed to TBP’s idea, and I was blinded by the fact that I found people willing to do business together with me.

Lesson: Do not let your heart run your business decisions. Your heart can take a bench break.

Despite what my gut instincts and brain were telling me, I chose to try to make it work. My two business partners (we formed a company soon after), TBP and ABP have… shall we say qualifications that added some letters before and after their names. Who was I to judge?

I confirmed with TBP if TBP had any further ideas, such as monetisation or marketing the app or getting initial customers or … anything at all. TBP had no further ideas beyond the original idea.

My gut shot that red flag to my brain so quickly I nearly choked but my heart brushed it aside just as quickly. (I was really lonesome for like-minded people)

Alright, I’m going to try to describe the app as best as I can and you can judge it on its own merit. I named it FoodSkim. My two business partners were next to worthless when it came to naming, and I had to do something (I was the CEO after all).

So you would go to your favourite cafe Mooncoin, fire up the FoodSkim app, select Mooncoin as the eatery, select your favourite beverage CinnaSoyLattecino Triple Shot with the signature Coin Cake, and then send it off as an order.

FoodSkim would send your order to Mooncoin’s corresponding FoodSkim server on Mooncoin’s computer for processing (probably in the kitchen or something). Mooncoin would still need you to pay at their cashier counter, but you know, that’s just a minor inconvenience compared to Oh Em Gee you can rate the food item and share your opinions on the food/eatery on your favourite social media sites!

It must have been a superbly brilliant idea because I couldn’t get TBP and ABP to see the practicality of convincing businesses to do business with us based on that.

How were we to convince them of setting up our FoodSkim server program on their computer? Do they even have a computer? “If they don’t, we provide them with a (cheap) computer.” I’m flabbergasted.

How were we to interface with their Point-Of-Sales (POS) system? Can we interface with their POS? Should we interface at all? Would they allow us to interface? How difficult would it be to interface? (Because no interface means the customer, that’s you, would still have to go queue up and pay at the cashier, which defeats the purpose of choosing food items at your leisure)

TBP also suggested we allow FoodSkim users to preorder food before they’re at the eatery.

How could the eatery trust that the customer would show up, because they have to prepare the food (no payment yet, remember)?

“Oh we put GPS location lock on the customer and the eatery location.”

That meant we had to enter the eatery GPS location into our database. What if they move (they’d have to inform us, and why would they think it’s important to inform us?)? Data maintenance would be a problem.

Despite me bringing up those questions of practicality, I was brushed aside. Ok, how about the initial set of businesses? Neither TBP nor ABP did anything to get eateries to list their businesses with us.

I actually went out to a few eateries to talk with the owners. I asked them if they’d be interested to be listed. I gave them my name card. No one contacted me. I wasn’t surprised, but I did the leg work. I tried to make it work and give it my best effort just in case it did.

Finally, I couldn’t take it anymore. It was almost two years after the company was formed. TBP was nowhere to be seen nor heard from. TBP just disappeared without telling me. ABP told me that both of them were still in contact, and ABP told me TBP was afraid of me.

Really? I wonder why.

Coward.

I wound up development on FoodSkim. At that point, I was forking out my own money to keep the company and the FoodSkim project going. TBP and ABP didn’t offer any money at all to help.

I could no longer tell myself my company and FoodSkim were going to work.

I told ABP of my decision and ABP was ok with closing the company. Then I went through a long process of terminating the funding agreement with the venture capitalist organisation. Even the liaison from the venture capitalist organisation disappeared and didn’t help me or give me advice.

The termination took a few months to finally get settled. Then I went through the long process of closing my company.

During that entire period of time, I kept telling myself that, in five or ten years time, Future Vincent would look back on the memory of this period and laugh. Because Present Vincent was in a lot of emotional pain and stress. Without any self-motivation and self-talk, Present Vincent would have had a nervous breakdown.

I still look at that period of time as a learning experience. I still feel bittersweet when I think of the times when I did payroll. The sense of responsibility of taking care of the company bank account. Swallowing my pride when talking to potential customers. Putting up a face of calm when presenting to the VC.

I’m also more cynical of people now, and hopefully a better judge of character.

I paid a hefty price for that experience, in terms of money, of sweat and tears, of lost opportunities, of loss of time.

It took me 3 years to recover to the point where I’m able to talk to you about it. I hope you learnt something from my experience, and that you have a better time than me.

Closing my company was painful

I never thought closing my company would be such a relief.

Three years ago, about this time of the year, I was preparing the final documents for the very last Annual General Meeting for my company. I was doing so as both the (sole) company director and the CEO. Before that, I had already sent the accountant all the payment receipts, invoices, the company cheque book and other finance related documents for review and to generate the financial statements (to be presented to the stakeholders during the AGM).

The only agenda of the AGM was to accept or reject the closing of the company.

On the fateful day of the AGM, I waited in the appointed room for the other two stakeholders. They were business partners only in name, but legally speaking they were considered stockholders.

There was one particular business partner that I hoped fervently did not appear for the AGM.

When the other business partner arrived, I breathed a small sigh of relief. I needed *this* business partner to appear and that the other business partner to *not* appear.

If at this point you’re thinking that I’m doing some sort of subterfuge, you’re right. I hated to have to do it, but it was necessary because that other business partner had been giving me trouble to no end.

Legally speaking, I needed a majority from the stockholders to approve of the closing of the company before I can proceed to close it. You’d think I have the majority of the stocks but you’d be wrong. I was fairly sure I could convince the amiable business partner to agree, since we’ve already decided beforehand that it was best for the both of us and for the company.

I told my secretary the amiable business partner had arrived. That business partner, my secretary and I waited in the room. 15 minutes passed the appointed time. Half an hour passed the appointed time. I called for the AGM to proceed without all the stockholders present.

I presented to the amiable business partner the financial statements of the company. The partner reviewed the documents, and asked me and my secretary questions, including why the other business partner wasn’t present.

I’m not going to tell you how I managed to get the other business partner to not appear. It’s still painful (even after 3 years) and I hope I never have to do something like that ever again. Well maybe in a future post, I’ll talk about it…

In any case, the amiable business partner agreed to the closing of the company. I closed off the AGM and thanked the business partner for coming. I discussed with my secretary the final document preparation of the closing of the company. Then I left the office.

I don’t remember what I did after that, but I *do* remember the immense weight that was lifted off my shoulders. I might have stood still and shivered. I might have cried a little.

Because it was the first time in a long time that I felt… free.

Don’t get me wrong, I don’t regret running the company. I had to work with the venture capitalist organisation that funded the company project. I had to make payroll (it was sobering to see how much money was draining from the company bank account every month). I learnt to do company taxes and all sorts of company admin work (that only I as the CEO/director could do).

I was also doing consultancy work and running my own private business at the same time. Because I didn’t get paid anything for being the CEO nor being the company director. I was doing the equivalent of three jobs. I had trouble sleeping. I had to sometimes consciously remind myself to breathe because my breaths were so shallow. And my blood boiled every time I thought of that troublesome business partner.

It was not a good way to live.

Next time, I’ll tell you of the heart attack I almost got when the bank closed the company bank account with a final figure that did not tally with that from my accountant.

How to fix Open XML SDK created spreadsheet for iOS devices

Note that this is only for Open XML SDK 2.0. I haven’t tested for SDK 2.5 (or later, but there’s no “later” version at the point of this writing).

The fix

You have to manipulate the [Content_Types].xml file. This XML file is zipped together in the spreadsheet file, and is at the root of the file. If you don’t know what I’m talking about, you’re probably reading the wrong article.

Unfortunately, this can’t be done within Open XML SDK. As I understand it, the SDK runs internally on System.IO.Packaging namespace objects.

Now a package is a zip file with structure. But a zip file is not necessarily a package. (go maths logic!) See Microsoft reference (bottom of page).

As I understand it, you can’t manipulate a package’s [Content_Types].xml with any of the methods or classes from the System.IO.Packaging namespace. This XML file is supposed to be tamper-proof.

So if you can’t change it with the Packaging stuff, then you’ll have to manipulate it as a pure zip file. And as at .NET Framework 3.5 (because I’m using Open XML SDK 2.0 as reference), there’s no in-built zipping mechanism for the kind of zipping algorithm you need (the Gzip and Deflate isn’t exactly the tool).

This means you need an outside zip library. I leave it to you to find your favourite library. Assuming you found one, here’s why you need to change the [Content_Types].xml file.

The one generated by Excel looks something like this:

<?xml version="1.0" encoding="UTF-8" standalone="true"?>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
<Default ContentType="application/vnd.openxmlformats-package.relationships+xml" Extension="rels"/>
<Default ContentType="application/xml" Extension="xml"/>
<Override ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml" PartName="/xl/workbook.xml"/>
<Override ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml" PartName="/xl/worksheets/sheet.xml"/>
<Override ContentType="application/vnd.openxmlformats-officedocument.theme+xml" PartName="/xl/theme/theme.xml"/>
<Override ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml" PartName="/xl/styles.xml"/>
<Override ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml" PartName="/xl/sharedStrings.xml"/>
<Override ContentType="application/vnd.openxmlformats-package.core-properties+xml" PartName="/docProps/core.xml"/>
</Types>

The one generated by Open XML SDK 2.0 looks something like:

<?xml version="1.0" encoding="UTF-8"?>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
<Default ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml" Extension="xml"/>
<Default ContentType="application/vnd.openxmlformats-package.relationships+xml" Extension="rels"/>
<Override ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml" PartName="/xl/worksheets/sheet.xml"/>
<Override ContentType="application/vnd.openxmlformats-officedocument.theme+xml" PartName="/xl/theme/theme.xml"/>
<Override ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml" PartName="/xl/styles.xml"/>
<Override ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml" PartName="/xl/sharedStrings.xml"/>
<Override ContentType="application/vnd.openxmlformats-package.core-properties+xml" PartName="/docProps/core.xml"/>
</Types>

Spot the difference time!

The workbook part is missing. Specifically, look for the XML tag with the ContentType attribute equal to “application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml”

Open XML SDK, for whatever reason, doesn’t explicitly set the PartName=”/xl/workbook.xml” part. This is why iOS devices can’t see the spreadsheet file.

I don’t know whether the fix will work on Android devices or Windows phones. But a developer emailed me that iOS 6.0 devices seem to still be able to read the spreadsheet files by Open XML SDK, but iOS 7.0 just gives up.

Microsoft, please, you created the Open XML specs. Other companies are following the specs and the one useful tool you made to help generate Open XML documents fail to follow the specs.

How to found a company

Just do it.

But jokes aside, the bigger question is not how. It’s why.

[Disclaimer: any information you read here pertains to Singapore laws and regulations. Your country’s laws and regulations might differ.]

I have people emailing me “Wow Vincent, you’re running your own business! That’s totally awesome. I wish I could do something like you did.”

Or “I don’t really have a product to sell.”

Or “I have this small thing that I’m working on, but it’s too early to tell.”

Or “I have a family to take care of.”

Or “I’m scared.”

All perfectly valid reasons. And at some point in time, all of them were applicable to me. And I’m still working for myself now.

Now for the big news. I founded a company! Yay! (ok I co-founded a company, but the circumstantial details are more complex than I’d like it to be. I might talk about it in an email. Sign up on the right side bar [or wherever it might be in case the position is changed]).

So about the how thing. It’s not hard. It’s just frustratingly tedious. Mostly because I don’t know what forms to fill in, in what sequence, and “Is there anything else I need to do because I don’t wanna get sued and go to jail!”.

Also, because I’ve never done it before. Most people will feel scared if they’re doing something they’ve never done before. So they find it frustrating and tedious and moan and groan and go drink a bottle of whiskey and go to bed.

You go to ACRA, come up with a company name, decide on the shares allocated to each share holder (probably decide beforehand and not on the spot), put in share holder details, company official member details, pay ACRA for the registration and you’re done!

There’s also quite a bit of legalese and fine print. Since I don’t want to get sued and go to jail, I read them. You might want to go on the wild side and just skip them. To each his own.

So it’s not so much the how. Find a strong enough reason for why, and you’ll just do it.

By the way, I founded a company! The company name is One North Soft. I have a secret project in the works. Tell you more in future.

Regular polygon equation (solved)

So I’ve finally solved this. You can read about the background and context for the question on:

This is the Wolfram Alpha friendly command:
polarplot [ cos(Pi/7)/cos( | (t mod (2Pi/7)) – (2Pi/(2*7)) | ) , {t,0,2Pi}]

That will generate a regular polygon with 7 sides, with a circumradius of 1 unit. Substitute all the 7’s with the number of sides you want and voila! And the general equation is thus:

cos(Pi/N) / cos( ABS( (t mod (2Pi/N)) – (2Pi/(2*N)) ) )

where t is in [0,2Pi], and N is the number of sides

So how did I get the equation?

The formula for the apothem is cos(Pi/N). The apothem is the shortest distance from the centre to the side. With that, I bring your attention to this illustration. (this is a regular polygon with 4 sides. “It’s a square!”. Yes, I know)

Apothem and regular polygon equation explanation

The length “A” is the apothem, and t is the angle running in the equation we stated above. “apm” is the angle the apothem (for this particular segment of t) makes with the positive X axis.

And L is what we want to find.

We will define the first segment as the segment immediately after the segment whose apothem lies on the positive X axis. (so the apothem illustrated above is for the first segment) That will uniquely identify our segments.

Now convince yourself that the angle apm is in multiples of 2PI/N radians.

To find L, we need to find the angle s (I’m running out of colours…). And angle s = t – apm.

So s = t – 2PI/2N

“But that’s not exactly right!” you say. And you’re right. Because that didn’t take care of the multiples of 2PI/N radians thing.

To get the working t angle we’re using, it should be

“working t angle” = t modulus 2PI/N

Convince yourself that’s true. Substitute N with 4 or 5 or 100.

“But that’s not exactly right!” you say. And you’re right.

Because s = “working t angle” – 2PI/2N
can be negative (suppose the red line L is on the right side of A). That’s why we have

s = ABS( (t modulus 2PI/N) – 2PI/2N )

Why do we need to find s again? Because we want to find L. And L can be found with this equation:

A/L = cos(s)

Revise your trigonometry rules. Cosine of the acute angle is equal to adjacent side divide by the hypotenuse.

So L = A/cos(s)
= cos(PI/N) / cos(ABS( (t modulus 2PI/N) – 2PI/2N ))

So why do we need to find L again? In polar coordinates, you only need the angle and the radius (or length from origin) to uniquely determine a point. Since we have the angle, we just need the radius (or length).

That’s why the polar plotting from Wolfram Alpha works.

You can probably convert that from a polar coordinate point equation representation to a Cartesian point equation representation, but I’m done for now.

Considerations for storing Excel cell value in code

You may hate Excel, but you may find a discussion of how Excel stores cell values interesting.

So I have a spreadsheet library. The biggest concern at the initial stage was how to store all the spreadsheet data efficiently. I hear people talking about millions of cells, so I’m scared. If my program stores a spreadsheet cell using 10 bytes (for example), a million cells would take up 10 million bytes in memory.

Let’s start by looking at all the different types of information you can type into a spreadsheet cell. You have:

  • booleans: TRUE or FALSE
  • numbers
  • text
  • rich text (different styled text within the entire text itself)
  • dates and times

For us programmers, “numbers” can be separated into floating point or integer types. An Excel user won’t see a difference.

So how does Excel actually store those values? I’m going to focus only on Open XML because I’m not interested in BIFF files…

  • booleans: TRUE stored as text “1” and FALSE stored as text “0”
  • numbers: stored as text
  • text: duh
  • rich text: stored in a separate shared strings list, with the index to that list stored as text here.
  • dates and times: stored as number that’s in text form

You will see everything is basically stored as text. That’s because the underlying XML files are text files. There’s a property (XML attribute) that differentiates the data, such as boolean, number, string, inline string, shared string.

So why are dates stored as a number? It’s easier to do date calculations with 41449 than “24 June 2013”. So how is this number obtained? See here.

So if you’ve been looking closely enough, Excel’s optimisation tactic is to store everything as numeric text as far as possible. So I want to follow that.

Before doing so however, I went to read what other people are doing AKA open source spreadsheet libraries. In code, they use an object to store the cell value. As in System.Object, the mother of all data types in .NET.

So you have an integer? Dump it into the object variable. Floating point? Dump into object. String of characters? Dump.

How do you read it out? Boxing and unboxing. You remember it’s a floating point value and cast it back from an object to a double variable type.

So what did I do? I have a double variable and a string variable, and I store the cell value in one or the other based on the input.

The “all in object” way has variable (no pun intended) memory size, based on the contents. Sort of. I’m not an expert in this.

My way has a fixed memory size for double’s. Each double takes up 8 bytes (for sure?). A string variable takes up variable size, but because the optimisation tactic is to store data as a number, I can assign the data to the double variable and set the string variable to null. This means the string variable size is sort of fixed too.

So this is what I do. If it’s a number, I store it in the double variable and set the string variable to null. If it’s text, I convert it to a number by using shared strings (out of scope for discussion here) and store the index into the double variable and set the string variable to null. The only cases where the string variable is actually used is if I store the text there, or if I want to store the actual number there (because “1.23456789” may not be stored exactly as that in a double variable. Go read on how floating points are implemented for details), which are rare.

According to Jon Skeet, strings take up 20 + (n/2)*4 bytes (where n is the number of characters). But a null string takes up 8 bytes (it’s either 4 or 8 bytes. I’ll assume the worse scenario).

This means for the most part, each cell has a double variable that takes up 8 bytes and a null string that takes up 8 bytes. A cell value of 10 or 3.14 or 12345678.9 takes up 16 bytes regardless.

Since 16 bytes is less than 20 + (n/2)*4 bytes, I save more memory in most cases. I also have less boxing and unboxing operations, which make things go faster.

File upload size limit in IIS

Yay file uploads. As if letting the users to type in stuff into the web application giving me SQL injection nightmares weren’t enough, now I have to let users upload files.

Peachy.

So during my investigations into the limits of file uploading, I found that I couldn’t upload a file more than 30MB on my test server. It failed faster than Superman could jump a building in a single bound, and with just as much sound.

In short, here are my findings. The default file size limit set in IIS (6 and below? Read on for more details) is 4MB. In IIS7 (on Windows Server 2008), the file size limit is 30MB (technically it’s 28.61MB because it’s 30000000 bytes but who’s keeping track. Hey you read on!).

So how do you change the limits? In the web.config file. We’re doing ASP.NET applications.

<httpRuntime executionTimeout="3600" maxRequestLength="20480" />

That will give you a timeout period of 1 hour (3600 seconds) and a file size limit of 20MB (20480 KB. Yes, that attribute is in kilobytes).

For IIS7, we do this:

<security>
    <requestFiltering>
        <requestLimits maxAllowedContentLength="134217728" />
    </requestFiltering>
</security>

That gives you a 128MB limit (128 * 1024 * 1024). Yes it’s in number of bytes.

So why was I doing file uploads? Documents from university staff or students. The most important of which is the final doctoral thesis.

I asked how large can that thesis be, assuming it’s in PDF form. I got an answer where a 40MB limit seems too small. Really?

I had trouble auto-generating an Excel file of 40MB just to test the server limits. Do you know how large 40MB is?

If it’s a video or sound file, then yes I can believe it. I have video files of over 100MB, some over 200MB. But a PDF? With mostly text?

Go check out the Open XML specs from ECMA. The largest document is about 28MB. It’s over 5000 pages. I doubt any thesis can match that number of pages.

Academic self-publishing

As of this writing, I’ve worked in the academic industry for slightly over 3 months. More on this later.

Claire Morgan sent me this article on academic self-publishing. There are good points and bad points regarding self-publishing, which are exaggerated particularly so for the academic industry. I should know, since I’m making a web application for internal use in a university.

As part of my work, I learnt a lot about how the Ph.D. degree students go through their academic years, and what are the processes they go through. Yeah my web application is going to be used by staff and future doctors (albeit Ph.D.’s). Go me.

One of the more important parts of being a Ph.D. student is publications. It’s not necessary to publish any papers but they help increase your credibility. Perhaps in helping with raising the impressions of examiners who attend your thesis defence. Every little bit helps, I guess.

But you can’t just publish your work anywhere. The publisher has to be of repute and your work must be peer reviewed.

This means self-publishing is looked down upon even more by the academic industry.

But wait!

There are 2 points I found interesting in Claire’s article.

The 1st point is that you don’t have to publish your entire work. Maybe a non-vital piece of your research but is still informative and useful. “Non-vital” is of course relative to your entire research work as a whole.

The 2nd point is that you can publish mistakes or research results that didn’t go anywhere. These don’t help you and your final research publication, but they might help some other poor fellow from wasting resources going down that route.

So what’s happening lately for me?

As I said, I’m working in a university now. Well, technically they outsourced the work to me so I’m still considered self-employed. We’ll see…

I’m stationed in a research lab. I’m surrounded by Ph.D. students. My manager is a Ph.D. student. Or at least he’s the project officer who’s my liaison between the IT support department and me. But psshht, semantics.

As part of my work, I’m using ASP.NET MVC (model-view-controller) and jQuery. Both of which I’m not familiar with at the start of my contract. Fun times… I was more of a back-end kind of guy.

Speaking of back-end, my spreadsheet library is doing well. Go check out SpreadsheetLight if you haven’t, and it’s also on NuGet (which I just learnt about, even though I’ve been using Visual Studio for like donkey years. Like I said, I’m more of a back-end guy. How do you pronounce “NuGet”? Like “nugget”?).

So yeah, if you haven’t, go read that article. Tell me what you think.

Specious spreadsheet security

If not for Chinese, it would’ve worked.

So in Excel, you can set a password for either protecting a particular worksheet, or protecting the entire workbook/spreadsheet. This password is then hashed, and the result is stored within the spreadsheet contents.

Now with the use of Open XML spreadsheets, this means the resulting hash is stored in “plain text” within XML files. Without going into too much detail, here’s the algorithm for the hash as documented in the Open XML SDK 2.0 help docs:

// Function Input:
//    szPassword: NULL-terminated C-style string
//    cchPassword: The number of characters in szPassword (not including the NULL terminator)
WORD GetPasswordHash(const CHAR *szPassword, int cchPassword) {
      WORD wPasswordHash;
      const CHAR *pch;
 
      wPasswordHash = 0;
 
      if (cchPassword > 0)
            {
            pch = &szPassword[cchPassword];
            while (pch-- != szPassword)
                  {
                  wPasswordHash = ((wPasswordHash >> 14) & 0x01) | ((wPasswordHash << 1) & 0x7fff);
                  wPasswordHash ^= *pch;
                  }
            wPasswordHash ^= (0x8000 | ('N' << 8) | 'K');
            }
      
      return(wPasswordHash);
}

This algorithm is wrong. Or at least it doesn't give the resulting hash that Excel produces.

Granted, I didn't really expect the algorithm to be correct. Because from the SDK help:

An example algorithm to hash the user input into the value stored is as follows:

It's an example algorithm, so it may or may not be the one that Excel actually use. However, for the purposes of usability, the password used by users have to be encrypted using Excel's algorithm, so we have to somehow get the resulting hash. Either we get the algorithm itself, or we simulate an algorithm such that the resulting hash matches that of Excel's.

Which is what Kohei Yoshida did. See his modified algorithm. This algorithm worked!

Given that I'm Chinese, I did what's natural: I used Chinese characters as the password.

And the modified algorithm failed. It only worked if the password consisted only of Latin alphabets. I tried Japanese characters. Failed too.

This is why I don't support password protection in SpreadsheetLight. I don't want to give the false impression that the worksheet/workbook encryption works. This is one feature where "partially worked" is unacceptable.

Granted Open XML spreadsheets also support other types of encryption, and you can store the name of the algorithm and salt value you used, and even the number of times the hash algorithm was run.

But.

This is in the context of a spreadsheet library.

What are spreadsheet libraries mostly used for? Automation.

Which means minimal (if at all) human interaction and intervention.

And so the question comes up.

Where do you store the password?

If a human is protecting the worksheet/workbook, she will provide the password herself, and then encrypts it (well Excel does it), and she just remembers the password.

If a spreadsheet library is generating the workbook, and encrypting it, the password has to be gotten from somewhere, right? So it's stored, maybe in a text file, maybe in a database, maybe hardcoded in code, or whatever.

The point being that the password is not held solely by a human being. And a computer hard drive is easier to hack into than a human brain.

And I will prefer not to be a party to facilitating insecure spreadsheet generation. Besides, it's Open XML. The data is supposed to be open and sharable. Password protection seems to be the opposite. Even Microsoft cautions the use of depending just on encrypted Excel files.

We already have social engineering used by devious people to deceive people into giving their passwords over. Storing passwords on a computer seems suicidal because computers have no common sense at all.

As a final word, I'd say using the Open XML SDK can be either verbose, or obscenely painstakingly verbose. Simple tasks need a couple of dozens of lines of code, and complex tasks take at least 2 magnitudes of work to do. For individualistic, compartmentalisable (that's not a word, right?) tasks, you can do it from scratch. Add even a smidgeon of complexity, and you'll find a library more useful. Try mine.