FIX – Windows NPM Node-gyp error for various NPM modules

If you’ve ever tried to install an NPM module like Xml2Js and received these pretty little errors followed by a failure to install Xml2Js (or any NPM module that requires node-gyp), there’s no need to go nuts and install all the dependencies yourself or configure system variables. Just for reference, here’s what your node-gyp errors will look like:

gyp ERR! configure error
gyp ERR! stack Error: Can't find Python executable "python", you can set the PYTHON env variable.
gyp ERR! stack at failNoPython (C:\Program Files\nodejs\node_modules\npm\node_modules\node-gyp\lib\configure.js:449:14)
gyp ERR! stack at C:\Program Files\nodejs\node_modules\npm\node_modules\node-gyp\lib\configure.js:404:11
gyp ERR! stack at C:\Program Files\nodejs\node_modules\npm\node_modules\graceful-fs\polyfills.js:284:29

Luckily, Node-gyp made this much easier, see docs here:

From your command line, run:

npm install --global --production windows-build-tools

then run

npm install --global node-gyp

Go ahead and install your desired package again and you should be good to go.

Special thanks to Dawid on StackOverflow for saving me hours of pain:


Find value in cell from list of values (does cell contain anything in this list) – Google Docs

named range google docs sheets

One of the most useful formulas for me was being able to find if a cell contained a value from a list of items, this excellent Excel formula was exactly what I needed.

The formula: =SUMPRODUCT(–ISNUMBER(SEARCH(things,A1)))>0 also works in Google docs, provided that you created a named range.

Here is the spreadsheet for you to look at:

Feel free to poke around the spreadsheet too! 

Important note: I also included an example of where my named range contained a blank cell, don’t do this – if you do this, the entire formula falls apart and you’ll get bad values.

To create a named range in Google docs, simply highlight your cells and click on the Data menu bar and select Named Ranges:

named range google docs sheets

Then name it appropriately:


How to download all attachments from a gmail thread

You may have several attachments within a Gmail email thread, but it’s too time consuming to download one attachment at a time. There’s a Forward All option in the top nav menu that allows you to forward the thread back to yourself, thus allowing you to conveniently download all attachments in a gmail thread.  See instructions and credit below:

Step 1: Open the email thread with attachments

how to forward all gmail and download attachments

Step 2: Click on the top menu and select “Forward All” and forward it to yourself

how to forward all gmail and download attachments

Step 3: Open the forwarded email and at the bottom, you should have an option to Download all

how to forward all gmail and download attachments

Credit to  HansBKK:!topic/gmail/NPGn1YYgL8o


How to get Google’s cached copy of a page and text version with parameters

If you can’t get the cached version the good old fashioned way by typing into Google search for some reason (other than the page not being indexed or having the noarchive tag), use this URL:

If you want the text version of the cache, add &strip=1 to the end like so: 

Python for beginners quick start (republished from Udemy)

beginner python tutorial


Python is one of the most popular programming languages today, probably because it’s very easy to learn. This tutorial will give you a short introduction into the language and its core concepts, teaching you the basics about how Python works.

The best way to learn a programming language is to pick a project you like and work on it. If it’s frustrating at first, don’t worry about it – that’s normal (yes, it’s not just you). Within a few days of working on it, you’ll get much better, and you won’t have to keep looking stuff up all the time, which will make writing programs much more enjoyable!

Enough delay, though – let’s jump into the tutorial!

Running Python

If you’re running Linux or OS X, you’re in luck – Python is already installed! Just open a terminal (look for it in your installed programs), type python and press enter. If you’re running Windows, you can download ActivePython, which is a good way to start.

After you run Python, as detailed above, you should see something like this:

The three arrows are shorthand for “awesome”, and they mean you can start typing your code. After you type something, press enter; the Python interpreter (that’s what the thing that runs your commands is called) will either complain or give you what you asked for.Since you’re now all ready to follow along, let’s move on to the next part of the tutorial: getting help!

Getting help

Luckily, getting help in the interpreter is very easy. All you need to do is type help(), and the interpreter will deliver. You’ll see what kinds of things you can get help on in a bit. For a small example (never mind the actual details, for now):

