Nobody told me to do that

Nobody told me to write a guide on Open XML spreadsheets, but I did it anyway.

Nobody told me I could continue publishing my own magazine, without any revenue, and armed only with the passion to spread my ideas and finding like-minded individuals, but I did it anyway.

Nobody told me to start making videos, but I did it anyway.

Nobody told me to help people with maths questions, but I did it anyway (for free).

Nobody told me to help people for free when I offer a programming guide for purchase, but I did it anyway.

Nobody told me to write a thank you email to customers when they buy from me, but I did it anyway.

Nobody told me to write blog posts here, but I did it anyway (because I enjoy writing here).

You don’t need anyone to tell you to do anything. Losing weight. Gaining muscle. Be a better speaker. Be a better programmer. Learn to dance. Learn a new language. Travel the world. Travel the world on a budget. Start a new business. Have children. Teach children. Teach someone a skill.

You don’t need the year to end, and a new year to begin, to start. If you don’t need permission from someone to start, you certainly don’t need permission from the Earth rotating about the Sun to start.

Say “I will do that.” Then go do that.

Absolutes are relative

I came upon a realisation in my first year of university. There are very few absolutes in the universe.

I was sitting in the lecture theatre, taking notes of the professor’s lesson. I was in my first year, and in my first semester, and I haven’t any friends I knew there. “Friends” were people I saw frequently (if you could call the first 2 weeks “frequently”). After two and a half years of being conscripted in the army, my brain was raring to go (about the most mentally strenuous activity I remember was figuring out how dBase IV and FoxPro work [those are database systems by the way]. Oh and how to make the records print nicely. That’s interesting, considering that I had to send letters to over 500 military personnel, and one choke of the printer sent hours and tons of paper to waste. Lining up address information on the paper could be quite challenging. Another story for another time…).

It was a maths lecture (not surprisingly…) about fundamental logic (I think). I learnt of the term “for all” (or “for every” or something similar), which is represented by an inverted capital A. For example, for all even numbers, one of the factors is 2.

This “for all” term is not used lightly. When you say, “for all”, it means for all conditions, circumstances, situations, universes, even alternate realities, that the next statement is true.

And as the professor said, all you need is one example of the statement being false, and the whole statement collapses.

A related concept is the negative. For example, “There is no such thing as a zombicorn.” First, there’s no such thing as a zombie. Second, there’s no such thing as a unicorn. Uh, I’m not going to contest you on that. Go Google it or something…

What you mean by “There is no such thing as XYZ”, is that for all conditions, circumstances, situations, universes, even alternate realities, that the statement is true. And all you need is the existence of XYZ for that statement to be false.

Because of this, the professor also said that it’s impossible to prove a negative. We just barely found Earth-sized, possibly habitable planets at the outer reaches of our exploration of space. How can anyone possibly search the entire known (and unknown) to find that one existence of proof? Have you searched all the planets out there? Do you know for sure, that there is absolutely no way that XYZ can possibly exist?

This is why I find maths interesting. Some of its concepts can be proven. For example, the statement “There is no such thing as an even number with a factor that’s 2.” All I need to disprove that statement is find the existence of an even number with 2 as a factor. For example, 6 (with 2 and 3 as factors).

Once I realised that about the only absolute statements are in maths (and possibly physics, but I suck at physics, so, yeah…), and even then those absolute statements are held in the strictest of scrutiny, I also realised that (almost?) everything is relative. Yes, I know I’m way behind some fellow named Einstein who mentioned some theory of relativity somewhat…

The notion that nothing is absolute scares the hashbrown out of some people. Those people need to know that this is right and that is wrong. That this is black and that is white. That there are clear cut lines with which they can stand behind of. That there are “right” arguments and opinions they can back themselves with.

For example, the statement “You’re always late.” really means the person is saying you’re always late in the person’s mind. Never mind the few times that you are early, because that person will conveniently forget about those instances (because of cognitive dissonance. The person had to convince herself that she’s right about you being always late, and thus fabricates proof that substantiates her opinion). Also, it presupposes that you will continue to always be late. And all you need is to be early once, and that statement is false (but cognitive dissonance will thwart your attempts at defending yourself).

This taught me to be tolerant of other people’s views. When nothing is absolute, then nothing is certain. Like I said, this scares the cranberry out of some people.

And this coming from a maths lecture. More interesting still, it came from a discipline that’s known for its strictness.

Optimising only for profit is a lousy strategy

I felt sorry for the woman when I heard she was going to be let go by the company. I felt even more sorry when I heard that she would be replaced by 3 graduates in China. Seriously, graduates were that cheap in China?

This reminds me of a Chinese phrase. “In the past, having a degree was a big deal. Now, the whole street’s filled with graduates.” Not all degrees are created equal.

Let’s start off with a few baseline understandings…

Infinity and beyond

John Cook said this about infinity,

