Skip to main content

NGINX Redirect .html to just slugs

I like Nikola’s pretty URLs feature and have been using it at the personal site.

And after a year of prettiness there and .html here, I decided to switch this site to use it too.
All my urls look nice now :)
Which also means all the old links are now broken.
And so, the last bit of work was to redirect all the links in the wild and on the blog to the new addresses

A quick web search led me to this stackoverflow answer.

#at the top of location /
if ($request_uri ~ ^/(.*)\.html$) {  return 302 /$1;  }

#within \.php$
if ($request_uri ~ ^/([^?]*)\.php($|\?)) {  return 302 /$1?$args;  }

All I needed was the top bit and all was well, with my world :)

Update: Gave up on the redirect idea, beacause it was breaking pagination on the blog. Well, I tried :)

French, Week 11

Didn’t listen to podcasts.
But kept up with the app.

I can now listen to the french sentences in the app and kind of get it.
No so yet, with stuff outside.

But I somehow think, I’m gaining the teensiest bit of fluency.

How to Say No, Better

Another James Clear pick today.

How do you make it easier on yourself to say no?
To stick to that diet?
To stop goofing off and buckle down and study or work?


The ability to overcome temptation and effectively say no is critical not only to your physical health, but also to maintaining a sense of well–being and control in your mental health.

We do this, by assertion rather than denying ourselves day in and day out.
Not that I can’t do this. Just that I don’t. I am a person who eats good food. So I don’t eat junk food.
I am a person who wants to be a programmer. So I don’t browse the web aimlessly all day.
I am a person who wants his mind in his control all the time. So I don’t drink.

When you decide ‘who’ you want to be, it becomes easier to decide, ‘what’ you don’t want to do.

Here’s an anecdote, James shares,

Group 1 was told that anytime they felt tempted to lapse on their goals they should “just say no.” This group was the control group because they were given no specific strategy.

Group 2 was told that anytime they felt tempted to lapse on their goals, they should implement the “can't” strategy. For example, “I can't miss my workout today.”

Group 3 was told that anytime they felt tempted to lapse on their goals, they should implement the “don't” strategy. For example, “I don't miss workouts.”

For the next 10 days, each woman received an email asking to report her progress. They were specifically told, “During the 10–day window you will receive emails to remind you to use the strategy and to report instances in which it worked or did not work. If the strategy is not working for you, just drop us a line and say so and you can stop responding to the emails.”

Here's what the results looked like 10 days later…

  • Group 1 (the “just say no” group) had 3 out of 10 members who persisted with their goals for the entire 10 days.
  • Group 2 (the “can't” group) had 1 out of 10 members who persisted with her goal for the entire 10 days.
  • Group 3 (the “don't” group) had an incredible 8 out of 10 members who persisted with their goals for the entire 10 days.

The words that you use not only help you to make better choices on an individual basis, but also make it easier to stay on track with your long–term goals.

So, say, I don’t, and you’ll say no more effectively :)

Why does this work better than I can’t?
How do I apply this to my life?
Read James’ article to find out.

P.S. And, go subscribe to the newsletter, if you are reading this on the web :)

How Do You Keep Keep Going?

Or how do you actually go do anything else you committed to do for yourself?
I always got confused on what to do when the going got tough and life happened and my goals then got waylaid.
Other than feeling lost and giving up on projects and promising to do better tomorrow, or next time?
(which took a looooooong time to come)
What could I do?

James Clear offers a lovely heuristic, that I have been applying to my writing since the year began.
(along with Seth’s advice to queue things up)

3. Reduce the scope, but stick to the schedule.

I've written previously about the importance of holding yourself to a schedule and not a deadline.
There might be occasions when deadlines make sense, but I'm convinced that when it comes to doing important work over the long–term, following a schedule is much more effective.

When it comes to the day-to-day grind, however, following a schedule is easier said than done.
Ask anyone who plans to workout every Monday, Wednesday, and Friday, and they can tell you how hard it is to actually stick to their schedule every time without fail.

To counteract the unplanned distractions that occur and overcome the tendency to be pulled off track, I've made a small shift in how I approach my schedule.

My goal is to put the schedule first and not the scope, which is the opposite of how we usually approach our goals.

For example, let's say you woke up today with the intention of running 3 miles this afternoon.
During the day, your schedule got crazy and time started to get away from you.
Now you only have 20 minutes to workout.

At this point, you have two options.

The first is to say, “I don't have enough time to workout today,” and spend the little time you have left working on something else.
This is what I would usually have done in the past.

The second option is to reduce the scope, but stick to the schedule. Instead of running 3 miles, you run 1 mile or do five sprints or 30 jumping jacks.
But you stick to the schedule and get a workout in no matter what.
I have found far more long-term success using the this approach than the first.