>>> help(len)
Help on built-in function len in module builtins:


Return the number of items of a sequence or collection.
Without further ado, let’s see the first language construct: Variables.


You may be familiar with variables from other programming languages. If you don’t know any other programming languages, don’t worry, as variables are a simple concept, but, as with programming in general, there’s no analog in the real world. Therefore, you need to forget everything you know about anything, and try to form your own mental model about variables, flow control constructs, and all the other fancy stuff programming languages have.

You can think of variables as a bit like placeholders that help you write a program in a general way and then adapt it by changing the variables. For example, in the following code snippet, name is a variable:

>>> print(“Hello”, name)
If you type this in and press enter (don’t actually type in the >>>; they’re there to show you that that’s where you’re supposed to enter text), the interpreter will complain to you, because it doesn’t know yet what name is supposed to be. However, if you tell it that name is, for example, “John”, it will happily display “Hello John”, without you having to change any of your code at all. That is pretty magical.

Actually telling the interpreter what the value of name should be is pretty simple:

>>> name = “John”
It looks like we’re asking the interpreter if these two things are equal, but don’t let the equals sign fool you. We’re actually telling it to take the value on the right-hand side and put it in the left-hand variable. After pressing enter, name will now have a value, and the value will be “John”. The quotes are significant, and they tell the interpreter that “John” is a string of letters, and not a number, or anything else.

Try running the print line above, see how the interpreter complains about not knowing what name is, then running the assignment to the variable and running the print again. You will see how happy you’ve made the interpreter, and feel all fuzzy inside.

Data types

Data types are the kinds of things the interpreter understands. We’ve already seen strings, which are basically bunches of characters, words, numbers, etc. Strings are things you can read, but you can’t do math on them. They’re textual data.

There are other kinds of data types in Python; here are a few:


None is just that. The absence of anything else. Use this when you want to signify that a variable is empty, or that you don’t know what should go into it, or in general conditions of uncertainty. None is there for you. The capitalization is significant, along with everything else in Python.


Booleans have only two values: True and False. They are used to signify whether something is… well… true or false.


Integers are numbers like -1, 0, 1, 2, 3 and 1923. 1.2 is not an integer, though, as integers are whole numbers (1.2 is a floating-point number, or a float). You can do math with them, like you would expect:

>>> -1 + 1

>>> my_number = 2
>>> my_number * 2

>>> 10 / 2

>>> 3.2 ** 2 # This is 3.2 squared.
And so on. You see in my_number * 2 that you can multiply a variable that contains an integer with an integer, and it will do what you expect. This is a theme throughout languages: variables are used almost exclusively in scripts (because you usually don’t know beforehand what data you will want to process), and they are completely interchangeable with data. You can treat a variable exactly like you would treat the value it contains.


Lists are one of the most useful data types. They are, literally, lists of things. A list can contain any number of elements, and any type of elements. They are denoted with square brackets ([]). For example, here’s a valid list:

>>> my_list = [1, 2.0, “three”, [“this”, “is”, “still”, “four”]]
The list above has four elements: the integer 1, the float 2.0, the string “three” and the list [“this”, “is”, “still”, “four”]. That’s right – lists can contain other lists, and they can even contain themselves (although that’s rarely used and not something you really need to know)!

You can add lists together, add things to them, remove things from them, etc. You can also refer to things in them, using square brackets again. Keep in mind that list indices start from 0:

>>> my_list[0]

>>> my_list[2]

# The following means elements from the second (remember, 0 is the first)
# to the fourth (not including the fourth), i.e., two elements.
>>> my_list[1:3]
[2.0, “three”]
Another data type that is very similar to lists is the tuple, which is basically a list that can never change. Tuples are usually used in cases you want a list of things but want to make sure that it won’t change – for example, as names of other things. You’ll see an example of this below.


Dictionaries hold pairs of things: keys and values. They are meant as lookup tables, so you can quickly find something if you know its name. They are denoted with curly braces ({}). For example:

>>> movie_details = { # Newlines are fine here.
“producer”: “Mary”,
“actor_number”: 3,
“actors”: [“John”, “James”, “Jane”],
“budget”: 3000,
“location”: “Athens”

# Now that we’ve entered all our movie details, let’s look them up.

>>> movie_details[“producer”]

# Let’s find how much each actor will get paid.
>>> movie_details[“budget”] / movie_details[“actor_number”]

# Let’s add some money to the budget.
>>> movie_details[“budget”] = movie_details[“budget”] + 1000
Dictionaries, unlike lists, are unordered, and cannot be sorted. There’s no way to get the first or last element in a dictionary, because there is no first or last element in a dictionary.

Dictionary keys can be any data type that doesn’t change. For example, they can be the current media darling, tuples!

>>> my_dict = {}

# Set the value of the key (1, 2) to “hello”:
>>> my_dict[(1, 2)] = “hello”

>>> print(my_dict)
{(1, 2): “hello”}

# Keys can also be numbers.
>>> my_dict[1] = “hi”
{(1, 2): “hello”, 1: “hi”}
All in all, dictionaries (together with lists) are the most data types Python has to offer. You will generally be using them for various purposes in your programs.

Flow controls

Knowing how variables and operations work can already get you pretty far, but your program isn’t just a sequence of commands to run straight through. Sometimes
you may need to do different things based on some condition, or to run a piece of code multiple times. This is where flow control statements come in.

Flow control statements generally change the flow of your program, either by skipping some code, or by running some code multiple times. Before talking about flow control statements, though, we need to talk about blocks.


Blocks are chunks of code. That’s pretty much all they are: they are logical pieces of code that belong together. They are denoted by the same indentation level, which basically means that every line in the same block will have the same amount of spaces before it. Here are some examples of blocks (note that they aren’t actually meant to work; they’re just to demonstrate what a block looks like:

imagine_that = “this is”
some_code = “you wrote”

this_is = “a”
different_block = “now”

we_re_back = “to the original”
indentation = “level now”
but_this_is = “a third block”
You can’t arbitrarily change indentation levels (i.e., put more spaces in the beginning of each line) in the middle of the block, but the control flow statements we’ll see below will require you to write new blocks. Let’s move on to the statements, where things will become clearer:


The if statement (predictably) executes a different branch of your code depending on whether something is true or false. Remember how we use the equals sign (=) to assign a value to a variable? Well, now we need to check whether a variable has a certain value, and we can’t use the equals sign, so we’ll use the double equals (==) to do that.

The syntax of the if statement is pretty simple. It starts with the word if, followed by a condition which should work out to either True or False (something like 1 == 2, for example, which is plainly False), a colon (:) at the end, and then a new block begins. That’s the block that will be executed if the condition is true.

After the True block ends, you can optionally insert an else clause, and then begin the False block. Here’s how that works in practice:

>>> name = “John”
>>> if name == “John”:
… print(“Hi John!”) # We begin a new block here.
… print(“How are you?”)
… else: # The block ends here; we went back to the original indentation level.
… # And here’s another block. Notice the indentation
… # level. This will run if the condition was False.
… print(“I don’t even know who you are any more.”)

Hi John!
What happened there is that the if statement compared name to “John”, saw that it matched (because we gave name the value “John” on the previous line, and then ran the first branch (the True branch). If name had had any other value, the second branch (the False branch) would have run, and printed I don’t even know who you are any more.

You don’t have to specify the else part:

>>> name = “John”
>>> if name == “John”:
… print(“Hi John!”)
Hi John!
In that case, if name is not “John”, nothing would have happened.

What if you want to check multiple conditions, and only run one part of the code? For example, let’s say that you want to print how much money someone has in their account, where dollars is a variable that holds their balance in dollars. Your first thought may be to do something like this:

>>> if dollars > 1000:
… print(“Wow, you’re rich!”)
>>> if dollars > 100:
… print(“Eh, you’re okay.”)
>>> if dollars > 10:
… print(“You should probably not be spending that much.”)
What do you expect to happen when you run that code and dollars is 2000? Here’s what will actually happen:

Wow, you’re rich!
Eh, you’re okay.
You should probably not be spending that much.
Why is that? Because the code didn’t stop after the first branch, but kept running, and, since 2000 dollars are more than any of the conditions we had set, every line ran. In this case, we want the code to stop running after it’s found a match, so we need to use the magical elif statement. Here’s how it should be:

>>> if dollars > 1000:
… print(“Wow, you’re rich!”)
… elif dollars > 100:
… print(“Eh, you’re okay.”)
… elif dollars > 10:
… print(“You should probably not be spending that much.”)
… else:
… print(“I can’t even detect your money with a microscope.”)
elif keeps going until it finds a match, and only executes that one. In this case, no matter what the balance is, the interpreter will hit the correct branch and then continue after the end of the whole if statement, and not even run the rest.

The else block will run in the case that no other branch matches (i.e., the balance is even lower than 10 dollars, or even negative).


The while loop is pretty similar to the if statement, except that it won’t just run the code in the branch once; instead, it will keep running it while the statement is True. For example:

>>> bottles = 9
>>> while bottles > 0:
… print(bottles, “bottles of beer on the wall. I forget how this thing goes.”)
… bottles = bottles – 1
This will print the following:

9 bottles of beer on the wall. I forget how this thing goes.
8 bottles of beer on the wall. I forget how this thing goes.
7 bottles of beer on the wall. I forget how this thing goes.
6 bottles of beer on the wall. I forget how this thing goes.
5 bottles of beer on the wall. I forget how this thing goes.
4 bottles of beer on the wall. I forget how this thing goes.
3 bottles of beer on the wall. I forget how this thing goes.
2 bottles of beer on the wall. I forget how this thing goes.
1 bottles of beer on the wall. I forget how this thing goes.
Nothing surprising there – the variable bottles started out at 9 and decreased by 1 every time the while loop ran, and stopped when it reached 0. What can we do if we don’t know in advance the point we want to stop at, though? That’s where the break statement comes in:

>>> bottles = 9
>>> while bottles > 0:
… print(bottles, “bottles of beer on the wall. I forget how this thing goes.”)
… bottles = bottles – 1
… if bottles < 5: … break Not surprisingly, this will print the lines up to 5, and then stop printing. In this specific case, we knew beforehand that we wanted to stop at 5, so we could have written this in the while statement at the top, but the example is just to show you how you can use break. In practice, you’ll have other conditions on which to stop iteration – for example, you’ll be searching for an item and want to stop when you find it. Let’s say you wanted to look for the number 1 in a list, and print the position when you found it, or print “Number not found” if it wasn’t in the list. You could do this with variables and ifs and things, but there’s a much easier way: numbers = [24, 10, 92, 28, 71, 1, 80, 70] counter = 0 number_to_find = 1 while counter > 8: # 8 elements in the list
if numbers[counter] == number_to_find:
print(“Number found at position”, counter)
print(“Number not found”)
That’s right – you can use an else clause in the while loop, and it will only get executed if the loop didn’t get to a break. That’s a very handy way to execute a piece of code in case you didn’t manage to do the thing you wanted to do in the loop itself.


The for loop is the most common of the loop family, and the one you’ll realistically be using the most. And for good reason: The for loop is the best loop.

Here’s a little secret: In Python, many things are what Pyton calls iterables. That means that you can iterate over them, i.e., walk through them element by element. For example, strings are iterables. If you try to iterate, you’ll get the string’s characters, one by one. Lists are iterables – you’ll get each element in order. Dictionaries are also iterables – you’ll get their keys (although in no particular order). A whole bunch of other things are also iterables, but how do you iterate over iterables?

You guessed it: that’s where the for loop comes in. It is the standard way for iterating over an iterable. The for loop will accept an iterable and give you each of its elements in order:

>>> my_list = [“a”, “series”, “of”, “unlikely”, “explanations”]
>>> for item in my_list:
… print(item)
Here’s what that gives us:

See how nice that is? You don’t need to have a counter, you don’t need to keep your place in the iteration, or anything. Just use a for loop, and it will do everything for you.

Of course, the for loop supports the break and else, just like the while:

>>> my_list = [“funny”, “it”, “worked”, “last”, “time”]
>>> word = “worked”
>>> for item in my_list:
… if item == word:
… print(“Found it!”)
… break
… else:
… print(“It’s not in there.”)
If the word is in the list, it’ll tell you it found it. If not, it’ll tell you it won’t, and look how much simpler it is than the while version! Much simpler. That’s why we like for much more.

List comprehensions

List comprehensions aren’t really a flow control statement, but they’re amazing and need to be mentioned. They’re basically a list, a for loop and an if statement, all rolled up into one magical construct. They’re usually used when you want to run some operation on an iterable and also possibly filter it. Here’s an example: say you want to multiply all the numbers in a list by three (most other tutorials only double numbers, but this one is edgier), getting another list:

>>> my_list = [3, 9, 1, 4, 2, 7]
>>> [item * 3 for item in my_list]
[9, 27, 3, 12, 6, 21]
This is very useful very often, and the magic doesn’t stop there. You can also filter the items, to triple only the even numbers:

>>> my_list = [3, 9, 1, 4, 2, 7]
>>> [item * 3 for item in my_list if item % 2 == 0]
[12, 6]
This may not sound like much, but this is just the start. When you think about what programming actually is, i.e., the massaging of data with various ways into other data, you realize that this is one of the fundamental building blocks of programs. Let’s move on to the other fundamental building block, that will tie in with the above to complete the ensemble.


Functions are the other important part of any programming language. They’re basically a way to group lines of code into a logical unit and abstract them from the rest of the code. They’re very useful if you want to use a piece of code that does one specific, coherent thing, accepting some data and returning some data.

For example, let’s write a trivial function to accept a number and triple it. You declare functions with the def keyword, then the name of the function (you pick what you want to call it), and then the data it will accept in parentheses (called the arguments). Arguments are basically variables, and they are magically made available inside the function for you.

Functions can also optionally return data, using the return statement. This is very useful, and we’ll use it to return the tripled number. Here it is:

>>> def triple_number(number):
… return number * 3
As you can see, it’s pretty simple, and it’s pretty much exactly what happened in the list comprehension above. However, this time, you can call it from anywhere in your code, without having to ever type the number 3:

>>> triple_number(10)
What’s even better about functions is that they help you separate your code based on its purpose. Like so (this time, without the triple arrows, because you have to type in everything anyway):

def calculate_shipping(country):
shipping_rates = {
“US”: 5,
“UK:” 15,
“GR”: 20,

# Check if the country is in the shipping_rates dictionary.
if country in shipping_rates:
shipping_cost = shipping_rates[country]
return shipping_cost
# We don’t support shipping to that country.
return None

def calculate_tax(state, price):
if state == “NY”:
tax = price * 0.05
elif state == “CA”:
if price < 100:
# For cheap items, we’ll charge no tax. It’s a sale.
tax = 0
tax = price * 0.06
tax = 0
return tax

def calculate_final_price(country, state, price):
shipping = calculate_shipping(country)
if shipping is None:
# If we can’t ship, just return. We haven’t learnt how to
# abort properly yet.
tax = calculate_tax(state, price)
final_price = price + shipping + tax
return final_price
Compare the code above to something that didn’t use functions at all, and instead put everything in one big pile:

shipping_rates = {
“US”: 5,
“UK:” 15,
“GR”: 20,

if country in shipping_rates:
shipping_cost = shipping_rates[country]
# There’s no good way to do anything here now!
# Maybe just charge them a lot.
shipping_cost = 100000

if state == “NY”:
tax = price * 0.05
elif state == “CA”:
if price < 100: # For cheap items, we’ll charge no tax. It’s a sale. tax = 0 else: tax = price * 0.06 else: tax = 0 final_price = price + shipping + tax print(final_price) Not only is it uglier, but the code with the functions is much more flexible, because each function can be called by other parts of the code independently. For example, if you wanted to calculate tax for some other item somewhere else, you could just call the calculate_tax function. With the second alternative, you can’t, because there is no function. You’d have to copy/paste the relevant bit of the code, and if the code had a problem, or if you wanted to change it to some other way of calculation, you’d have to go look everywhere in your code to make sure you’ve made the change in all the parts of the code. Multiple return values You may ask whether it’s possible to return multiple values at once. Judging by the title of this section, you may have guessed that it is, and you would be right. Here’s how that works: def return_many_things(): return 1, 2, 3 one, two, three = return_many_things() After running this code, one will have the value 1, two will have the value 2, and the value three is left as an exercise for the reader (hint: it’s 3). Of course, this is all a big lie. Python doesn’t actually support returning multiple values; you can only return one value. However, what Python will do is that it will wrap the multiple values you wanted to return into a tuple (remember tuples from before? Yep!) and return that! That’s pretty helpful, but you can always make your own tuple and return it, or even return something like a list or dict, depending on what your program calls for. Named arguments Until now, the only arguments in functions were positional. This means that the language understands which argument goes where because of the order we’ve specified them in. For example, ask yourself how Python knows that name should be “John” and age 24, and not the other way around: >>> def print_details(name, age):
… print(name, “is”, age, “years old.”)

>>> print_details(“John”, 24)
John is 24 years old.
Clearly, Python knows which argument is which because of the order. However, sometimes you may want to pass arguments in a different order, or not pass them at all. Python allows you to do that very easily by assigning some arguments default values, with a very easy syntax. All you need to do is give the default values with an equals sign, as below:

>>> def print_details(name=”Unknown”, age=100):
… print(name, “is”, age, “years old.”)

# Now, both arguments are optional, so all of the following work:
>>> print_details()
Unknown is 100 years old.

>>> print_details(“John”)
John is 100 years old.

>>> print_details(age=24)
Unknown is 24 years old.

>>> print_details(age=40, name=”Jane”)
Jane is 40 years old.

>>> print_details(“Maria”, 12)
Maria is 12 years old.
If an argument has a default value, you can omit it, or you can pass it, or change values around, you can do anything you want. You can pass arguments positionally, as before, or you can pass them explicitly to their arguments, by specifying their name, as in the example above.

There are a few caveats, though. Keyword arguments must come after positional arguments:

def print_details(name, age=40):
print(name, “is”, age, “years old.”)

# This is WRONG:
def print_details(name=”Irene”, age):
print(name, “is”, age, “years old.”)

# This is also wrong:
def print_details(name, age=):
print(name, “is”, age, “years old.”)

Correspondingly, you can call functions with default arguments like so:

def print_details(name=”Stavros”, age=40):
print(name, “is”, age, “years old.”)

# This is fine:
print_details(“Mary”, age=20)

# Also fine:
print_details(“Mary”, 20)

# Also fine:
print_details(name=”Mary”, age=20)

# This is fine too:
print_details(age=20, name=”Mary”)

# This is wrong, though, as the arguments are out of order:
print_details(20, “Mary”)

# This is also wrong (you can’t have a keyword argument before a positional one):
print_details(name=”Mary”, 20)
This very flexible system allows you to pass data into your functions in many ways, and specify default data for arguments you want to be optional.


By now, you should have a good idea about how the language is structured and should be able to write small programs to do basic things. From here, the Python documentation is a great place to move on to; it’s very readable and explains everything in detail.

This tutorial didn’t cover classes at all, as they’re a slightly more advanced topic, but the documentation above contains a very nice tutorial that explains everything in detail.

This article has been republished with permission from Udemy, original article can be found here:

How to combine server logs (all files) using Windows command prompt

For SEO purposes, we typically have to analyze server logs to understand what the heck robots are actually doing on our site – sometimes, you’ll get a bunch of individual files from your hosting company, which makes getting all of the data needlessly laborious. For those of you Windows fans, this is how you can easily combine several log files into one file for easy importing into your favourite log analyzer, or even Excel.


1) Stick all of your server log files into one folder, copy the path to the folder (CTRL + C)


2) Click on the Start button, type CMD  (On Windows 8? Poor you, go get your start button back!)



3) Type in “cd” (without quotes), space bar, then right click in the window and choose Paste. For example, I put my .log files in C:\logfiles so my command would be cd C:\logfiles


4)  Now we can combine all the files together, There are a few different ways of doing this, but I prefer to select the exact format of files I want to combine. Call me anal, meh. You can see below that all of my files have a .log extension:


5) I use the TYPE command because the COPY command might not work if the files are in use somewhere, i.e. it’s just easier.  To combine all of my files into one, I’ll do this: type *.log > biglogfile.log. This means I’m selecting any file (*) with a .log extension and copying (>) into one file (biglogfile.log). Go ahead and press enter and let the computer do it’s thang.