Problems are often formulated in terms of infinity to make things easier and to solve realistic problems. Infinity is usually a simplification. Think of infinity as “so big I don’t have to worry about how big it is.”

(Emphasis mine)

Companies like infinity. Particularly when it comes to describing (theoretical) growths and market share. This is false. More on this later.

Basic economics

We will assume this simple generalised equation for the purpose of this article:

Profit (or earnings) = Revenue – Cost

You can think of revenue as the price of an item. Cost covers everything from the cost of manufacturing an item to storing the item, to paying employees, to paying rent (for use of space), to paying utilities.

Just keep in mind that profit is calculated from 2 components.

The gold standard and Bretton Woods

Back in the old days (way way back), the value of money was static. If you held on to a dollar, 10 years later, that dollar was still worth a dollar. That’s because the value of money was tied to gold.

Historically, a bank was legally responsible to give anyone gold in exchange for the money bill given. That means if you handed the bank 100 dollars, the bank had to give you 100 dollars worth of gold. This meant that banks had to keep large reserves of gold, just in case.

The invention of the money bill dollar note thingy just made it easier so you don’t have to carry around nuggets of gold. Gold’s heavy.

In July 1944, the Bretton Woods Agreement was signed. Basically, many countries agreed to tie their currency to the US dollar. The US dollar was tied to the gold standard, so this wasn’t a problem. (This was part of the reason why US rose to be a dominant force in the world in the early days, because practically everyone was using the US dollar as a reserve currency)

In August 1971, the United States stopped the convertibility of the US dollar to gold. It might have something to do with funding the battles of the Vietnam War. The US ran out of funds. To continue funding, the US needed to print money out of thin air. And you couldn’t do that if your currency was pegged to gold. (Note: I’m not bashing on Americans. I read this in an economics book. No I can’t remember which book… you should know me by now…).

This also “freed” the other countries from tying their currencies to the US dollar. Which (probably) gave rise to the idea of foreign currency exchange rates.

The dissolution of the Bretton Woods Agreement also meant the creation of fiat money. Meaning that dollar you have there is worth what the government say it’s worth. Printing money out of thin air also gave rise to the concept of inflation. Meaning that dollar you have there is probably worth less than a dollar a year ago.

Saturation limits

31 October 2011 was designated as the day when the world population became 7 billion. It’s a big number, but it’s not infinity.

Which is where the companies made their mistake.

In the post-World-War-2 era, everyone wanted a better life. We’ve sacrificed enough. We’ve suffered enough. We want a better life! (baby boomers, hello!)

Babies were made. Population grew. Household appliances made their ways into homes. Henry Ford created the automobile. Product categories multiplied. Industries boomed.

Revenue was up. Sales quintupled. Profits were up.

Just when local markets seemed exhausted, globalisation came and opened up the world. International trade continued the seemingly upward trend.

People started expecting growth as a natural consequence. Companies started paying more attention to Wall Street and upholding shareholder value.

“We just need to capture 1 more percent of market share!”

That started to get harder. The customers who wanted to buy your product had already bought your product.

I read that in America, there were more licensed vehicles than licensed drivers. Meaning there were more vehicles than people who could drive them. I understand there’s a surplus of 31 million of such vehicles. Supposedly, every man, woman and child in Canada could have a vehicle from this surplus.

There are probably more cell phones than cell phone users. There’s more food produced than needed to feed every person in the world (yet there are millions starving).

What happens if Microsoft succeeds in placing a computer (with Windows, naturally) on every desktop and in every home? What happens if Apple succeeds in placing an iPhone/iPad in everyone’s hands? What if everyone has already bought Angry Birds on their iPhone/iPad? What happens if McDonald’s succeeds in getting everyone to eat at their restaurants? What if everyone used an Oral B toothbrush? What if everyone used Body Shop products? What if every male used Old Spice?

What if every business person is already flying with your airline? What if every Harry Potter fan already has all 7 books? (that’s probably a rhetorical question…) What if every C# programmer already owns a copy of your C# programming book? What if every tea lover in your area is already frequenting your tea house?

What if every possible customer already has your product? What if every possible customer already maxed out his/her rate of consumption of your product?

The natural limit is population. The next limit is rate of consumption. Every company hits these 2 limits. The limits just weren’t as prominent a couple of decades ago.

Revenue started stalling

When you hit those natural limits, the company growth stalls. To give the illusion of growth, we go back to that equation again.

Profit = Revenue – Cost

The outside world (mainly Wall Street and the stock market) views growth in relation to profit. The assumption is that if a company is making a profit, it’s still healthy. As in it’s still bringing in revenue.

But if you’re not bringing in revenue, it means you’re not making any more sales. Maybe it’s because your customers switched brands. Maybe your customers switched to a cheaper version of your product (which cannibalises on your own sales, but hey at least you didn’t lose that customer).

