2012-10-04

The Node.js REPL and Backslashes in Strings

I thought there was something weird going on with the node.js REPL's handling of backslashes in Strings. I was thinking, "Why are there twice as many backslashes!?" Then, it hit me: the output is correct! It is escaping the value of the string, just as if a programmer were to have typed it. Duh. You can use the output as-is when copy-and-pasting. No need to manually add extra backspaces! That's pretty convenient, eh? This really had me confused me at first, though, because I am so used to the behavior of Chrome's console, which prints out the unescaped string values (even though it does put quotes around the value).

$ node
> "\ "
' '
> JSON.stringify("\ ")
'" "'
> "\\"
'\\'
> JSON.stringify("\\")
'"\\\\"'
> new Buffer("\\")
<Buffer 5c>
> new Buffer([0x5c]).toString()
'\\'
> new Buffer([0x5c, 0x5c]).toString()
'\\\\'

2012-02-29

U+2665 BLACK HEART SUIT

I was reading an article on StackOverflow when one of the ads caught my eye. It looked something like this:

1
2
3
4 <p>
5 &#x2665;
6 Your Job
7 </p>
8
9

"What character is that?" I wondered whilst automatically opening up the in-browser console.

> String.fromCharCode(0x2665)
""

Hey, it's the U+2665 BLACK HEART SUIT! So, that would make the message: ♥ Your Job.

Cool.

2012-01-06

Tomcat v6.0.35 and UTF-8 Parameters

Update 1 (2012-01-07): I don't have access to the problematic system right now and am unable to confirm; but, when I tried simplifying this down to just one JSP, it worked fine. It also worked fine with one mayaa file. This leads me to think that there must be some system-specific issue.

The recent release of Apache Tomcat, v6.0.35, seems to break the handling of parameters encoded in UTF-8. For example, if I pass "%E6%97%A5%E6%9C%AC" (which is the string of URL-escaped UTF-8 bytes for "日本"), it gets incorrectly interpreted. Both URIEncoding="UTF-8" and useBodyEncodingForURI="true" are set for the necessary Connectors in server.xml, and it works as expected prior to v6.0.35.

Expected:
$ cat nippon && cat $_ | hexdump -C
日本
00000000  e6 97 a5 e6 9c ac 0a                              |.......|
00000007

Actual:
$ cat tomcat-bug && cat $_ | hexdump -C
æ¥æ¬
00000000  c3 a6 c2 97 c2 a5 c3 a6  c2 9c c2 ac 0a           |.............|
0000000d

I cloned the GitHub mirror of tomcat60 and did a quick git-bisect. The offending commit is 1ef4156 (r1200601 in SVN), which corresponds to the last two items of the Catalina changelog for unreleased version 6.0.34.

So, in other words, Tomcat properly interprets parameters prior to (and fails starting from) 1ef4156.

It is hard to tell exactly what the problem is, though, because 1ef4156 is such a large commit. My best guess, without digging into the code, is that ISO-8859-1 is being used instead of UTF-8 in the decoding process—i.e., it seems that the charset is not being correctly passed to the parameter processor.

The same "mistaken" decoding can be done with iconv, as follows:
$ cat nippon | iconv -f ISO-8859-1 -t UTF-8 | hexdump -C
00000000  c3 a6 c2 97 c2 a5 c3 a6  c2 9c c2 ac 0a           |.............|
0000000d

Maybe I'll have a look later and try to fix the problem.

2011-10-08

Different fetch/push URLs for git clone

UPDATE 1
It turns out to be reeeeallly easy!
git remote set-url --push origin git@example.com:username/repo.git


I always use passphrases on my ssh keys. Everyone does, right? Anyway, it gets kind of annoying entering it in each time when fetching from an upstream repository. I don't have enough need to set-up a key-ring, though. So, I took a quick look at git config --help and figured out how to set-up different URLs for git-push and git-fetch.
remote.<name>.url
    The URL of a remote repository. See git-fetch(1) or git-push(1).
remote.<name>.pushurl
    The push URL of a remote repository. See git-push(1).

I just opened up .git/config and set remote.origin.url to the read-only URL, and remote.origin.pushurl to the initial value of remote.origin.url.

Now, I can git-fetch/git-pull without the annoying passphrase prompt. Yay.

There's probably a way to do it with git-remote; but, I'm too lazy to figure it out right now...

2010-07-21

Cygwin.bat

I use Cygwin in combination with Poderosa for my terminal emulator (because it has tabs, unlike PuTTY), as a replacement for the Win32 console. These two are usually the first things that I install on a new Windows box.

I recently changed the drive letter of the drive to which Cygwin (v1.7.5) had been installed. After the change, Cygwin just ceased to start-up at all. Even after running setup again.

After some digging, I finally figured out that path\to\cygwin\Cygwin.bat contains an absolute reference to Cygwin's bin directory. However, it seems that this path only gets set once, at initial installation.

After updating the drive letter manually, though, everything is back to normal. I think the setup should detect and correct issues with this batch file...

@echo off

E:
chdir E:\cygwin\bin

bash --login -i