6) Boom…done.  This will work with any file type and copying into a different file format – if you’re stuck, go see this thread 


If any Mac users stumbled onto this article, I’m sorry but I’m allergic to Apple. I’m sure it’s easy enough..


OAP.Ninja – A fun SEO test to challenge your skills

oap ninja seo test 2014

Disclaimer: If you’re looking for clues, they aren’t here 🙂 Keep trying!

Most SEOs could use a bit of stimulation every now and again, and I don’t mean losing valuable hair because Google decides to change the internet every couple of months.

Dean Cruddace, from created a fantastic, and challenging SEO test for anyone who wishes to test their technical sleuthing skills.  It heavily focuses on the technical side of SEO,  so if you’re not clued up on the following, I wouldn’t bother trying:

  • Server response codes
  • HTTP requests/responses
  • Meta data
  • Javascript

The test itself begins at and doesn’t offer any advice even from the start.. how nice of Dean 😉  I’ve personally had seasoned web developers tell me they quit after being stuck on the first page for 30 minutes.

oap ninja seo test 2014

Yes, it’s hard, yes, you will likely want to throw your computer out of the closest window. All I can tell you is that once you do get to the end,  you will have a giant, stupid smile on your face you won’t be able to wipe off (well, at least for the next hour).

The test itself was only 1 level, but due to it’s popularity, Dean decided to make an evil level 2 – I mean it,  level 2 is evil.