But in today’s hyperconnected world, the reason is probably that your customer “market share” is already saturated. You might think 7 billion people is still a lot of people, but a large part of those people are in poverty. They simply cannot buy your product. Or those who can buy your product, don’t want your product.

Some new startup shows up and gets millions of users within a month. It continues at a steady pace and then… stops. The natural equilibrium is reached.

The company CEO has to do something to show that the company is still growing (because the people watching Dow Jones is breathing down her neck). So if revenue doesn’t increase as much, what can you do to increase profits? Reduce costs.

Cost reduction policies

I’d say as a broad generalisation, there’s only so much you can do to reduce costs. Rent space? Consolidate people and equipment in fewer locations. Equipment maintenance costs? Have less equipment, or more efficient equipment, or just get rid of the whole thing.

But one of the most costly line items (if not the most costly) is hiring people. (Be honest. Tell me when I said “cost reduction” you didn’t think of “layoffs”)

Let’s see. The world population is growing (albeit more slowly now). Generally speaking, more people are working (I know the current economy sucks with few jobs being created. Stay with me). Less people are dying. More people are having longer lives. Less opportunities to move up the corporate ladder (because the high level managers are still there).

Yet people still expect pay raises every year. I’m not pro-Malthusianism, but the supply of money is kinda limited… Wait, good thing the Bretton Woods Agreement was dissolved.

Since people have feelings (and machines and raw materials don’t), companies hesitate to fire people (in case of major backlashes). So something has to give.

Outsourcing (the bad kind). Mergers and acquisitions (probably where the term “wholly owned subsidiary” came from). Subtle changes in accounting books (which is illegal, don’t do it).

Anything to create the illusion of growth and profits. (And with the fiat currency system, money itself is kind of an illusion. But that’s another topic…)

It’s made people commit suicide to make an iPhone. It’s made people to over-consume (creating obesity as a problem and the dieting industry to exist). It’s made people buy houses they couldn’t really afford. It’s made people to allow those people who couldn’t afford houses to buy houses.

It’s made people look for shallower qualities in marriage partners (diamonds, big car, big house, big breasts [I hesitated on including this one], big paycheck), which caused increasing divorce rates, which increased the number of divorce lawyers needed, which increased the number of real estate agents needed (to split the property).

It’s caused the dot com bust. It’s caused tech startups to look for the fastest exit strategy, because the venture capitalists backing the startup forced the founders to do so (so the VCs could get their return on investment).

Optimising only for profit is a lousy strategy.

Pictures in Excel have way too much power…

You’d think inserting a picture into an Excel worksheet is pretty straightforward. If you’re just inserting the picture, then it is.

Then you check what other properties you can play with manipulating the picture. Woah amigo! There’s a whole plethora of options!

Excel picture format options

That’s like giving the typical user a (good enough) subset of rendering functions, including 3D. And here I thought you could just resize the picture, and maybe rotate it… If you’re not going for full 3D manipulation as in OpenGL or DirectX, Excel will do it for you.

Excel respects alpha/transparency of the picture (right now, I only know of PNG images that contain alpha information AND is fairly prevalent). And you can outline the picture and fill the transparent portions with a colour.

SpreadsheetLight picture fill and outline

You can even do shadows!

SpreadsheetLight picture shadows

Do you know it can take a phenomenal amount of work to get shadows working in 3D renderings? You’ve got to know the light source position, calculate the rays of light blocked by an object to create the illusion of a shadow (by creating a polygon that’s the outline of that object as described by those blocked rays of light). Well, technically speaking, Excel has got it easy, since the object is always a rectangle (an image).

Speaking of light, we can also do reflections. Let’s run a full gamut of the 3D power.

SpreadsheetLight 3D pictures

I lost the software keys to my 2 3D rendering software (Bryce 4 and TrueSpace). It sucked that I couldn’t render landscapes anymore… But, I’m seeing Excel as an alternative to getting some 3D-ish images.

Well, the above screenshots were from a spreadsheet generated by my software library, SpreadsheetLight. The library is based on the Open XML SDK, which in turn is based on what Excel can do. Here’s how the source code looks like:

SLDocument sl = new SLDocument(SLThemeTypeValues.Oriel);

SLPicture pic;
                
sl.SetCellValue(2, 2, "Accent 1");
sl.ApplyNamedCellStyle(2, 2, SLNamedCellStyleValues.Accent1);
sl.SetCellValue(2, 3, "Accent 2");
sl.ApplyNamedCellStyle(2, 3, SLNamedCellStyleValues.Accent2);
sl.SetCellValue(2, 4, "Accent 3");
sl.ApplyNamedCellStyle(2, 4, SLNamedCellStyleValues.Accent3);
sl.SetCellValue(2, 5, "Accent 4");
sl.ApplyNamedCellStyle(2, 5, SLNamedCellStyleValues.Accent4);
sl.SetCellValue(2, 6, "Accent 5");
sl.ApplyNamedCellStyle(2, 6, SLNamedCellStyleValues.Accent5);
sl.SetCellValue(2, 7, "Accent 6");
sl.ApplyNamedCellStyle(2, 7, SLNamedCellStyleValues.Accent6);

