ラベル Cocoa の投稿を表示しています。 すべての投稿を表示
ラベル Cocoa の投稿を表示しています。 すべての投稿を表示

2011年10月29日土曜日

Sample: Nest of 'WebScriptObject ( Javascript associative array ) to NSDictionary' or 'WebScriptObject ( Javascript array ) to NSArray ) '

SampleAppDelegate.h

#import <Cocoa/Cocoa.h>
#import <WebKit/WebKit.h>
@interface SampleAppDelegate : NSObject <NSApplicationDelegate> {
NSWindow *window;
}

@property (assign) IBOutlet NSWindow *window;

+ (id)structueWithWebScriptObject:(WebScriptObject *)obj
webScriptObject:(WebScriptObject *)scriptObj;

@end

SampleAppDelegate.m

#import "SampleAppDelegate.h"
@implementation SampleAppDelegate
@synthesize window;
+ (NSDictionary *)dictionaryWithWebScriptObject:(WebScriptObject *)obj
webScriptObject:(WebScriptObject *)scriptObj
{
NSMutableDictionary *ret= [NSMutableDictionary dictionary];
id keys= [scriptObj callWebScriptMethod:@"_f0_"
withArguments:[NSArray arrayWithObjects:obj, nil]];
NSArray *keyAry= [SampleAppDelegate structueWithWebScriptObject:keys
webScriptObject:scriptObj];
unsigned i;
for(i= 0; i<[keyAry count]; i++) {
NSString *key= [keyAry objectAtIndex:i];
id val= [obj valueForKey:key];
if ([val isMemberOfClass:[WebScriptObject class]]) {
val= [SampleAppDelegate structueWithWebScriptObject:val
webScriptObject:scriptObj];
}
[ret setObject:val forKey:key];
}
return [[ret retain] autorelease];
}
+ (id)structueWithWebScriptObject:(WebScriptObject *)obj
webScriptObject:(WebScriptObject *)scriptObj
{
@try{
NSMutableArray *ret = [NSMutableArray array];
NSUInteger count = [[obj valueForKey:@"length"] integerValue]; //exception occure if associative array
unsigned i;
for (i = 0; i < count; i++) {
id val= [obj webScriptValueAtIndex:i];
if ([val isMemberOfClass:[WebScriptObject class]]) {
val= [SampleAppDelegate structueWithWebScriptObject:val
webScriptObject:scriptObj];
}
[ret addObject:val];
}
return [[ret retain] autorelease];
}
@catch (NSException *e) {
return [SampleAppDelegate dictionaryWithWebScriptObject:obj
webScriptObject:scriptObj];
}
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
WebView *webView = [[WebView alloc] init];
[[webView mainFrame] loadHTMLString:@"" baseURL:NULL];
WebScriptObject *scriptObject = [webView windowScriptObject];

NSString *_f0_= @"function _f0_(hash){var ret=[];for(var key in hash){ret.push(key);}return ret;}";

NSString *returnValue= @"[{'key0':['val000', 'val001'], 'key1':'val01'}, {'key0':'val10', 'key1':['val110', 'val111']}]";
NSString *code= [NSString stringWithFormat:@"function main(){return %@;}", returnValue];
NSString *script = [NSString stringWithFormat:@"try { %@ %@ } catch (e) { e.toString() }", code, _f0_];

id ret0= [scriptObject evaluateWebScript:script];
if (![ret0 isMemberOfClass:[WebUndefined class]]) {
NSLog(@"ret(main): %@", ret0);
}

id ret= [scriptObject callWebScriptMethod:@"main" withArguments:nil];
if (ret && [ret isMemberOfClass:[WebScriptObject class]]) {
WebScriptObject *obj= (WebScriptObject *)ret;
NSArray *nsRet= [SampleAppDelegate structueWithWebScriptObject:obj
webScriptObject:scriptObject];
NSLog(@"%@", nsRet);
}
}
@end


Result
Javascript

[{'key0':['val000', 'val001'], 'key1':'val01'}, {'key0':'val10', 'key1':['val110', 'val111']}]

Cocoa

(
{
key0 = (
val000,
val001
);
key1 = val01;
},
{
key0 = val10;
key1 = (
val110,
val111
);
}
)

Sample: WebScriptObject ( Javascript associative array ) to NSDictionary ( WebScriptObject ( Javascript array ) to NSArray )

Addtion(20111029T2300): Nest Version



SampleAppDelegate.h

#import <Cocoa/Cocoa.h>
#import <WebKit/WebKit.h>
@interface SampleAppDelegate : NSObject <NSApplicationDelegate> {
NSWindow *window;
}

@property (assign) IBOutlet NSWindow *window;

@end

SampleAppDelegate.m

#import "SampleAppDelegate.h"
@implementation SampleAppDelegate
@synthesize window;
+ (NSArray *)arrayWithWebScriptObject:(WebScriptObject *)obj
{
NSMutableArray *ret = [NSMutableArray array];
NSUInteger count = [[obj valueForKey:@"length"] integerValue]; //exception occurs if it is associative array.
unsigned i;
for (i = 0; i < count; i++) {
[ret addObject:[obj webScriptValueAtIndex:i]];
}
return [[ret retain] autorelease];
}
+ (NSDictionary *)dictionaryWithWebScriptObject:(WebScriptObject *)obj
webScriptObject:(WebScriptObject *)scriptObj
{
NSMutableDictionary *ret= [NSMutableDictionary dictionary];
id keys= [scriptObj callWebScriptMethod:@"_f0_"
withArguments:[NSArray arrayWithObjects:obj, nil]];
NSArray *keyAry= [SampleAppDelegate arrayWithWebScriptObject:keys];
unsigned i;
for(i= 0; i<[keyAry count]; i++) {
NSString *key= [keyAry objectAtIndex:i];
[ret setObject:[obj valueForKey:key] forKey:key];
}
return [[ret retain] autorelease];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
WebView *webView = [[WebView alloc] init];
[[webView mainFrame] loadHTMLString:@"" baseURL:NULL];
WebScriptObject *scriptObject = [webView windowScriptObject];

NSString *_f0_= @"function _f0_(hash){var ret=[];for(var key in hash){ret.push(key);}return ret;}";
NSString *code= @"function main(){return {'key0':'val0', 'key1':'val1'};}";
NSString *script = [NSString stringWithFormat:@"try { %@ %@ } catch (e) { e.toString() }", code, _f0_];
id ret0= [scriptObject evaluateWebScript:script];
if (![ret0 isMemberOfClass:[WebUndefined class]]) {
NSLog(@"ret(main): %@", ret0);
}

id ret= [scriptObject callWebScriptMethod:@"main" withArguments:nil];
if (ret && [ret isMemberOfClass:[WebScriptObject class]]) {
WebScriptObject *obj= (WebScriptObject *)ret;
NSDictionary *dict= [SampleAppDelegate dictionaryWithWebScriptObject:obj
webScriptObject:scriptObject];
NSLog(@"%@", dict);
}
}
@end