On a daily basis, the impact of doing five sprints isn't that significant, especially when you had planned to run 3 miles.
But the cumulative impact of always staying on schedule is huge. No matter what the circumstance and no matter how small the workout, you know you're going to finish today's task.
That's how little goals become lifetime habits.

Finish something today, even if the scope is smaller than you anticipated.

If you like this tip the whole post is even more awesome.
Go find out Time Management Tips That Actually Work on his blog.

P.S. You should subscribe to the mailing list, you know. :)
P.P.S I haven’t missed a single week since I started doing this!

Study, Day 4

Back at it after a short personal break. Lots of stuff to catch up on!

MITx, 6.00.1x, Introduction to Computer Science and Programming Using Python

Learning about lists.

  • They are
  • iterable, i can run through its elements one by one and do stuff
  • mutable, i can change things inside them
  • append, will append stuff to the end
  • extend, will take another iterable (another list, for example) and then take those elements one by one, and tack them on the the end of this one
  • i can go back and forth, between lists and strings, converting one to the other and vice versa

  • i can sort and reverse sort the items in them.

  • sorted will return a new list
  • .sort will mutate and sort the list itself as will .reverse.
  • since i can change them at will, i need to be careful about things that might break.
  • 10 names pointing to the same list. changing something in one, changes them all.
  • consider cloning a list and making seperate copies. (this is how’d i’d naturally do it. but is it expensive with resource usage?)
  • one example is iterating over lists
    • if you modify them as you run over them, it can lead to all sorts of trouble and confusion, if items get added, removed or changed
    • best to clone the list, iterate over the clone and modify your original
  • i can nest lists. have lists of lists!

  • you’ll get confused and make mistakes. it’s ok.

Learnt about Functions as objects

do i still remember functions?

  • pieces of code (functionality, my customised shit) that i write that i can call from elsewhere.
  • first class objects in python
  • can be elements of data structures (i can have a function in a list)
  • can appear in expressions
  • i can assign a function to something (a variable for example)
  • can use it as an argument to another function.
    • (i have a function that does things to lists. this function could call a function that sorts and sanitises the list, first)
  • basically, i can use them the same way i’d use numbers, or strings or lists

this inceptive programming, using function as arguments to others and combining them with other elements like lists (or inside lists to do shady shit on other lists)? it’s fancily called higher order programming.

  • i could apply a series of functions to a list
  • i could apply a series of lists to a function

