over 6 years ago

I have a site which sends out emails through my corporate email account (Outlook), here are the steps need to send emails using Django:

Let's say my username is cheng@blah.com and the password is 123 for my email account.

  1. Make sure the following settings are in your settings.py
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'email.blah.com' # double check the settings in your outlook mailbox to make sure the host name is correct

EMAIL_PORT = 587  # double check the settings in your outlook mailbox and make sure the port number is correct

EMAIL_HOST_USER = 'cheng'  # don't include the @blah.com part! I have made this stupid mistakes before

  1. In your code:
from django.core.mail import EmailMessage
import traceback

def send_email():
    email = EmailMessage(
        to=['someone1@blah.com', 'someone2@blah.com'],
        reply_to=['cheng@blah.com'],  # when the reply or reply all button is clicked, this is the reply to address, normally you don't have to set this if you want the receivers to reply to the from_email address

    email.content_subtype = 'html' # if the email body contains html tags, set this. Otherwise, omit it

        return HttpResponseRedirect(reverse('apply:success'))
    except Exception:
        print traceback.format_exc() # you probably want to add a log here instead of console printout

That should be it :)

over 6 years ago

Two special characters are involved here:

  • Carriage Return (CR or \r in many programming languages)
  • Line Feed (LR or \n)

I never understood what those terms mean until I read that they are inherited from typewriters. When typing on a type writer, two physical actions have to happen in order to continue typing on the next line. First, the carriage needs to return to the very beginning (the far left and makes the ding sound). Then, the typewriter needs to move the page up a little so that we can type on a new line. The moving page up action is called line feed.

Windows uses CR+LR (i.e. \r\n) to denote a new line but on Unix and Unix-like machines (e.g. Linux), only LF or \n is used.

Some interesting behaviour of how CRLF is treated in JavaScript [*]:

JavaScript and XPath treat CRLF pairs as two line breaks. ^ matches in the middle of and after CRLF, while $ matches before and in the middle of CRLF.

over 6 years ago

I run into a problem today, here is the snippet:

var i = 101;
console.log('101: ' +  i.toString(2));
console.log('101 >> 1: ' + (i >> 1).toString(2));

var l = -101;
console.log('-101: ' + l.toString(2));
console.log('-101 >> 1: ' + (l >> 1).toString(2));'


"101: 1100101"
"101 >> 1: 110010"
"-101: -1100101"
"-101 >> 1: -110011"

Why -101 >> 1 is -110011 instead of -110010?

Here is what I learned by reading Professional JavaScript for Web Developers:

When js stores a negative number, it does the following things:

  1. get the binary representation of the absolute value of the negative number
  2. replace 0s with 1s and 1s with 0s
  3. add 1 to the result of step 2

So in my case -101 >> 1, we first convert -101 to its binary representation:

The binary representation of Math.abs(-101) is:

0000 0000 0000 0000 0000 0000 0110 0101

invert the 0s and 1s:

1111 1111 1111 1111 1111 1111 1001 1010

add 1 to the end:

1111 1111 1111 1111 1111 1111 1001 1011

Now, shift it to the right by 1:

1111 1111 1111 1111 1111 1111 1100 1101

The binary above should be the correct result of -101 >> 1, but when logging a negative number's binary representation, Javascript simply puts a negative sign in front of the binary representation of the positive number:

var x = 15;
console.log(x.toString(2)); // output: 1111

var y = -15;
console.log(y.toString(2)); // output: -1111

For our example, this means that when logging the result of -101 >> 1, JS will output minus sign + the binary representation of the positive number. But the positive number is not 101 >> 1 because 101 >> 1 gives you:

(101 >> 1).toString(2);  // output: 110010

(-101 >> 1).toString(2); // output: -110011, not -110010!

To get the correct result, we have to reverse the aforementioned step 1-3:

1111 1111 1111 1111 1111 1111 1100 1101   // this is the result we get from step 4

Reverse step 3 by subtracting 1, we get:

1111 1111 1111 1111 1111 1111 1100 1100

Reverse step 2 by invert 0s and 1s:

0000 0000 0000 0000 0000 0000 0011 0011

Reverse step 1 by converting this binary to integer:

parseInt(110011, 2); // output: 51

Finally, when JS logs the result of -101 >> 1, it should be in the format of minus sign + the binary representation of 51:

(51).toString(2);        // output:  110011

(-101 >> 1).toString(2); // output: -110011
over 6 years ago