pic = new SLPicture("mandelbrot.png");
// anchor at cell (4,2) with 0 horizontal and vertical offsets.
pic.SetRelativePositionInPixels(4, 2, 0, 0);
sl.InsertPicture(pic);

pic = new SLPicture("mandelbrot.png");
pic.SetRelativePositionInPixels(4, 6, 0, 0);
pic.SetSolidFill(DocumentFormat.OpenXml.Drawing.SchemeColorValues.Accent3, 20);
pic.SetSolidOutline(DocumentFormat.OpenXml.Drawing.SchemeColorValues.Accent4, 0);
pic.SetOutlineStyle(4, DocumentFormat.OpenXml.Drawing.CompoundLineValues.Double, DocumentFormat.OpenXml.Drawing.PresetLineDashValues.LargeDash, DocumentFormat.OpenXml.Drawing.LineCapValues.Round, SLPicture.SLPictureJoinType.Bevel);
sl.InsertPicture(pic);

sl.AddWorksheet("Sheet2");

sl.SetCellValue(2, 2, "Accent 1");
sl.ApplyNamedCellStyle(2, 2, SLNamedCellStyleValues.Accent1);
sl.SetCellValue(2, 3, "Accent 2");
sl.ApplyNamedCellStyle(2, 3, SLNamedCellStyleValues.Accent2);
sl.SetCellValue(2, 4, "Accent 3");
sl.ApplyNamedCellStyle(2, 4, SLNamedCellStyleValues.Accent3);
sl.SetCellValue(2, 5, "Accent 4");
sl.ApplyNamedCellStyle(2, 5, SLNamedCellStyleValues.Accent4);
sl.SetCellValue(2, 6, "Accent 5");
sl.ApplyNamedCellStyle(2, 6, SLNamedCellStyleValues.Accent5);
sl.SetCellValue(2, 7, "Accent 6");
sl.ApplyNamedCellStyle(2, 7, SLNamedCellStyleValues.Accent6);

pic = new SLPicture("mandelbrot.png");
pic.SetRelativePositionInPixels(4, 2, 0, 0);
// transparency 0%, blur 6pt, angle 90 degrees, distance 3pt
pic.SetInnerShadow(DocumentFormat.OpenXml.Drawing.SchemeColorValues.Accent1, 0, 6, 90, 3);
sl.InsertPicture(pic);

pic = new SLPicture("mandelbrot.png");
pic.SetRelativePositionInPixels(4, 6, 0, 0);
// transparency 50%, horizontal size 100%, vertical size -23%, horizontal skew -13.34%, vertical skew 0%
// blur 6pt, angle 45 degrees, distance 3pt
// origin at picture's bottom left, don't rotate with picture.
pic.SetPerspectiveShadow(DocumentFormat.OpenXml.Drawing.SchemeColorValues.Accent2, 50, 100, -23, -13.34m, 0, 6, 45, 3, DocumentFormat.OpenXml.Drawing.RectangleAlignmentValues.BottomLeft, false);
sl.InsertPicture(pic);

sl.AddWorksheet("Sheet3");

sl.SetCellValue(2, 2, "Accent 1");
sl.ApplyNamedCellStyle(2, 2, SLNamedCellStyleValues.Accent1);
sl.SetCellValue(2, 3, "Accent 2");
sl.ApplyNamedCellStyle(2, 3, SLNamedCellStyleValues.Accent2);
sl.SetCellValue(2, 4, "Accent 3");
sl.ApplyNamedCellStyle(2, 4, SLNamedCellStyleValues.Accent3);
sl.SetCellValue(2, 5, "Accent 4");
sl.ApplyNamedCellStyle(2, 5, SLNamedCellStyleValues.Accent4);
sl.SetCellValue(2, 6, "Accent 5");
sl.ApplyNamedCellStyle(2, 6, SLNamedCellStyleValues.Accent5);
sl.SetCellValue(2, 7, "Accent 6");
sl.ApplyNamedCellStyle(2, 7, SLNamedCellStyleValues.Accent6);

