Tuesday, December 18, 2007

JNI library testing on OSX 10.5

Refactoring a bunch of the JNI H-ITT code that I was working on last month caused me grief when I was nailed with the presence of UnsatisfiedLinkError during my maven build. My Mac prototype code was very simplistic and I had all the libraries (and Java test driver) in the same directory and it worked flawlessly. Sheesh, LD_LIBRARY_PATH in OSX 10.5 is not the right env variable, should be DYLD_LIBRARY_PATH. Once that was added to my pom I was good to go, tests passed as expected.

Thursday, December 13, 2007

Madison Summit Oxfords, second pair

Three years ago I wrote about a horrible experience with junk shoes from Wal-Mart . Tonight I bought my second pair of Timberland Madison Summit Oxfords. I love these shoes and forwarded my thoughts to Timberland:

To Whom it May Concern,

I just wanted to write a quick note and thank you for such fantastic shoes. Two years ago I was looking for a new pair of shoes that I could use for work (business-casual), for school (walking around college campus), for home (playing sports with my kids, shoveling the walk, and wearing around the house) and for anything else. I was talking with a fellow in my church congregation and he suggested Timberland. I headed over to a local sporting good store and the sales guy immediately showed me your Madison Summit Oxford.

I purchased that pair of shoes 23.5 months ago and they has served me very, very well. I have worn them exclusively, for every activity. The best part about this shoe was how well it "restored" when I regularly applied my leather-weather cream.

Tonight I purchased my new pair, the exact same size and model for $30 cheaper than two years ago. I commend you on a fine product and its outstanding endurance. I appreciate your company's values and commitment to the environment. I hope this next pair will last me another two years and that I can continue on with my Madison Summit Oxford addiction in the foreseeable future (2010, 2012, 2014...).

Wednesday, December 12, 2007

TextMate: Subversion Annotate command

I really like vc-annotate in emacs. Considering the other very easy command I created earlier, thought I'd give this one a shot too (since it's not in the default Subversion bundle). Again, extremely simple and minutes to complete. Here's the command (edited from the Info command):

require_cmd "${TM_SVN:=svn}"
: ${TM_RUBY:=ruby}
FORMAT_INFO="${TM_BUNDLE_SUPPORT}/format_annotate.rb"

"$TM_SVN" annotate "$TM_FILEPATH" |"$TM_RUBY" -- "$FORMAT_INFO"




And here's the Ruby formatter:

require ENV['TM_BUNDLE_SUPPORT']+'/svn_helper.rb'
include SVNHelper

puts html_head(:window_title => "Info", :page_title => "SVN Annotation", :sub_title => 'Subversion')
puts '<div class="subversion">'
STDOUT.flush
@colors = ['BlanchedAlmond',
'BlueViolet',
'Brown',
'BurlyWood',
'CadetBlue',
'Chartreuse',
'Chocolate',
'Coral',
'CornflowerBlue',
'Crimson',
'Cyan',
'DarkBlue',
'DarkCyan',
'DarkGoldenRod',
'DarkGray',
'DarkGreen',
'DarkKhaki',
'DarkMagenta',
'DarkOliveGreen',
'Darkorange',
'DarkOrchid',
'DarkRed',
'DarkSalmon',
'DarkSeaGreen'] #see http://www.w3schools.com/html/html_colornames.asp for more pretty colors

@color_hash = Hash.new
@color_ind_size = @colors.size() -1

def color_for_rev(rev)
color = @color_hash[rev]

unless (color)
color_index = rev % @color_ind_size
color = @colors[color_index]

@color_hash[rev] = color
end

color
end

$stdin.each_line do |line|
rev = line.strip.split(" ").first.to_i

color = color_for_rev(rev)
colored = "<div style='color:#{color}'>#{htmlize(line.strip)}"

puts(colored)
end

puts("</div>")
html_footer()


TextMate command db query prompt

I decided to give TextMate another whirl last night. I thought since I gave NetBeans 6 some time recently I'd see how efficient a couple of days with TextMate would be (compared with my life-blood emacs). I was pleasantly surprised at its extendability, speed and myriad of bundle choices. While perusing the SQL bundle I noticed I couldn't see of a way of directly typing in a query. I really like sql-mysql in emacs, so I was hoping I could do something similar--the workaround being typing a query into a buffer, selecting it, then invoking the command to send it. After poking around in the TextMate manual I was shocked at how easy it appeared to be to add custom commands. In less than a minute I had this (edited straight from the manual example of showing a dialog for input):