I was running a django app on a linux machine and when I tried to login to the admin page, I kept getting redirected to the login page itself. It looks like this:

  1. POST /login/ 302
  2. GET / 302 < - should give me a 200 single I have logged in successfully but returns 302 instead
  3. GET ?next=/ 200 <- back to login page again

The site works when I use ./manage runserver but it wouldn't work when I use gunicorn to run it. I clear the cookie but it didn't work. I tried to set debug = False didn't work either. Eventially I found the problem, I wanted to use the database to store sessions, so I did this:


SESSION_ENGIN = 'django.contrib.sessions.backends.cache'

For some reason, my session cache is messed up and I have to use this setting instead:

SESSION_ENGIN = 'django.contrib.sessions.backends.cached_db'

Instead of storing cache in memory which disappears after server restart, cached_db writes it to the database. I have used the cache option before and worked but not this time.

over 6 years ago

I had the pleasure of setting up my own pypi server last week because the server I had to work with is behind a corporate firewall.

To setup your own pypi server, here is what to do:

  1. Download pypiserver, then:
unzip pypiserver-1.1.10
cd pypiserver-1.1.10
python setup.py install

Config pypyserver settings:

cd ~
touch .pypirc

Enter the following info in to .pypirc:

index-servers =


repository: http://localhost:8080

Setup the packages dir, this is the place where you store the packages:

cd ~
mkdir packages


pypi-server -p 8080 ~/packages

You might want to keep the server running even after you logout of terminal:

nohup pypi-server -p 8080 ~/packages &

You need to stuff your packages folder so that there will be something for pip install, here are essential packages you need to at least get a virtual environment running:

  • pbr
  • pip
  • setuptools
  • six
  • stevedore
  • virtualenv
  • virtualenv-clone
  • virtualenvwrapper
  • wheel

To download these packages, just go to https://pypi.python.org/pypi/ and search for the package name, then download the tar.gz version of that package. Once downloaded, move the zip file to the ~/packages folder.

To verify that the server is up and running, simply go to localhost:8080/simple/, you should see a list of package names (or empty if you haven't copied any packages into the packages folder yet).

Config your client to download python packages from your server:

cd ~
mkdir .pip
touch .pip/pip.conf

Put the following lines into pip.conf

index-url = http://localhost:8080/simple
trusted-host = localhost

Done! Try using pip install and it will download a package instantly from your ~/packages folder and install it :)

over 6 years ago

Found an excellent snippet here by monikkinom, which compresses all uploaded images to jpg before saving to disk:

from PIL import Image as Img
import StringIO

class Images(models.Model):
    image = models.ImageField()

    def save(self, *args, **kwargs):
        if self.image:
            img = Img.open(StringIO.StringIO(self.image.read()))
            if img.mode != 'RGB':
                img = img.convert('RGB')
            img.thumbnail((self.image.width/1.5,self.image.height/1.5), Img.ANTIALIAS)
            output = StringIO.StringIO()
            img.save(output, format='JPEG', quality=70)
            self.image= InMemoryUploadedFile(output,'ImageField', "%s.jpg" %self.image.name.split('.')[0], 'image/jpeg', output.len, None)
        super(Images, self).save(*args, **kwargs)

According to the official doc, the parameters for the InMemoryUploadedFile are:

file, field_name, name, content_type, size, charset, content_type_extra=None


If you want to scale the image and still keeps its aspect ratio:

new_width = 800
img.thumbnail((new_wdith, new_width * self.image.height / self.image.width), Img.ANTIALIAS)
over 6 years ago

To understand the concept of iterator in Javascript, it is important to memorize the following three protocal:

1. Mark an object iterable

To mark an object iterable, you need to add a Symbol.iterator property to it:

var obj = {};
obj[Symbol.iterator] = function() { return iteratorObject; }

The Symbol.iterator part looks really odd if you don't know what Symbol is all about. One way to think about it is to see it as metadata that describes the hidden behaviors of an object. When an object is marked with the iterator symbol, it means you can loop through it like an array.

2. Return an iterator object

The code snippet above returns an iterator object. An iterator object needs to have a next method which is a function that returns an iterator result object:

iteratorObject = {
    next: function(){
        return iteratorResultObj;

3. Return an iterator result object

Finally, I mean finally we can return some real values rather than wrappers that conforms to the iterable and iterator protocal.The iterator result object has to have two properties, one named value and the other named done.

iteratorResultObj = {
  value: ...,
  done: ...  // either true or false


As long as an object has the three traits explained above, it is iterable and can be used in a for...of loop or being spreaded [...myObj].

Putting it all together

var obj = {};

obj[Symbol.iterator] = function (){  // mark an object as iterable

  var i = 1;
  return {    // this is the iterator object

    next: function(){
      return i < 5 ? 
      {  // this is the iterator result object

        value: i++,
        done: false
      } : { done: true } // when the iterator reaches the end, value = undefined and done = true


var iter = obj[Symbol.iterator]();
console.log('value: ' + iter.next().value);
console.log('value: ' + iter.next().value);
console.log('value: ' + iter.next().value);
console.log('value: ' + iter.next().value);
console.log('done: ' + iter.next().done);

// the code above is equivalent of the following loop

for(var j of obj){

Here is a jsbin link of the code above.


To use ES6 syntax and define an iterator within a class:

class MyArray {
    constructor(...items) {
        this.items = items;

    [Symbol.iterator]() {
      let pos = 0;
      let data = this.items; // the value of `this` changes to undefined inside the next() function below, thus, we need to store it in a variable first

      return {
        next: () => {
            return pos < data.length? 
              { value: data[pos++], done: false } 
            : { done: true }

let arr = new MyArray(1,2,3)

for(const i of arr){

jsbin link

over 6 years ago

The HTTP 1.1 specification states:

A single-user client SHOULD NOT maintain more than 2 connections with any server or proxy.

But many modern browsers supports more than that:

IE 6 and 7:      2
IE 8:            6
IE 9:            6
IE 10:           8
IE 11:           8
Firefox 2:       2
Firefox 3:       6
Firefox 4 to 17: 6
Opera 9.63:      4
Opera 10:        8
Opera 11 and 12: 6
Chrome 1 and 2:  6
Chrome 3:        4
Chrome 4 to 23:  6
Safari 3 and 4:  4

The connection limitation is per hostname not IP address. [1]

Thus, even a.test.com and b.test.com points to the same ip address, you can still double the number of parrallel connections.

source: http://stackoverflow.com/questions/985431/max-parallel-http-connections-in-a-browser

over 6 years ago

On Ubuntu 14.04, the conifg file for sshd is located at:


Before making any modification, make a copy of the original config and make it read-only:

sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.factory-defaults
sudo chmod a-w /etc/ssh/sshd_config.factory-defaults

Then, open up sshd_config and modify the following lines:

LogLevel VERBOSE # also logs failed attempts, the log file can be found at /var/log/auth.log

AllowUsers user1 user2@ # only allow user1 and user2 from for example

PasswordAuthentication no # disable password login, use public key login instead

AllowTcpForwarding no # do not allow forwarding

X11Forwarding no

Restart ssh service to make the new config effective:

sudo service ssh restart

To limit the number of login attempts during a time period, enable the Uncomplicated Firewall by:

sudo ufw enable

Then, limit the number of ssh login attempts within 30 seconds to be 10 tries. More attempts will be dropped by issuing this command:

sudo ufw limit ssh

How to config your client

Once the server config has taken effect, you need to update your client ssh config which is found at ~/.ssh/config on your computer.

Host tinBox
User root
PubKeyAuthentication Yes
IdentityFile ~/.ssh/private_key

Make sure PubKeyAuthentication and a absolute/relative path to the private_key are added.

over 6 years ago

I work on a Ubuntu (14.04) machine with Postgres 9.4 installed. The config file directory of Postgres is located at:


Inside the config file, uncomment and adjust the following lines:

log_destination = 'stderr, csvlog'  # save logs as .log file and a .csv file

logging_collector = on # required to be on for csvlogs

log_directory = '/var/log/postgresql' # use any directory the postgres user have read and write access to. /var/log/postgresql is a pretty good place to start with

log_filename = 'postgresql-%Y-%m-%d_%H%M.log' # modify the %modifiers to suit your need

log_truncate_on_rotation = on # should logs be saved in separated files instead of one gigantic file

log_rotation_age = 1d # save the logs into a new file everyday. If you'd rather seperate files based on file size, modify log_rotation_size instead of this one

log_line_prefix = '%t [%p-%l] %q%u@%d ' # what information should each line of logs include

log_statement = 'all' # check out here for more info: http://www.postgresql.org/docs/9.4/static/runtime-config-logging.html#GUC-LOG-STATEMENT

log_timezone = 'Asia/Shanghai' # what timezone should be used for timestamp each log

These are the basic options I enabled, and to make this new change effective immediately, restart postgres by:

sudo service postgresql restart

For more config explanation, check the official doc here