pic = new SLPicture("mandelbrot.png");
pic.SetRelativePositionInPixels(6, 3, 0, 0);
pic.SetFullReflection();
// width 6pt, height 6pt
pic.Set3DBevelBottom(DocumentFormat.OpenXml.Drawing.BevelPresetValues.Convex, 6, 6);
// width 3pt, height 4pt
pic.Set3DBevelTop(DocumentFormat.OpenXml.Drawing.BevelPresetValues.ArtDeco, 3, 4);
// extrusion colour transparency 0%, extrusion (or depth) height 15 pt
pic.Set3DExtrusion(System.Drawing.Color.Green, 0, 15);
// contour colour transparency 40%, contour width 4pt
pic.Set3DContour(DocumentFormat.OpenXml.Drawing.SchemeColorValues.Accent3, 40, 4);
pic.Set3DMaterialType(DocumentFormat.OpenXml.Drawing.PresetMaterialTypeValues.TranslucentPowder);
// 5 pt above "ground"
pic.Set3DZDistance(5);
// field of view 105 degrees, zoom 100%
// camera latitude, longitude, revolution in degrees (50, 40, 30)
// light rig latitude, longitude, revolution in degrees (0, 0, 30)
pic.Set3DScene(DocumentFormat.OpenXml.Drawing.PresetCameraValues.PerspectiveFront, 105, 100, 50, 40, 30, DocumentFormat.OpenXml.Drawing.LightRigValues.Sunrise, DocumentFormat.OpenXml.Drawing.LightRigDirectionValues.TopLeft, 0, 0, 30);
sl.InsertPicture(pic);

sl.SaveAs("Pictures.xlsx");

I use the enumerations available in Open XML SDK as far as possible. This means you can sort of port over any programs you have written using Open XML SDK. And also that I don’t have to invent my own enumerations that are essentially copies of the SDK enumerations.

One thing that confused me was the 3D rotation options in Excel.

SpreadsheetLight 3D picture rotation options

Excel used the vertical “axis” as the X value, and the horizontal “axis” as the Y value. To the user, the X, Y and Z values are like the first, second and third values of … something.

To me, X, Y and Z have special meanings, particularly when applied to the context of 3D. Those values don’t even increase in a consistent manner. The X value decreases if you use the right-hand rule (the left button), but the Y and Z values increase when you use the right-hand rule (left and right buttons respectively).

The Open XML SDK then complicates matters by using the terms latitude, longitude and revolution. Each ranging from 0 degrees to 359.9 degrees (or strictly less than 360 degrees in other words).

And in case you’re wondering about the state of the spreadsheet library progress, I froze the feature set of SpreadsheetLight for version 1. Otherwise, I’d never get it shipped. I’m now documenting the hashbrown out of the source code. The point is to make it ridiculously easy for a programmer to pick up SpreadsheetLight and start using it (without having to refer to a manual, which I’ll also be writing).

Simplifying the difficult is itself difficult

“Vincent, you will lead the task force.”
“What?!?”

The annual survey results were just delivered by the respective company directors to their respective departments. The directors would gather their department staff together, and deliver a PowerPoint presentation about the various survey results. Typically, they would also discuss what the company plans were (when relevant), or major/foreseeable changes, since everyone was gathered.

I would be slightly fearful. Because my department director knew me by name. Not that I’m singled out, since he knew many of his staff by name too. The reason was that I’m the only one with a maths background (I think he hired me because I had a maths background. He’s in charge of the billing support arm of the IT department).

The survey was conducted by an external company, and the results would contain a couple of mathematically phrased terms. The most prominent one was “statistically insignificant”. At which point, the director would say something like, “Probably only Vincent knows what ‘statistically insignificant’ means, since he’s the mathematician.”. At which point, I’d hope he didn’t ask me to explain it, because I suck at statistics…

I believe the company CEO wanted something done about the worst 2 “complaints” from the survey results. One of the survey questions was “Do you feel safe at work?” What do you mean “safe”? It’s not like the copier machine was going to eat my hand. Do paper cuts count? My office was situated beside 2 large hydrogen containers (I could see them through the window. Hey, Large Hydrogen Container = LHC. Lol…). Does that count? And no, “Do you feel safe at work?” wasn’t one of the issues.

The task force I’m to lead was to address the issue, “Do you feel safe to speak up?”. Apparently, the answer was a statistically significant “No”.

I can’t remember what the other issue was, but I was to co-run the entire task force with another person, who’d be in charge of that other issue. One of the reasons cited was “There’s no point speaking up, since no one’s listening.” (or some such). I think the more interesting point is why the word “safe” was used.

Anyway, I presented the findings in a PowerPoint presentation to the director and the high level managers. I was actually asked to create a PowerPoint that reads like a report, and submit it beforehand. I resisted, and said I could write up a proper report (in Word) if it’s required, but the PowerPoint presentation was to remain. I won. (yay!)

The presentation went off fine. I even managed to insert “Law of Large Numbers” as a point on one of the slides. Hey, I am a mathematician (a couple of the managers chuckled). I even managed to squeeze in a joke about vacuum cleaners and how something sucks.

Presentation over. Task force assembled to tackle issue. Do something about 2 worst complaints. Check.

I believe it was a difficult problem. Not the task itself, but the issue. So it’s easier to speak up to me, than it was to speak up to management? That spells a fundamental problem that a small task force wasn’t going to solve.