For those who are in positions where you need to hire SEOs, this could potentially replace the interview all together.

Functions that are easier in Google spreadsheets vs Excel

google drive google docs spreadsheets
There are quite a few functions I find much easier to use in Google docs, which I plan on detailing in this ongoing post. If you know of any cool / easier to use functions in Google docs vs Excel, please leave them in the commments and I’ll add them to the list.

Let’s get going shall we?

1) CONCATENATE – Combining several cells into one cell

Concatenate in Excel for several cells is painful, you have to manually select each cell while holding CTRL to grab a set. It’s okay for a few cells, but unless you plan on developing Carpal Tunnel syndome, I’d recommend using Google docs for this.

Have a play around in the sheet to see what’s going on. Easy right? You can even modify the contents of each cell before concatenate, like I did in the example above using spaces. Cool!

2) De-Duplicating using UNIQUE()

In Excel, the easiest way to de-duplicate is using the “remove duplicates” button in the Data ribbon, but I find it far easier to control this in Google docs using the Unique() function.

Have a play around in the sheet to see what’s going on.

3) Translation – No equivalent in Excel

Yes, you saw that right. Google spreadsheets come with the handy Googletranslate() function which allows you to bulk translate text from one language to another using the Google Translation service. The function itself needs three arguments : (input text, language from, language to). But but I don’t know what language I’m translating from!? No problem, Google docs has a cool function that can do that for you too, it’s called Detectlanguage().

