XPath and Clojure

9 11 2008

I’ve modified previous script to use Java’s XPath to extract RSS titles.

(import '(javax.xml.parsers DocumentBuilderFactory DocumentBuilder)
        '(org.w3c.dom Document Node)
        '(javax.xml.xpath XPathFactory XPath XPathExpression XPathConstants)
  )

(let [domFactory (doto (. DocumentBuilderFactory newInstance) (setNamespaceAware true))
      builder (. domFactory newDocumentBuilder)
      doc (. builder parse "/Users/jgoamakf/hotnews.rss")
      factory (. XPathFactory newInstance)
      xpath (. factory newXPath)
      expr (. xpath compile "//title/text()")
      result (. expr evaluate doc (. XPathConstants NODESET))
      ]
   (loop [index 0
          len (. result getLength)]
     (if (< index len)
       (do
         (println (. (. result item index) getNodeValue))
         (recur (inc index) len)))
))




RSS titles with Clojure

2 11 2008

This script prints every title appeared in RSS 2.0 feed.

(clojure/refer 'clojure.xml)

(let 
  (doseq entry content
    (let [el  (get (get entry :content) 0)]
      (if (= (get el :tag) :title)
        (println (get (get el :content) 0))
      )))
)

You need a RSS 2.0 XML file on your local hard drive before invoke.

% ftp http://images.apple.com/main/rss/hotnews/hotnews.rss
% java -cp clojure/clojure.jar clojure.lang.Script rsstitles.clj




Emacs and Dropbox

28 10 2008

Emacs usually creates backup files(filename~) and autosave files(#filename#)
when you modify existing text files.

In my opinion, this behavior is not optimum for Dropbox folder because

  1. The Dropbox folder is already version controlled, so you don’t need backup copies
  2. Frequent writes to a remote folder result in waste of network bandwidth

These elisp configurations prevents Emacs from creating backup and autosave files
inside the Dropbox folder.

Don’t create backup files.

(setq backup-enable-predicate
      (lambda (name)
        (not (string-match "Dropbox" name))))

Create autosaves under /tmp/jgoamakf.

(setq auto-save-file-name-transforms '((".*/Dropbox/.*" "/tmp/jgoamakf/\\1" t)))




Custom Sheets don’t need their own xib files

9 08 2008

When you want to use custom sheets, Apple’s Documentation suggests that you create another xib file for the sheets(Using Custom Sheets).

But in fact, you don’t have to use a separate xib.

1. Create a controller class which handles both parent window and sheet window.

SheetTestController.h

@interface SheetTestController : NSObject {
	IBOutlet NSWindow *mainWindow;  //paent window
	IBOutlet NSWindow *sheetWindow; //sheet window
}

- (IBAction)showSheet:(id)sender; // open sheet on parent window
- (IBAction)closeSheet:(id)sender;// close sheet

@end

SheetController.m

@implementation SheetTestController

- (IBAction)showSheet:(id)sender
{
	[NSApp beginSheet: sheetWindow
	   modalForWindow: mainWindow
		modalDelegate: self
	   didEndSelector: @selector(didEndSheet:returnCode:contextInfo:)
		  contextInfo: nil];
}

- (IBAction)closeSheet:(id)sender
{
    [NSApp endSheet:sheetWindow];
}

- (void)didEndSheet:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
{
    [sheet orderOut:self];
}

@end

2. Add “Show Sheet” button to parent window.

parentWindow

3. Add a sheet window, and put “close sheet” button on the window.

sheetWindow
make sure that “Visible At Launch” is unchecked.
sheetWindowAttributes

4. Add a SheetTestController object to the xib.

sheetControllerInstance

5. Connection settings of SheetTestController should be like this.

sheetControllerConnections

This is a little easier than “separate xib” way, but has disadvantages noted below.

  • increses memory usage because the sheet window always takes up some memory instead of instanciated only when necessary.
  • It’s difficult to use the sheet window from other xib files.




Fast Enumeration with NSEnumerator

2 04 2008

While reading The Objective-C 2.0 Programming Language, I found that Fast Enumeration can be used with NSEnumerator(The Objective-C 2.0 Programming Language: Fast Enumeration).

Suppose you have an array which you want to itarete over.

NSArray *tmpArray =
    [NSArray arrayWithObjects:@"first", @"second", @"third", nil];

Use the for statement against the reverseEnumerator obtained from the array. It loops through the array starting from the last element and proceed to the first.

NSEnumerator *enumerator = [tmpArray reverseObjectEnumerator];
for(NSString *s in enumerator) {
    NSLog(@"%@", s);
}




Draw on CGLayer

24 03 2008

I modified Create an on-memory CGImageRef to draw the small blue rectangle on a CGLayer, and combines the CGLayer to the background graphics context to generate the image. The result should remain same.

const int height = 250;
const int width = 400;

CGColorSpaceRef  imageColorSpace = CGColorSpaceCreateWithName( kCGColorSpaceGenericRGB );

CGContextRef context = CGBitmapContextCreate (NULL, width, height,
                                    8, width * 4,
                                    imageColorSpace, kCGImageAlphaPremultipliedLast);

CGContextSetRGBFillColor (context, 1.0, 0.8, 0.8, 1);
CGContextFillRect (context, CGRectMake (0, 0, width, height ));

// Addition starts here.
CGLayerRef          layer;
CGContextRef        layerContext;

layer = CGLayerCreateWithContext(context,CGSizeMake(width, height),NULL);
layerContext = CGLayerGetContext(layer);

CGContextSetRGBFillColor(layerContext, 0, 0, 1, 1);
CGContextFillRect (layerContext, CGRectMake (80, 80, 40, 30));

CGContextDrawLayerInRect(context, CGRectMake(0, 0, width, height), layer);
// Addition finished.

CGImageRef image = CGBitmapContextCreateImage(context);

[imageView setImage:image imageProperties:nil];

CGColorSpaceRelease( imageColorSpace );
CGLayerRelease(layer);
CGContextRelease(layerContext);
CGContextRelease(context);
CGImageRelease( image );




Create an on-memory CGImageRef

21 03 2008

To create an on-memory CGImageRef object and display it through IKImageView, follow these steps.

  1. Create a Bitmap Graphics Context with the CGBitmapContextCreate() function.
  2. Draw some graphics on the Bitmap Graphics Context.
  3. Create an CGImageRef object from the Bitmap Graphics Context with the CGBitmapContextCreateImage() function.This CGImageRef object contains the same image as the Bitmap Graphics Context drawn in step 2.
  4. Pass the CGImageRef to IKImageView.
const int height = 250;
const int width = 400;

CGColorSpaceRef  imageColorSpace =
        CGColorSpaceCreateWithName( kCGColorSpaceGenericRGB );

CGContextRef context = CGBitmapContextCreate (NULL, width, height,
         8, width * 4, imageColorSpace,
         kCGImageAlphaPremultipliedLast);

CGContextSetRGBFillColor (context, 1.0, 0.8, 0.8, 1);
CGContextFillRect (context, CGRectMake (0, 0, width, height ));

CGContextSetRGBFillColor(context, 0, 0, 1, 1);
CGContextFillRect (context, CGRectMake (80, 80, 40, 30));

CGImageRef image = CGBitmapContextCreateImage(context);

[imageView setImage:image imageProperties:nil];

CGColorSpaceRelease( imageColorSpace );
CGContextRelease(context);
CGImageRelease( image );




Disable WYSIWYG HTML editor on WordPress

5 03 2008

Here is an option you can disable WordPress’s “visual editor”. After show your Dashboard,

1. Click “Users”

wordpress1

2. Click “Your Profile”

wordpress2

3. Uncheck “Use the visual rich editor when writing” and click “Update Profile >>”

wordpress3

I prefer this because visual editor almost always strips line breaks.





mod_perl handler skeltons

29 02 2008

Because I rarely write mod_perl handler from scratch, tend to forget very basics of how it should be.Note “bare minimum” mod_perl response handlers here so that I can quickly start writing handlers from copying it.

Suppose installation of Apache 2.2, mod_perl and libapreq2 is successfully finished.

Apache configuration

LoadModule perl_module lib/httpd/mod_perl.so
LoadModule apreq_module lib/httpd/mod_apreq2.so

PerlSwitches -Mlib=/home/www

<Location /hello>
    SetHandler perl-script
    PerlResponseHandler My::Hello
</Location>

<Location /handler>
    SetHandler perl-script
    PerlResponseHandler My::Handler
</Location>

static handler

In /home/www/My/Hello.pm,

package My::Hello;
use strict; use Apache2::RequestRec;
use Apache2::RequestIO;
use Apache2::Const -compile => 'OK';

sub handler : method {
    my ($class, $r) = @_;
    $r->content_type('text/plain');
    print 'Hello, world';
    return Apache2::Const::OK;
}
1;

http://localhost/hello should return ‘Hello, world’.

Dealing with parameters

In /home/www/My/Handler.pm,

package My::Handler;
use strict;

use Apache2::RequestRec;
use Apache2::RequestIO;
use Apache2::Request;
use Apache2::Const -compile => 'OK';

sub handler : method {
    my ($class, $r) = @_;

    $r->content_type('text/plain');

    my $req = Apache2::Request->new($r);
    print $req->param('test1');

    return Apache2::Const::OK;
}

1;

Should take parameter from query like http://localhost/handler?test1=Hello or form like below.

<form action="/handler" method="POST">
<input type="text" name="test1">
<br>
<input type="submit">
</form>




HTTP GET by CFNetwork

24 02 2008

I came across the same problem described in fraserspeirs: HTTP Nerdery, or, Why NSURLConnection Sucks For POST.I tried to send POST reqeust to a HTTP server with NSURLRequest and NSURLConnection, but nothing sent.

So I decided to use CFNetwork instead.Here is my first attempt. Because this code blocks until the server returns HTTP response, I’m modifying to non-blocking version which make use of “Run Loops”.

CFURLRef url = CFURLCreateWithString(NULL, CFSTR("http://www.google.co.jp/"), NULL);
CFHTTPMessageRef httpRequest = CFHTTPMessageCreateRequest(NULL, CFSTR("GET"), url, kCFHTTPVersion1_1);
CFReadStreamRef readStream = CFReadStreamCreateForHTTPRequest(NULL, httpRequest);
CFReadStreamOpen(readStream);

CFIndex bytes;
int bufSize = 1024;
UInt8 buf[bufSize];

do {
    bytes = CFReadStreamRead(readStream, buf, sizeof(buf));
    if( bytes > 0 ){
        NSString *responseString = [[NSString alloc] initWithBytes:buf length:bytes encoding:NSUTF8StringEncoding];
        NSLog(responseString);
    } else if( bytes < 0 ) {
        CFStreamError error = CFReadStreamGetError(readStream);
    }
} while( bytes > 0 );

CFHTTPMessageRef httpResponse = (CFHTTPMessageRef)CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPResponseHeader);

if(httpResponse) {
    CFStringRef responseStatus = CFHTTPMessageCopyResponseStatusLine(httpResponse);
    NSLog((NSString *)responseStatus);
}