Non-Interactive Redis Install

To build Redis from source, we first need to install TCL 8.5 or newer, this is needed for make test later:

$ sudo apt-get install -y tcl

Now clone and make:

$ git clone https://github.com/antirez/redis
$ git checkout 2.8.13
$ make
$ make test
$ sudo make install
$ sudo utils/install_server.sh

Binary (redis-cli and redis-server) will be installed into /usr/local/bin.

The last command with utils/install_server.sh is an interactive command. Since the script is a shell script using the read built-in command and -p option for prompt, we can make it non-interactive by redirecting input from echo command:

$ echo -n | sudo utils/install_server.sh

Without pumping any value into the script, the default values are used.

If really want to customize it, we can add our own values:

$ echo -e \
  "${PORT}\n${CONFIG_FILE}\n${LOG_FILE}\n${DATA_DIR}\n${EXECUTABLE}\n" | \
  sudo utils/install_server.sh

There are 6 read statements, hence n - 1 newline characters. Without using -n, the last newline character is supplied by echo.

Here are the default values:

PORT=6379
CONFIG_FILE=/etc/redis/6379.conf
LOG_FILE=/var/log/redis_6379.log
DATA_DIR=/var/lib/redis/6379
EXECUTABLE=/usr/local/bin/redis-server

The utils/install_server.sh script should return something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Welcome to the redis service installer
This script will help you easily set up a running redis server

Selecting default: 6379
Selected default - /etc/redis/6379.conf
Selected default - /var/log/redis_6379.log
Selected default - /var/lib/redis/6379
Selected config:
Port           : 6379
Config file    : /etc/redis/6379.conf
Log file       : /var/log/redis_6379.log
Data dir       : /var/lib/redis/6379
Executable     : /usr/local/bin/redis-server
Cli Executable : /usr/local/bin/redis-cli
Copied /tmp/6379.conf => /etc/init.d/redis_6379
Installing service...
 System start/stop links for /etc/init.d/redis_6379 already exist.
Success!
/var/run/redis_6379.pid exists, process is already running or crashed
Installation successful!

Set an alias for Redis client:

$ cd /usr/local/bin && sudo ln -s redis-cli redis

For more advanced install, see the README file.

Gulp Task Alias

Gulp API does not have a method to create an alias task. But, there are two ways to do this now:

  1. Create a task alias by dependency
  2. Create a task alias by duplication

Dependency

Gulp dependency system can be used to create an alias of a task:

gulp.task('task', function(){});
gulp.task('alias', ['task']);

Here, task alias is the alias of the task task. When list the tasks, it shows the dependency tree:

$ gulp --tasks
Tasks for ~/gulpfile.js
├── task
└─┬ alias
  └── task

When running the tasks, the dependency is obvious:

$ gulp alias
Starting 'task'...
Finished 'task' after 49 μs
Starting 'alias'...
Finished 'alias' after 6.83 μs

Duplication

Another way to create a task alias is by duplicating the task definition:

var task = function () {};    
gulp.task('task' , task);
gulp.task('alias', task);

But in this way, there is no implicit relationship that will indicates that one task is an alias of another. As you can see from the task list:

$ gulp --tasks
Tasks for ~/gulpfile.js
├── task
└── alias

To Gulp, there are two different tasks. But when the alias task is run, the console log is cleaner than the dependency one:

$ gulp alias
Starting 'alias'...
Finished 'alias' after 45 μs

Gulp is still involving, therefore, API might change regarding for creating alias of a task. At the moment, I like the second option. Alias and dependency are two different concepts. Dependency should be left as dependency. Alias is just another name to run the same task.

Extended Pattern Matching

Bash supports extended pattern matching. By using the built-in utility we can check if it is enabled or not:

$ shopt extglob

If not, to enable it:

$ shopt -s extglob

By default extglob is on in interactive shells, but off in non-interactive shells.

The key about extended pattern matching is pattern list via | (what we usually see as a OR operator). But do not think about it as that, think about it as a list of array pattern that are separated by | instead of ,. And actually one of them is the same as {} or brace expansion, but it can do more than expanding.

Here are the pattern operators:

? * + @ !

Create some example files:

$ touch a{,1,2,11,12}.js && ls
a11.js  a12.js  a1.js  a2.js  a.js

?(pattern-list)

Zero or one (any one) occurrence of the giving pattern:

$ ls a?(2|1).js
a1.js  a2.js  a.js

*(pattern-list)

Zero or more occurrences of the giving pattern (essentially everything):

$ ls a*(2|1).js
a11.js  a12.js  a1.js  a2.js  a.js

+(pattern-list)

One or more of the giving pattern (notice a.js is missing):

$ ls a+(2|1).js
a11.js  a12.js  a1.js  a2.js

@(pattern-list)

Any one of giving pattern:

$ ls a@(2|1).js
a1.js  a2.js

!(pattern-list)

None of the giving pattern:

$ ls a!(2|1).js
a11.js  a12.js  a.js

One mistake I had was getting confused between extended pattern matching and brace expansion, for example:

$ ls test/@{src|spec}/*.js
ls: cannot access test/@src/*.js: No such file or directory
ls: cannot access test/@spec/*.js: No such file or directory

Extended pattern uses parentheses () not braces {} as in brace expansion.

Also, these two patterns are the same:

test/@(src|spec)/*.js
test/{src,spec}/*.js

In some situations, extended pattern matching does not work, for example, matching files from the current directory and from one of the subdirectories with the following directory structure:

1
2
3
4
5
6
7
8
9
$ tree
.
├── app.js
├── lib
│   └── util.js
└── test
    └── main.js

2 directories, 3 files

I would like to match js files from the current directory and lib/ directory, sort of like:

$ ls *.js lib/*.js
app.js  lib/util.js

But this does not do it:

$ ls @(.|lib)/*.js

Instead, use brace expansion:

$ ls {.,lib}/*.js

Finally, Node’s Minimatch supports brace expansion, extended globbing and globstar.

Inherited Accessor Property Can Only Be Overridden by Accessor Property

In Javascript, define a property prop as an accessor property via getter/setter:

1
2
3
4
var obj = {
  get prop() {},
  set prop() {}
};

And the property will have the following attributes:

> Object.keys(obj)
[ 'prop' ]
> Object.getOwnPropertyDescriptor(obj, 'prop')
{ get: [Function: prop],
  set: [Function: prop],
  enumerable: true,
  configurable: true }

Now, create a new object that inherits obj, and attempt to overwrite the accessor property by a data property:

1
2
var foo = Object.create(obj);
foo.prop = 'data';

But, the same property of the new object cannot be created:

> Object.keys(foo)
[]
> Object.getOwnPropertyDescriptor(foo, 'prop')
undefined

That is because that the property is an accessor property and it cannot be overridden by a data property. It can only be overridden by an accessor property:

1
2
3
4
5
6
Object.defineProperty(foo, 'prop', {
  get: function prop() {},
  set: function prop() {},
  enumerable: true,
  configurable: true,
});

Then, the foo object will have its own property named prop:

> Object.keys(foo)
[ 'prop' ]
> Object.getOwnPropertyDescriptor(foo, 'prop')
{ get: [Function: prop],
  set: [Function: prop],
  enumerable: true,
  configurable: true }

Getter and Setter Methods without Function Identifier Restriction

A JavaScript identifier must start with either a letter, underscore, or dollar sign:

1
2
3
4
5
6
7
8
> function 7/11(){}
SyntaxError: Unexpected number
> function '7/11'(){}
SyntaxError: Unexpected string
> var 7/11 = function(){}
SyntaxError: Unexpected number
> var '7/11' = function(){}
SyntaxError: Unexpected string

But object property does have such a limitation:

1
2
3
> var obj = { '7/11': function(){} }
> obj['7/11']
function (){}

And it works with accessor properties or getter and setter methods:

1
2
3
> var obj = { get '7/11'(){ return '7/11'; } }
> obj['7/11']
"7/11"

The syntax get '7/11'(){} looks like function '7/11'(){}, but it is not, getter and setter are still object properties. That is why it works. That’s another reason to use JavaScript object.

Get Rid of '<200e>' Control Characters in VIM

The left-to-right mark character is an invisible control character. If you open up a text file in VIM containing such a character, you will see it as <200e> in Unicode.

If you want to get rid of all occurrences of this control character, you can do:

:%s/<ctrl>+<shift>+u200e<enter>//g

That’s <ctrl>+<shift>+u to enable entering the character by Unicode code points, followed by the actual character code and <enter> key. It will loke like this:

:%s/<200e>//g

However, not all terminals are supported.

Tiny HTTP Servers

This is a simple way to run a tiny web server via command line:

$ python -m SimpleHTTPServer 8080

which will server static files from the current directory.

There is Knod for Ruby, and of course there is one for Node: http-server.

To install:

$ sudo npm install -g http-server

To run:

$ http-server

Server will be accessible via http://localhost:8080/.

Avoid Assigning undefined to an Object Property

A property value should be any JavaScript value except for undefined. If you do something like this (albeit it is legal):

1
var foo = { bar: undefined };

will leads to confusing code. Because when accessing the property value:

1
console.log(foo.bar); // undefined

It will returns undefined. But you are not sure if it means the property exists or not or the value of the property is set to undefined. Therefore, you should do:

1
var foo = { bar: null };

This indicates that the property is expected, and with the value of null.

You do be able to check the existence of a property by:

1
2
Object.keys(foo); // ['bar']
foo.hasOwnProperty('bar'); // true

But more importantly, if you serialize the object with JSON.stringify, properties with undefined will be omitted:

1
JSON.stringify({ bar: undefined }); // '{}'

According to JSON specification, a value can be a string in double quotes, or a number, or true or false or null, or an object or an array. undefined is not a valid JSON value.

null is fine:

1
JSON.stringify({ bar: null }); // '{"bar":null}'

So, for the best practice, avoid assigning undefined to a property of an object. Use null to indicate the expected property without a value. This will increase portability when using JSON to serialize.

Proxy GitHub Files for Hotlinking

I have a library that I would like to try in JSFiddle, for example, Marked, a markdown parser and compiler. But I cannot by hotlinking the minified JavaScript file directly:

1
<script src="https://raw.githubusercontent.com/chjj/marked/master/marked.min.js"></script>

Error:

Refused to execute script from ‘https://raw.githubusercontent.com/chjj/marked/master/marked.min.js‘ because its MIME type (‘text/plain’) is not executable, and strict MIME type checking is enabled.

Double check the headers:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ curl -I https://raw.githubusercontent.com/chjj/marked/master/marked.min.js
HTTP/1.1 200 OK
Server: Apache
Content-Security-Policy: default-src 'none'
Access-Control-Allow-Origin: https://render.githubusercontent.com
X-XSS-Protection: 1; mode=block
X-Frame-Options: deny
X-Content-Type-Options: nosniff
Strict-Transport-Security: max-age=31536000
Content-Type: text/plain; charset=utf-8
Cache-Control: max-age=300
Content-Length: 19160
Accept-Ranges: bytes
Via: 1.1 varnish
X-Served-By: cache-lax1429-LAX
X-Cache: MISS
X-Cache-Hits: 0
Vary: Authorization,Accept-Encoding
Source-Age: 0

The two headers that prevents hotlinking:

  • Content-Type is set to text/plain, we are expecting application/javascript.
  • Access-Control-Allow-Origin is not set to *, which prevents AJAX request.

The solution is to proxy the file by running your own server, or use RawGit:

1
2
3
4
5
6
7
8
9
10
11
12
13
$ curl -I https://rawgit.com/chjj/marked/master/marked.min.js
HTTP/1.1 200 OK
Server: nginx
Content-Type: application/javascript; charset=utf-8
Connection: keep-alive
Vary: Accept-Encoding
X-Content-Type-Options: nosniff
X-Robots-Tag: none
RawGit-Naughtiness: 0
Access-Control-Allow-Origin: *
Cache-Control: max-age=300
Vary: Accept-Encoding
RawGit-Cache-Status: MISS

The Content-Type has been updated to application/javascript and the CORS restricted has been relaxed via Access-Control-Allow-Origin.

Problem sovled and the fiddle works as expect:

Inventing on Principle

Bret Victor, “Inventing on Principle”, January 20, 2012:

Bret Victor’s principle:

Creator needs immediate connection.

Following a principle, following your passion, and doing things you love.