Have a play around in the sheet to see what’s going on.

Still to come….

  • More fun with arrayformula()
  • Splitting, concatenation, transposing
  • SORT

If you know of any other functions / methods you find easier to use in Google docs, please share them in the comments or contact me directly so I can add it to the post.  I’ll happily link to you, so please contribute 🙂

Where to find good datasets online – Quick list

dataset sources

Whether you’re looking for data for your high school statistics class, creating an infographic, or just generally interested in reading Census results before bedtime, here’s a decent list of sources online. Some datasets are completely free, some aren’t – I can’t guarantee the quality of the data, but I’ve cut down the list to the sites I’ve personally used data from before.

Cross domain canonicals from Blogspot blog

blogger blogspot canonical


I think Blogspot / blogger is a piece of cr*p. I don’t blame you for having a blogspot blog, but now that you’ve had to Google around to find a cross domain canonical fix, you know exactly how bad it is. For the love of {insert your preferred deity here}, DO NOT HOST ANYTHING WORTH OF ANY VALUE ON BLOGSPOT EVER AGAIN – sincerely, your friendly professional SEO, Dave.

Okay, so for some reason you need to create cross domain canonical tags from your blogspot blog to “wherever”, and you need to control this at page level. I am going to save you from hours of torture, hair loss, and potentially an aggravated trip to Mountain View.