2010-01-20

Installing RMagick

The other day I had to install RMagick in order to get a RoR project running on a local box to do some maintenance and add new functionality.

Well, I thought everything would be all fine and dandy because I had installed ImageMagick to mess around with previously. But, for some reason, gem install rmagick was complaining it couldn't find Magick-Config or something.

I ended up trying a bunch of suggestions from other blogs (which I conveniently forgot to list...sorry for not giving credits) and somehow came up with this configure for ImageMagick:
./configure --disable-static --with-modules --without-perl --without-magick-plus-plus --with-quantum-depth=8

I've not had the time nor the patience to figure out which option is the key to this all; but, RMagick installed without problem.

2009-12-30

Closure Compiler

I've been trying out Google's supposedly wicked Closure Compiler. It seems to work well for normal things; but, there still is a bit farther to go. I don't know if there is something wrong with the way that I write javascript; but, it seems that the Closure Compiler just can't handle it properly...

By the way, there was a very eye-opening and interesting post on the Google Code Blog. Basically, they came up with a wonderful idea: send all modules, split-up and commented-out, to the client, then eval() them on-the-fly. Now, why the hell didn't anyone think of that before!? D'OH!!! Anyway, props to the thinker who came up with that solution.

Well, okay, back to the point of this blog.

In order to see how well the compiler works, I wrote some slightly bloated code (see code appendices below).

For some reason, though, the output is really not as optimized as I would have hoped...

For example:
if((b=b)&&f===b.tagName){a=b.innerHTML||"";b.parentNode.removeChild(b)}a=(a=a)?a.replace(/^\s*\/\*\s*(.*?)\s*\*\/\s*$/,"$1"):void 0;if(a){a=["{",a,"}"].join("");eval(a)}

Could probably be further reduced to:
if(b&&f===b.tagName){a=b.innerHTML||"";b.parentNode.removeChild(b)}if(a){eval(["{",a.replace(/^\s*\/\*\s*(.*?)\s*\*\/\s*$/,"$1"),"}"].join(""))}

And even further yet to:
if(b&&f===b.tagName){eval(["{",(b.innerHTML||"").replace(/^\s*\/\*\s*(.*?)\s*\*\/\s*$/,"$1"),"}"].join(""));b.parentNode.removeChild(b)}

Maybe there's some cross-browser stuff (of which I should mention I am not really familiar). I dunno.

All-in-all, from what I've seen so far, it's really good at reducing unnecessary, or "dead", code. As such, I'd have say that I want to start using the Closure Compiler for my own projects! At this point it looks like nothing beats a hand-coder for optimization, though--I'll have to go over the output and manually fix all the (a = a) stuff.





Appendix


module.js
// ==ClosureCompiler==
// @compilation_level ADVANCED_OPTIMIZATIONS
// @output_file_name default.js
// @formatting pretty_print
// ==/ClosureCompiler==

// ADD YOUR CODE HERE
var xvn = function(doc){
 var SCRIPT = doc.createElement('script').tagName;

 var __loaded_modules = {};
 function mark_as_loaded(id) {
  __loaded_modules[id] = true;
 }
 function is_loaded(id) {
  return (id) && (__loaded_modules[id]);
 }

 function get_elm(id) {
  var elm;
  if (id) {
   elm = doc.getElementById(id);
  }
  return elm;
 }

 function grab_js(elm) {
  var js;
  if (elm && SCRIPT === elm.tagName) {
   js = elm.innerHTML || "";
   elm.parentNode.removeChild(elm);
  }
  return js;
 }

 function clean_js(js) {
  if (!js) return;

  return js.replace(/^\s*\/\*\s*(.*?)\s*\*\/\s*$/,"$1");
 }

 function eval_js(js) {
  if (!js) return;

  var new_js = ['{', js, '}'].join("");
  eval(new_js);
 }

 return {
  'load_module':function(id){
   if (!is_loaded(id)) {
    eval_js(clean_js(grab_js(get_elm(id))));
    mark_as_loaded(id);
   }
  }
 };
};
window['xvn'] = xvn;

module-compiled.js
window.xvn=function(d){var f=d.createElement("script").tagName,e={};return{load_module:function(c){if(!(c&&e[c])){var a;var b;if(c)b=d.getElementById(c);if((b=b)&&f===b.tagName){a=b.innerHTML||"";b.parentNode.removeChild(b)}a=(a=a)?a.replace(/^\s*\/\*\s*(.*?)\s*\*\/\s*$/,"$1"):void 0;if(a){a=["{",a,"}"].join("");eval(a)}e[c]=true}}}};

index.html
<!DOCTYPE html>
<html>
<head>
 <title>Module Loading Tests</title>
 <script type="text/javascript" src="./module-compiled.js"></script>
</head>
<body>
 <div id="click-me-man" onclick="my_xvn.load_module('mod1');">Load Mod1</div>

 <script type="text/javascript" id="mod1">
 /*
  alert("Hey!");
 */
 </script>

 <script type="text/javascript">
  var my_xvn = new xvn(document);
 </script>
</body>
</html>