Yet the problem was hoisted onto my shoulders, expecting me to simplify that difficult problem into a series of simple tasks to solve that problem. Simplifying things is hard.

You simplify things very often. Ever write a function? That’s simplification. You thought about a problem, came up with some code that does something, and that could be reused. The bad programmers write functions that could be used only in certain conditions, even though they could be rephrased for a more general use. The great programmers write functions that you feel confident using, even if you don’t really know the innards of the function (and if you did look, the code will be elegant or easy to follow).

Mathematicians come up with mathematical models to describe and solve a problem as best as they could. Programmers come up with a bunch of code to describe and solve a problem as best as they could. No model is infallible, nor is any program infallible.

That’s because simplifying the difficult is itself difficult. But we can still come up with a suitably close enough approximation to a solution.

Simple tasks are sometimes the hardest to do

Time slowed as her hair gently brushed against my face. I smelled the briefest of whispers of vanilla as she continued to twirl. I caught her to bring her revolution to a stop. I held her right hand with my left, and cupped my right hand ever so gently on her left shoulders. Just as she laid her left hand on my shoulders for support. We danced and danced …

And tried very hard not to step on each other’s toes. I was learning to dance the rumba.

Back in my previous employment, one of my colleagues then persuaded me to join a rumba dance class. He’s biased, since he could dance the cha cha, salsa, rumba and do ballroom dance (he won regional competitions). So after weeks of his persuasion, I decided to go for one of the rumba classes.

First thing I noted was that there were no “young” male dancers (“young” being relative, of course). The class welcomed any male participants, since they almost always lacked male dance partners (Dating advice? Dance classes typically starved for men. Consider salsa).

Second thing I noted was that I was the only first-timer there. Everyone had already taken classes in some other dance, such as salsa or cha cha. This meant I had a lot of catching up to do, since the instructor moved the pace of the class up.

Third thing I noted was my normal work clothes were really not designed for rumba dancing. While I’m not that buff, my pectorals and biceps and triceps fill out my long sleeved shirt enough to restrict freer movement. And although I have a 29 inch waist, I typically buy pants for 31 or 32 inch, because I have muscular thighs (oh, there goes my modesty…). And even then my pants were still fairly tight. Do you know the kinds of things you have to do with your waist in rumba?

Alright, alright, we’ll get back to my dance partner. Her name’s White Snow, translated directly from Chinese. Her family name’s White. What, you have Barry White and Snow White, but we can’t have White Snow? (that said, is Snow White the entire name? Or is there a family/last name?).

She’s pretty enough. I don’t know if she had a boyfriend. I didn’t ask. (Although everyone back at the office was like, “Hey Vincent, that girl there? What do you think?”) I much prefer Caucasian women.

[
Inner Critic: Is this really the platform to be telling everyone your dating preference?
Me: It’s my blog. I can do whatever the hashbrown I want.
Inner Critic: Why are you using the word “hashbrown”, which isn’t even a wor…
Me: It’s my flying fishball blog. I can use “hashbrown” whenever the hashbrown I want.
]

The dance instructor (who’s especially tall. And that’s saying something, since I’m 1.78 metres tall) taught a dance routine. We rotated dance partners as we went. Each lesson, he’d teach a new segment of the routine, and we’d practise it. Then we’d go from the beginning of the routine all the way to the new segment.

There were 10 lessons in all, and typically, the instructor would have taught the entire routine only at the 9th or even 10th lesson. For that particular class, I think he finished it on the 8th (or 7th) lesson. That meant the pace was very fast. He also told me I was quick to learn and catch up. For the first few lessons though, it was all I could do to remember what to do with my feet, let alone what to do with my arms.

Which brings us to the basic moves. At the start of each class, we’d go through some basic moves. They were all on the feet movement. However, your hands must be up in the default position. What’s the default position?

Stand up. Go on, I’ll wait. Hold your arms straight out to your sides, as though you’re a scarecrow. Then bend your arm at the elbow, keeping your upper arm still parallel to the ground. So now your upper arms point out to the side, and your forearms point in front of you. There. Now keep your arms in that position the whole time.

If during the dance, your hands are not either holding on to your partner, or twirling her, or doing some particular dance move, your arms go to that default position.

It’s a very simple position, yet it’s critical, because it makes the dancers look good. You’re supposed to be dancing in high energy, with grace and proper posture. My dancer colleague even told me he had to practise smiling even though he’s heaving from exhaustion. Did you know the male dancer is the one leading the entire dance? The female follows the male’s lead. When the female returns to your embrace from her twirling, you’ve got to catch her and hold her steady. And not fall out of balance (I mimed the *boing boing boing* of me hopping on one leg and my friend laughed).

For rumba, that’s the simple task. Hold your arms up. My arms were ready to drop after the first few lessons. It’s very tiring to keep them up the whole time.

