Abi Travers

My Blog. Full Stack Software Engineer. Ex-Growth Hacker.

Posts by Abi

The Ruby Kata; Minimum Bonus, A Codewars Challenge

So it is week 4 of the pre-course for Makers Academy. I know what you are thinking .. where have you been on week3? I don’t see any posts? … Well the answer to your question is Barcelona, which meant having to do the whole of week 3 in two days .. which NO i do not recommend doing…

I thought I would delight my reader by creating a post on a codewars kuta I am bumbling through, since this week is all about achieving a level 5 kyu.

You can find my GitHub Repository to this challenge HERE so you can follow along with the commits and steps there if you prefer…  I would love it if you gave my little independent blog the chance to shine and stay on here though (..please mum …I know you don’t really read this, dad).


ruby kuta on codewars, minimum bonus

Obviously I was going to use a post on ‘kata’s to show off my pictures of Japan.

The Challenge:

Task which was given by codewars:

International hackers group organized a programming competition, in which n teams participated.

They were assigned to separate rooms for competitions, and the rooms were lined up in a straight line.

The game was over and each team scored points. It's time to pay bonuses. The rule is:

- The bonus unit is 1K($1000), and each team gets at least 1k.
- The bonus payment process is not public.
- A team can know the bonus amount of its adjacent team, if the
  score of the adjacent team is lower than itself.
- If a team finds that its bonus is no higher than the adjacent team whose
  score is lower than itself, the team will not be satisfied
Given an integer array scores represents the score of all teams. Your task is to calculate how much bonuses international hackers group need to pay to keep all teams satisfied.

Note, the unit of bonus is 1K. All teams are in a straight line, and their order is the same as that of the array elements.


For scores = [10,20,30], the output should be 6.

team1's score = 10
team2's score = 20
team3's score = 30

team1 can get 1K, The team was satisfied
because it knew nothing about the other teams.

team2 can know team1's bonus amount,
So team2 at least get 2K to be satisfied

team3 can know team2's bonus amount,
So team3 at least get 3K to be satisfied

1 + 2 + 3 = 6
For scores = [10,20,20,30], the output should be 6.

The possible bonus amount of each team can be:[1,2,1,2]

For scores = [20,30,10,30,40,10,20,30,40,30], the output should be 20.

The possible bonus amount of each team can be:[1,2,1,2,3,1,2,3,4,1]


The Solution:

Step 1:

Understanding what is being asked and breaking it down into an english Explanation of what I want the code to do:

breaking the ruby kata down into english

def minimum_bonus(scores)
Making sense of the problem - writing it out in English 
  #scores are an array of numbers
  #the length of this array should be known/ calculated??)
  #1 (value) is asigned to the first number
  #if the second number is larger than the first it is given 2 (new_value =value +1)
  #if the second number is the same size or smaller than the first it is given 1
  #if the 3rd number is larger than the second it returns 3 (new_value +1)
  #if the 3rd number is smaller than the second it returns 1 (value)
  #all the values returned are added together and calculated.

The first thing I did was google; ‘how to select each element in an array with it’s index number’.

I found one extremely useful bit of information on how to best iterate through an array in ruby on stackoverflow:

  • each is sufficient for many usages, since I don’t often care about the indexes.
  • each_ with _index acts like Hash#each – you get the value and the index.
  • each_index – just the indexes. I don’t use this one often. Equivalent to “length.times”.
  • map is another way to iterate, useful when you want to transform one array into another.
  • select is the iterator to use when you want to choose a subset.
  • inject is useful for generating sums or products, or collecting a single result.

So I did this in irb:

2.4.0 :031 > minimum_bonus=[20,30,10,30,40,10,20,30,40,30]
 => [20, 30, 10, 30, 40, 10, 20, 30, 40, 30]
2.4.0 :032 > minimum_bonus.each_with_index
 => #<Enumerator: [20, 30, 10, 30, 40, 10, 20, 30, 40, 30]:each_with_index>