res=$(CocoaDialog inputbox --title "Send query" \
--informative-text "Enter query text:" \
--button1 "Submit" --button2 "Cancel")

[[ $(head -n1 <<<"$res") == "2" ]] && exit_discard res=$(tail -n1 <<<"$res") db_browser.rb --query="$(tr '\n' ' ' <<< "$res")"


If I can just get over my remaining habits (screen splitting, hippie-expand, and more), I may end up paying for this editor. Too bad it's not OSS :(

Wednesday, November 21, 2007

Rxtx to MINA H-ITT Flash integration out of the park

That's a lame title, but it advertises all of the relevant (okay, short of Java's role, which is inherent since Apache MINA is written in Java) technologies in my latest project at work. We'll be using a Flash based application for our next training platform. One of the goals of the platform is to integrate an audience response system with the training. We specifically chose H-ITT as our provider because the offer a simple SDK (cross-platform translation library) and they appeared to have the most developed system and provide solid support.

Today I finished a proof of concept and made it available to them, here are the relevant sections of my email (heading home soon, this saves me time from repeating myself):
--begin email chunk--
I wanted to let you know that I have successfully completed a workable Windows H-ITT-Java-Flash prototype. I have some of the code operational in OSX but haven't pursued it in light of our goal of a single Windows deliverable (with embedded JRE) that _doesn't_ require an installation routine. I've used Java as the communication layer, natively interfacing through your SDK, and created a rudimentary TCP protocol for communication with the Flash application. I've heavily relied on the open-source Apache MINA project in conjunction with the Rxtx libraries (which will be included in a later stable release of MINA), Simple-Log and Launch4j.

The prototype simply exhibits the ability to auto-detect the transceiver's serial port (baud can be manually configured via a properties file, defaults at 19200), sets up the appropriate serial connection, and then forwards the responses to the Flash app. Java logging is written to disk unless executed from a read-only medium. The Flash prototype provides an "Acquire" button that kicks off the auto-detect, a log console (scrolling is there, but not so visible, I'm not a Flash guru), and also virtual buttons related to the remote. Thus, when configuration is successfully complete, pressing the buttons on the remote invokes the related event in the Flash app to show which button was pressed. The whole setup serves as a basic proof-of-concept for what we're pursuing with our next-gen training platform.
--end email chunk--

Thanksgiving is tomorrow, I'm feeling grateful: So I've already plugged H-ITT in the beginning of the post, but I really gotta say they've been great to work with and very prompt in answering questions. Next plug goes to the MINA team. MINA intuitively and simply (relatively, I thought the docs and examples were sufficient) provided a great framework for custom socket communication with Flash. It's elegantly architected (IMHO) and easily integrated with what I had envisioned for the Java communication layer. Props to Mike Heath for recommending MINA and assisting my approach. Simple-log and Launch4j simplified logging and customizing a single Windows .exe file. Lastly, Rxtx provided the crux of the serial-communication and I applaud the development team in their cross-platform approach and deliverables. Finally, my thanks to Ross Asay for the JNI help, since I was intending a cross-platform delivery to correspond with H-ITT's libraries this proved to be a good challenge and learning experience.

Wednesday, September 12, 2007

Failed to get IPC connection

This convenient message showed up tonight on a Windows 2003 Server VM under VMWare server. Restarting the service, no go. Restarting the VM, no go (same message). Remove devices and change the VM settings, no go. Restarting host (Suse), no go.

A bit of looking around didn't help much, but someone mentioned a permissions issue. Here's the log entry:
Sep 12 18:13:56: vmx| CnxAcceptConnection: Could not receive fd on 187: invalid control message
Sep 12 18:13:56: vmx| Failed to get IPC connection


Going out to the directory of the VM, and executing a "chown root:root -R ." did the job. Restarting the VM after that brought it up nice and happy. So the question remains as to what caused this to occur.

Wednesday, August 15, 2007

Why I love Apache's Ldap Studio