reference: "Notes on Cocoa - Convert a Javascript array to an NSArray"

2011年10月6日木曜日

NSTableViewのカラムのValueに対してプログラム中でBindingをする


NSTableView *tableView;
NSArrayController *arrayController;
NSString *key;

NSTableColumn *tc= [[[NSTableColumn alloc] init] autorelease];
[[tc headerCell] setStringValue:key];
NSString *modelKey= [NSString stringWithFormat:@"arrangedObjects.%@", key];
[tc bind:@"value" toObject:arrayController withKeyPath:modelKey options:nil];
[tableView addTableColumn:tc];

tableViewからtableColumnを取得してもよいはず.

円弧のNSBezierPath

- (void) appendBezierPathWithArcWithCenter:radius:startAngle:endAngle:でいいじゃんとか言わない.

double CX= __CENTER_X_;
double CY= __CENTER_X_;
double r= __RADIUS__
double b= __RATIO__0_TO_1_;

NSBezierPath *path= [NSBezierPath bezierPath];
double a= 4.0/3.0 * (sqrt(2)-1) * r;
double c= 0.0;
[path moveToPoint:NSMakePoint(+r, 0)];
if (b>0.25) {
[path curveToPoint:NSMakePoint(0, +r)
controlPoint1:NSMakePoint(+r, +a)
controlPoint2:NSMakePoint(+a, +r)];
b-= 0.25;
c+= 90.0;
}
if (b>0.25) {
[path curveToPoint:NSMakePoint(-r, 0)
controlPoint1:NSMakePoint(-a, +r)
controlPoint2:NSMakePoint(-r, +a)];
b-= 0.25;
c+= 90.0;
}
if (b>0.25) {
[path curveToPoint:NSMakePoint(0, -r)
controlPoint1:NSMakePoint(-r, -a)
controlPoint2:NSMakePoint(-a, -r)];
b-= 0.25;
c+= 90.0;
}
if(b==0.25) {
[path curveToPoint:NSMakePoint(+r, 0)
controlPoint1:NSMakePoint(+a, -r)
controlPoint2:NSMakePoint(+r, -a)];
//b-= 0.25;
//c+= 90.0;
}
else if (b<0.25) {
NSAffineTransform *affine= [NSAffineTransform transform];
[affine rotateByDegrees:c];
double t= b/0.25;
double it= (1.-t);
[path curveToPoint:[affine transformPoint:NSMakePoint(+cos(t*M_PI_2)*r, +sin(t*M_PI_2)*r)]
controlPoint1:[affine transformPoint:NSMakePoint(+r, +a*t)]
controlPoint2:[affine transformPoint:NSMakePoint(+(it*it*r+2*it*t*r+t*t*a), +(it*it*0+2*it*t*a+t*t*r))]
];
}
NSAffineTransform *affine= [NSAffineTransform transform];
[affine translateXBy:CX yBy:CY];
//[affine rotateByDegrees:45];
[path transformUsingAffineTransform:affine];


開始点を変更したい場合は最後の平行移動前(書く時は後ろ)にて回転させればよい.(コメント部)
描画ならCGContextAddArcか.

参考: s.h's page - [graphic] ベジエ曲線

2011年9月14日水曜日