I will assume the following:

  1. You’re not able to redirect your entire blogspot blog to a custom domain – directions here
  2. You have a complete list of all URLs and page titles from your blogspot blog
  3. You’ve exported your content and managed to load it onto a different domain – directions here
  4. You have admin access to the blogspot blog, obvious, but just making sure.
  5. You’ve got basic Excel skills and know how to Vlookup match your exported pages to your new pages via page titles

Passed all those?

Here’s the code for cross domain canonical in the template:

<b:if cond=’data:blog.canonicalUrl == “”‘><link href=”” rel=”canonical”/></b:if>

Easy right? Woohooo! Nay friend, nay.

Bullshit to watch out for #1 – The “canonicalURL” works….so does:

  • etc…

Yep, Google decided to duplicate every single f*cking URL on international cctlds, regardless if you wanted it or not. So how do they solve the issue of ridiculous amounts of dupe content? Well, they rel canonical back to one version, slick and totally fu*king unnecessary in the first place.

There’s a bunch of old blog posts you’ll probably come across that mention using <b:if cond=’data:blog.url… which wasn’t wrong at the time, but since some drunk at Google decided to auto-implement this geo-bullshit, well, that doesn’t work so well anymore. I tried for ages, and it basically ignored <b:if cond=’data:blog.url every friggin time. Why? No clue, I’d have a better shot explaining why Taco Bell is still allowed to serve Americans grade F dog meat in their burritos.