I've gotta modify some attributes on people in our ActiveDirectory. The fun Microsoft way to do this is to download ADAM-adsi management console plugin, and then go from there. It's pretty basic and is usual MS ugliness. On the other hand, Apache Ldap Studio provides a much better user experience. Being built on top of Eclipse enables a slick interface and a very intuitive way of dealing with your directory (browsing, searching, editing). Kudos to the guys that wrote it, I can now enjoy mucking with AD from my Mac with ease and finesse.

Thursday, August 09, 2007

Remote files in Emacs

Today I decided I was sick of always SSHing everywhere only to open up a couple of files for editing and then saving them. It doesn't make sense to copy my .emacs everywhere either. I discovered Tramp, and it just makes me all the more happy with my Emacs zealotry. Even better, my current snapshot already includes it.

Works great with dired too:
/ssh:hoser@somebox:/whateverdirectory

Wednesday, August 01, 2007

installing the latest nginx on OS X

I've read a lot about nginx lately and wanted to test its performance for our up-and-coming Ruby on Rails CRM application. It looked very easy to setup and easily configurable (especially with this). My first attempt was installing it through MacPorts, but that didn't fly, as I received the unpleasant "dyld: Library not loaded: /usr/local/lib/libpcre.0.dylib". Turns out I had the same problem when trying to execute after building straight from source (which happened to be a newer version).

So with MacPorts I installed pcre 7.2_0, deactivated 7.0_0, created the symlink as "sudo ln -s /opt/local/lib/libpcre.0.dylib /usr/local/lib/" and was then able to start up nginx from the source build. Unfortunately the generated configuration file I am using expected a user and group for "nginx". A quick work around for that was to just reference myself instead. Here's what I ended up with (awaiting tweaks and optimizations):


#user and group to run as
user russ russ;

# number of nginx workers
worker_processes 2;

# pid of nginx master process
pid logs/nginx.pid;

# Number of worker connections. 1024 is a good default
events {
worker_connections 1024;
}