メモ的: Twitterのhome_timelineの情報を無理矢理4storeに入れてみる(いろんな意味でいろいろ間違ってるとは思う)

  • OAuthConsumerフレームワーク('#import <OAuthConsumer/OAuthConsumer.h>')についてはこちら
  • 4storeのクライアントライブラリ(っぽいなにか)('#import "FourStore.h"')についてはこちら

    #import "TwTurtleAppDelegate.h"
    #import <OAuthConsumer/OAuthConsumer.h>
    #import "FourStore.h"

    @implementation TwTurtleAppDelegate

    @synthesize window;

    - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
    {
    OAConsumer *consumer = [[OAConsumer alloc] initWithKey:@"XXXXXXXXXXXXXXXXXXXXXX"
    secret:@"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"];

    OAToken *accessToken= [[OAToken alloc] initWithKey:@"XXXXXXX-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
    secret:@"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"];

    NSURL *url= [NSURL URLWithString:@"http://api.twitter.com/1/statuses/home_timeline.xml"];
    OAMutableURLRequest *requestWithBodyParams = [[[OAMutableURLRequest alloc] initWithURL:url
    consumer:consumer
    token:accessToken
    realm:nil
    signatureProvider:nil] autorelease];

    OADataFetcher *fetcher = [[[OADataFetcher alloc] init] autorelease];

    [fetcher fetchDataWithRequest:requestWithBodyParams
    delegate:self
    didFinishSelector:@selector(apiTicket:didFinishWithData:)
    didFailSelector:@selector(apiTicket:didFailWithError:)];

    }
    - (void)fourstoreWithTurtle:(NSString *)turtle
    {
    FourStore *store= [[FourStore alloc] initWithEndpoint:@"http://localhost:8000/sparql/"];
    [store addPrefix:@"tsp" uri:@"http://example.org/twitter/status/predicate/"];
    [store addPrefix:@"tu" uri:@"http://example.org/twitter/users/"];

    NSString *message0= [store deleteWithGraph:@"http://example.org/twitter/status/"];
    NSLog(@"message0 %@", message0);


    NSString *message1= [store addTurtle:turtle graph:@"http://example.org/twitter/status/"];
    NSLog(@"message1 %@", message1);

    NSString *message2= [store queryWithString:
    @"SELECT ?s ?p ?o \nWHERE {\nGRAPH <http://example.org/twitter/status/> {\n?s ?p ?o .\n}\n}\n"];
    NSLog(@"message2 \n%@", message2);

    }
    - (NSString *)createTurtleWithXMLData:(NSData *)data
    {
    NSMutableString *turtle= [NSMutableString string];

    NSXMLDocument *document = [[[NSXMLDocument alloc] initWithData:data
    options:NSXMLDocumentTidyHTML
    error:NULL] autorelease];
    NSError *error= nil;
    NSArray *nodes = [document nodesForXPath:@"//status" error:&error];
    NSEnumerator *nodesEnum= [nodes objectEnumerator];
    NSXMLNode *node= nil;
    while(node= [nodesEnum nextObject]) {
    NSArray *idnodes= [node nodesForXPath:@"id" error:&error];
    if ([idnodes count]==0) continue;
    NSString *idString= [[idnodes objectAtIndex:0] stringValue];
    NSEnumerator *childrenEnum= [[node children] objectEnumerator];
    NSXMLNode *child=nil;
    while(child= [childrenEnum nextObject]) {
    NSString *name= [child name];
    if ([name isEqualToString:@"id"])
    continue;
    NSString *value= nil;
    if ([name isEqualToString:@"retweeted_status"]){
    NSArray *cidnodes= [child nodesForXPath:@"id" error:&error];
    if ([cidnodes count]==0) continue;
    NSString *cidString= [[cidnodes objectAtIndex:0] stringValue];
    value= [NSString stringWithFormat:@"<%@>", cidString];
    } else if ([name isEqualToString:@"user"]){
    NSArray *cidnodes= [child nodesForXPath:@"id" error:&error];
    if ([cidnodes count]==0) continue;
    NSString *cidString= [[cidnodes objectAtIndex:0] stringValue];
    value= [NSString stringWithFormat:@"<tu:%@>", cidString];
    } else {
    if ([[child stringValue] length]==0) continue;
    value= [child stringValue];
    value= [value stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""];
    value= [value stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"];
    value= [NSString stringWithFormat:@"\"%@\"", value];
    }

    [turtle appendFormat:@"<%@> tsp:%@ %@ .\n", idString, name, value];
    }
    }


    return turtle;
    }
    - (void)apiTicket:(OAServiceTicket *)ticket
    didFinishWithData:(NSData *)data
    {

    if (0)
    NSLog(@"didFinish %@", [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]);

    NSString *turtle= [self createTurtleWithXMLData:data];

    if (0)
    NSLog(@"\n%@", turtle);

    [self fourstoreWithTurtle:turtle];
    }
    - (void)apiTicket:(OAServiceTicket *)ticket
    didFailWithError:(NSError *)error
    {

    NSLog(@"%@", error);
    }
    @end



    やってみてアレコレ悩んだ足跡.
  • 2011年9月12日月曜日

    Cocoa ( Objective-C )での 4store の Client Library (?)

    動機
    4storeを入れてみた.rubyのclient用ライブラリをみて,似たものをcocoaでやってみようと思った(たぶん既にどこかにあるだろうけど).
    入れる際(環境: MacOSX10.7)にハマった点
  • MacPortsでraptorとrasqalを入れたのだがraptorに1.x(www/raptor)と2.x(www/raptor2)があり, rasqal0.9.26がraptor2.xを利用して入っているのにraptor 1.xが入ったままだと4storeのmake時にエラーがでたこと.
  • "git clone https://github.com/garlik/4store.git"でとってきたらconfigureがなかったので(そういうものなのかな?), "sh autogen.sh"から始めたこと.



  • やってみた(rubyにあるload作ってないしsetもマネの途中)
    FourStore.h

    @interface FourStore : NSObject
    {
    NSURL *_urlSPARQL;
    NSURL *_urlDATA;
    NSMutableArray *_prefixs;
    }
    - (id)initWithEndpoint:(NSString *)endpoint;
    - (void)addPrefix:(NSString *)prefix uri:(NSString *)uri;
    - (NSString *)addTurtle:(NSString *)turtle graph:(NSString *)graph;
    //- (NSString *)setTurtle:(NSString *)turtle graph:(NSString *)graph;
    - (NSString *)queryWithString:(NSString *)query;
    - (NSString *)deleteWithGraph:(NSString *)graph;
    @end

    FourStore.m

    #import "FourStore.h"

    @implementation FourStore

    - (id)init
    {
    self = [super init];
    if (self) {
    }
    return self;
    }
    - (id)initWithEndpoint:(NSString *)endpoint
    {
    if (![endpoint hasSuffix:@"/sparql/"]) {
    return nil;
    }
    self = [self init];
    if (self) {
    _urlSPARQL= [[NSURL URLWithString:endpoint] retain];
    NSArray *ary= [endpoint componentsSeparatedByString:@"/sparql/"];
    _urlDATA= [[NSURL URLWithString:[NSString stringWithFormat:@"%@/data/", [ary objectAtIndex:0]]] retain];
    _prefixs= [[NSMutableArray array] retain];
    }
    return self;
    }
    - (void)dealloc
    {
    [_urlSPARQL release];
    [_urlDATA release];
    [super dealloc];
    }
    + (NSString *)sendRequest:(NSURLRequest *)request
    {
    NSURLResponse *response=nil;
    NSError *error= nil;
    NSData *data= [NSURLConnection sendSynchronousRequest:request
    returningResponse:&response
    error:&error];
    if (error) {
    NSLog(@"statusCode %ld", [response statusCode]);
    NSLog(@"error code %ld", [error code]);
    }

    NSString *message= [[NSString alloc] initWithData:data
    encoding:NSUTF8StringEncoding];
    return [message autorelease];
    }
    + (NSString *)send:(NSString *)request url:(NSURL *)url method:(NSString *)method
    {
    NSMutableURLRequest *requestWithBodyParams = [[NSMutableURLRequest alloc] initWithURL:url];
    NSData *requestData = [request dataUsingEncoding:NSASCIIStringEncoding
    allowLossyConversion:YES];
    [requestWithBodyParams setHTTPBody:requestData];
    [requestWithBodyParams setValue:[NSString stringWithFormat:@"%d", [requestData length]]
    forHTTPHeaderField:@"Content-Length"];
    [requestWithBodyParams setValue:@"application/x-www-form-urlencoded"
    forHTTPHeaderField:@"Content-Type"];
    [requestWithBodyParams setHTTPMethod:method];

    NSString *msg= [FourStore sendRequest:requestWithBodyParams];
    [requestWithBodyParams release];

    return msg;
    }

    - (void)addPrefix:(NSString *)prefix uri:(NSString *)uri
    {
    [_prefixs addObject:[NSDictionary dictionaryWithObjectsAndKeys:
    prefix, @"p", uri, @"u", nil]];
    }
    - (NSString *)prefixsOfQuery
    {
    NSMutableString *ret= [NSMutableString string];
    NSEnumerator *prefixsEnum= [_prefixs objectEnumerator];
    NSDictionary *dic;
    while(dic= [prefixsEnum nextObject]) {
    [ret appendFormat:@"PREFIX %@: <%@>\n", [dic objectForKey:@"p"], [dic objectForKey:@"u"]];
    }
    return [[ret retain] autorelease];
    }
    - (NSString *)prefixsOfTurtle
    {
    NSMutableString *ret= [NSMutableString string];
    NSEnumerator *prefixsEnum= [_prefixs objectEnumerator];
    NSDictionary *dic;
    while(dic= [prefixsEnum nextObject]) {
    [ret appendFormat:@"@prefix %@: <%@> .\n", [dic objectForKey:@"p"], [dic objectForKey:@"u"]];
    }
    return [[ret retain] autorelease];
    }
    - (NSString *)queryWithString:(NSString *)query
    {
    NSString *fullquery= [NSString stringWithFormat:@"%@%@", [self prefixsOfQuery], query];

    NSString *request= [NSString stringWithFormat:@"query=%@&soft-limit=%@",
    [fullquery stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding], @""];

    return [FourStore send:request url:_urlSPARQL method:@"POST"];
    }
    - (NSString *)addTurtle:(NSString *)turtle graph:(NSString *)graph
    {
    NSString *fullturtle= [NSString stringWithFormat:@"%@%@", [self prefixsOfTurtle], turtle];

    NSString *request= [NSString stringWithFormat:@"mime-type=%@&data=%@&graph=%@",
    [@"application/x-turtle" stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
    [fullturtle stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
    [graph stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];

    return [FourStore send:request url:_urlDATA method:@"POST"];
    }
    //- (NSString *)setTurtle:(NSString *)turtle graph:(NSString *)graph
    //{
    // NSString *fullturtle= [NSString stringWithFormat:@"%@%@", [self prefixsOfTurtle], turtle];
    //
    // NSString *request= [fullturtle stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    //
    // NSURL *url= [NSURL URLWithString:[NSString stringWithFormat:@"%@%@", [_urlDATA absoluteString], graph]];
    //
    // return [FourStore send:request url:url method:@"PUT"];
    //}
    - (NSString *)deleteWithGraph:(NSString *)graph
    {
    NSURL *url= [NSURL URLWithString:[NSString stringWithFormat:@"%@%@", [_urlDATA absoluteString], graph]];

    return [FourStore send:@"" url:url method:@"DELETE"];
    }
    @end



    使い方(?)

    FourStore *store= [[FourStore alloc] initWithEndpoint:@"http://localhost:8000/sparql/"];
    [store addPrefix:@"dc" uri:@"http://purl.org/dc/elements/1.1/"];

    if (1) {
    NSString *msg= [store addTurtle:@"<http://example.org/book/book1> dc:title \"SPARQL Tutorial\" ."
    graph:@"http://example.org/book"];
    NSLog(@"%@", msg);
    }
    if (1) {
    NSString *msg= [store queryWithString:
    @"SELECT ?title \nWHERE {\nGRAPH <http://example.org/book> {\n<http://example.org/book/book1> <http://purl.org/dc/elements/1.1/title> ?title .\n}\n}\n"];
    NSLog(@"%@", msg);

    }
    if (1) {
    NSString *msg= [store queryWithString:
    @"SELECT ?title \nWHERE {\nGRAPH <http://example.org/book> {\n<http://example.org/book/book1> dc:title ?title .\n}\n}\n"];
    NSLog(@"%@", msg);

    }
    if (1) {
    NSString *msg= [store deleteWithGraph:@"http://example.org/book"];
    NSLog(@"%@", msg);
    }

    [store release];


    結果

    (> 4s-backend-setup [KB])
    > 4s-backend [KB]
    > 4s-httpd -p 8000 -U [KB]


    > 200 added successfully
    This is a 4store SPARQL server v1.1.3-54-gd8008fc

    > <?xml version="1.0"?>
    <sparql xmlns="http://www.w3.org/2005/sparql-results#">
    <head>
    <variable name="title"/>
    </head>
    <results>
    <result>
    <binding name="title"><literal>SPARQL Tutorial</literal></binding>
    </result>
    </results>
    </sparql>

    > <?xml version="1.0"?>
    <sparql xmlns="http://www.w3.org/2005/sparql-results#">
    <head>
    <variable name="title"/>
    </head>
    <results>
    <result>
    <binding name="title"><literal>SPARQL Tutorial</literal></binding>
    </result>
    </results>
    </sparql>

    > 200 deleted successfully
    This is a 4store SPARQL server v1.1.3-54-gd8008fc

    2011年8月20日土曜日

    Cocoa / nsAlert setAccessoryView:でJOptionPane.showInputDialog(Java)っぽいこと


    NSTextField *textField= [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 20)];

    NSAlert *alert = [[NSAlert alloc] init];
    [alert setMessageText:@"Message text"];
    [alert setInformativeText:@"Informative text"];
    [alert setAccessoryView:textField];
    [alert runModal];

    NSLog(@"DONE: %@", [textField stringValue]);

    [textField release];
    [alert release];


    IBにてCustomViewにNSFormくっつけてaccessoryViewを用意する方がカッコイイかも.
    (NSFormの入力フィールドにBindingするときはForm CellのValueになるように.)

    Quartz Composer / Automator / AutomatorのパッチでQCRender関連のナンカを実装してみた

    動機
    これをやったのでこれ的なQCRenderネタをやってみようかと安易に思った('Quartz コンポジションフィルタをイメージに適用'ってパッチが既にありますが).


    やってみた
    0.プロジェクトの作成
    プロジェクトの修正等はこちらを参照下さい
    xibのFile's Ownerのクラスも上記と同じクラス名で修正する(こちらの3.xibを編集を参照のこと).
    OpenGLとQuartzのframeworkを追加した.


    1.コード

    #import <Automator/AMBundleAction.h>
    #import <Quartz/Quartz.h>

    @interface QuartzComposer : AMBundleAction

    - (id)runWithInput:(id)input fromAction:(AMAction *)anAction error:(NSDictionary **)errorInfo;

    - (IBAction)openQTZ:(id)sender;

    @end



    #import "QuartzComposer.h"

    @implementation QuartzComposer
    - (IBAction)openQTZ:(id)sender
    {
    NSString *compositionPath= [[NSBundle bundleForClass:[self class]] pathForResource:@"composition" ofType:@"qtz"];
    [[NSWorkspace sharedWorkspace] openFile:compositionPath withApplication:@"Quartz Composer"];
    }

    - (id)runWithInput:(id)input fromAction:(AMAction *)anAction error:(NSDictionary **)errorInfo
    {
    NSUInteger width= 16;
    NSUInteger height= 16;
    NSString *compositionPath= [[NSBundle bundleForClass:[self class]] pathForResource:@"composition" ofType:@"qtz"];

    QCRenderer *renderer= nil;
    {
    NSOpenGLPixelFormatAttribute attributes[]= {
    NSOpenGLPFAPixelBuffer,
    NSOpenGLPFANoRecovery,
    NSOpenGLPFAAccelerated,
    NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)24,
    NSOpenGLPFASampleBuffers, (NSOpenGLPixelFormatAttribute)1,
    NSOpenGLPFASamples, (NSOpenGLPixelFormatAttribute)16,
    (NSOpenGLPixelFormatAttribute)0
    };
    NSOpenGLPixelFormat *format= [[[NSOpenGLPixelFormat alloc] initWithAttributes:attributes] autorelease];
    NSOpenGLPixelBuffer *pixelBuffer= [[NSOpenGLPixelBuffer alloc] initWithTextureTarget:GL_TEXTURE_RECTANGLE_EXT
    textureInternalFormat:GL_RGBA
    textureMaxMipMapLevel:0
    pixelsWide:width
    pixelsHigh:height];

    NSOpenGLContext *openGLContext= [[NSOpenGLContext alloc] initWithFormat:format shareContext:nil];
    if(pixelBuffer == nil || openGLContext == nil) {
    NSLog(@"no buffer or no context");
    return nil;
    }

    [openGLContext setPixelBuffer:pixelBuffer
    cubeMapFace:0
    mipMapLevel:0
    currentVirtualScreen:[openGLContext currentVirtualScreen]];

    renderer= [[QCRenderer alloc] initWithOpenGLContext:openGLContext pixelFormat:format file:compositionPath];
    }

    NSMutableArray *outputPaths= [NSMutableArray array];
    if(renderer) {
    NSMutableArray *inputPaths= [NSMutableArray array];
    if ([input isKindOfClass:[NSArray class]]) {
    [inputPaths addObjectsFromArray:input];
    }
    else if ([input isKindOfClass:[NSString class]]) {
    [inputPaths addObject:input];
    }
    int i;
    for(i=0;i<[inputPaths count];i++) {
    NSString *inputPath= [inputPaths objectAtIndex:i];
    NSImage *inputImage= [[[NSImage alloc] initWithContentsOfFile:inputPath] autorelease];
    [renderer setValue:inputImage forInputKey:@"InputImage"];

    if(![renderer renderAtTime:0.0 arguments:nil]) {
    NSLog(@"no rendering");
    return nil;
    }
    [renderer createSnapshotImageOfType:@"NSBitmapImageRep"];

    NSImage *image= (NSImage *)[renderer valueForOutputKey:@"OutputImage"];
    NSBitmapImageRep *bitmapImage= [NSBitmapImageRep imageRepWithData:[image TIFFRepresentation]];
    if(bitmapImage) {
    char *tempNameBytes = tempnam([NSTemporaryDirectory() fileSystemRepresentation], "QCComposition_Result_");
    NSString *tempName = [[[NSString alloc] initWithBytesNoCopy:tempNameBytes
    length:strlen(tempNameBytes)
    encoding:NSUTF8StringEncoding
    freeWhenDone:YES] autorelease];
    NSString *outputPath= [tempName stringByAppendingPathExtension:@"png"];


    NSDictionary *properties= [NSDictionary dictionaryWithObjectsAndKeys:
    [NSNumber numberWithFloat:1.0], NSImageCompressionFactor,
    nil];
    NSData *pngImageData= [bitmapImage representationUsingType:NSPNGFileType
    properties:properties];

    [pngImageData writeToFile:outputPath
    atomically:YES];
    [outputPaths addObject:outputPath];
    }
    }
    }
    else {
    NSLog(@"no render");
    }

    return outputPaths;
    }

    @end


    2.composition.qtzを作成する
    Quartz Composerで作成する.この際にInputImageというPublished InputとOutputImageというPublished Outputを用意する.


    3.Supporting Files(リソース)にコンポジション(composition.qtz)を加える
    Build PhasesのCopy Bundle Resourcesに含まれていること.


    4.Viewまわり
    xlbにボタンを配置して(IBAction)openQTZ:に繋ぐ.


    あとはBuildして配置(~/Library/Automator/下).



    結果


    Motion Blurなのでこんな感じ.

    2011年8月13日土曜日

    Xcode4.1のAutomator Plugin ProjectをCocoaでつくる際のテンプレートの修正点

    Automator Plugin Projectを作成


    Cocoa の指定を確認


    プロジェクトの設定(Infoタブ)を確認

    Principal classがAMShellScriptActionになぜかなってる.
    このまま作成し配置. AMで利用すると実行時に"launch path not accessible"って言われて終了しちゃう.


    修正

    プロジェクト作成でできるObjective-C class("- (id)runWithInput:(id)input fromAction:(AMAction *)anAction error:(NSDictionary **)errorInfo"の実装を書くオブジェクト.AMBundleActionの派生)名(テンプレートではファイル名と同じ)に修正.

    2011年8月9日火曜日

    OAuthConsumer.frameworkを使う(TwitterへPOST)

    動機
    前回の物を使ってみるため,あちらこちらのサンプルを継ぎ接ぎして(例えば)以下の様にしたら動いた..

    やってみた.
    フレームワークの追加

    ~/Library/Frameworks/のOAuthConsumer.frameworkを追加
    /System/Library/Framewokrs/のSecurity.frameworkを追加


    フレームワークの利用のためのHeader
    
    
    #import <OAuthConsumer/OAuthConsumer.h>



    インスタンス変数
    
    
    OAConsumer *consumer;
    OAToken *accessToken;


    インスタンス変数の初期化
    
    
    consumer = [[OAConsumer alloc] initWithKey:@"[Consumer Key]"
    secret:@"[Consumer Secret Key]"];
    accessToken= nil;

    Consumer Key/Consumer Secret KeyはTwitterの開発者サイトで登録し取得する.

    ConsumerKey/ConsumerSecretKeyからRequestTokenを取得へ
    
    
    - (void)requestRequestToken
    {
    NSURL *url = [NSURL URLWithString:@"https://api.twitter.com/oauth/request_token"];

    OAMutableURLRequest *request = [[OAMutableURLRequest alloc] initWithURL:url
    consumer:consumer
    token:nil
    realm:nil
    signatureProvider:nil];

    [request setHTTPMethod:@"POST"];

    OADataFetcher *fetcher = [[[OADataFetcher alloc] init] autorelease];

    [fetcher fetchDataWithRequest:request
    delegate:self
    didFinishSelector:@selector(requestTokenTicket:didFinishWithData:)
    didFailSelector:@selector(requestTokenTicket:didFailWithError:)];
    }
    - (void)requestTokenTicket:(OAServiceTicket *)ticket
    didFinishWithData:(NSData *)data
    {
    if (ticket.didSucceed) {

    }
    }
    - (void)requestTokenTicket:(OAServiceTicket *)ticket
    didFailWithError:(NSError *)error
    {
    NSLog(@"%@", error);
    }

    RequestTokenから認証のWebページ(PIN)の取得へ
    
    
    - (void)requestTokenTicket:(OAServiceTicket *)ticket
    didFinishWithData:(NSData *)data
    {
    if (ticket.didSucceed) {
    OAMutableURLRequest *request;
    NSString *responseBody = [[NSString alloc] initWithData:data
    encoding:NSUTF8StringEncoding];

    if (accessToken != nil) {
    [accessToken release];
    accessToken = nil;
    }

    accessToken = [[OAToken alloc] initWithHTTPResponseBody:responseBody];
    [responseBody release];

    NSURL *url = [NSURL URLWithString:@"https://api.twitter.com/oauth/authorize"];

    request = [[[OAMutableURLRequest alloc] initWithURL:url
    consumer:consumer
    token:accessToken
    realm:nil
    signatureProvider:nil] autorelease];


    OARequestParameter *p0 = [[OARequestParameter alloc] initWithName:@"oauth_token"
    value:accessToken.key];
    NSArray *params = [NSArray arrayWithObject:p0];
    [request setParameters:params];

    [[NSWorkspace sharedWorkspace] openURL:[request URL]];

    [p0 release];
    }
    else {

    }

    }


    (デフォルトブラウザでURLが開かれる.ここではTwitterサイトでの認証であり数字キー(PIN)が手に入る

    PINからAccessTokenの取得へ
    
    
    - (void)authorizationWithPin:(NSString *)pin
    {
    OAMutableURLRequest *request;
    OADataFetcher *fetcher;

    NSURL *url = [NSURL URLWithString:@"https://api.twitter.com/oauth/access_token"];

    request = [[[OAMutableURLRequest alloc] initWithURL:url
    consumer:consumer
    token:accessToken
    realm:nil
    signatureProvider:nil] autorelease];


    OARequestParameter *p0 = [[OARequestParameter alloc] initWithName:@"oauth_token"
    value:accessToken.key];
    OARequestParameter *p1 = [[OARequestParameter alloc] initWithName:@"oauth_verifier"
    value:pin];
    NSArray *params = [NSArray arrayWithObjects:p0, p1, nil];
    [request setParameters:params];

    fetcher = [[[OADataFetcher alloc] init] autorelease];

    [fetcher fetchDataWithRequest:request
    delegate:self
    didFinishSelector:@selector(accessTokenTicket:didFinishWithData:)
    didFailSelector:@selector(accessTokenTicket:didFailWithError:)];

    [p0 release];
    [p1 release];
    }
    - (void)accessTokenTicket:(OAServiceTicket *)ticket
    didFinishWithData:(NSData *)data
    {
    if (ticket.didSucceed) {

    }
    }
    - (void)accessTokenTicket:(OAServiceTicket *)ticket
    didFailWithError:(NSError *)error
    {
    NSLog(@"%@", error);
    }

    accessTokenを生成してDefaultUserInfoへ保存
    
    
    - (void)accessTokenTicket:(OAServiceTicket *)ticket
    didFinishWithData:(NSData *)data
    {
    if (ticket.didSucceed) {
    NSString *responseBody = [[NSString alloc] initWithData:data
    encoding:NSUTF8StringEncoding];

    if (accessToken != nil) {
    [accessToken release];
    accessToken = nil;
    }

    accessToken = [[OAToken alloc] initWithHTTPResponseBody:responseBody];
    [responseBody release];

    [accessToken storeInUserDefaultsWithServiceProviderName:@"NAME"
    prefix:@"KEY"];

    }
    }


    (ちなみにDeaultUserInfoから取り出すときは

    accessToken= [[OAToken alloc] initWithUserDefaultsUsingServiceProviderName:@"NAME"
    prefix:@"KEY"];
    )

    accessTokenを使ってPOSTしてみる

     NSString *message= @"Hello World!";

    NSURL *url= [NSURL URLWithString:@"http://api.twitter.com/1/statuses/update.xml"];
    OAMutableURLRequest *requestWithBodyParams = [[[OAMutableURLRequest alloc] initWithURL:url
    consumer:consumer
    token:accessToken
    realm:nil
    signatureProvider:nil] autorelease];
    NSString *encodedParameterPairs= [NSString stringWithFormat:@"status=%@", [message URLEncodedString]];
    NSData *requestData = [encodedParameterPairs dataUsingEncoding:NSASCIIStringEncoding
    allowLossyConversion:YES];
    [requestWithBodyParams setHTTPBody:requestData];
    [requestWithBodyParams setValue:[NSString stringWithFormat:@"%d", [requestData length]]
    forHTTPHeaderField:@"Content-Length"];
    [requestWithBodyParams setValue:@"application/x-www-form-urlencoded"
    forHTTPHeaderField:@"Content-Type"];
    [requestWithBodyParams setHTTPMethod:@"POST"];

    OADataFetcher *fetcher = [[[OADataFetcher alloc] init] autorelease];

    [fetcher fetchDataWithRequest:requestWithBodyParams
    delegate:self
    didFinishSelector:@selector(apiTicket:didFinishWithData:)
    didFailSelector:@selector(apiTicket:didFailWithError:)];
    - (void)apiTicket:(OAServiceTicket *)ticket
    didFinishWithData:(NSData *)data
    {

    }
    - (void)apiTicket:(OAServiceTicket *)ticket
    didFailWithError:(NSError *)error
    {
    NSLog(@"%@", error);
    }


    結果
    http://twitter.com/#!/p_g_/status/100810688833912833

    OAuthConsumer.frameworkを設置(インストール)してみる

    動機
    OAuth周りのCocoaの実装であるOAuthConsumer.frameworkというのを知ったのでインストールしてみる.

    やってみた
    コンソールで以下を実行.obj-cフォルダが出来上がる.
    > svn checkout http://oauth.googlecode.com/svn/code/obj-c



    checkoutしたフォルダ内の以下を開く(Xcode).
    obj-c/OAuthConsumer/OAuthConsumer.xcodeproj



    コンパイル
    Build for Running


    OAuthConsumer.frameworkを確認

    Finderでの表示.



    インストール先をターミナルで開く
    > mkdir -p ~/Library/Frameworks
    > open ~/Library/Frameworks/



    OAuthConsumer.framework をドラッグして ~/Library/Frameworks/ へドロップ



    できた.

    2011年5月26日木曜日

    Quartz Composer / QCViewからのスナップショット

    メモ
    [nsBitmapImageRep initWithFocusedViewRect:]や[nsView cacheDisplayInRect:toBitmapImageRep:]では背景色の四角形(QCViewサイズの)が出てくるだけだったので?と思ったら専用のメソッドがQCViewにあったのでメモ.
    NSBitmapImageRep *imgRep= [qcView createSnapshotImageOfType:@"NSBitmapImageRep"];

    引数の文字列はNSBitmapImageRep, NSImage, CIImage, CGImage, CVOpenGLBuffer, CVPixelBufferのどれかで返り値もそのインスタンスとなる.そうだ.

    参考
    QCView Class Reference / createSnapshotImageOfType:

    2011年3月21日月曜日

    正規表現のメタ文字をエスケープした文字列を返す

    参考:
    NSArray と NSPredicate を使った正規表現検索 / Cocoaの日々 - 2005年10月
    Regular Expression Metacharacters / Regular Expressions - ICU User Guide
    感謝

    コード:
    - (NSString *)escapedStringWithString:(NSString *)string
    {
    NSString *value= [NSString stringWithString:string];
    NSString *targets= @"\*?+[(){}^$|./";
    NSInteger i;
    for(i= 0; i<[targets length]; i++) {
    NSString *findC= [targets substringWithRange:NSMakeRange(i, 1)];
    NSString *replaceS= [NSString stringWithFormat:@"\\\\%@", findC];
    value= [value stringByReplacingOccurrencesOfString:findC
    withString:replaceS];
    }
    return value;
    }

    バックスラッシュについては一番最初に行うことで,エスケープ用のバックスラッシュが置換されないようにしている.
    きっともっと賢いやり方や一撃メソッドがあるんだとは思う.

    2010年12月4日土曜日

    ノートパソコンを縦てに置いて見るPDF Viewer

    動機
    MacBook Proの画面でA4 PDFを全画面表示すると両端が余るのをみて,もっとでっかく表示できるはずだよな.と思ったので.
    1ページPDFならプレビューの回転でよいが2ページ以上で一度に全部を回転できなかった(やり方の問題だったりして).
    探せば既に便利ツールがありそうな気もしたがPDFViewを試すつもりで自作


    やってみた
    できた.

    便利に使えるかどうかはわからないけどできたので“PDFViewの試しの産物”として置いてみた.http://sites.google.com/site/pgtwitter/cocoa

    2010年11月14日日曜日

    読みを取り出す

    追記: portで入れた辞書の利用にはdylibを/opt/local/lib/libmecab.dylibにして, 'mecab_new2("-d /opt/local/lib/mecab/dic/ipadic-utf8/");'と引数を与える.



    動機
    Mecabに関する前回の結果から読みを取り出せないか?ということで挑戦.


    やってみた
    0.どうもappleの辞書では読みが取り出せない(おいらのやり方がわるいためだろうか).
    1.portでmecabのutf-8の辞書を入れてみる.('sudo port install mecab-ipadic-utf8')
    2.mecabの分析を以下のように変更
    - (NSArray *)mecabResultWithString:(NSString *)input
    {
    NSMutableArray *ret= [NSMutableArray array];
    if (input==nil || [input length]==0)
    return ret;
    const char *buf= [input cStringUsingEncoding:NSUTF8StringEncoding];
    NSUInteger l= [input lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
    const mecab_node_t *node = mecab_sparse_tonode2(mecab, buf, l);
    if (node == NULL) {
    return ret;
    }
    node = node->next;
    for (; node->next != NULL; node = node->next) {
    NSString *f = [NSString stringWithCString:node->feature encoding:NSUTF8StringEncoding];
    NSString *yomi= [[f componentsSeparatedByString:@","] objectAtIndex:7];
    [ret addObject:yomi];

    }
    return ret;
    }

    3.読みをローマ字にしてみた.
      int i, ic= [mecabResult count];
    NSMutableString *str= [NSMutableString string];
    for(i= 0;i<ic;i++) {
    [str appendFormat:@"%@ ", [mecabResult objectAtIndex:i]];
    }
    CFStringTransform(str, NULL, kCFStringTransformHiraganaKatakana, YES); //カタカナ→ひらがな
    CFStringTransform(str, NULL, kCFStringTransformLatinHiragana, YES); //ひらがな→ローマ字(?)
    NSLog(@"%@", str);

    4.発声してみるならこういうコードらしい
     NSSpeechSynthesizer *synth = [[NSSpeechSynthesizer alloc] init];
    [synth startSpeakingString:str];
    [synth autorelease];


    結果
    入力: 微かなオレンジの香りが残っていた
    出力: kasuka na orenji no kaori ga noko~tsu te i ta

    2010年11月13日土曜日

    NSXMLElementの下にあるテキスト部を抜き出す

    動機
    これで取り出したものに対してこれをやってみたいなぁっていうあたりからタグを外さないとと思い立って始めた(コード1).(タイトルはここまで.これを記録するためのエントリー)
    ところが,MeCabにHTMLタグ付きで入れてもそれらを対象とせずに問題なく処理するらしいことを後で知った.のでこれだけなら単純にNXSMLNodeのstringValueメソッドでもよかた.
    ただ,この方法ではエンコードされた文字('>'→'&gt;')などはそのままになってしまう.そこでNSAttributedStringを利用してこれを解決してみた(コード2).参考


    やってみた
    コード1(戦略: HTMLのパース結果であるNSXMLNodeの種類を利用してNSXMLTextKindを収集することでタグのない部分を集める)
    - (NSString *)textStringWithNode:(NSXMLNode *)elem
    {
    NSMutableString *ret= [NSMutableString string];
    int j, jc= [elem childCount];
    for(j= 0; j<jc; j++) {
    NSXMLNode *elmeChild= [elem childAtIndex:j];
    if ([elmeChild kind] == NSXMLTextKind) {
    [ret appendString:[elmeChild stringValue]];
    }
    else {
    [ret appendString:[self textStringWithNode:elmeChild]];
    }
    }
    return ret;
    }

    コード2(戦略: HTMLソース文字列からNSAttributedStringを生成し,stringメソッドでNSString化することでタグ類を外す.タグ類は属性となっているのでstringには出てこない)
    - (NSString *)textStringWithHTMLNode:(NSXMLNode *)elem
    {
    NSString *input= [elem stringValue];

    NSDictionary *option= [NSDictionary dictionaryWithObjectsAndKeys:
    [NSNumber numberWithInt:NSUTF8StringEncoding],
    NSCharacterEncodingDocumentOption,
    nil];
    NSAttributedString *as= [[NSAttributedString alloc] initWithHTML:
    [input dataUsingEncoding:NSUTF8StringEncoding]
    options:option
    documentAttributes:nil];
    [as autorelease];
    return[as string];
    }

    このメソッドの引数は都合でNXSMLNodeにしているが,一行目の処理どおり,HTMLソースを文字列(NSString)として持っている場合でも,利用することができそうだ.

    2010年11月11日木曜日

    MacOS X 10.6にデフォルトで入っているlibmecab.dylib ( MeCab )を使ってみた

    追記(2011/2/4): FYI 'Google groups / cocoa-dev-japan / 日本語文字列を文節に分解するには?'

    追記2(2010/11/12): lengthOfBytesUsingEncodingで文字列の長さを出してmecab_sparse_tonode2を用いることで解決.参考サイトの通りに作ればちゃんと動く.

    追記(2010/11/12): 半角が入ると止まる.mecabさんの設定になにかする必要があるのかしら…。CFStringTransformで「全角から半角」の逆変換をかけてUTF16LEへ変換して,mecabへ入れてみたが,あまりうまくいってない.



    動機
    なんとなく.


    やってみた
    0.Cocoaプロジェクトを作る('Untitled').
    1./usr/libをFinderで開き(コンソールで'open /usr/lib'とかする),libmecab.dylibをDnDにてプロジェクトに追加.(コピーはしない)
    2.コードを書く
    UntitledAppDelegate.h
    #import <Cocoa/Cocoa.h>
    #include "mecab.h"

    @interface UntitledAppDelegate : NSObject <NSApplicationDelegate> {
    NSWindow *window;

    mecab_t *mecab;
    NSString *_inputString;
    NSArray *_mecabResult;
    }
    @property (assign) IBOutlet NSWindow *window;
    @end

    UntitledAppDelegate.m
    #import "UntitledAppDelegate.h"
    @implementation UntitledAppDelegate
    @synthesize window;
    - (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    mecab = mecab_new2("-d /usr/lib/mecab/dic/apple/ja/LE");
    if (mecab == NULL) {
    fprintf(stderr, "error in mecab_new2: %s\n", mecab_strerror(NULL));
    }
    }
    - (void)dealloc
    {
    mecab_destroy(mecab);
    [super dealloc];
    }
    - (NSString *)inputString
    {
    return [[_inputString retain] autorelease];
    }
    - (void)setInputString:(NSString *)inputString
    {
    [_inputString release];
    _inputString= [inputString retain];
    [self setMecabResult:[self mecabResultWithString:_inputString]];
    }
    - (NSArray *)mecabResult
    {
    return [[_mecabResult retain] autorelease];
    }
    - (void)setMecabResult:(NSArray *)mecabResult
    {
    [_mecabResult release];
    _mecabResult= [mecabResult retain];
    }
    - (NSArray *)mecabResultWithString:(NSString *)input
    {
    NSMutableArray *ret= [NSMutableArray array];
    if (input==nil || [input length]==0)
    return ret;
    const char *buf= [input cStringUsingEncoding:NSUTF16LittleEndianStringEncoding];
    const mecab_node_t *node = mecab_sparse_tonode(mecab, buf);
    NSUInteger l= [input lengthOfBytesUsingEncoding:NSUTF16LittleEndianStringEncoding];
    const mecab_node_t *node = mecab_sparse_tonode2(mecab, buf, l);
    if (node == NULL) {
    return ret;
    }

    node = node->next;
    for (; node->next != NULL; node = node->next) {
    NSString *w = [[NSString alloc] initWithBytes:node->surface
    length:node->length
    encoding:NSUTF16LittleEndianStringEncoding];
    [ret addObject:w];
    [w release];
    }
    return ret;
    }
    @end

    3.IBにてNSTextFiledとNSTokenFieldを配置.
    4.IBにて上記それぞれのインスペクタ/Bindingsタブにてvalue属性についてUntitledAppDelegateに対してModel Key PathをinputString, mecabResultと設定する.
    5.実行

    実行

    参考サイト
    感謝!
    きまぐれ日記: Mac OS X Leopard に「標準で」インストールされている MeCabを使ってみる

    2010年11月5日金曜日

    Webページ内をXPathで指定して抜き出して保存するなどしてみた.

    追記(2010/11/07): NSThread sleepForTimeInterval:でリクエスト間隔をあけるようにしてみた.



    動機
     TumblrみたいなバックアップとれればSpotlightで文字列検索できるのになぁ…。


    やってみた
    条件
    ・URLでは引数,page=%dでページが送れる
    ・ページ内のバックアップ単位はdiv要素とclass属性の値で指定できる.
    ・同div要素にはidがありバックアップが取りたい単位に対して一意である.



    #import <Foundation/Foundation.h>

    int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];


    int i, ic, j= 1;
    do {
    if (j>1)
    [NSThread sleepForTimeInterval:30];
    NSString *urlString= [NSString stringWithFormat:@"http://hoge.net/user/hoge?page=%d", j++];
    NSURL *url = [NSURL URLWithString:urlString];
    NSData *data = [NSData dataWithContentsOfURL:url];

    NSXMLDocument *document = [[[NSXMLDocument alloc] initWithData:data
    options:NSXMLDocumentTidyHTML
    error:NULL] autorelease];

    NSError *error= nil;
    NSArray *nodes = [document nodesForXPath:@"//div[@class='hoge']"
    error:&error];
    if (error!=nil) {
    NSLog(@"%@", error);
    break;
    }
    ic= [nodes count];

    for(i= 0;i<ic;i++){
    NSError *err= nil;
    NSXMLElement *elem= [nodes objectAtIndex:i];
    NSString *idString= [[elem attributeForName:@"id"] stringValue];
    NSString *content= [elem XMLStringWithOptions:(NSXMLNodePrettyPrint|NSXMLNodeCompactEmptyElement)];
    NSMutableString *outputString= [NSMutableString stringWithString:@"<html>"];
    [outputString appendString:@"<head>"];
    [outputString appendString:@"<meta http-equiv='Content-Type' content='text/html; charset=utf-8'/>"];
    [outputString appendString:@"<base href='http://hoge.net/'>"];
    [outputString appendString:@"</head>"];
    [outputString appendFormat:@"<body>\n%@\n</body>", content];
    [outputString appendString:@"</html>"];
    [outputString writeToFile:[NSString stringWithFormat:@"/path/to/backup/%@.html", idString]
    atomically:YES
    encoding:NSUTF8StringEncoding
    error:&err];
    if (err!=nil) {
    NSLog(@"%@", err);
    break;
    }
    }
    } while (ic>0);

    [pool drain];
    return 0;
    }





    気がついたこと
     divのclassの値の末尾に空白が並んでいるサイトであったがこの空白はXPathで指定する際は削ってあげないと一致として扱われなかった.

    2010年7月6日火曜日

    (色々決め打ちだけど,まずは)ARTK_MMDのMMD再生ライブラリ部をQCパッチでやってみた.

    追記(2010/12/20): 公開しました.こちら

    追記(2010/12/13): ARTK_MMDのサイトが引っ越されていました.こちら



    NyMMDはJavaだがオリジナルのARTK_MMDはC++なのでARTK_MMDのMMD再生ライブラリ部をQuartz Composer Custom Patchでできないか?と思いあれこれやってみて,現在こんな感じ.
    (ARTK_MMD, NyMMDの作者様に感謝)




    (pmd: '初音ミク'(MMD添付モデル),vmd: '【MMD】みくみくにしてあげる♪【してやんよ】【Project DIVA】' 感謝)


    パッチっぽく(決め打ちでなく,portやパネルでパラメタ指定)できたら公開してみたい.