2.4.0 :033 > minimum_bonus.each_with_index do |x, index|
2.4.0 :034 >     if x[index

…..and before completing it I though .. oh I don’t think I need the index ..What I need is to change the input scores into the bonus number .. so I need map?

  • map is another way to iterate, useful when you want to transform one array into another.

The next thing I tested in irb was this:

def minimum_bonus(scores)
    scores.map do |x|
        x(1) = 1

Then I googled:

“how to access an element in an array by its index number ruby”

And I came across each_with_index again, so decided to give it another chance.

def minimum_bonus(scores)
    scores.map.each_with_index do |item, index|
        if index == 0 then 
          item = 1


I still needed the map because I needed to alter the values in the original array.

When I tried this in irb it seemed to work:

2.4.0 :054 > scores=[20,30,10,30,40,10,20,30,40,30]
 => [20, 30, 10, 30, 40, 10, 20, 30, 40, 30]
2.4.0 :055 >     scores.map.each_with_index do |item, index|
2.4.0 :056 >             if index == 0 then
2.4.0 :057 >                 item = 1
2.4.0 :058?>             end
2.4.0 :059?>       end
 => [1, nil, nil, nil, nil, nil, nil, nil, nil, nil]

When I extended the logic from this method it did not seem to work:

2.4.0 :088 > scores.map.each_with_index do |item, index|
2.4.0 :089 >             if index == 0 then
2.4.0 :090 >                 item = 1
2.4.0 :091?>             end
2.4.0 :092?>           if index[1] > index [0] then
2.4.0 :093 >                 item = 2
2.4.0 :094?>             end
2.4.0 :095?>         end
 => [nil, nil, 2, nil, nil, nil, 2, nil, nil, nil]
2.4.0 :096 >

So it looks like separating out the if statements over-rides the first one and the item in the array is only set for the second statement when it is returned.

It also looks like there is an issue with the numbering I am assigning to the index.

2.4.0 :096 >   scores.map.each_with_index do |item, index|
2.4.0 :097 >             if index == 0 then
2.4.0 :098 >                 item = 1
2.4.0 :099?>             elsif index[1] > index [0] then
2.4.0 :100 >                 item = 2
2.4.0 :101?>             end
2.4.0 :102?>     end
 => [1, nil, 2, nil, nil, nil, 2, nil, nil, nil]

I noticed I was still messing up on the index number while comparing values in the array. It then dawned on me that this is a ‘comparator’ question. We are to compare values in an array with each other and then assign them a new value based on that. So map may still be correct but I needed to set about googling:

“Comparing numerical values in an array with each other, Ruby”

I started to realised I had been spending too long on this kata and it is currently above my ability. I thought the best thing for me to do was to look at the answer and try to understand it and walk through it.

The Answer:

def minimum_bonus(scores)
  not_satisfy = true
  bonus = [1]
  (1...scores.size).each { |i| bonus << (scores[i] > scores[i-1] ? bonus[i-1]+1 : 1) }
  while not_satisfy
    (1...bonus.size).each do |i|  
      bonus[i-1]+=1 if bonus[i] == bonus[i-1] && scores[i] < scores[i-1]
    (1...bonus.size).each do |i|
      if bonus[i] == bonus[i-1] && scores[i] != scores[i-1]
        not_satisfy = true
        not_satisfy = FALSE


The Walk Through:


So there you have it, my complete thought process and logical reasoning while working through a codewar’s kuta on comparing elements within an array. I am very new to Ruby so I am assuming I will look back on this in the future and cringe at how long winded my approach was and how I went so wrong.


Logical Reasoning and Problem Solving With Ruby-Kickstarter

For those of you who aren’t regular readers of my blog, aka everyone but my mum and dad, allow me to set the scene:

I have enrolled on the intensive computer programming bootcamp at the Makers Academy. Before starting the full-time, on-campus, course you complete 4 weeks of pre-course. In this 4 weeks you get a real feel of how coders go about problem solving while learning some of the basics of Ruby, git & command line.

On week two we are given the choice of working through one of two Ruby tutorials:

Chris Pines Book, Learn to Programme. Chapter 8–End (since we did up to 8 for the interview).

Josh Cheeks Ruby Kickstarter, Session 1–3

Reading the reviews I saw past students had said the Kickstarter was more challenging and had video tutorials, so I decided I would go with that one.

I am not going to lie, I found it very challenging. Having got stuck on many of the challenges throughout sessions 1, 2 and 3 I thought I would write a post on one I am still struggling on, to show how I worked through this problem and hopefully expose where I am still going wrong.

Cue Session 3:2.

The Challenge:

Given a nonnegative integer, return a hash whose keys are all the odd nonnegative integers up to it and each key’s value is an array containing all the even non negative integers up to it.


staircase 1 # => {1 => []}
staircase 2 # => {1 => []}
staircase 3 # => {1 => [], 3 => [2]}
staircase 4 # => {1 => [], 3 => [2]}
staircase 5 # => {1 => [], 3 => [2], 5 =>[2, 4]}

My Solution

How I broke the problem down and tried to solve the challenge. The steps I took:

Breaking the challenge down into smaller more manageable pieces:

Step 1

Check out possible examples and theory which may help, using ruby documents on hashes, google and Josh Cheeks cheatsheets:

The information I decided may be useful:

Hash.new { |this_hash, key| this_hash[key] = Array.new }
hash = Hash[ *[ Array(‘a’..’j’) , Array(1..10) ].transpose.flatten ] # populating
hash # => {“a”=>1, “b”=>2, “c”=>3, “d”=>4, “e”=>5, “f”=>6, “g”=>7, “h”=>8, “i”=>9, “j”=>10}
hash.values_at ‘j’ , ‘e’ , ‘i’ , 😡 # => [10, 5, 9, nil]

Step 2

Breaking the problem down into sudo code:

integer_hash = [*[Array(starting from 0 increment numbers which   are odd up to the nr_given) , Array(starting from 0 increment numbers which are odd up to the nr_given).transpose.flattern]]
key array upto(nr_given)
value array up_to(nr_given) next if (i %2) != 0
#need to work out how to increment values and if up_to is method

Step 3

Deciding which bit to tackle first:

Incrementing the arrays seems like a good place to start as I can isolate my code for that part and test it with irb.

This was my first attempt:

Array(0..nr_given).map! {|x| puts x next if(x.even?)}

Next attempt:

Array(0..nr_given).map! {|x| if x.even? puts “x”}


Array(0..nr_given).map {|x| if x.even? puts “x”}

When I ran this in the irb it returned nothing even when I input a number, 77, in place of nr_given.

So I tried:

Array(0..nr_given).select do |x|
  if x.even?

When I run these in irb I still get no output even when I put a number in ‘nr_given’. I thought it may be something wrong with the way I created a new array so I tried to fix that:

a = *(1..77)

and that worked.

Then I tried setting a to that array. Checking it was definitely set by typing in a again, then playing with the .select method.

a.select { |x| return x if (x%2)==0 }

I got the following error:

unexpected return
from (irb):8:in `block in irb_binding’
from (irb):8:in `select’
from (irb):8

I looked up the select method in Ruby docs and it states the following:

[1,2,3,4,5].select { |num| num.even? } #=> [2, 4]

I therefore changed my code to:

#keys are:
a = *(0..nr_given)
a.select {|x| x.odd?}
And tested it doing:
a = *(0..77)
a.select {|x| x.odd?}

And it worked!! I changed it to a shorter version and checked that also worked:

a = *(0..77).select {|x| x.odd?}

Step 4

Joining these to the rest of the code to solve the whole challenge.

My first attempt to put these arrays into the rest of my code:

def staircase(nr_given)
integer_hash = [*[*(0..nr_given).select {|x| x.odd?} , *(0..nr_given).select {|x| x.even?}.transpose.flattern]]

This failed the rake test. I got the following error message from it:

Failure/Error: expect(method :staircase).to be
undefined method `staircase’ for class

So I referred back to my notes on how to set a hash out :

character_counts = Hash.new { |this_hash, key| this_hash[key] = 0 }
character_counts[“a”] # => 0
character_counts # => {“a”=>0}

Looking at this I changed my code to:

def staircase(nr_given)
   return_hash = Hash.new
   *(0..nr_given).select {|x| x.odd?}
   return_hash[x] = *(0..nr_given).select {|x| x.even?}.transpose.flattern

It failed the rake test so I decided the get rid of the part I didn’t feel was necessary ‘.transpose.flattern’.

def staircase(nr_given)
   return_hash = Hash.new
   *(0..nr_given).select {|x| x.odd?}
   return_hash[x] = *(0..nr_given).select {|x| x.even?}

This was still failing on the line starting with ‘*’. So I changed this round a bit:

def staircase(nr_given)
   return_hash = Hash.new
   (0..nr_given).to_a.select {|x| x.odd?}
   return_hash[x] = (0..nr_given).to_a.select {|x| x.even?}

I realised I was missing an if statement in the .select method:

def staircase(nr_given)
   return_hash = Hash.new
   (0..nr_given).to_a.select {|x| if x.odd?}
   return_hash[x] = (0..nr_given).to_a.select {|x| x.even?}

I was getting an error because I had closed the statement off too early . The ‘}’ after the odd meant that it was not finishing off the if statement. It was not putting this newly created array into the return_hash[x] — the keys of the hash. This statement could not accept the x as I had closed off the select method too early. I was saying if x.odd? then not telling it what to do with x.

def staircase(nr_given)
   return_hash = Hash.new
   (0..nr_given).to_a.select do |x|
   if x.odd?
   return_hash[x] = (0..nr_given).to_a.select {|x| x.even?}

I was now getting an error about the .select method. I noticed a few errors here, first I had forgotten to ask if the x was even then I had forgotten to tell it to return the value if it was.

def staircase(nr_given)
   return_hash = Hash.new
  (0..nr_given).to_a.select do |x|
  if x.odd?
  return_hash[x] = (0..nr_given).to_a.select {|x| return x if   x.even?}

This is still failing. If anyone reading this can see where I am going wrong I would love to hear from you.

For now, I am parking this to move onto the next challenge in the hope a fresh head will shed some light on the problem and I will magically stumble upon the solution.

Talking Through a Logical Ruby Challenge

As part of the Makers Academy  pre-course week 2 we have been tasked with working through the Ruby-Kickstarter github tutorials by Josh Cheek.

I decided to go through my thought process on one of the challenges I got stuck on, 1:6, in the hope that this may help me discover the solution. This post is about how I went about trying to understand the challenge and what I am still confused about. I have ordered this post as the way I looked at the information, worked through it in a lineal time format.

So hold tight as we ride through the waves of my mind … and apologizes if i stray off on a visual tangent ..


Question Asked:


You'll get a string and a boolean.

When the boolean is true, return a new string containing all the odd characters.

When the boolean is false, return a new string containing all the even characters.

If you have no idea where to begin, remember to check out the cheatsheets for string and logic/control

# odds_and_evens("abcdefg",true)    # => "bdf"

# odds_and_evens("abcdefg",false)   # => "aceg"


So two things that are seemingly unrelated are now bound together by a method I am to create …

My solution:

def odds_and_evens(string, return_odds)

  if return_odds

   string.size.times do |n|

   next if n % 2 == 0

   print 'n'



    string.size.times do |n|

    next if n % 2 != 0

   print 'n'





Initial Issues:

  1. I don’t understand why this does not ‘print’ the answer to the screen when I call the method odds_and_evens(“abcdefg”,true).
  2. When I run the rake test on the file I get the following error messages.:


syntax error, unexpected end-of-input, expecting keyword_end

rake aborted!

Command failed with status (1):


The Given Solution:


def odds_and_evens(string, return_odds)

to_return = ""

string.size.times do |index|

next if return_odds && index.even?

next if !return_odds && index.odd?

to_return << string[index]





My thought process, the steps it went through:

We want to design a method which takes two arguments, one is a string of characters the other is a true or false statement.

The first step is therefore to create this method name it ‘odds_and_evens’ and pass it two arguments ‘string’ and ‘return_odds’.

def odds_and_evens(string, return_odds)

We want this method to return the string, given to it, in an altered way.

We need some mechanism to return the string at the end.

We will have to split this string into an array of it’s characters in order to count which index number each character sits at. So we need something which converts it back to a string.

By putting a variable set as ‘to_retrun’ then assigning it a value of an empty string we can then push the characters of the original string which has passed through our if argument, back into it.

to_return = ""
to_return << string[index]

We want it to split up this string into its characters. So the string is now an array of it’s characters.


The index number of the character in a string is what will determine if it is odd or even. Index numbering starts at 0. All the characters with an odd index number are add, all the characters with an even index number are even.

The method .size returns the character length of a string.


.times do is a loop. What this does is say ‘for’ a certain amount of times (we have assigned this number with the .size method) ‘do’ the following block of code.

string.size.times do |index|

What I am still confused about here:

Does .times do or .size split a string into an array? I Have tried to look for this answer but cannot find it.

Potential answer:

We not need to split the string into its characters, do we simply need to assign a number to each character in the string depending on it’s place and act on those numbers … drawing the string back according to those numbers.

We need to do something different to the string depending on weather the returns_odd variable, is true or false.

We need an if statement which looks at the returns_odd varaibale and the split string. We need a Boolean here.

&& index.even?
&& index.odd?

If it is true then we need to return only the characters at the odd index number.

If returns_odd is not an object, i.e. it is false, we need to return only the characters at the even index numbering.

The string is passed through the loop block of code.

string.size.times do |index|

next if return_odds && index.even?

next if !return_odds && index.odd?

The name  ‘index’ is given to the block of code as a placeholder for every character in the string. So on the first loop around the code it represents the character at index 0, then on the next, the character at index 1 and so on.

The block of code then assesses if the character which is now the ‘index’ has an odd or even index number.


I need to go through the loop again:

When the string is split up into its characters, an index number is assigned to each character according to it’s original string, starting with 0:

string.size.times do |index|

next if return_odds && index.even?

next if !return_odds && index.odd?


So for size(the arrays’ length or size) number of times each character is assigned to the ‘index’ placeholder.

The character at the ‘index’ placeholder is then put through the argument;

Is the returns_odd object true? If so pass over all those characters whose index number is even.

If retruns_odd is not an object, give me back all the characters which appear at an even index number. Do not give me back any characters which have been assigned an odd index number.

At the moment these characters are still an index number.

We need to return the string which has been through the the argument.

We push this new ‘string’  into the empty string variable we set at the beginning.

to_return << string[index]

The string is now an array which has the elements assigned to ‘index’. As it is displayed as string[index].


Walking through this solution in depth, explaining the coding solution to myself in english has allowed me to really understand what is going on with it. As a beginner looking at a seemingly difficult logical problem can seem very daunting if you don’t understand what it is saying. I highly recommend talking, (or writing), yourself through some code. It helped to understand the logic and hopefully apply it in future. Ruby seems like a game of cards, or musical instrument, the more you play the better you get but this only comes with practice …

(Apologize to those who are simply trying to learn ruby and are not interested in the shameless plug of my photographs).


Git IS a Version Control System | But What Does This Mean?

how does git help me


It is week one of the pre-course at Makers Academy and I am working through our Git and Github tutorials.

One of the learning objectives is for us to be able to explain how git is a version control system. I thought I would delight the whole two readers I get to my blog (thanks mum and dad), by answering that question here:

What is version control?

Version control systems are ones which record changes made to files or a group of files in a directory.

YOU choose when to make these bookmarked changes. Once you have done this you can always go back to that version of the file / files.

This is useful on an individual or group basis.

As an individual it allows you to track your changes. You can compare a file against it’s earlier version so see where you may have gone wrong or how your mind was working when you made improvements.

It is very useful if you are worried a change you want to make may break something and cause it not to run the way you wanted. – Which is something which happens a lot when coding!

It allows effective collaboration!

It means that you can work with someone else at the same time on the same project but (here is the ground breaking part) on your own computer or work station!!


What is so great about being able to work from two computers on the same project… at the same time …without having to worry about replicating the work-load or clashes?

I hear you ask … :-/ (and by you I mean mum .. as I know dad has drifted off by now)

git merging files- version contro


This is incredible for two reasons!

Lean Development – like an efficient ford assembly line people can work on the exact same project at the same time without having to wait for someone else to complete their part of the project.

It is like building a house by building the roof and the floor at the same time, even though there are no walls!

git hub version control building a house analogy

This also means that a mistake in one doesn’t delay or immediately effective another part. The mistake can be more efficiently identified and solved!

See told you it was mind blowing …

Better still you can both work on the roof together .. in fact everyone can work on the roof at the same time! Yay…Here is another picture of a house to celebrate …

git house analogy version control


To do it like this you start with a master copy which you pull to your computer. As you edit and add on parts you update it in a centralised system. Before adding this to the ‘master branch’ everyone on the project can check they are happy.  If someone else has edited the same bit but differently you can quickly identify this and merge your changes quicker.

Think of this as two people editing an article, both correcting gramma and spelling but both doing it on the original document. When they bring these together you would have to check both documents against the original individually and it could lead to a waste of time as both editors are making the same spelling corrections.

An additional note to make here is git is NOT a centralised version control system. Versions are not held on one central server or system .. all versions are equal. The client computer (thats mine and yours) doesn’t just look at snapshots of files; they fully mirror the repositories!! This is a flat non-hierarchical system which allows you to collaborate as an equal !!

equality in git version control


So there you have it, my explanation of how git is a (de-centralised) version control system. Thank you for reading if you are still here. I feel like here is a good time to add the disclaimer that my parents don’t even read this blog…. 🙁

5 Things That Blew My Mind When Learning The Basics of Command Line

So here goes, my first week doing the pre-course at the Makers Academy coding bootcamp. It all started with a set of tutorials on the basics of command line.

After teaching myself online marketing & Growth Hacking it doesn’t half feel good having a bit of guidance and structure to my learning this time.

I get very excited about all things so naturally learning command line was one of them… So here is a post on the top 5 things I learnt doing this tutorial including when I went a bit off piste …. WARNING: Only very beginners will also find these things interesting …

learning command line basics

1. The Spaces Are Important.

importances of observing spaces in command line controls

Put them in the wrong place or leave them out and you fill face the wrath of command line…(that is if you also feel like an error message can be considered as wrath).

I first came across this simple finding when executing the tail command:

tail -3 longtext.txt

I had foolishly written as:

tail-3 longtext.txt

In this example I am trying to pass the parameter ‘longtext.txt’ file to the command tail – 3 which prints that last 3 lines of a file. However, without the space in-between ‘tail’ and ‘-3’ all I was getting was an error message.

I am glad I learnt about observing the spaces in commands as this came in useful later on when I was running more ‘complicated’ commands.

2.  ‘Read’, ‘Write’ & ‘Execute’ Permission.. and some …

Running the command:

ls -l

allows you to see which user classes have which type of access to a given file within a directory.

For those of you who are not aware the user classes are;

user Your account
group Any permissions group that your account belongs to
other Any account that is not yours and that does not belong to a permissions group that your account belongs to

When doing this I found more information against some of the files than the tutorial suggested.

The tutorial states that you can see the different permissions of a files in a directory by listing them in ‘long’ format with:

ls -l

This is what I saw when I did that:

command line showing permission of different users to files with ls -l command

Following the tutorial I learnt how to read the meaning of:


The first – represents nil or not. Here is where a d appears if the file is a directory as opposed to a file. Because it is not a directory the – appears instead of the d.

rw- represents ‘read’, ‘write’ but the ‘-‘ where the ‘x’ should be means no execute permission. This first sequence of three is the permission for the ‘user’ class (this is you on your computer). So the ‘user’ class has read and write but not execute permission on this file.

r– represents ‘read’, no write no execute permission. This second sequence of 3 is the permission for the ‘group’ class. The ‘group’ class in this subDirectory example is “staff”. A group class simply means a group of users. The best example of this is when there are several users accessing a computer or system remotely.

The last r– represents ‘read’, no write no execute permission for the last class, the “other” class of users. Other users are simply users that don’t fall into the other two classes.

So that is what I learnt from the tutorial … but what is that last @ at the end of some of this data?e.g.


So I had a google…

Turns out the @ means a file had extended attributes and that you can use the


command to view and modify them like so:

the @ symbol in the permission data of a file shown in command line by ls -l screenshot

Wait… this raised some more questions …. what is an extended attribute?

Extended File Attribute 

Regular attributes such as ‘permission’ have a purpose which is strictly defined by the filesystem they are part of (aka the directory etc).

Extended file attributes enable uses to associate files with metadata not interpreted by the file system.

The typical use of these are;

  • -storing the author of a document,
  • -the character encoding of a plain-text document,
  • -a checksum (a code which detects errors, for example in a digital network to detect accidental changes to raw data.),
  • -a digital certificate (a digital certificate used to prove the ownership of a public key),
  • -or ‘discretionary’ access control information (another way of restricting access permissions to groups or users but done by a ‘trusted computer system evaluation criteria‘).

Ok well great but still what is com.apple.metadata:_KMDItemUserTags doing on my file??


My first bit of googling led me to find out that this MAY (yes i can’t even be sure of this right now) be associated with something called:


and that it is something to do with this Mavericks file tagging system.

Further googling has lead me to see that this is something to do with ISO’s, so my macs, file labeling/ tagging system. Ok this doesn’t 100% make sense still but I trust you apple, I feel this tagging system is helping me out in some way …

3. YOU can become a SUPERUSER / the “root”.

becoming the superuser/ root with command line

If you become a superuser you automatically get super powers

Some actions on a computer require administrative POWER to do. This power is only bestowed upon a SUPERUSER.

Turning yourself into a SUPERUSER means (as long as you know the superuser password) you can delete a file you haven’t got permission to delete…

I am pretty sure this isn’t the coolest thing it can do, especially with super in it’s name, but still, I am impressed.

You become a SUPERUSER (it sounds so powerful that it just needs capitals) by prefixing (starting) a command with the word sudo.


sudo rm inaccessiblefilesname

Allows you to delete that pesky inaccessible file.

4. You can see all the processes your computer is running.

The ‘ps’ command allows you to see what processes you have launched within a directory.  You can use the ‘x’ flag to see ALL processes running on your computer:

ps x

You can filter for the processes you want to see by redirecting the output to grep, then use the wc to count the number of them instead of listing:

ps x | grep bash | wc -l

Will count all the bash processes you have running.


5. You can hide secrete data in your code!

Hidding secrete data in environmental variables in command line

You do this by modifying environmental variables!

Modifying environmental variables in command line allows you to hide sensitive data like passwords or secret keys which allow you access to information you want to keep private.

Say you are making a Ruby programme which calls on the users facebook photos. You want to make this programme open source and you need to use your facebook photos as a sample. You can set an environmental variable with a secrete key, e.g.

export SECRET_KEY=1453637600kk

in your command line. Then in your Ruby code read this variable with:

secret_key = ENV['SECRET_KEY']

At the moment this environmental variable will be deleted when we exit the current terminal session. This would be an issue if we wanted to call on these variables in our Ruby code on a more permanent basis.

To solve this we can create permanent env vars (environmental variables) by putting them in our bash profile:

echo "export SECRET_KEY=1453637600kk" >> ~/.bash_profile

The double >> means append, whereas single means overwrite, so be careful to use two here!

This nifty command line control also allows you to modify paths which I am sure will also come in handy for security reasons in the future. But for now, I am the most impressed by it’s ability to hide data from those you don’t want accessing it.


So there you have it, my MINDBLOWING 5 things I got most excited by when learning the basics of command line.  Yes I know what you are thinking .. ‘this girl is very easily amused’…

Learning Ruby The Hard Way | How I Beat the Un-stoppable Error Messages

Trouble shooting exercise 25 of learning ruby the hard way by zed

I have enrolled at the intense computer programming bootcamp, the Maker Academy, next month. To get a head start I thought I would work through Zed Shaw’s Learn Ruby the Hard Way book.

Exercise 25 seems to be testing my problem solving skills so I thought I would write a post documenting how I worked out then fixed my error messages. This post is aimed at newbies to the programming world as I imagine it is very basic things which I am getting wrong.

First Script – The Start of the Problem 

This was my first attempt at writing exercise 25’s script in my editor:

exercise 25 of Learn ruby the hard way by zed shaw error messages













When I ran this in the terminal I got the following error message:

ex25.rb:2:in `<main>’: undefined local variable or method `ex25′ for main:Object (NameError)

The first thing I did was google the error message.

Solving the Error Message with Google 

I found an answer on Stackoverflow. It told me I was accidentally typing Alt + Space on my Mac, therefore creating non-breaking space. That this is considered by Ruby as part of the variable name as opposed to the whitespace it was intended to be.

It gave two solutions to this problem:

1.  Remapping Alt + Space to space to stop this typo occurring again.

2. Highlighting invisible characters in text editor to immediately realise the typos.


The preference seemed to be for solution 2  so I thought I would try this way first. It seemed the most simple and quick to fix. I wanted to rule out the off-the-shelf issue to my broken code.

Highlight invisible characters in my text editor – Part 1

Next I googled how to highlight invisible characters with my text editor, Sublime Text editor 2.

Turns out this is supposed to be a default feature of my text editor. Every time I highlight text I am supposed to be able to see little white dots like the image below (look close they are there in the empty spaces):

how to highlight invisible characters with Sublime Text editor 2









So I highlighted the text and nothing happened:

textselected in sublime text editor 2 learn ruby the hard way ex25


I decided to park the problem of ‘non-breaking’ spaces here for now and try and solve my error message an easier way. I am relatively new to coding so the next solution for finding ‘non-breaking’ spaces, fixing the preferences or default key assignments in Sublime Text editor, did not seem like the easiest way to solve my problem.

Googling the exercise itself

The next thing I did was google ‘Ex25 learn Ruby the hard way’ to see if anyone else was having the same issues as I was. I found a blog with the exercise typed out. I compared our files word for word on my screen.

I could not SEE any difference between our files (indicating the hidden non-breaking spaces may be what is causing my error).

However I needed to rule out the idea there was a typo I couldn’t spot somewhere, so I typed out the whole file again. Figuring this was a quicker way to get to the solution.

My second file worked when I ran it in the terminal. No error message.

Here is the second file:

Script for exercise 25 learn ruby the hard way. no errors

I was intrigued where I went wrong with the first file still, so I compared them line for line.

Comparing the working script to the one with an error message

Compared them on my screen and noticed two differences which I fixed one at a time.

exercise 25 of learn ruby hard way. Errors

1.  When the earlier functions were called in later ones eg.

def ex25.print_first_and_last(sentence)

words = ex25.break_word ..

The ex25.break_word function looked like it had not been recognised in the error script (one on the right) whereas the Ex25. appeared blue in the other script (left).

The most obvious reason I could come up with  was that the ‘e’ wasn’t capitalised. So I changed all Ex25’s in the broken script to a capitalised e.

exercise 25 of learning ruby the hard way, broken script


I ran the script but still got the same error message:

ex25.rb:2:in `<main>’: undefined local variable or method `ex25' for main:Object (NameError)
2. The next easy fix I noticed was the file name and the function name in the broken script were the same but in my new script I had named the file EX25b.rb.

Maybe it was this difference in naming which was responsible for the error?

Nope ..

ex25.rb:2:in `<main>’: undefined local variable or method `ex25' for main:Object (NameError)

Had I read the whole of the exercise in Learning Ruby the Hard Way I would have seen this wasn’t the answer:

“The Ex25 module doesn’t have to be in a file named ex25.rb. Try putting it in a new file with a random name then import that file and see how you still have Ex25 available.”

So I decided to go back to the first solution, non-breaking space as I had now exhausted the easy options and couldn’t for the life of me  see any difference between the error or the correct script.

Highlight invisible characters in my text editor- Part 2 

I read how to do this here.

1.  Open the ‘preferences’ within Sublime text editor & select ‘key bindings’.

Preferences, key bindings within Sublime text editor 2







2.   Insert into the left side, the ‘user’ tab the following code:


"keys": ["alt+space"],
"command": "insert_snippet",
"args": {"contents": " "}


User tab of key binding sublime text editor

code inserted sublime text editor changing key bindings to show up alt + space bar on macs















3.   Saved then re-opened the original (broken 🙁 ) file.

Sure enough there was the accidental Alt and space bar non-breaking space:

Alt and Space bar error on a mac and sublime editor 2



HALLELUJAH .. I thought.. I have finally fixed my old script…….

I ran it again and I STILL had the same error message!

Here is where I probably should have thought:

“I got it correct once and managed to work through the exercise and complete it. I will just call it a day and not worry about the file which is returning an error message”.

But I am too curious / stubborn to settle for just allowing the error to hang over my first script.

I ran irb in the terminal.

I ran the file I had got correct again & the file with the error message:

Error message in terminal. Incorrect Ex25 of learning Ruby the hard way

I tried to work out what was the difference between the two files.

Maybe it was the directories they were saved in?

I check and sure enough they were saved in different directories.

So I saved the error file in the same directory as the file that worked…. STILL the error message!!

I could see no other difference so I ….

Copied and pasted the text from the working file to the error file.

Then something terrible happened!

BOTH the files stopped working!!!!

The same error message appeared for the first file and now the working file was returning ‘false’ when I ‘required’ it with irb:

Ex25 script from learn ruby the hard way returning false in the terminal

Possible cause of this problem:

Too many files with the same or similar name in the same directory?

I deleted all but one… And like magic ..


I ran the working script for Ex25 in the terminal and followed the instructions on how to use irb to call it’s functions.

Here are my results and my explanation of what is happening:

The correct script for Ex25

Script for exercise 25 learn ruby the hard way. no errors

Running the script in command line ‘irb’

Ex25 in the terminal correct


















I have labeled the points where I had to think a bit about how it was working. Here is my explanation:

1.   Prints ‘wait’  because the function is acting on the ‘words’ array which is not sorted. The sorted array is called ‘sorted_words’.

2.   ‘Words’ array has had the first and last (“all’ and ‘wait’ ) values shifted off  in the print function.

3.  Calling on the ‘sorted_words’ array, not the ‘words’ array which has the missing values. Therefore ‘all’ is still in the array.

4….Seems to be missing from the picture … So I clearly deemed it irrelevant then therefore i will do the same again now..

5.  Using the original ‘sentence’ variable and passing this through the function. It is breaking this sentence variable into an array every time it encounters a space. Then using Ex25.sort_words function to sort this array of words.

6.  It is taking the original variable ‘sentence’, breaking it into an array of words then printing the first and last value of that array.


So we have now come to the end of my struggling with exercise 25 of Learn Ruby the Hard way. I hope you have enjoyed and found useful  my higgledy piggldy problem solving which eventually resulted in me beating the error messages given by running my script.  Please do contact me if you are by a slim chance reading this & need any help understanding it.

Enjoy, 🙂

How to Run A Ruby File In Terminal | On A Mac

Bash: “command not found”

Where is my Ruby file and how have i forgotten how to run a .rb file in terminal already?

Why is bash not finding and loading my ruby file

After having taken a few days off programming and learning Ruby to do some freelance marketing work something terrible seems to have happened. I have forgotten the most simple of terminal commands … How to run a Ruby file.

So in getting myself quickly up to scratch again I thought I would write a quick guide for everyone who is getting started (or started again in my case) with learning Ruby and Terminal.

Now, if you are a complete beginner, you may be thinking:

“What is ‘Terminal’ & why are you telling me to use it? I thought I was supposed to be using ‘Command Line’? “


Most Ruby scripts do not have graphical user interfaces then they are ran using the command line or command prompt. The command line or prompt as far as I am aware, can only be accessed though the terminal.

How To Find The Terminal On A Mac 

1. Click on the search icon on the top right hand corner of your screen. The Spotlight search bar will then appear.

spotlight search button on a mac - how to use it to find terminal






2. Type ‘Terminal’ into the search bar.

3. The terminal will pop up.


1. Click on ‘Finder’ icon in the dock.

finder icon in the mac doc.








2. Go to the ‘Applications’ folder on the right hand hand side.

3. Search in this folder for the Terminal.

Creating Your Ruby File 

At this point I am going to assume you have been learning ruby so have written a few ruby documents before. However if not follow the simple steps below:

1. Download or open your text editor. I use  Sublime text editor, which is a good one for beginners like myself.

2. Create a ruby file by typing into your text editor:

puts “Hello Wold”

3. Save this file as ex1.rb – the important part of this is the .rb this must be at the end of any file for your computer to recognise it as a ruby document.

Installing Ruby To Your Mac

On a Mac Ruby should be pre-installed. Check this by typing into the terminal:

ruby -v            (the space after ruby before ‘-‘ is important)

You should get a message similar to:

     ruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-darwin16]

2.4.1 may not be the same number you will see as the pre-installed ruby does not tend to be the latest edition. I advise updating your ruby and checking you are running the latest version. How to do that can be found in these guides:

This is the guide I used for installing Ruby & Rails.

This is a simple guide for Ruby  – For beginners stop just before the installation of a database as that isn’t necessary for you for now.

Running Your Ruby File 

When you open your terminal you should find some script already there. It will most likely contain information on your computer and username then be followed with your prompt.

The prompt is usually a single character: $ or #.

1st | Make sure you are in the folder that your .rb file is saved in. To do this input:

pwd (print working directory)

to show the folder you are in.

I save all my .rb files in a folder I have named “Ruby work”. This is usually not the folder my command line starts in so I change it to this folder (or directory) using the command:

 cd (change directory)

I type into the command line:           cd Ruby work

2nd | (Optional) Check the your .rb file is in the folder (directory) you have changed to by typing:

ls (list directory)

into your command line. This will give you the full list of all the files in the folder.

3rd | Run your ruby file by typing into your command line:

ruby ex1.rb 

Do not forget to type in ‘ruby’ before your file name. This is because you need to tell the terminal that you are wanting to use the Ruby programming framework to run your file.

If you have used the example .rb file you should see the following script appear in your terminal:

Hello world.

Getting An Error Message?

why can't i run a ruby file in my terminal


If you are getting an error message, something along the lines of:

syntax error, unexpected keyword_end, expecting end-of-input

that means there is an issue with your code in your .rb file, not the terminal or the running of the file itself.

How To Stop Terminal Running Your Script

If you have gone wrong somewhere you may need to stop the terminal or go back up to where you started. You can do this simply by closing and re-opening the terminal.

Or you can force a quit “kill” by pressing:

“Ctrl” & “C” at the same time.


That is all for me for now. Hope this helped you get started or get back to running ruby files within your terminal. If you have any questions while learning ruby then send me a message.

Thanks for read 🙂

Lessons From A Successful Indonesian Startup

While trying to figure out what makes successful founders tick, a quick search on Google would lead you to articles or interviews citing Silicon Valley titans like Elon Musk or Jeff Bezos. You are unlikely to find much information on outstanding Asian innovators and entrepreneurs.

After having worked in Asia for over a year now I was totally unsatisfied with the lack of knowledge coming out of the region to the West. So I decided to help generate some of this noise by interviewing some startup funders out here.

I have started with Sayed, the Founder of LocalBrand.co.id. Local Brand is a startup which went from a simple idea, to one of the biggest e-commerce platforms in South East Asia in just three years.

Here is his story with some actionable growth secrets sprinkled along the way.

LocalBrand went from 0 to 1000 customers in just three months

The Ideation Stage

Supply or Demand? Who Should Marketplaces Startups Target First?

Sayed: We went for supply first. We had contacts with designers and brands who already had an established customer base. The brands had a real need for our solution, because they could not sell online. As soon as the brands came onboard, they brought all their customers, so the demand side was easy.

localbrand is a successful Indonesian startup

LocalBrand now has 1000s of Indonesian Brands onboard

Should Startups Go For Funding Straight Away?

Sayed: At this point, we made a mistake. If I could do it again, I would raise funds straight away. Instead, I used my own money for the company, and by the time big players such as Lazada jumped in, it was too late to call for investment. We just couldn’t compete with the promotions that they offer. Customers go where it is cheaper, and the brands eventually follow.

“Marketplace startups face issues with brand loyalty. So if you are building one I would advise getting funding early on.”

The Acquisition Stage

How Long After Launch Should Startups Expect To Get Their First 1000 Customers? What Is A Good BenchMark?

Sayed: We received our first 1000 customers within 3 months after our launch. I think 3–4 months is a good timeline to aim for.

Which Channels Worked Best To Aquire Customers At This Stage? What Strategy Did You Use?

Sayed: We were lucky to have successfully executed a few online and offline growth strategies right from the beginning.

Offline, we started Local Fest — an event to showcase Local Brands and allow offline sales.

We used the festivals to learn more about our customers and define them for targeting purposes. I would recommend really taking the time to do this if you have a smaller budget. Identify one customer type and zero in on it. Map out their journey and find out where they hang out online.

Make sure you develop the product based on what you learn from this. In our case, the customers followed fashion bloggers and influencers, so we targeted these people and partnered with them to get them talking about our service.

Localfest Indonesia, the secrete to this asian startup's success

LocalFest Indonesia- The offline event which skyrocketed organic traffic.

Which Online Channel Worked Best? How Did You Make it Work?

Sayed: We employed quite a few successful online tactics. We found the organic channels were by far the most effective.

1. Social Media. We were one of the first companies to use Instagram. Indonesia is now one of the most active countries on social media, but back when LocalBrand had just started, not many people were on there. We correctly identified the early adaptors of Instagram as our target customer, and were able to make the most of this channel.

2. Influencers & Affiliate Marketing. We defined an influencer as anyone with over 1000 followers. We built relationships with local fashion influencers early on, and got them to endorse our products. Now they have millions of followers, and we still maintain the same partnerships. These online celebs have consistently brought a lot of traffic to our site, so identifying our ideal customer as someone who follows them was a good tactic.

3. Content Marketing.Aside from targeted outreach, we made sure to leverage our relationships with influencers to drive LocalBrand’s SEO strategy as well. They wrote articles about us, and we did interviews with them. They would link to us a lot and through this, our page built authority and trust from Google quickly.

4. SEO. At the start, we focused on target long-tail keywords where the competition was low. Local, Indonesia-specific terms which had low competition but high search volume. These keywords were easier to get on the first page of Google for, and so helped to build our page authority as well as traffic.

blogging and social media contributed to this Indonesian/ Asian startups success

Content Marketing Is Still The Most Powerful Tool To Bring Customers To LocalBrand’s Site so bloggers played a massive role.

The Growth Stage

Which Channel Brought The Highest Number of Converting Customers? Would You Recommend it?

Sayed: The mix of offline and online worked the best for us as both of these reinforced each other.

We executed one large and well-organised offline event every year. This brought us a lot of customers for the following reasons:

1. Partnerships. Every event has at least 50 partners, including those from the media. All our partners used their social media to promote us. We made sure we included this in all our agreements.

2. PR. We got media and bloggers to cover the event. We paid for some, but we also received organic coverage by using our existing partnerships with celebrity bloggers and influencers. We told the press and media about it, and many dropped by of their own accord. By Year Two, we managed to achieve an attendance of 40,000 people at Local Fest over 3 days.

Is There A Difference Between The Growth Channels Which Work Here And Those Which Work In Western Countries?

Sayed: The main difference is the timing.

“Trends tend to repeat themselves, so what was big in the US is big in Indonesia 1–2 years later. Staying ahead of this curve gave us a very effective free growth channel — Instagram.”

Indonesians are more likely to buy products from social media than customers in the US. We use these channels as a means to inform ourselves on where the demand lies, much more than US marketplaces or retailers.

How a local brand in Indonesia became a successful startup using social media

Having High Customer Retention Is Often Cited As Key To Building A Successful Startup. How Do You Make Sure You Achieve This?

Sayed: Actually that’s our biggest problem right now.

In e-commerce, Indonesian startups, like those the world over, struggle to compete with the big guys when it comes to scaling.

We have loyal customers who identity with the brands on the platform, and we keep everything we do focused on these customers and what we know about them. But when it comes to retention, it’s hard to keep most people because the big platforms such as Lazada can offer promotions such as free delivery.

Customers will ultimately go where it is cheaper and the brands will follow.

What Is The Biggest Challenge You Faced? Do You Have Advise For Anyone Who May Share This Issue?

Sayed: User retention is our biggest challenge. We have overcome this by first realising that we cannot compete in terms of price with the players with a lot of funding, so we have had to change our tactics. We decided to partner with these large marketplaces instead of compete with them.

Thus, we created LocalBrandAsia, which is a connection for the local brands to all the market places and e-commerce sites. We focused on our strength — a connection with the local brands, instead of our weakness, an inability to provide the cheapest prices.

By making this move, we made Localbrand.id even more focused on our targeted customer, and created a lifestyle brand for them.

Do You Have Any Advise For Someone Looking to Create A Startup In Indonesia?

Sayed: Yes, don’t give up.

“Failure only happens when you stop trying”

It is so rare that anyone will succeed on their first attempt. Make sure you learn from your mistakes and bring those insights with you to your next attempt. So many of the companies I see here give up after their very first failure. See it as a learning opportunity, pick yourself back up and carry on.

coconuts and pineapple, turquoise colours. Bali

How to Compress Images in Bulk | Optimising Images for the Web

One of the main culprits slowing down your website load time can be your image size.

The speed your website loads is one of the most important factors for SEO. It effects how Google ranks your site. This is because user experience is reduced and frustrated if your website takes a long time to load. Google and the other search engines want to deliver the best possible user experience at all times so will penalise slow loading pages. The slower your site load speed the more likely your site will rank lower.

As a rule of thumb – it should not take longer than 4 seconds for your page to load.

Not only will Google downgrade a slow page, so will your users and you will suffer from a very high bounce rate if your load time creeps over the 4 second rule. This means you will lose valuable customers.

As a photographer, I know too well that a good user experience is also more likely to happen if you have great high quality images on your site.

The best solution for user experience and SEO is therefore a combination of a fast page load time and high quality images. But how do you achieve this? Make sure all images are optimised and compressed to the perfect size. I will walk you through exactly how to do this in this article.

I would usually use Photoshop to compress my images one by one. However, there are quicker options if you need to compress and resize images in bulk. A better tool to use for this is XnConvert.

For me the best way to learn is to first understand what is going on and why. So first, I will walk you through some basics of image compression.

What is an Image?


There are two basic types of image files: Bitmaps & Vectors.

example of the difference between Vector and bitmap image

Bitmap Images

Bitmap image files are assortments of many coloured pixels. A pixels is is the smallest controllable element of a picture when it is on a screen.

Most photographs, especially high resolution ones, are Bitmaps.

Bitmaps are generally speaking the only images which need to be compressed.

Think of a bitmap image like a mosaic. As long as this image isn’t enlarged or zoomed in on too much then the image appears as it should, smooth and grainless. But when you zoom in too much you can see the individual pixels.

example of a bitmap image. grainy image

Vector Images

Vector image files are sets of co-ordinates which plot out the shapes, lines and colours which appear in a particular position on an image.

They cannot accurately capture variation, texture and tone which is needed to make up a photograph.

They can be re-produced at any size and they don’t lose their quality as they just apply the co-ordinate data to a different scale.


vector image example

What are the different types of image compression?


There are two types of image compression; Lossy and Lossless.

Lossy Image Compression

Lossy compression throws away from an image information the human eye does not notice.

It uses complex algorithms to determine what is the best data (Pixels) to discard to maintain the same viewing effect.

Examples: JPG, GIF

How exactly does this compression work?

I will use JPEG Image compression as an example to explain this.

JPEG compression splits the image into blocks, applies compression to each block using a discrete cosine transform operation. These blocks are assembled together, like pixels, to form the image.

This is basically the removal of colour information and brightness in areas of the picture where it will be least visible through the human eye. Information is shed from the image. This is why sometimes using JPEG compression can give the image a patchy or blocky look.

Lossless Image Compression

Lossless image compression is a compression algorithm which allows the original image data to be completely and perfectly constructed from the compressed data.

It retains all the original data so the file size is significantly larger than lossy image compression.

Lossless images still remain quite large so are not typically as useful for web compression. The exception is when you are doing this one by one and using something like Photoshop where you can manually reduce the number of pixels.

Examples: PNG, PSD, TIF, EPS.

An Example of a PNG compressed image

An example of an image i have compressed as a PNG file.

Neither of these are the same as file compression which reduces size by grouping any repetitive data together. This works for any type of file but is not suitable for images which you need to display on the web. These files are saved as zip or gzip.


Now you have an understanding of  what is going on when images are compressed, let’s move on to how you can compress images to increase your page load time and keep the quality of your images high.

In which way should I compress my Image?


JPEG is generally thought of as the best solution for compressing images needed for the web.

You can compress an image by altering one or all of the following:

1. Size

2. Dots Per Inches (DPI)

3. Compression Type –Lossy or lossless image compression

4. File Type

1. Size

Changing the size changes the height and width of the image.

This therefore alters the height and width of the image on the site so is not the best option if it already fit the area as you want. It is also not recommended if you want to keep the image responsive (so that it changes its size with the size of the screen so it still appears at the same ratios).

The ratios that I usually prefer are:

1920 pixels (px) x 1200px when I want the image to look it’s best.

1280px x 1024px for most images

800px x 600px for the smallest and quickest loading image. (This works best for mobile intensive sites)

image compression. optimising image size screenshot

If you have an image where you want to keep the dimensions as they are you can use the chrome plugin Measurelt, to measure which size you need to upload the image (pixels).

2. Dots Per Inch (DPI)

The number of dots per inch is essentially the amount of information per square inch. It is basically the number of pixels per inch. (It is not called pixels per inch because it is an old term left over from the print era.)

The rules of thumb here are:

300dpi is a good size to use for high resolution printing, such as banners and massive advertisements.

150dpi is a good size for A4 size printing.

75dpi is a good size for most websites or applications. Mobile can go even smaller but if you want your site across desktop too then it is best to stick at 75.

3. Compression Type

The compression type means whether you are going to compress an image using a lossy or lossless compression method.

Choosing which one you should use also helps you decide on the file type, as typically they relate to a certain type of compression method. It also depends on which tool you want to use to do the compressions as they all have their own preferred methods.

4. File Type

This is where PNG and JPEG and the types of file compression apply. It is related to the above (compression type).

Two Examples of image change type:

1. PNG (Portable Network Graphics) – Lossless file format

PNG are typically bitmap images.

The most common place I have encountered PNG is when I edit a JPEG or RAW photograph in Photoshop and then export the edited picture at a compressed size in PNG format.

This type of compression works best for simple colour images, images with hard lines, as it is not a vector image.

PNG photographs straight from Photoshop will typically need to be compressed more for the web.

To the human eye at website level, there is little difference between a JPEG image and a PNG image. This is an example of a JPEG image.

To the human eye at website level, there is little difference between a JPEG image and a PNG image. This is an example of a PNG image.

2. JPEG(Joint Photographic Experts Group) – Lossy file format

JPEG are typically vector images.

These type of vector images can be used for complex-colour photographs. The most common place I have encountered JPEG images are when shooting photographs on a digital camera.

JPEG photographs straight from a camera will typically need to be compressed more for the web.

When saving a JPEG you can choose quality or compression. A smaller and more compressed file will lose more quality so you need to decide on the level of trade off. You can play around with these ratios to find the best balance between image qualities and file size.

To the human eye at website level, there is little difference between a JPEG image and a PNG image. This is an example of a PNG image.

This is an example of a PNG image taken on the same camera as the previous JPEG example.

Now you have an understanding of ways we can reduce an image size I will walk you through how to do this with xnConvert.

How to decide which images to compress


Typically, you would be able to see the size of an image before you upload it or you know you have a set of high quality images you wish to publish on the web.

If you don’t know which images you have already uploaded to your site which are causing a slow page load time you can use one of the following to find out:

1. Google Page Speed Insights

2. GTMetrix.com

I mainly use page speed for image optimisation as it will actually compress the images for you. You can use this to find the optimised images:

google pagespeed insights tool. image optimisation


Click on ‘show how’ to fix and it will give you the file paths of the images you need to optimise & how much you need to reduce them by.

How to compress multiple images with xnConvert (on both a Mac and Pc)


1.  Import the files you want to compress.

If you don’t have these files on your pc but you know which ones you want to compress, then you can download them from your C-panel.

If you don’t know which files you need to compress use ‘Google Page Speed Insights to find which ones it suggests.

screenshot of xnconvert importing images

2.  Choose your compression type. – Known in xnconvert as ‘Actions’


A. Size

screenshot of xnconvert resizing images for optimising page speed

screenshot of xnconvert resizing images 2 for optimising page speed

B. Set DPI


screenshot of xnconvert set DPI for optimising page speed

C. Compression format is not available to choose from here as the tool automatically does it for you

screenshot of xnconvert file format for optimising page speed

D. Select your file type

Here I will select JPEG because I like the ability to choose the ideal mix of size and quality.


Output > file format (Jpeg) > Settings


E. Remove meta data from the image.

screenshot of xnconvert clean metadata optimising page speed

This gets rid of any un-necessary information and thus reduces the file size.

Save these images to your computer. It is very important here to NAME THEM THE SAME AS YOUR OLD UNCOMPRESSED IMAGES. This will make it a lot easier to replace them on your site.

Then you are good to upload these images.

1. Login to your Cpanel

cpanel login screenshot

2.  Open up ‘File Manager’

file manager screenshot in cpanel

3. Find the folders containing the images which needed to be compressed. Open these up.

If you are not sure how to find these files. They are usually within ‘public html folders’ (this is the root folder where all WP files are kept.) then ‘wp-content’.

You can find the exact file location then from the image URL Google Page Speed Insights gave you.
file manager screenshot cpanel

4. Select ‘Upload’

upload of file manager in cpanel screenshot

Tick ‘overwrite existing files’.

screenshot showing uploading images in your cpanel.

Then ‘select file’. Select the images you have compressed and want to upload.

image upload in cpanel when image optimisation

Then click ‘go back to …’.

When you go back these should automatically have replaced your old large files. This is why it is important to name them the exact same as the old folder.

How to replace your images with the compressed version


You can do this two ways. Either one by one on your WordPress site, or in bulk within Cpanel.

I will walk you through the second of these options as it is far quicker when you are replacing more than one image.

How to check the images are loading and look correct on your website


To view the results of your site with images optimised you have to either clear your browser caching or view in an incognito window (Chrome) or private window (Firefox). Otherwise it may take a while for your browser to pick up the changes.

The best way to clear your browser caching is with ‘hard reset’ for your site, as opposed to clearing all of your internet caching.

How to ‘hard reset’:

1. Enable inspector mode

More Tools > Developer Tools > Chrome Inspector Mode

how to hard reset in inspector mode screenshot

When you see the inspector window appear right click on the refresh button. Then the below will appear. Click the “Empty Cache and hard reload’.

how to hard reset when in inspector mode. screenshot

Once this is complete it is best to check with the Google Page Speed Insights Tool that all the images are compressed and optimised.

Some final words

Understanding what an image is and how it is compressed should help you to make a tailored decision for how to best optimise your site. The above steps, I believe are the quickest and best way to increase your page speed while maintaining the desired quality of your images. If you follow them you should have a page load speed of below 4 seconds and images good enough to deliver a great all round user experience. This great user experience will in turn help your SEO score and ensure Google and other search engines ranks you higher.


Additional – Side Note on WordPress Plugins for Image Optimisation

Optimising your images and page speed this way should hopefully mean you would not have to use word press plugins. The reason I would stay away from plugins is because they can crash your entire site even some time after you have installed them.

However, if you do want to optimise further with WordPress plugins then I would highly recommend you do two things before installing anything.

  1. Backup your site at the server side.
  2. Ensure you have ftp access as it is best to delete the faulty plugins within ftp.



Why This Silicon Valley Founder Chose To Re-Locate to Vietnam

Vietnam.why so many startup founders are moving to ho chi minh city

Vietnam is a place close to my heart, I lived there for a year. I have always thought there was something special about this country, something which set it apart from any other.

The Vietnamese have a distinct, underlying kindness and sense of greater good. Once they trust an outsider they will always put them first.

I have watched as many large western companies try and fail to break into this new asian tiger. How they fail to capitalise on this nations collectivism, its sense of a greater good, it’s urge for a shared meaning and purpose.

When I heard about a successful American founder moving over to Vietnam to start a new venture, I knew I had to speak to him. I wanted to find out why he is doing this and if he saw in the people what i did.

Vietnam, where many startup founders are choosing to re-locate

Marcus, founder of HackerFleet & CoderSchool, came to Vietnam after a colleague invited him to visit.

The invitation turned out to be a request to help found CoderSchool.

Founder, marcus who chose to relocate from silicon valley to Vietnam to found his new startup

Marcus Ellison, Founder of HackerFleet

Marcus describes himself as driven by a desire to always climb mountains.

To always try to push himself and others around him to new extremes, to be the best they can be, to find a shared purpose and push towards achieving this no matter what.


He is a strong believer that being around others with the right attitude is what allows someone to be the best, that greater things are achieved together than alone.

Previously they had worked in the San Francisco based company, CodePath, which specializes in world class, professional training for engineers at Facebook, Airbnb, Twitter, and other top Silicon Valley technology companies.

CoderSchool was born from their experience there.

why so many are choosing to relocated to ho chi minh city to start a tec company

Vietnam provided a place where they could combine what they were inspired by with the opportunity to create a difference.

Their goal was to bring Silicon Valley training to Vietnamese engineers. Marcus soon realised that Vietnam was the right place for him to climb mountains.

Marcus spent 1 year at CoderSchool before creating a new venture, HackerFleet. HackerFleet is a venture-building studio that partners with entrepreneurs and investors to build startups.

why tec entrepeneur are choosing to relocate in vietnam for their next ventures

Instead of only training engineers, HackerFleet is a way to connect the best talents around the world to build startups.


The best talent in Vietnam work with the best talent across the world.

This breaks down the geographical barriers by allowing talent in Vietnam to learn from the best.

HackerFleet is  a new model for the venture building industry. It Creates talented startup teams on demand to build innovation better.

Vietnam.why so many startup founders are moving to ho chi minh city

The streets of HCMC are full of some of the best coffee shops and co-working spots available.

What have you found to be an advantage of Vietnam over the US (expect for the obvious such as cost)?

The Vietnamese people are some of the most welcoming, authentic, giving people I’ve met anywhere in the world.

Vietnam exists amongst a backdrop of Confucian pragmatism and Marxist ideology. What does this mean for how the people operate their everyday lives? Purpose matters.

In the U.S. the individual is the reason why you act. In Vietnam, there is always a greater good, whether that be family, friend, or community. This provides a solid anchor by which the people here form their commitment. It is humbling to work with people that believe in you.

the collectivism of asia is a big draw for startup founders from silicon valley who re locate to Vietnam

The startup I worked at in HCMC. The collectivism in asian startup teams is something I have experienced first-hand.

Tell me about the challenges which you faced in Coderschool. Did these inform anything you did at Hackerfleet?

In Coderschool the growth was quick and we had no shortage of leads from those wanting to be trained.

The issue was getting the partnerships from big technology companies as they just weren’t in Vietnam.

This caused us to iterate on our business model. At times we relied on sponsorship. At times we relied on recruitment revenue. Hackerfleet came from this challenge.

Without the large tec companies it is difficult for the engineers here to improve once they reach a certain point. They are extremely talented but they are limited by the experience of those around them.

To be the best you need to be surrounded by the best.

The people here are talented, but they needed something extra. Something that could make them even better.

At Hackerfleet we believe that something is the people they work with. One of the best lessons I learnt from Coderschool was how to spot people with the right mentality. I realized who were attracted by the salary as opposed to personal growth were not right for the company.

At Hackerfleet we only want to employ passionate people, who want to build a better community and a better world collectively.

The streets of HCMC are full of some of the best coffee shops and co-working spots available. It is no wounder so many american startup founders are moving to hcmc

The Lab Saigon, The company behind Work Saigon, a premium and FREE co-working space.

Why have you chosen Vietnam over the US to start your second company, Hackerfleet?

Vietnam is a hugely exciting emerging market.

Millions of people are just starting to get online and become internet savy.

Vietnam is developing so quickly. I want to position myself in the world in a place where it is changing, where I can affect more people’s lives.

In Vietnam I can make a real difference and that is why I would want to be here over the US. I want to give people with real talent the access they need to the right people.

I am drawn to the Vietnamese culture. How it is so misunderstood from the outside. How the people are one of the kindest nations. They work for a greater good, once they trust you you become their greater good.

Nest Saigon by Work saigon. free co-working spots are one of the many reasons founders are choosing to start their startups in vietnam and asia

NEST by The Lab Saigon


After speaking to Marcus and reflecting on my own experience I feel one of the main reasons other western companies seem unable to win the Vietnamese market is they miss the importance of trust.

The Vietnamese are not a nation who will even speak up until they trust you. When you realise something is wrong it is too late.

If you have a good cause and want to improve the nation you can spend time winning the trust of the people. Once they trust you then there is nothing they will not do to help you achieve this greater cause.

From San Francisco to Ho Chi Minh Marcus takes the ethos that people come first in business and this is the case no matter where in the world you are.

This is a model which sits well in Vietnam and I am sure is responsible for his success in the country.

Vietnamese coffee - why startups are moving to vietnam and asia