You need to use the data:blog.canonicalUrl Blogger XML variable to get the cross domain canonical condition to fire on all ccTLDs. Don’t ask why, just do it and get back to drinking.

Bullshit to watch out for #2 – The default “canonical”

You know what happens when you have 2 canonical instructions on one page? Google ignores both completely.

In your template, you’ll probably have this line of code:

<b:include data='blog' name='all-head-content'>

You know what that means? It means Google is going to automatically insert whatever they want, because they know best. In this specific scenario it’s going to insert a few extra meta tags that you don’t give a sh*t about anyway since you’re cross domain canonical’ing anyway, but most importantly, it will insert a default canonical tag which cannot be there if you need to add your own custom canonical tag.

Get rid of it, it’s about as useful as flesh eating disease to you at this point. 

Bullshit to watch out for #3 – Homepage canonical

The homepage is special, you’ll need to add another if statement to handle this, preferably at the top. Pay very close attention to how I reference the URL, you must reference it with the trailing slash or it won’t work!

<b:if cond='data:blog.canonicalUrl == ""'><link href="" rel="canonical"/></b:if>

That’s it, add that to the final block of code in the final implementation section below.

Bullshit to watch out for #4 – Copy & Pasting my code

‘ ” and other characters get bastardized pretty quickly on different platforms.  The biggest culprits are single quotes (‘), just re-type them in okay?

The final implementation!

Now that you’ve gotten rid of that rancid <b:include data=’blog’ name=’all-head-content’> and done all the steps I’ve told you about in the “assumed” section at the top of this post, you’re now going to Excel the shit out of your current blogspot URLs to match your new domain’s URLs.

You should probably back up your template first..

In the <head> section of the template editor (html editor), add ALL of your if statements:

<b:if cond='data:blog.canonicalUrl == ""'><link href="" rel="canonical"/></b:if>

<b:if cond='data:blog.canonicalUrl == ""'><link href="" rel="canonical"/></b:if>

Save it, then go have a beer.

If you have other questions, drop me a line below – I may/may not respond (just being honest, I treasure my free time).