It doesn’t matter what it is. Refactoring some code. Giving a good variable name. Taking the garbage out. Thinking or finding out a good algorithm. Replying “No” to that email.

Just because it’s simple doesn’t mean it’s easy.

Rich strings and inline strings in spreadsheets

Quite a while ago, I was mucking around in Excel and I discovered you can set the text in a cell to different fonts! Even different colours! (Ok, you’re probably bored of me going on about spreadsheets and Open XML, but it’s all I’m thinking about right now…) Granted, it’s a limited set of font style manipulations, but I’ve always thought the text in a cell was completely subjected to the cell style. I never thought you could change anything within a cell. I’m not an expert Excel user, ok?

The term used is an “inline string”. At least that’s what it’s referred to in the Open XML SDK, as the InlineString class.

This gave me a problem. How do I implement this in my spreadsheet library? It’s not as easy as just setting a cell value. You’d have to set up all the fonts and colours and bolds and italics and underlines, and then dump that bunch of stuff into a cell.

If you do it by hand, you’ll run (haha, foretelling a pun) into the DocumentFormat.OpenXml.Spreadsheet.Run class. Basically, you’re appending style runs. Here’s how you do it in Excel:

Inline string

You select the text in the formula box (not within the cell). Then you apply any font styles you want.

Aaannd… here’s where I tell you how my spreadsheet library is going to make your life easier. Here’s a sample screenshot of a result:

SpreadsheetLight inline string

Let’s look at the source code to generate that.

SLDocument sl = new SLDocument(SLThemeTypeValues.Metro);

SLFont font;
SLRstType rst;

font = new SLFont();
font.FontColor = System.Drawing.Color.Red;
rst = new SLRstType();
rst.AppendText("Roses are ");
rst.AppendText("red", font);
sl.SetCellValue(2, 2, rst.ToInlineString());

font = new SLFont();
font.FontColor = System.Drawing.Color.Blue;
rst = new SLRstType();
rst.AppendText("And violets are ");
rst.AppendText("blue", font);
sl.SetCellValue(3, 2, rst.ToInlineString());

font = new SLFont();
font.Bold = true;
font.Italic = true;
font.Underline = UnderlineValues.Double;
font.SetFont(FontSchemeValues.Major, 11);
font.SetFontThemeColor(SLThemeColorIndexValues.Accent2Color);
rst = new SLRstType();
rst.AppendText("But seriously...", font);
sl.SetCellValue(4, 2, rst.ToInlineString());

font = new SLFont();
font.SetFont(FontSchemeValues.Minor, 15);
font.SetFontThemeColor(SLThemeColorIndexValues.Accent1Color);
rst = new SLRstType();
rst.AppendText("you don't ", font);
                
font = new SLFont();
font.Italic = true;
rst.AppendText("have ", font);

rst.AppendText("to ");

font = new SLFont();
font.Underline = UnderlineValues.Single;
font.FontColor = System.Drawing.Color.OrangeRed;
rst.AppendText("emphasise ", font);

rst.AppendText("it ");

font = new SLFont();
font.Bold = true;
font.SetFontThemeColor(SLThemeColorIndexValues.Accent3Color);
rst.AppendText("so ", font);

rst.AppendText("much...");

sl.SetCellValue(5, 2, rst.ToInlineString());

SLStyle style = new SLStyle();
style.Fill.SetPatternForegroundColor(SLThemeColorIndexValues.Accent1Color);
style.Fill.SetPatternType(PatternValues.Solid);
sl.SetCellStyle(7, 2, style);
sl.SetCellValue(7, 3, "Accent 1");

style = new SLStyle();
style.Fill.SetPatternForegroundColor(SLThemeColorIndexValues.Accent2Color);
style.Fill.SetPatternType(PatternValues.Solid);
sl.SetCellStyle(8, 2, style);
sl.SetCellValue(8, 3, "Accent 2");

style = new SLStyle();
style.Fill.SetPatternForegroundColor(SLThemeColorIndexValues.Accent3Color);
style.Fill.SetPatternType(PatternValues.Solid);
sl.SetCellStyle(9, 2, style);
sl.SetCellValue(9, 3, "Accent 3");

style = new SLStyle();
style.Fill.SetPatternForegroundColor(SLThemeColorIndexValues.Accent4Color);
style.Fill.SetPatternType(PatternValues.Solid);
sl.SetCellStyle(10, 2, style);
sl.SetCellValue(10, 3, "Accent 4");

style = new SLStyle();
style.Fill.SetPatternForegroundColor(SLThemeColorIndexValues.Accent5Color);
style.Fill.SetPatternType(PatternValues.Solid);
sl.SetCellStyle(11, 2, style);
sl.SetCellValue(11, 3, "Accent 5");