# start the http module where we config http access.
http {
# pull in mime-types. You can break out your config
# into as many include's as you want to make it cleaner
include conf/mime.types;

# set a default type for the rare situation that
# nothing matches from the mimie-type include
default_type application/octet-stream;

# configure log format
log_format main '$remote_addr - $remote_user [$time_local] $status '
'"$request" $body_bytes_sent "$http_referer" '
'"$http_user_agent" "http_x_forwarded_for"';

# main access log
access_log logs/access.log main;

# main error log
error_log logs/error.log debug;
#error_log logs/error.log debug_http;

# no sendfile on OSX
sendfile on;

# These are good default values.
tcp_nopush on;
tcp_nodelay off;
# output compression saves bandwidth
gzip on;
gzip_http_version 1.0;
gzip_comp_level 2;
gzip_proxied any;
gzip_types text/plain text/html text/css application/x-javascript text/xml application/xml
application/xml+rss text/javascript;

# this is where you define your mongrel clusters.
# you need one of these blocks for each cluster
# and each one needs its own name to refer to it later.
upstream vscrm {
server 127.0.0.1:8000;
server 127.0.0.1:8001;
server 127.0.0.1:8002;
}

# the server directive is nginx's virtual host directive.
server {
# port to listen on. Can also be set to an IP:PORT
listen 80;

# sets the domain[s] that this vhost server requests for
server_name vscrm;

# doc root
root /home/russ/forge/svn/vscrm/trunk/public;

# vhost specific access log
access_log logs/vscrm.access.log main;

#Set the max size for file uploads to 50Mb
client_max_body_size 50M;

# this rewrites all the requests to the maintenance.html
# page if it exists in the doc root. This is for capistrano's
# disable web task
if (-f $document_root/maintenance.html){
rewrite ^(.*)$ /maintenance.html last;
break;
}

if ($host ~* "www") {
rewrite ^(.*)$ http://vscrm$1 redirect;
break;
}

location / {


# needed to forward user's IP address to rails
proxy_set_header X-Real-IP $remote_addr;

# needed for HTTPS
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect false;
proxy_max_temp_file_size 0;

# check for index.html for directory index
# if its there on the filesystem then rewite
# the url to add /index.html to the end of it
# and then break to send it to the next config rules.
if (-f $request_filename/index.html) {
rewrite (.*) $1/index.html break;
}

# this is the meat of the rails page caching config
# it adds .html to the end of the url and then checks
# the filesystem for that file. If it exists, then we
# rewite the url to have explicit .html on the end
# and then send it on its way to the next config rule.
# if there is no file on the fs then it sets all the
# necessary headers and proxies to our upstream mongrels
if (-f $request_filename.html) {
rewrite (.*) $1.html break;
}

if (!-f $request_filename) {
proxy_pass http://vscrm;
break;
}
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}

Tuesday, July 31, 2007

sanitizing Rails input parameters

I really like how Tapestry automagically escapes HTML input when posted from a form. In fact, it was just great never having to worry about that when coding. I'd like to have the same functionality in Rails especially after reading about Rails XSS vulnerabilities and work-arounds. Since the webapp I'm writing has no requirements for allowing formatted user input, I just need something simple to clean/sanitize all the params. Here's the latest:

#escapes all HTML from the given hash's values (recursively applied as needed)
def sanitize(hash)
dirty_hash = hash

dirty_hash.keys.each do |key|
value = dirty_hash[key]

if(value.kind_of?Hash)
dirty_hash[key] = sanitize(value)
else
if (value && value.kind_of?(String))
dirty_hash[key] = CGI.escapeHTML(value)
end
end
end

hash = dirty_hash
end

This is then invoked by a before_filter. Seems to do the job, is there a better/cleaner/faster way of doing this? Let me know how it could be improved...

Wednesday, July 11, 2007

Ruby: constant time for include?

Sure would be nice if the Ruby docs (including this book) would provide more details to the implementation of the Set class. According to this, Set implements its backing collection with a Hash, which would essentially mean that it's synonymous (to some degree) with Java's HashSet. Thus providing a constant time lookup when Set#include? is invoked. Just for grins I benchmarked this in irb with a million Fixnums and was pleased with the 15 microsecond lookups. I looked at the source of both and found a fair amount of similarity.

Friday, June 22, 2007

Sorting serialized objects from a YAML file, Ruby vs Java

I recently had a large dataset that I needed to sort, basically a bunch of objects with 9 string attributes. I dumped them to a YAML file so I could benchmark various aspects of sorting (Class#to_yaml really rocks, really). As it turns out Enumerable#sort_by was the more efficient way to go rather than Enumerable#sort (check it). The dataset contained 5429 unique objects, here's the benchmarking I did in irb:

>> bm do |x|
?> x.report("all"){results.sort{|a,b|a.account_name <=> b.account_name}}
>> end
user system total real
all 0.070000 0.000000 0.070000 ( 0.073835)
>> bm do |x|
?> x.report("all"){results.sort_by{|a|a.account_name}}
>> end
user system total real
all 0.020000 0.000000 0.020000 ( 0.020745)


Noticeable difference between the two methods, and quite pleasing to see how fast sort_by performed (Apple MBP 2.33GHZ 2GB RAM Ruby 1.85). Then the thought occurred to me, since I have this in a YAML file, I could write something really quick in Java and see how fast the sort would be by dumping it into a TreeSet.

So I set off to find out how I could marshal the data into POJOs from the YAML file. JYaml and JvYaml are the only (insofar as I looked) open source Java YAML libraries. Both seem half-baked in their own right, likely containing just the functionality the respective author needed and not much more (at least that's how it appeared). I ended up using JvYaml and had to search-replace the yaml entry identifier("tag:yaml.org,2002:map") so that JvYaml would create HashMap instances for me instead of its completely worthless PrivateType class.

From there I iterated through the maps to create the POJOs and shoved them into a HashSet. Once that was completed I created the comparator for my POJO, passed it into the TreeSet constructor and then timed an addAll giving it the entire HashSet:
#1: 55ms
#2: 28ms
#3: 27ms (pretty much constant thereafter)

Interesting results eh? The dataset I used was from a randomized generator and now that I have these initial numbers ( Ruby appears to have won this round), I want to test a larger set. And to be really fair I should do more research on benchmarking best practices (in addition to still needing to take my stats class).

Tuesday, April 17, 2007

X11 tunneling via SSH in OSX

-X isn't enough for the ssh args in OSX according to this post. So, "ssh -XY hoser@remotebox" worked just great when remoting in to a Suse server and firing executing fvwm.

Thursday, April 12, 2007

1024 vs 2048 RSA encryption/decryption fun in Ruby

Using Tobias's handy openssl wrapper I decided to run a couple timing tests to see how well Ruby's openssl implementation performed in encrypting/decrypting a set of 1000 identical messages, with 1024 bit and 2048 bit keys. Nothing scientific about this, just three runs of the script on my MacBook Pro (2.33 GHZ, 1G RAM).

Encrypted text: "This is a much longer message since than what I intend to encrypt"

Encryption results, avg time
1024: 0.000300691s
2048: 0.001010027s

Decryption results, avg time
1024: 0.005472064s
2048: 0.035524023s

Pick your poison.

Monday, April 02, 2007

One last hitch

According to this, friendly errors such as

/opt/local/lib/ruby/gems/1.8/gems/soap4r-1.5.5.20061022/lib/soap/mapping/mapping.rb:520:in `class_schema_variable': undefined method `class_variables' for nil:NilClass (NoMethodError)
from /opt/local/lib/ruby/gems/1.8/gems/soap4r-1.5.5.20061022/lib/soap/mapping/mapping.rb:353:in `schema_ns_definition'
from /opt/local/lib/ruby/gems/1.8/gems/soap4r-1.5.5.20061022/lib/soap/mapping/mapping.rb:380:in `schema_definition_classdef'
from /opt/local/lib/ruby/gems/1.8/gems/soap4r-1.5.5.20061022/lib/soap/mapping/registry.rb:198:in `schema_definition_from_class'
from /opt/local/lib/ruby/gems/1.8/gems/soap4r-1.5.5.20061022/lib/soap/mapping/literalregistry.rb:73:in `any2soap'
from /opt/local/lib/ruby/gems/1.8/gems/soap4r-1.5.5.20061022/lib/soap/mapping/literalregistry.rb:37:in `obj2soap'
from /opt/local/lib/ruby/gems/1.8/gems/soap4r-1.5.5.20061022/lib/soap/mapping/literalregistry.rb:127:in `stubobj2soap'
from /opt/local/lib/ruby/gems/1.8/gems/soap4r-1.5.5.20061022/lib/soap/mapping/literalregistry.rb:114:in `each'
from /opt/local/lib/ruby/gems/1.8/gems/soap4r-1.5.5.20061022/lib/soap/mapping/literalregistry.rb:114:in `stubobj2soap'
... 15 levels...
from /opt/local/lib/ruby/gems/1.8/gems/soap4r-1.5.5.20061022/lib/soap/rpc/proxy.rb:126:in `call'
from /opt/local/lib/ruby/gems/1.8/gems/soap4r-1.5.5.20061022/lib/soap/rpc/driver.rb:179:in `call'
from (eval):6:in `search'


prohibit the following default generated objects from correctly mapping when invoking the NetSuite searches:

  • OpportunitySearchBasic

  • EmployeeSearchBasic

  • PartnerSearchBasic

  • ItemSearchBasic

  • TimeBillSearchBasic


Each of which contain an entity named 'class', and while soap4r intelligently generates an attribute 'v_class', it also erroneously generates accessor methods that override Object.class. Big woops. Extremely easy fix just by renaming those methods.

Wednesday, March 28, 2007

NetSuite and Ruby, the final chapter

NetSuite requires a maintainable session for subsequent requests after the initial login by way of several cookies they return upon successful authentication. The standard Net::HTTP library requires mucking with headers by hand in order to perpetuate cookie information. We were easily able to override SOAP::NetHttpClient::Response and SOAP::HTTPStreamHandler in the soap4r gem in order to provide the functionality for maintaining the NetSuite session.

However
, NaHi's http-access2 library already provides cookie management (even persistence if needed). After installing visnu's gem it's simply a matter of turning off the SSLConfig#verify_mode and everything works flawlessly. The final test code:
require 'rubygems'
require_gem 'soap4r'
require 'defaultDriver' #generated by soap4r
require 'pp'

driver = NetSuitePortType.new
driver.wiredump_dev = STDOUT
driver.proxy.streamhandler.client.ssl_config.verify_mode = nil

passport = Passport.new
passport.email = '123123123@123123123.com'
passport.password = '123123123'
passport.account ="123123"
passport.role = RecordRef.new
passport.role.xmlattr_internalId = '123123123'

driver.login(LoginRequest.new(passport))

record = RecordRef.new()
record.xmlattr_internalId = '123123123'
record.xmlattr_type = RecordType::Customer

pp driver.get(GetRequest.new(record))

Everything said and done, this has been a good learning experience. But more than anything it has exposed one of the Ruby community's greatest weaknesses: documentation. I've known this since the beginning of my Ruby days (2004) and have grown accustomed to reading code. Nevertheless, that takes time, and usually more time than scanning decently-documented APIs. The other side of this story is that I understand the Japanese/English language barrier which may intimidate or otherwise prevent library maintainers from providing more documentation. In the end, Ruby is a community-driven language, which is not sponsored by massive corporate dollars (cough, Java, cough, .Net) and its beginnings have solid Japanese roots. Here's to hoping that documentation improves as more libraries become available and the language matures. In the mean time, thank goodness for Google, mailing lists, blogs and IRC. I believe that documentation practices exhibited by 37Signals and the Rails community are the guiding example, they're not perfect, but the situation continues to progress.

soap4r and NetSuite revisited

In the last post I mentioned that the generated file (default.rb) contained redundant object definitions. I also ended with the concern about the RecordRef element not appearing to be correct. That led me to look at the generator and as it turns out I was invoking the wrong one. Funny thing, the soap4r gem ships with wsdl2ruby.rb and places them in two different locations. The first (in OSX) was in /opt/local/bin where the second was in /opt/local/lib/ruby/gems/1.8/gems/soap4r-1.5.5.20061022/bin/. Yesterday we explictly invoked the one in the gem, disregarding the the executable wrapper in /opt/local/bin. That was the mistake, as the results can be easily reproduced with executing
ruby /opt/local/lib/ruby/gems/1.8/gems/soap4r-1.5.5.20061022/bin/wsdl2ruby.rb --wsdl https://webservices.netsuite.com/wsdl/v2_5_0/netsuite.wsdl --type client
The problem being that the wrapper adds the necessary "requires" for referencing the gem's code (correct results) and not the standard (incorrect results).

Using the correct wsdl2ruby the following test works without any modifications to the generated code:


require 'rubygems'
require_gem 'soap4r'
require 'defaultDriver'

driver = NetSuitePortType.new
driver.wiredump_dev = STDOUT

passport = Passport.new
passport.email = 'test'
passport.password = 'test'
passport.account ="test"

role = RecordRef.new
role.xmlattr_internalId = '123123123'

passport.role = role

response = driver.login(LoginRequest.new(passport))

pp "successful login: #{response.sessionResponse.status.xmlattr_isSuccess}"

Tuesday, March 27, 2007

adventures in soap4r and NetSuites webservices

Spent most of the day becoming familiar with soap4r in order to communicate with NetSuite. Turns out that the soap4r shipping with Ruby 1.8.5 is outdated and quite buggy compared to its gem counterpart. In fact, we would've saved a couple hours if we knew that was an option before we even started setting breakpoints.

WSDL2Ruby worked decently enough with NetSuite's WSDL but the generated file containing the classes (default.rb) had redundant entries, like 35 definitions for the Passport object. Next, there was an issue with some of the classes being incomplete. For example, RecordRef was:

class RecordRef
@@schema_type = "RecordRef"
@@schema_ns = "urn:core_2_5.platform.webservices.netsuite.com"
@@schema_element = []

def initialize
end
end
which is incorrect as it is defined as:

<complextype name="RecordRef">
<complexcontent>
<extension base="platformCore:BaseRef">
<attribute name="internalId" type="xsd:string">
<attribute name="externalId" type="xsd:string">
<attribute name="type" type="platformCoreTyp:RecordType">
<!-- primary record internalId -->
<!-- record type -->
</attribute>
</attribute>
</attribute>
</extension></complexcontent></complextype>

The object we created to get the request working correctly is

class RecordRef
@@schema_type = "RecordRef"
@@schema_ns = "urn:core_2_5.platform.webservices.netsuite.com"

attr_accessor :internalId
attr_accessor :externalId
attr_accessor :type

def initialize(internalId = nil, externalId = nil, type = nil)
@internalId = internalId
@externalId = externalId
@type = type
end
end


Finally, calling

response = driver.login(LoginRequest.new(passport))
produced a successful response from NetSuite. However, something still seems awry with the request as the role element is not properly formed:

<n1:login xmlns:n1="urn:messages_2_5.platform.webservices.netsuite.com" xsi:type="n1:LoginRequest">
<n1:passport xmlns:n2="urn:core_2_5.platform.webservices.netsuite.com" xsi:type="n2:Passport">
<n2:email>test </n2:email>
<n2:password>test</n2:password>
<n2:account>test</n2:account>
<n2:role xsi:type="n2:RecordRef">
</n2:role>
</n1:passport>
</n1:login>

Friday, March 09, 2007

Geocoding service findings and comparison

Google Maps:

  • requires an API key

  • http geocode service that'll return results in XML or JSON

  • lots of documentation on javascript implementation

  • issues in resolving bad addresses by suggesting alternatives and flagging them with the best accuracy-level

  • comma separated values on the query string

  • 50k per day limit


Yahoo MapService:

  • http geocode service return results in XML or PHP

  • cleaner documentation

  • ApplicationID required

  • address suggestion behaves more as expected and accuracy seems better

  • query string attributes expected in request

  • 5k per day limit


Note regarding accuracy statements above: I tested both services with variations on my home address which can be identified strictly by number coordinates or with the street name (Valley Sage Drive). Google's service did not find my address in any format I tried but continued to respond with varied suggestions none of which were applicable (though it stated they were the highest level of accuracy). As for yahoo, it found my address in every variation and for those that it suggested it clearly indicated a warning as an attribute of the ResultSet. Odd that Google Maps works for my address, but the geocoding service does not (and they're supposed to be integrated).


Both services provide city and state values when given a zip.

Determining valid addresses may prove to be a bit difficult given that both services "suggest" what the closest match could be.

Thursday, March 08, 2007

a more efficient top for OS X

echo "alias top=\"top -d -o cpu\"" >> ~/.profile


The "-d" bypasses the strain on Mach"-o cpu" and will sort by procs consuming the most CPU.

Wednesday, March 07, 2007

HttpUtility.UrlEncode, fails again

Bitten a couple months ago by the fact that System.Web.HttpUtility.UrlEncode does NOT encode ticks/single-quotes ('). How lovely. I filed a bug, someone at MS closed it out almost a month later with no explanation. It's current state is "won't fix".

Bitten again by another bug in the same function. What a shocking surprise. UrlEncode does not escape/encode the plus (+). It should encode it as %2B, but no, it doesn't, it just leaves it in the string.

Hosers.

Monday, February 26, 2007

Mike Heath stumbles upon pile of java JIT

Mike has had a great time with this and we've had some intriguing conversations about it. Once he posts his svn repo url I'll snag the code, run the tests on my MacBook Pro and add the results to his matrix.

Wednesday, February 21, 2007

UPS xml online tools and Ruby

UPS provides "XML Online Tools" to account holders here. Once you register as a developer you can get access to these tools and the associated specs and sample code. I needed access to the Rates and Service Selection tool, which happened to contain VB script and Java sample code from 2001. The docs are very thorough, but the code (as expected) was very outdated. Once I had it working with 1.5 (not too difficult at all) I was able to better understand what was needed for working with their HTTP-XML services.

The following barebones Ruby code is the result of a quick implementation:

require 'net/https'
require 'uri'

auth_xml = (access request xml doc goes here)
req_xml = (request xml doc goes here)
both_xml = auth_xml + req_xml

url = URI.parse("https://....")
request = Net::HTTP::Post.new(url.path)
request.body = (both_xml)
request.content_type = 'application/x-www-form-urlencoded'

http = Net::HTTP.new(url.host,443)
#http.set_debug_output $stderr
http.use_ssl = true
http.timeout = 30

@response = nil
http.start do
@response = http.request(request)
end

p @response.body

Wednesday, January 31, 2007

Another reason I dislike Microsoft

http://ajax.asp.net

Hooray, welcome to the Ajax world ASP.NET. It's been around long enough, someone bright in Redmond actually started the movement back in the mid 90's. But, Microsoft, could you not kill the term by branding your Ajax components as AjaxThisOrThat when it's really just a wrapper for DHTML functionality? It appears to me that you're trying to capitalize on the current wave by simply naming DHTML controls as Ajaxed controls. Which is simply wrong. Then again, I suppose that's no surprise considering your failed attempt at changing the meanings of things anyway.

Sadly, for the ASP.NET developers who may be new to it, they'll now be dumbed down (once again?) to the real concepts and essentials of what Ajax _really_ is and how/why it works.

Oh, and nice job on making it only work with web services and kudos to making configuration a breeze.

Monday, January 29, 2007

Quote model, has_many and a couple hours of grief

I have two models, Quote and QuoteLineItem using the has_many and belongs_to respectively. I was having issues with AR dumping out insert statements like

INSERT INTO quote_line_items (`created_on`, `quote_id`, `price`, `modified_on`, `product_id`, `quantity`, `modified_by_person_id`) VALUES(#<Quote:0x36551f0>,
#<Quote:0x364dba8>, #<Quote:0x3645728>, #<Quote:0x363efa4>, #<Quote:0x362ef3c>, #<Quote:0x3636728>, #<Quote:0x3624618>))


This drove me nuts so I jumped into rdebug to figure out the issue. Turns out there is an ActiveRecord method name collision when using

belongs_to :quote


so you have to provide an alternative, something like

belongs_to :related_quote, :class_name => "Quote"


Wish I knew that when I was creating this migration....

UPDATE:
http://dev.rubyonrails.org/ticket/4248

Tuesday, January 23, 2007

Spotlight and indexed content

UPDATE: Check it out: http://www.arcadianvisions.com/downloads/RubyImporter.html

Became apparent to me today as I was searching for some files that Spotlight only indexes content for files based on their extension (and plugin, if installed). I was able to confirm this with the following code:

echo "hello you hoser" > something.java
mdls something.java

There's a bunch of data there associated specifically to the .java extension. Find that file based on its contents:

mdfind "you hoser" |grep java

Aha, there's the file.
Trying this again with, say, a .rb extension:

echo "take off you nob" > somethingelse.rb
mdfind "take off you" | grep something

No results. mdls shows that there are some attributes associated with the .rb extension, but somehow the content isn't indexed.

XCode provides a project template called "Metadata Importer" so you can write your own to deal with custom extensions. Apple's doc explains the process.

Friday, January 12, 2007

quicksilver shortcut for locking the screen in OSX

I copied the ScreenSaverEngine.app from System/Library/Frameworks/Screensaver.framework/Versions/A/Resources/ScreenSaverEngine.app
to a cataloged QuickSilver directory. From there I just bound a key through the Triggers. Now I can lock the machine with ctl-option-l.

Monday, January 08, 2007

Suse 10.2 64-bit and VMWare Server

Need a 64-bit server so we can run our VMWare machines on it and utilize the 8+ gig of RAM. Originally tried CentOS but because VMWare Server is compiled against 32-bit libraries, it would be a nasty amount of work to install the needed libraries one-by-one (ldd spit out at least 20 libraries we needed). After digging around online it turns out that VMWare "officially" supports Suse but not much else. Time was of the essence and we bagged Gentoo for that reason.

The 10.1 install was pleasant, but the user experience was very unpleasant. I didn't actually install it, but a coworker did and it was only a matter of days until he migrated to Ubuntu. We were hoping that some of the usability issues were resolved in 10.2, happy to report that is the case. We installed the base system, developer libraries, kernel development and the 32-bit libraries during the initial package selection. After that, once the system was up and running, vmware installed without issue.

To use vnc (via ssh) we enabled Remote Login in Login Window Preferences (not sure why that's a System Application but not in the Control Center). The command to enable port forwarding for local vncviewer execution is "ssh -g -L localhost:5901:machine:5901 user@machine -X", then "vncviewer localhost::5901" will connect right up through that ssh tunnel (also, ssh with the -g enables anyone to use your tunnel).