and all this stuff generalised and abstracted are called higher order procedures
python provides something like this, called map
very simply put, map

  • takes a function that expects a single argument. (len for example or abs)
  • and then runs them on a list (or it creates a list where it applies that function to each element in it.
  • what it returns is an iterable (think of it as the elements of the list, coming out one by one, but you get your grubby paws on them, before they go into some defined data structure like a list.)
  • you can then do what you want with those hot cross buns, er, elements. print them. put them in a list. whatever. it’s all good.
  • i can now amp this up to a 11. map can
    • take n functions and run them on n collections of arguments.
    • simple example, run through the elements of two lists, compare them, and pop out the lower number for each element. print or save or whatever.
    • mind fucking blown. insert Keanu going, ’I know Kung Fu!’

Common operations across strings, tuples, ranges and lists

if i assume seq is any of these data structures, i can,

  • seq[i] - get the ith element in that list or string or range or tuple
  • len(seq) - get its length
  • seq1 + seq2 - concatenate two of them (not range)
  • n*seq - repeat them (not range)
  • seq[start:end] - slice and dice them
  • e in seq - will return true if e exists in the sequence
  • e not in seq - will return true if it’s not
  • for e in seq - will iterate over each element in that sequence


Why? They save me time!
Instead of indexing on numbers, like I do with the 1st element or the 0th element of a list, i can just index on things, I define myself

  • Like there’s a list of names and I can then attach attributes to them. relationships, address, phone number, whatever.
  • works just like a real dictionary. i can look up a word and then see all the information related to that word.

In python you create dictionaries using braces. and store data using key value pairs. here’s a few

  • dictionary_of_names = {} creates an empty dictionary.
  • dictionary_of_ages = {'Jason':40, 'Tess':48; 'Leo':76} creates a dictionary of names (keys) with their related ages (values)
  • and now I can just ask for Tess’s age with a dictionary_of_ages['Tess'] without having to lookup where and at what location Tess is in the dictionary

  • dictionaries are mutable

  • I can add entries (dictionary_of_ages['Puppy'] = 4 will add the age of my stray doggo to the dictionary)
  • I can test for existence of entries ('Leo' in dictionary_of_ages)
  • I can delete entries with a del
  • i can list my keys by calling the dictionary like a function using the keys method like so (dictionary_of_ages.keys()) and similarly I can get at the values with a dictionary_name.values()
  • unlike a proper dictionary though, there is no order to the way things are stored in a software dictionary. mostly its the order you shoved stuff in; and that can change.
  • on keys and values
  • values
    • can be any type
    • can be duplicated (different people having the same age)
    • can actually be any data structure (lists, numbers, strings, other dictionaries)
  • keys, on the other hand
    • have to be unique (can't have two folks with the same name. if they do, then probably time to think of indexing on something else?)
    • need to be immutable (which restricts me to ints, floats, strings, tuples or booleans. can’t have strings in there)
      • actually according to Prof Grimson they need to be hashables, but I’ll cross that bridge when I come to it.
    • careful using floats as keys, because of accuracy issues.

So because of their flexibility on what they can store and index on, dictionaries are much more capable than other data types

Testing & Debugging

It’s like soup!
You’re making soup and there are bugs falling in, from the ceiling.
So how do you get good soup?
You could,

  • Check the soup and remove the crawlies if any. (that is testing your code)
  • Keep the soup pot covered. (defensive programming)
  • Clean the kitchen, so there are no bugs (eliminate the source of bugs. debug it. kill it.)

Defensive programming is,

  • how do you structure your code?
  • how do you write code that plans ahead?
  • it has three parts
    1. write specifications for the functions you write
      • use docstrings
      • mention what you expect as input and what you will provide in return
    2. Write modular programs
      • break up your program into obvious pieces.
      • something that collects data for e.g., and something else that works on it (could be one, or more pieces) and something elser that delivers it out.
      • help you while testing, because you can test each little piece seperately
    3. Check conditions on inputs and outputs.
      • i don’t know what this entails, will update this later

Testing code, basically boils down to checking inputs and outputs.

  • What did i expect to come in? What is my expected result?
  • If stuff’s not working, what do I do to debug it?
  • What can I do to stress test and break my program?

Yikes! I have a bug!
How do I kill it? What do I want to do to fix this?

  • Look at the events that led to the error
  • Ask yourself, “Why is it not working? What’s causing that?”
  • and then having found that, “How do I fix it, so all is right with the world again?”

Set yourself up, for easy testing and debugging

  • Design code so this part is easy!
  • Is your code modular?
  • Are docstrings in place? What are you expected inputs? Output?
  • Document your assumptions. Why did you write this piece of code the way you did?

When you test you can,

  1. Unit Test
    • validate each piece of your program
    • test each function seperately
  2. Regression Test
    • if you find bugs, test for them the next time around
    • catch reintroduced errors that were previously fixed
  3. Integration Test
    • Does the overall program work?
      It kind of feeds each other like a cycle, so don’t hesitate to go around and round the testing circle.

Testing Approaches

  • Intuition
    • what do you think you naturally need to test?
    • what makes sense?
    • just pick things at random
  • Black box testing
    • use you program like an appliance
    • it says it does this on the box. well does it do it? does it do it well?
  • Glass box testing
    • look at the code and then test each path in the code
    • can’t do this with every path properly sometimes
    • do the big branches


  • Overt
    • the program crashes
    • your computer hangs
  • Covert
    • the answers might not be expected
    • they might look ok, but are actually wrong. (off by 1?)
  • Persistent
    • happens every time you run the program
  • Intermittent
    • happens only some times

  • Overt & Persistent
    • Easy to detect
    • use defensive programming to try to steer bugs to fall into this category
  • Overt & Intermittent
    • if you can find what’s causing it, yay!
  • Covert

    • Really dangerous. you might be relying on wrong results and data that you wrongly trust!
    • could be a really long time before you catch something like this
  • Be Patient. this will take time to get good at

  • Use print statements liberally
    • when?
      • enter function
      • parameters
      • function results
    • use the bisection method
      • divide and conquer!
      • print halfway and then decide which half to focus on
  • Be systematic. Use your little grey cells.
  • Figure out the common errors (type errors, value errors, syntax errors)
  • Logic errors, the program does not work as expected
    • think of programming as a novel you write
    • dream up the path
    • explain your code
    • walk around trying to create the model in your head
    • how did i reach this place? this bug?
    • try explaining it to some one (or your rubber ducky)
  • Use the scientific method.
    • look at what you have,
    • figure out what could be causing the error,
    • think about what could fix it,
    • and then try it.
    • is it fixed? no? go back and try again :)

Work with small things.
Work in increments.
Test and debug it.
Use backups.
Have versions.
Test and compare across versions.
Feel free to work up and down the version tree

Professor Grimson is awesome, and teaches me the way, I imagined some one teaching me CS basics. So many aha moments!