style = new SLStyle();
style.Fill.SetPatternForegroundColor(SLThemeColorIndexValues.Accent6Color);
style.Fill.SetPatternType(PatternValues.Solid);
sl.SetCellStyle(12, 2, style);
sl.SetCellValue(12, 3, "Accent 6");

sl.SaveAs("InlineString.xlsx");

I’m using the Metro theme, which means the major Latin font is Consolas, and the minor Latin font is Corbel. The body text is in minor Latin font.

You’ll notice the 2 new classes, SLFont and SLRstType classes. The SLRstType models after the Open XML SDK (abstract) class RstType. I think it stands for “rich string type” (r + st + type).

I have filled in 6 cells with the accent colours, just so you can see how the colours are used. The accent colours are tied to the theme used, as is the major and minor Latin fonts. So if you use these colours and fonts, the text is automatically formatted against the current theme.

This is an advantage if you set the font as the minor Latin font, instead of directly as “Corbel”. If the user changes the theme of your resulting spreadsheet, the text changes to the new theme’s minor Latin font. Of course, if you want the text to stay as “Corbel”, regardless of the theme, then set it directly and explicitly as “Corbel”. The SLFont class has overloaded functions for this.

P.S. Can you tell I’m excited about this? I’m going to launch this baby. Soon. I will limit such “promotional” articles, but I really think Excel gives me surprises, so I thought you might want to know what your user thinks is normal Excel activity.

SpreadsheetLight gradient fill function

I’m fascinated by gradient fills in a spreadsheet. More specifically, why would anyone want to have a cell with gradient colours? Is a standard block colour fill not enough? Is a texture image fill not enough? I guess this comes down to the visual aspect. Humans like to look at pretty colours. Especially if you have to stare at financial figures in a spreadsheet for hours.

So, that spreadsheet library I’m working on? It can do this:
Gradient fills in SpreadsheetLight

The code to do that is

SLDocument sl = new SLDocument(SLThemeTypeValues.Flow);

SLStyle style = new SLStyle();
style.Fill.SetCustomGradient(GradientValues.Linear, 45, null, null, null, null);
style.Fill.AppendGradientStop(0, SLThemeColorIndexValues.Light2Color);
style.Fill.AppendGradientStop(0.2, System.Drawing.Color.Red);
style.Fill.AppendGradientStop(0.4, System.Drawing.Color.Green);
style.Fill.AppendGradientStop(0.6, System.Drawing.Color.Blue);
style.Fill.AppendGradientStop(0.8, System.Drawing.Color.Yellow);
style.Fill.AppendGradientStop(1, SLThemeColorIndexValues.Accent1Color, 0.5);

sl.SetCellValue(2, 3, "Custom gradient function");
sl.SetCellStyle(2, 2, style);

style = new SLStyle();
style.Fill.SetGradient(SLGradientShadingStyleValues.DiagonalDown2, SLThemeColorIndexValues.Accent2Color, SLThemeColorIndexValues.Accent6Color);

sl.SetCellValue(4, 3, "Built-in gradient function");
sl.SetCellStyle(4, 2, style);

sl.SetColumnWidth(2, 24);
sl.SetRowHeight(2, 108);
sl.SetRowHeight(4, 108);

sl.SaveAs("GradientFill.xlsx");

The gradient stops are positioned from 0.0 to 1.0. The “built-in” functions (simulating Excel) allow you to specify only 2 colours, even though you can have more.

You will notice that the library allows you to use both theme colours and System.Drawing.Color’s. You can even specify a tint modifier (as seen in the last gradient stop), which range from -1.0 to 1.0 (-1.0 being completely dark, and 1.0 being completely white).

You might also notice that you don’t need to declare many variables from the library. For most of your work, you just need to know SLDocument class (which handles most of the spreadsheet’s functions), and the SLStyle class (which handles all your styling needs). Most of the functions are overloaded, which is why the functions are squeezed into fewer classes.

Here’s my rationale: I walk into a party. I don’t really know anyone. I find one person that I recognise. Probably the host. Then I let the host introduce me to everything. Who the interesting people are. Where’s the food. Where’s the washroom. Look, I don’t mind meeting people in the party, but I’m not really into that particular party. I just want to mingle a little so I can tell my friend that yes, I was at the party. Mission accomplished…

Then I go to that other party that I really wanted to go. (no offense to the host of the first party. “None taken.” Aww, isn’t he a nice guy?).

I don’t want to burden you with yet another software library to learn. So I’ve made it easy. 2 classes for most of your needs. If you’re using one of them intelligent code editing software, you’d get auto-completion too. Exploring what else a class can do for you is just a “.” away.

Yes, I’m finishing the library. It’ll be ready soon, ok? Just a couple of features more, and some testing, and I’ll launch version 1 of the product. I don’t give a flying fishball about eternal software betas. (Just launch already, dammit! Stupid software startups…)