thefourtheye's weblog

opinions are my own; try code/suggestions at your own risk

JavaScript Lookbehind RegEx Alternative

| Comments

Recently one of my colleagues came to me with a problem. He had a string which looked like JSON but not a valid JSON string. For example,

[{\"name\":\"Kilua\"\\,\"age\":35}],{\"city\":\"SJC\"},\"US\"

and they wanted to split the string at all the commas, except when they are preceded by a backslash. That means, they wanted

[ '[{"name":"Kilua"\\,"age":35}]', '{"city":"SJC"},"US"' ]

as output. If the requirement was to split the string at commas followed by a certain string, then it would have been pretty straight forward. For example, if the string is a,1,b,2,c,3 and if they wanted to split the string at all commas except when they are not followed by numbers, then the solution would have been very simple, with negative lookahead, like this

console.log('a,1,b,2,c,3'.split(/,(?!\d)/));
// [ 'a,1', 'b,2', 'c,3' ]

Since JavaScript doesn’t have lookbehinds, we don’t have a straight forward solution to this problem. When I searched Stackoverflow, I found this solution

WTK's answer in Stackoverflowlink
'a\\,bcde,fgh,ijk\\,lmno,pqrst\\,uv'.replace(/([^\\]),/g, '$1\u000B').split('\u000B')

This solves the exact same problem which my colleague was facing. It compensates the absence of lookbehinds by breaking down the problem in two steps.

  1. Replace all the commas matching the condition with a marker string which does not appear anywhere in the string. (\u000B in this case)
  2. Then split the original string with the marker string.

JS Quirks: Stringified Numbers

| Comments

When I was working on Node.js PR 9492, this comment

This should probably test for a wider range of values. test/parallel/test-net-internal.js has some good examples.

made me look at that file. As I was going through the test, few of the bad values were interesting. I normally test with stringified positive decimal numbers and negative decimal numbers. But I saw stringified negative octal, binary, and hexa decimal numbers.

const bad = [-1, 'a', {}, [], false, true, 0xFFFF + 1, Infinity,
             -Infinity, NaN, undefined, null, '', ' ', 1.1, '0x',
             '-0x1', '-0o1', '-0b1', '0o', '0b'];

I got curious as I have never used them before, I just wanted to see their corresponding negative values. So I wrote a program like this

[-0x1, '-0x1', -0o1, '-0o1', -0b1, '-0b1'].forEach(item => console.log(item, +item));

and I was expecting to see the result

-1 -1
-0x1 -1
-1 -1
-0o1 -1
-1 -1
-0b1 -1

but all I got was

-1 -1
-0x1 NaN
-1 -1
-0o1 NaN
-1 -1
-0b1 NaN

The unary - operator simply negates the magnitude of the numbers. The stringified numbers were not processed in the same way as their number counterparts. So I looked at the ECMAScript specification’s ToNumber Applied to the String Type section (which is actually responsible for converting strings to numbers).

StrNumericLiteral :::
    StrDecimalLiteral
    BinaryIntegerLiteral
    OctalIntegerLiteral
    HexIntegerLiteral
...
...
StrDecimalLiteral :::
    StrUnsignedDecimalLiteral
    + StrUnsignedDecimalLiteral
    - StrUnsignedDecimalLiteral

Only the StrDecimalLiteral production allows signed numbers. If we look at the definition of others in the Numeric Literals section,

BinaryIntegerLiteral ::
    0b BinaryDigits
    0B BinaryDigits

BinaryDigits ::
    BinaryDigit
    BinaryDigits BinaryDigit

BinaryDigit :: one of
    0 1

OctalIntegerLiteral ::
    0o OctalDigits
    0O OctalDigits

OctalDigits ::
    OctalDigit
    OctalDigits OctalDigit

OctalDigit :: one of
    0 1 2 3 4 5 6 7

HexIntegerLiteral ::
    0x HexDigits
    0X HexDigits

HexDigits ::
    HexDigit
    HexDigits HexDigit

HexDigit :: one of
    0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F

So, as per the specification, only the decimal numbers can have signs in the stringified number form. That is why the others are not considered as numbers.

DSL-2730U Router's Ipv6 Problem in Ubuntu

| Comments

Today I faced a very strange problem. I got a new Tata DOCOMO connection and I wanted to fetch upstream changes from a GitHub repository, with git fetch --all. But all I got was
fatal: unable to access 'https://github.com/<repo>': Failed to connect to github.com port 443: Network is unreachable
I thought that the internet connection has a problem. But then I was able to ping github.com and access that site in my browser, although curl still failed.
➜  io.js git:(master) ✗ curl https://github.com
curl: (7) Failed to connect to github.com port 443: Network is unreachable
At this point I became curious and tried out the verbose curl,
➜  io.js git:(master) ✗ curl -v https://github.com
* Rebuilt URL to: https://github.com/
* Hostname was NOT found in DNS cache
* Trying 192.30.252.128...
* Trying 64:ff9b::c01e:fc81...
* connect to 64:ff9b::c01e:fc81 port 443 failed: Network is unreachable
* Failed to connect to github.com port 443: Network is unreachable
* Closing connection 0
curl: (7) Failed to connect to github.com port 443: Network is unreachable
Now, it figures out both the IPv4 address and the IPv6 address but favors IPv6 over IPv4. And it looks like, either the modem or the ISP don't support IPv6 based communication. I don't know how to confirm what the actual problem is. I tried to upgrade the firmware of my DSL-2730U router, by logging into 192.168.1.1. But it kept failing, saying the the firmware image file is too big.

So, I decided to disable IPv6 in my Ubuntu machine and I followed the instructions given here and it worked perfectly. Basically, I edited /etc/sysctl.conf file to include the following lines
# disable IPv6 on this machine
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
and then executed sudo sysctl --system and sudo sysctl -p.

Sane ECMAScript 6 Generators

| Comments

This post is cross posted in Medium, here.

I recently found one interesting thing about ES6 Generators. I come from Python background and I understood generators as in Python. So, I expected the following Python code's equivalent ECMAScript 6 code also to work as well.
>>> numbers = (num for num in range(10))
>>> for num in numbers:
... if num == 3:
... break
...
>>> next(numbers)
4
You can find the online demo for this Python program, here.

But then, when I used Babel to transpile the following code and executed it
function* NumberGenerator() {
for (var i = 0; i < 10; i += 1) {
yield i;
}
}

var numbers = NumberGenerator();

for (var num of numbers) {
if (num === 3) {
break;
}
}

console.log(numbers.next());
// {"done":true}
You can find the online demo for this JavaScript program, made with Babel's REPL, here. As you see here, when I broke out of the loop, the Generator Object got closed. This was pointed out to me by Logan Smyth in Babel's Slack discussion. I was really surprised by this behavior and found the 13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation ( lhs, stmt, iterator, lhsKind, labelSet ) section in the ECMAScript 6 Specification, which says
If LoopContinues(result, labelSet) is false, return IteratorClose(iterator, UpdateEmpty(result, V)).
I am not sure about the rationale behind that decision, but I am convinced that it would effectively limit the potential of the Generators. So I decided to fix this.

Sane Generators

To close the iterator, Iterator.prototype.return is called. (At the time of this writing, not many JavaScript Engines support this function. You can find the support for this feature by popular engines, here.) So I decided to override that and allow the actual return function to be invoked only when explicitly called with an argument.
function returnFunction(originalReturn, genObject) {
return function(arg) {
return arguments.length ? originalReturn.call(genObject, arg) : {
done: false
};
};
}

function SaneGenerator(genObject) {
var originalReturn = genObject['return'];

if (typeof originalReturn === 'function') {
Object.defineProperty(genObject, 'return', {
value: returnFunction(originalReturn, genObject)
});
}

return genObject;
}
You can see the actual and complete implementation in my GitHub repository, https://github.com/thefourtheye/sane-generator. Now, you can use the SaneGenerator like this
function* NumberGenerator() {
for (var i = 0; i < 10; i += 1) {
yield i;
}
}

var numbers = SaneGenerator(NumberGenerator());

for (var num of numbers) {
if (num === 3) {
break;
}
}

console.log(numbers.next());
// {"value":4,"done":false}
You can find the online demo for this JavaScript program, made with Babel's REPL, here.

NPM Module

This is available as an NPM module now. https://www.npmjs.com/package/sane-generator

Sublime Text 3 Unhiding Menu in Ubuntu - Simpler Solution

| Comments

The method which I mentioned in this blog post of mine, solves the problem, but then you have to
  1. Close the Sublime Text
  2. Fire up a terminal
  3. Execute a command or two
  4. Open Sublime Text again
Quite a lot of steps to do. But then I found a simpler solution today and it works like a charm for me. The solution is to use "Keyboard Shortcuts" :-) Let me explain in detail.
  1. Click Preferences -> Key Bindings - User
  2. In the window that opens, you need to add a new keyboard shortcut for the command "toggle_menu". For example, this is how my shortcuts looks like
    [{"keys": ["ctrl+\\"], "command": "toggle_side_bar"},
    {"keys": ["ctrl+shift+m"], "command": "toggle_menu"}]
  3. Save the file and start doing your happy dance.
Now, you can simply press the keyboard shortcut whatever you choose to assign to toggle menu :-)