tag:blogger.com,1999:blog-175957362024-03-05T11:52:52.953-06:00Push and PopBlog of hacker, inventor, and serial entrepreneur Noel Geren. Software/hardware, we don't discriminate. How-to's and how-not's. /dev/noelhttp://www.blogger.com/profile/03017211122191024916noreply@blogger.comBlogger30125tag:blogger.com,1999:blog-17595736.post-44110804318184735892015-09-05T10:18:00.002-05:002015-09-05T10:18:28.775-05:00BLE Super SoakerBluetooth LE controlled water gun turret made from the pump of a Super Soaker Thunderstorm gun.<br />
<br />
Features: <br />
<br />
* Wireless (phone or laptop) control range up to 60ft<br />
* 180 degree turret rotation<br />
* 12+ ft water stream range<br />
<br />
Originally created at the AT&T Developer Hackathon in Dallas on August 29th.<br />
<br />
<br />
<iframe allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/IoFBmvjTIZI" width="560"></iframe>/dev/noelhttp://www.blogger.com/profile/03017211122191024916noreply@blogger.com0tag:blogger.com,1999:blog-17595736.post-89991969869842226322015-04-28T08:08:00.005-05:002015-04-28T08:08:54.379-05:00Universal Devices ISY Home Automation Controller Mac OS X AppThe ISY Quick Controls App for Mac OS X gives users with a (Universal Devices) ISY Home Automation Controller lightning fast control of their Insteon and Z-wave devices. Works with both the ISY-994i and ISY-994iZw models.<br />
<br />
<br />
<iframe width="560" height="315" src="https://www.youtube.com/embed/S-5MECSoY8g" frameborder="0" allowfullscreen></iframe>/dev/noelhttp://www.blogger.com/profile/03017211122191024916noreply@blogger.com0tag:blogger.com,1999:blog-17595736.post-76681967724801272352015-01-05T08:42:00.000-06:002015-01-09T08:51:54.558-06:00Arduino Omnigraffle StencilI've been using the drawing/illustration/wireframing tool <a href="https://www.omnigroup.com/omnigraffle">Omnigraffle</a> for years. Lately I've found myself creating basic circuit prototypes (specifically those that use an Arduino) for showing others that would be confused with traditional schematics. I spent some time last week and developed an <a href="https://www.omnigroup.com/omnigraffle">Omnigraffle</a> stencil of the common Arduino boards. <strike>I've reached out to <a href="https://www.graffletopia.com/">Graffletopia</a> to get this added so others can use it.</strike><br />
<strike><br /></strike>
Download now from Graffletopia or Stencil Town!<br />
<br />
<a href="https://www.graffletopia.com/stencils/1413">https://www.graffletopia.com/stencils/1413</a><br />
<strike><br /></strike>
<a href="https://stenciltown.omnigroup.com/#stencil=arduino">https://stenciltown.omnigroup.com/#stencil=arduino</a><br />
<strike><br /></strike>
<div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE65iUcZBNubA5hWkyY46jtW2h7ObmiCoSQS0qQ6IRLrvKx5ae71IYogdzzGV9l3Xle-M6S6fc4yXkW_Oz-LtS3Zvej_BBBvKAA-qVyPNKROppVclUeYsFZPEQ_iY2WqivL2Zt/s1600/Screen+Shot+2015-01-03+at+5.04.25+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE65iUcZBNubA5hWkyY46jtW2h7ObmiCoSQS0qQ6IRLrvKx5ae71IYogdzzGV9l3Xle-M6S6fc4yXkW_Oz-LtS3Zvej_BBBvKAA-qVyPNKROppVclUeYsFZPEQ_iY2WqivL2Zt/s1600/Screen+Shot+2015-01-03+at+5.04.25+PM.png" height="200" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh262kxaTQLbvI5y5zF_eMqjhsr2DDuDgQ1yvW83f5qL1aNMoQl3ckVnQK-xo_kkX62mtmiiP08pw9OAvfHmKPXxFgjvCt0iwf0NgnA1UEetjdEe-ZyhU6l_Kqe2pNdzSTB_DaR/s1600/Screen+Shot+2015-01-03+at+3.19.55+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh262kxaTQLbvI5y5zF_eMqjhsr2DDuDgQ1yvW83f5qL1aNMoQl3ckVnQK-xo_kkX62mtmiiP08pw9OAvfHmKPXxFgjvCt0iwf0NgnA1UEetjdEe-ZyhU6l_Kqe2pNdzSTB_DaR/s1600/Screen+Shot+2015-01-03+at+3.19.55+PM.png" height="244" width="320" /></a></div>
<br /></div>
<div>
<br />
<br />
<span id="goog_2181255"></span></div>
/dev/noelhttp://www.blogger.com/profile/03017211122191024916noreply@blogger.com2tag:blogger.com,1999:blog-17595736.post-74253178005711667222015-01-03T19:01:00.002-06:002015-01-03T19:01:36.256-06:00iPhone Controlled Plant Watering DeviceI finally had a chance to finish up my phone controlled plant watering device that I started at the December Home Automation AT&T Hackathon. The device is built on a Raspberry Pi platform (Raspbian) with a hacked USB WIFI dongle, H-bridge pump driver board, <a href="http://www.amazon.com/Estone-Micro-Priming-1-5V-12V-RS-360SH/dp/B00FTXWRKO/ref=pd_sim_hi_2?ie=UTF8&refRID=1BJX5AQET0Z173Q61FRP">DC motor pump</a>, and a power circuit for handling both the Pi and pump drive. Three LEDs are mounted along the right side of the device to show power, internet connectivity, and whether or not the pump is running ( in this case-the plant is being watered).<br />
<br />
Once the plant watering device is connected to the internet (WIFI), a <a href="http://nodejs.org/">Node.js</a> process starts and subscribes to a private <a href="http://pubnub.com/">Pubnub</a> (device) channel and awaits commands. <br />
<br />
The device is controlled from a basic iPhone app, which allows the user to choose how long to water and shows a realtime progress indicator of the run. Once the "start" button is clicked, the selected # of seconds to run is sent to the pubnub (device) channel. Upon receiving the start request, the device sends back an acknowledgment to the pubnub (app) channel and begins a runtime loop until the specified number of seconds have passed. For each iteration of the runtime loop (each second), the device sends a status message to the pubnub (app) channel. When the app receives a status message it either updates the progress indicator or if the run has completed, resets the user interface for the next run.<br />
<br />
The plant watering device was built using:<br />
<br />
<ul>
<li><a href="http://www.raspberrypi.org/">Rapsberry Pi</a> w/ Raspbian Linux</li>
<li><a href="http://node.js/">Node.js</a></li>
<li><a href="http://pubnub.com/">Pubnub.com</a></li>
<li><a href="https://developer.apple.com/xcode/">Xcode</a> / <a href="https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Introduction/Introduction.html">Objectice-C</a></li>
</ul>
<br />
<br />
<iframe allowfullscreen="" frameborder="0" height="315" src="//www.youtube.com/embed/hE-eLWXusQQ" width="560"></iframe><br />/dev/noelhttp://www.blogger.com/profile/03017211122191024916noreply@blogger.com0tag:blogger.com,1999:blog-17595736.post-58880009255696192952014-06-22T22:31:00.003-05:002014-06-23T14:31:33.434-05:00Controlling a $10 R/C with hand gestures/movements <p>Modified the remote of a cheap R/C that we had lying around to accept commands through hand movement using an Adruino (Mini Pro) and a Gyroscope/Accelerometer. The boards are mounted to a custom 3D printed platform that has two loops on each side for attaching the mounting straps. The mounting straps are the traditional backpack-style, and have an adjuster on the bottom for tightening. The Arduino uses the position of the gyroscope to drop voltage of the directional and/or accelerate buttons based on the platform's position, using left to go left, right to go right, up/tilt to accelerate, and down/drop to stop.</p><br />
<iframe width="560" height="315" src="//www.youtube.com/embed/MP1wo0sJzMQ" frameborder="0" allowfullscreen></iframe>/dev/noelhttp://www.blogger.com/profile/03017211122191024916noreply@blogger.com0tag:blogger.com,1999:blog-17595736.post-9043102564795135002014-03-26T16:07:00.000-05:002014-03-26T16:07:47.750-05:00Split files on Mac OS X with the Text File SplitterEasily split a single large text file into smaller files on Mac OS X Mavericks while retaining the header row. Select the number of rows to split at, or enter a custom number. Splitting has been tested on files upwards of one million rows. Carriage return and new line terminated records are supported. Select between carriage-return and new-line output record termination.<br />
<br />
Great for splitting a single large CSV import file into multiple smaller files.<br />
<br />
<iframe src="https://widgets.itunes.apple.com/widget.html?c=us&brc=FFFFFF&blc=FFFFFF&trc=FFFFFF&tlc=FFFFFF&d=Click below to view the Text File Splitter on the Mac App Store.&t=Text File Splitter&m=software&e=macSoftware&w=325&h=300&ids=831715956&wt=playlist&partnerId=&affiliate_id=&at=&ct=" frameborder=0 style="overflow-x:hidden;overflow-y:hidden;width:100%;height:175px;border:0px"></iframe>/dev/noelhttp://www.blogger.com/profile/03017211122191024916noreply@blogger.com0tag:blogger.com,1999:blog-17595736.post-46727923841614219982014-03-20T13:54:00.001-05:002014-03-20T13:54:14.319-05:00BeagleBone Black / Android 4.2 / Linux 3.8 / Touch screen 4DCAPE / Custom cape demonstration Demo of my BeagleBone Black test project running Android 4.2.2 under Linux 3.8 kernel using the 4DCAPE (touchscreen) and a basic Android application to control a custom LCD cape. Custom LCD cape includes 5 LCDs and a toggle switch for testing input through the GPIO pins.<br />
<br />
<iframe width="560" height="315" src="//www.youtube.com/embed/DkRssqEFXb4" frameborder="0" allowfullscreen></iframe>/dev/noelhttp://www.blogger.com/profile/03017211122191024916noreply@blogger.com0tag:blogger.com,1999:blog-17595736.post-78942756780696834552013-06-03T16:54:00.000-05:002013-06-03T16:57:58.959-05:00Voice controlled home automation using Arduino, EasyVR shield, and Insteon DevicesContinuous voice controlled home automation using Arduino, EasyVR board, Insteon Devices, and a through-home custom intercom system. A Mac Mini running a custom Objective-C application provides the text-to-speech throughout the home, while monitoring internal home events and external events such as weather conditions, including watches and warnings.<br />
<br />
Technology:<br />
<br />
http://www.arduino.cc/<br />
http://www.veear.eu/<br />
http://www.insteon.com/<br />
<br />
<iframe width="560" height="315" src="http://www.youtube.com/embed/8Ws60Z2DVxg" frameborder="0" allowfullscreen></iframe>/dev/noelhttp://www.blogger.com/profile/03017211122191024916noreply@blogger.com0tag:blogger.com,1999:blog-17595736.post-10871468690316175852013-01-19T08:52:00.004-06:002013-01-19T08:53:36.033-06:00Insteon KeypadLinc Integrated Weather ReportingAdded a new video to my YouTube channel showing further progress with my custom home automation system. In this video, I use an Insteon KeypadLinc linked with my home controller, which gives the current outside weather conditions (provided by NOAA), over my intercom system.<br />
<br />
<a href="http://www.youtube.com/watch?v=yZLJGnI9zDU">http://www.youtube.com/watch?v=yZLJGnI9zDU</a>/dev/noelhttp://www.blogger.com/profile/03017211122191024916noreply@blogger.com0tag:blogger.com,1999:blog-17595736.post-9403248966453544702012-06-03T10:11:00.002-05:002012-06-03T10:17:04.844-05:00Using Facebook Graph API with NimbleKitYOU MUST configure your application according to the SSO process defined in the Facebook iOS SDK, including, selecting the proper authentication methods:<br />
<br />
* Native/Desktop<br />
* Native iOS App<br />
* iOS Bundle ID<br />
* iPhone App Store ID<br />
* Configured for iOS SSO (Enabled)<br />
* iOS Native Deep Linking (Enabled)<br />
<br />
///////////////////////////////////////////////////////////////////////////////////////////////////////////////<br />
// MyAppDelegate.h<br />
///////////////////////////////////////////////////////////////////////////////////////////////////////////////<br />
<script type="syntaxhighlighter" class="brush: ruby">
#import <UIKit/UIKit.h>
#import "FBConnect.h"
@interface MyAppDelegate : UIResponder <UIApplicationDelegate, FBSessionDelegate> {
NSDictionary* _parameters;
Facebook *facebook;
}
@property (retain) NSDictionary* _parameters;
@property (nonatomic, retain) UIWindow *window;
@property (nonatomic, retain) Facebook *facebook;
@end
</script><br />
<br />
///////////////////////////////////////////////////////////////////////////////////////////////////////////////<br />
// MyAppDelegate.m<br />
///////////////////////////////////////////////////////////////////////////////////////////////////////////////<br />
<br />
<script type="syntaxhighlighter" class="brush: ruby">
#import "MyAppDelegate.h"
#import "Nimble.h"
#import "NKBridge.h"
@implementation MyAppDelegate
@synthesize window = _window;
@synthesize _parameters;
@synthesize facebook;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
extern BOOL _mainWebViewLoaded;
// Enter your NimbleKit serial below
Nimble *nimble = [[Nimble alloc] initWithRootPage:@"main.html" window:self.window serial:@".........."];
[nimble release];
[self.window makeKeyAndVisible];
while (!_mainWebViewLoaded) {
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
}
// Enter your Facebook App ID
facebook = [[Facebook alloc] initWithAppId:@"............" andDelegate:self];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([defaults objectForKey:@"FBAccessTokenKey"] && [defaults objectForKey:@"FBExpirationDateKey"]) {
NSLog(@"Setting defaults (access token and expiration)");
facebook.accessToken = [defaults objectForKey:@"FBAccessTokenKey"];
facebook.expirationDate = [defaults objectForKey:@"FBExpirationDateKey"];
}
NSLog(@"Facebook accessToken: %@", facebook.accessToken);
NSLog(@"Facebook expirationDate: %@", facebook.expirationDate);
return YES;
}
// Implement other NK method signatures ... applicationWillTerminate, setNKParameters (if you need it) ..etc.
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
return [facebook handleOpenURL:url];
}
- (void)fbDidLogin {
NSLog(@"fbDidLogin called.");
NSLog(@"facebook.accessToken %@", facebook.accessToken);
NSLog(@"facebook.expirationDate %@", facebook.expirationDate);
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:[facebook accessToken] forKey:@"FBAccessTokenKey"];
[defaults setObject:[facebook expirationDate] forKey:@"FBExpirationDateKey"];
[defaults synchronize];
}
- (void)request:(FBRequest *)request didLoad:(id)result {
//NSString* id = [result objectForKey:@"id"];
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:@"Success"
message:@"Successfully posted to Facebook."
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
}
- (void)fbPost {
// We already checked during initialization, but in case something changed before this was called, check again.
// Enter your Facebook App ID
facebook = [[Facebook alloc] initWithAppId:@"....." andDelegate:self];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([defaults objectForKey:@"FBAccessTokenKey"] && [defaults objectForKey:@"FBExpirationDateKey"]) {
NSLog(@"Setting defaults (access token and expiration)");
facebook.accessToken = [defaults objectForKey:@"FBAccessTokenKey"];
facebook.expirationDate = [defaults objectForKey:@"FBExpirationDateKey"];
}
if (![facebook isSessionValid]) {
[facebook authorize:nil];
}
// Below, I hook into an HTML page (main.html) that reads data from my game to post to the News Feed
UIWebView* view = [[NKBridge sharedInstance] webViewForPage:@"main.html"];
NSString *message = [view stringByEvaluatingJavaScriptFromString:@"message"];
NSLog(@"Message: %@", message);
NSLog(@"Facebook: %@", facebook);
NSLog(@"Facebook accessToken: %@", facebook.accessToken);
NSLog(@"Facebook expirationDate: %@", facebook.expirationDate);
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys: message, @"message", nil];
// Post to the News Feed using the Graph API
[facebook requestWithGraphPath:@"/me/feed" andParams:params andHttpMethod:@"POST" andDelegate:self];
}
</script><br />
<br />
///////////////////////////////////////////////////////////////////////////////////////////////////////////////<br />
// main.html<br />
///////////////////////////////////////////////////////////////////////////////////////////////////////////////<br />
<br />
<html><br />
<head><br />
<meta name = "viewport" content = "initial-scale = 1.0, user-scalable = no" /><br />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/><br />
<script type="text/javascript" src="NKit.js"></script><br />
<script type="text/javascript" src="jquery-1.7.1.min.js"></script><br />
<link charset="utf-8" href="main.css" media="screen" rel="stylesheet" type="text/css" /> <br />
<script type="text/javascript"><br />
//disable touch scrolling<br />
document.ontouchmove = function(event){event.preventDefault();} <br />
var message; <br />
NKRegisterClass("MyAppDelegate");<br />
</script><br />
</head><br />
<body><br />
<a href="#" id="fb">Post to Facebook</a><br />
<script type="text/javascript"><br />
$("a#fb").click(function(evt){ <br />
evt.preventDefault();<br />
message = "I can post from NimbleKit to my Facebook News Feed!";<br />
CallNKitAction("fbPost?className=MyAppDelegate"); <br />
});<br />
</script><br />
</body><br />
</html>/dev/noelhttp://www.blogger.com/profile/03017211122191024916noreply@blogger.com0tag:blogger.com,1999:blog-17595736.post-13655226801647350842012-05-08T17:53:00.002-05:002012-05-08T18:06:58.137-05:00MySQL LOAD DATA LOCAL INFILE UTF8 WTFIt appears that using LOAD DATA LOCAL INFILE to populate a remote server using the --local-infile ignores the server's character set, and ONLY recognizes the database or sessions. Unfortunately, rebuilding the schema and specifying a default character set, quickly, was out of the question. The solution (that I found, there could always be others) -- was setting the MySQL session settings, "collation_database" and "character_set_database."
<br />
<br />
Example of LOAD DATA LOCAL INFILE (supporting different MySQL database charsets):
<br />
<br />
mysql --default-character-set=utf8 -h database_host -uuser -p --local-infile=1 -e "set session collation_database=utf8_general_ci; set session character_set_database=utf8; LOAD DATA LOCAL INFILE '/tmp/source.txt' INTO TABLE table_name (column, column, ....)" database_name/dev/noelhttp://www.blogger.com/profile/03017211122191024916noreply@blogger.com0tag:blogger.com,1999:blog-17595736.post-55190645765244904792012-04-18T11:06:00.000-05:002012-04-18T11:07:00.885-05:00Add timestamp to Rails BufferedLogger outputLittle monkey-patch to automatically add a timestamp next to each BufferedLogger log entry. Throw it in your Rails "initializers" directory as "make_buffered_logger_useful.rb" ;) <br /><br /><script type="syntaxhighlighter" class="brush: ruby"><br />module ActiveSupport<br /> # Format the buffered logger with timestamp<br /> class BufferedLogger<br /> alias :original_add :add<br /> def add(severity, message = nil, progname = nil, &block)<br /> message = "[#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}] #{message}"<br /> self.original_add(severity, message, progname, &block)<br /> end <br /> end<br />end<br /></script>/dev/noelhttp://www.blogger.com/profile/03017211122191024916noreply@blogger.com1tag:blogger.com,1999:blog-17595736.post-62080797875242800372012-03-02T08:08:00.004-06:002012-03-02T08:10:16.799-06:00iFilmFanatic movie trivia gameJust released iFilmFanatic - a movie quote trivia game for iOS.<br /><br /><a href="http://ifilmfanatic.com">ifilmfanatic.com</a><br /><a href="http://itunes.apple.com/app/id505386256?mt=8">http://itunes.apple.com/app/id505386256?mt=8</a>/dev/noelhttp://www.blogger.com/profile/03017211122191024916noreply@blogger.com0tag:blogger.com,1999:blog-17595736.post-6514965611251993572011-07-29T10:33:00.003-05:002011-08-01T15:54:37.877-05:00Remove a specific ActiveRecord error message from a models errors collectionExample (where user is an instance variable of my User model):<br /><br /><script type="syntaxhighlighter" class="brush: ruby"><br /><br /># remove "email" errors<br />user.instance_variable_get(:@errors).delete_if{|k,v| k.eql?('email') }<br /><br /># display our updated error messages<br />puts user.errors.full_messages<br /><br /></script>/dev/noelhttp://www.blogger.com/profile/03017211122191024916noreply@blogger.com0tag:blogger.com,1999:blog-17595736.post-79175546238595584372011-07-12T14:22:00.002-05:002011-07-12T14:54:02.852-05:00Retrieve monthly search volume for a keyword using the Google Adwords API and RubyI recently needed to pull down monthly search totals for a number of keywords, after a quick search, that came up empty, I decided to whip one out and post the code (simplified of course), which uses the Google Ads API, Ruby and the Ruby Google Ads API client library (http://code.google.com/p/google-api-ads-ruby/). In order to run this example, you must first initialize your sandbox accounts, described in my previous posting, as well as have ruby and the Ads API libraries installed.<br /><br /><script type="syntaxhighlighter" class="brush: ruby"><br />require 'rubygems'<br />gem 'google-adwords-api'<br />require 'adwords_api'<br /><br />keyword = ARGV[0]<br /><br /># only continue if we get a command line argument (the keyword)<br />if !keyword.nil? && keyword.size > 0 then<br /><br /> # you will want to update this to use a production authentication section if you plan on using this for anything other than testing/learning purposes (sandbox data is invalid and for development purposes only). Be sure and put a valid client email account # where "#" is (example: client_1+myaccount@gmail.com)<br /> config = {<br /> :authentication => {<br /> :method => 'ClientLogin',<br /> :developer_token => 'your-user-name@gmail.com++USD',<br /> :user_agent => 'Ruby Google Adwords API',<br /> :password => 'your-password',<br /> :email => 'your-user-name@gmail.com',<br /> :client_email => 'client_#+your-user-name@gmail.com'<br /> },<br /> :service => {<br /> :environment => 'SANDBOX'<br /> },<br /> :library => {<br /> :log_level => 'ERROR'<br /> }<br /> }<br /> <br /> # adjust the log level<br /> #config[:library][:log_level] = 'DEBUG'<br /><br /> # uncomment the following to see the SOAP payloads and responses (wire dumps)<br /> #ENV['ADWORDSAPI_DEBUG'] = 'true'<br /><br /> adwords = AdwordsApi::Api.new( config )<br /><br /> targeting_srv = adwords.service( :TargetingIdeaService, :v201101 )<br /> selector = {<br /> :idea_type => 'KEYWORD',<br /> :request_type => 'STATS',<br /> :requested_attribute_types => [ 'GLOBAL_MONTHLY_SEARCHES' ],<br /> :search_parameters => [<br /> {<br /> :xsi_type => 'RelatedToKeywordSearchParameter',<br /> :keywords => [ { :text => keyword, :match_type => 'EXACT' } ]<br /> }<br /> ],<br /> :paging => {<br /> :start_index => 0,<br /> :number_results => 100<br /> } <br /> }<br /><br /> begin<br /> monthly_searches = nil<br /> page = targeting_srv.get(selector)<br /> if page and page[:entries] then<br /> first_entry= page[:entries].first()<br /> if !first_entry.nil? && !first_entry[:data].nil? then<br /> first_data_entry = first_entry[:data].first()<br /> monthly_searches = first_data_entry[:value][:value] if !first_data_entry.nil?<br /> end<br /> end<br /> if !monthly_searches.nil? then<br /> puts "There are \"#{monthly_searches}\" searches for \"#{keyword}\"." <br /> else<br /> puts "Unable to retrieve monthly searches for \"#{keyword}\"." <br /> end <br /> end<br /><br />else<br /><br /> puts "Syntax: #{__FILE__} <keyword>\n"<br /> puts "Example: ruby #{__FILE__} test\n\n"<br /><br />end<br /></script>/dev/noelhttp://www.blogger.com/profile/03017211122191024916noreply@blogger.com2tag:blogger.com,1999:blog-17595736.post-90172719136742236112011-07-11T16:08:00.004-05:002011-07-11T16:11:31.025-05:00Adwords API Sandbox Initialization Using Adwords4r GEMThe following snippet initializes new accounts for the specified google account, within the Adwords SANDBOX , using the Adwords4r gem. Replace "your-user-name" with your google accounts user name. Happy Adwords'n.<br /><br /><script type="syntaxhighlighter" class="brush: ruby"><br />require 'rubygems'<br />require 'adwords4r'<br /><br />ENV['ADWORDS4R_DEBUG'] = 'TRUE'<br /><br />creds = AdWords::AdWordsCredentials.new({<br /> 'developerToken' => 'your-user-name@gmail.com++USD',<br /> 'password' => 'your-password',<br /> 'email' => 'your-user-name@gmail.com',<br /> 'environment' => 'SANDBOX'<br />})<br /><br />adwords = AdWords::API.new(creds)<br />account_srv = adwords.get_service(13, 'Account')<br />accounts = account_srv.getClientAccounts()<br />puts accounts.inspect()<br /></script>/dev/noelhttp://www.blogger.com/profile/03017211122191024916noreply@blogger.com2tag:blogger.com,1999:blog-17595736.post-70762625203616716472011-06-15T14:49:00.007-05:002011-06-15T15:14:57.056-05:00Simple PHP Bing SERP Ranking CheckerI needed a quick test script that I could fire up easily on almost any machine to validate the differences I was seeing in Bing results across their cluster as well as investigate their geo-targeted and facebook integrated results, so I whipped up this handy PHP script for scraping SERP rankings. Instead of filing it away in my massive archive of utility scripts, I thought I'd release it.<br /><br />Basic PHP script for scraping SERP rankings from Bing. For ease of packaging, I've included the connection class in the main script. If you're planning on building this out, I recommend putting it in a separate file and including it for easier maintenance.<br /><br />Features:<br /><br />* Free!<br />* Returns top 50 results<br />* Returns # of results for search term/query<br />* Encapsulated HTTP connection class using libCurl PHP wrappers<br />* Gzip compression (Can be enabled or disabled)<br />* Accessors for customizing User-Agent and Referer HTTP headers<br />* Accessors for setting cookies and additional HTTP headers<br /><br />NOTE: If you copy/paste this into a file, be sure to enclose it ALL within <?php ?> tags.<br /><br /><script type="syntaxhighlighter" class="brush: php"><br /><br />class PageRequester {<br /> var $url;<br /> var $proxy;<br /> var $referer = null;<br /> var $user_agent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.10) Gecko/20100914 Firefox/3.6.10";<br /> var $gzip = 1;<br /> var $header = 1;<br /> var $timeout = 5;<br /> var $headers = array();<br /> var $cookies = array();<br /> <br /> public function PageRequester( $url ) {<br /> $this->url = $url;<br /> }<br /> <br /> public function request() {<br /> $ch = curl_init();<br /> curl_setopt($ch, CURLOPT_URL, $this->url);<br /> curl_setopt($ch, CURLOPT_HEADER, $this->header);<br /> curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);<br /> // set a proxy server if provided<br /> if (isset($this->proxy))<br /> curl_setopt($ch, CURLOPT_PROXY, $this->proxy);<br /> curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);<br /> curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->timeout);<br /> // set referer if it's provided<br /> if (isset($this->referer) && strlen($this->referer) > 0)<br /> curl_setopt($ch, CURLOPT_REFERER, $this->referer);<br /> curl_setopt($ch, CURLOPT_USERAGENT, $this->user_agent);<br /> // use gzip compression if enabled<br /> if (isset($this->gzip) && $this->gzip == 1)<br /> curl_setopt($ch,CURLOPT_ENCODING , "gzip");<br /> <br /> $cookies = array();<br /> for($i = 0; $i < sizeof($this->cookies); $i++) {<br /> $cookie = $this->cookies[$i];<br /> array_push($cookies, $cookie);<br /> }<br /><br /> $request_headers = $this->headers; <br /> if (sizeof($cookies) > 0)<br /> array_push($request_headers, "Cookie: " . implode("; ", $cookies));<br /> if (sizeof($request_headers) > 0) <br /> curl_setopt($ch, CURLOPT_HTTPHEADER, $request_headers);<br /><br /> $response = curl_exec($ch);<br /> $info = curl_getinfo($ch);<br /> $error = curl_error($ch);<br /> $http_code = curl_getinfo ($ch, CURLINFO_HTTP_CODE);<br /> curl_close($ch);<br /><br /> list ($response_headers, $response_body) = explode ("\r\n\r\n", $response, 2); <br /><br /> $result['info'] = $info;<br /> $result['error'] = $error;<br /> $result['headers'] = $response_headers;<br /> $result['body'] = $response_body; <br /> $result['http_code'] = $http_code;<br /><br /> return $result; <br /> }<br /><br /> //getter and setter methods for object<br /> public function __set( $key, $val ) { $this->$key = $val; }<br /> public function __get( $key ) { return $this->$key; }<br />}<br /><br />$keywords = $argv[1];<br /><br />if (isset($keywords) && strlen($keywords) > 0) {<br /><br /> // request/fetch page<br /> $url = "http://www.bing.com/search?q=" . urlencode($keywords) . "&go=&form=QBLH&count=50";<br /> $pageRequester = new PageRequester($url);<br /> $pageRequester->referer = "http://www.bing.com/";<br /> // add us some headers for our request<br /> array_push($pageRequester->headers, "Cache-Control: no-cache");<br /> array_push($pageRequester->headers, "Pragma: no-cache");<br /> array_push($pageRequester->headers, "Accept-Language: en-us,en");<br /><br /> echo "Requesting URL: " . $url . "\n"; <br /> $result = $pageRequester->request();<br /><br /> if ($result['http_code'] == 200) { <br /> // load result body (response html content) into DOM <br /> $dom = new DOMDocument();<br /> $dom->loadHTML($result['body']);<br /> $xpath = new DOMXPath($dom);<br /> $num_results = $xpath->query("//span[@class='sb_count']");<br /> // find # of results returned by bing search<br /> echo "Results: " . $num_results->item(0)->nodeValue . "\n";<br /> // find all results in page<br /> $result_rows = $xpath->query("//div[@class='sb_tlst']/h3/a");<br /> // loop through our results (a DOMDocument Object) and stick the urls in an array<br /> $result_urls = array();<br /> foreach($result_rows as $result_object)<br /> array_push($result_urls, $result_object->getAttribute("href"));<br /> // loop through array entires and display each record w/ rank (index position + 1)<br /> echo "Parsed (" . sizeof($result_urls) . ") urls.\n";<br /> for($i = 0; $i < sizeof($result_urls); $i++) <br /> echo "[" . ($i + 1) . "] " . $result_urls[$i] . "\n"; <br />} else { <br /> echo "Error occurred!\n"; <br /> echo "HTTP response status code received: " . $result['http_code'] . "\n"; <br />} <br />echo "\n\n"; } else { echo "Syntax: php " . __FILE__ . " keyword\n"; echo "Example: php " . __FILE__ . " \"find search engine ranking\"\n"; echo "NOTE: Don't forget to enclose multi-word search strings within quotes when passing arguments.\n"; <br />}<br /><br /></script>/dev/noelhttp://www.blogger.com/profile/03017211122191024916noreply@blogger.com0tag:blogger.com,1999:blog-17595736.post-40407145202197983152011-06-01T16:03:00.003-05:002011-06-01T16:09:20.922-05:00ActiveModel Object With Multi-Part Attribute/Date SupportSimple Ruby ActiveModel class that works with View and Form helpers in Rails 3. Appears to handle dates properly. Let me know if any problems arise:<br /><br /><pre><br />class CreditCard<br /> include ActiveModel::Validations<br /> include ActiveModel::Conversion<br /> extend ActiveModel::Naming <br /><br /> attr_accessor :name<br /> attr_accessor :number<br /> attr_accessor :expiration_date<br /> attr_accessor :code<br /> <br /> validates_presence_of [ :name, :number, :expiration_date, :validation_code ]<br /> validates_format_of :number, :with => /^\d+$/, :if => Proc.new {|o| !o.card_number.blank? && !o.errors[:card_number] }<br /> validates_format_of :code, :with => /^\d+$/, :if => Proc.new {|o| !o.code.blank? && !o.errors[:code] }<br /> <br /> def initialize( attrs = {} )<br /> if !attrs.nil? then<br /> dattrs = {}<br /> attrs.each do |n, v|<br /> if n.match( /^(.+)\(.+\)$/ ) then<br /> an = Regexp.last_match[1]<br /> dattrs[an] = [] if dattrs[an].nil?<br /> dattrs[an] << { :n => n, :v => v }<br /> else<br /> send( "#{n}=", v) <br /> end <br /> end<br /> dattrs.each do |k, v|<br /> vs = v.sort_by{|hv| hv[:n] }.collect{|hv| hv[:v] }<br /> p1 = vs[0]<br /> p2 = ( vs[1].size() > 0 ? ( vs[1].size() == 1 ? "0#{vs[1]}" : vs[1] ) : "01" )<br /> p3 = ( vs[2].size() > 0 ? ( vs[2].size() == 1 ? "0#{vs[2]}" : vs[2] ) : "01" )<br /> dv = [ p1, p2, p3 ].join( "-" )<br /> begin send( "#{k}=", Date.parse( dv ) ); rescue; end<br /> end<br /> end <br /> end<br /> <br /> def persisted?<br /> false<br /> end<br /> <br />end<br /></pre>/dev/noelhttp://www.blogger.com/profile/03017211122191024916noreply@blogger.com0tag:blogger.com,1999:blog-17595736.post-36390372946567621482011-05-23T11:38:00.003-05:002011-05-23T11:40:53.500-05:00Handling gzip responses in Ruby Net::HTTP library<pre><br />require 'net/http'<br /><br />debug = Proc.new{|msg| STDERR.puts "[#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}] #{msg}" }<br /><br />page = nil<br />http = Net::HTTP.new( "www.google.com", 80 )<br />req = Net::HTTP::Get.new( "/search?num=20&hl=en&noj=1&q=test&btnG=Search", { "Accept-Encoding" => "gzip", "User-Agent" => "gzip" } )<br />debug.call( "Performing HTTP GET request for (#{req.path})." )<br />res = http.request( req ) <br />debug.call( "Received HTTP Response Code (#{res.code})" )<br />case res<br /> when Net::HTTPSuccess then <br /> begin<br /> if res.header[ 'Content-Encoding' ].eql?( 'gzip' ) then<br /> debug.call( "Performing gzip decompression for response body." ) <br /> sio = StringIO.new( res.body )<br /> gz = Zlib::GzipReader.new( sio )<br /> page = gz.read() <br /> debug.call( "Finished decompressing gzipped response body." ) <br /> else<br /> debug.call( "Page is not compressed. Using text response body. " ) <br /> page = res.body<br /> end<br /> rescue Exception<br /> debug.call( "Error occurred (#{$!.message})" )<br /> # handle errors<br /> raise $!.message<br /> end<br />end<br /><br />puts page<br /></pre>/dev/noelhttp://www.blogger.com/profile/03017211122191024916noreply@blogger.com3tag:blogger.com,1999:blog-17595736.post-32630225312287683242011-03-19T22:45:00.005-05:002011-03-19T23:51:16.192-05:00Directly access/validate underlying ActiveRecord model association record valuesI recently ran into a situation where proper table normalization in my design left me with a clunky UI implementation, and no change logging. I also needed a way to directly access underlying (has-one) records for an object, through it's own accessor (think batch import). In the past, for chang logging, I've used ActiveRecord observers, or used an existing library such as Paper Trail, but I wanted this to fit into my scoped non-library dependent design and allow easy access to the underlying has-one records.<br /><br />I've altered the exact implementation, the below is just an example:<br /><br /><b>Tables (users, phones) - sqlite3 syntax:</b><br /><ul><br /><li>create table users (id integer primary key, first_name text, last_name text, created_at text, updated_at text, deleted_at text);</li><br /><li>create table phones (id integer primary key, user_id integer, phone_type text, number text, created_at text, updated_at text, deleted_at text);</li><br /></ul><br /><br /><b>Models (User, Phone):</b><br /><br /><pre><br />class User < ActiveRecord::Base<br /> default_scope :conditions => { :deleted_at => nil }<br /> has_many :phones<br /> <br /> validates_presence_of [ :first_name, :last_name, :cell_phone ]<br /> validates_format_of :cell_phone, :with => /\d{3}-\d{3}-\d{4}/, :if => Proc.new {|o| !o.errors.on( :cell_phone ) }<br /><br /> accepts_nested_attributes_for :phones<br /> <br /> def cell_phone<br /> @cell_phone || ( !self.phones.empty? ? self.phones.cell.first.number : nil )<br /> end<br /><br /> def cell_phone=( value )<br /> @cell_phone = value<br /> if self.phones.cell.empty? then<br /> self.phones.build( :phone_type => 'cell', :number => value )<br /> else<br /> phone = self.phones.cell.first<br /> self.phones_attributes = [ { :id => phone.id, :number => value } ]<br /> end<br /> end <br /> <br /> def destroy<br /> self.update_attribute( :deleted_at, Time.now ) <br /> end <br />end<br /><br /><br />class Phone < ActiveRecord::Base<br /> default_scope :conditions => { :deleted_at => nil }<br /> named_scope :cell, :conditions => { :phone_type => 'cell' }<br /> <br /> belongs_to :user<br /> <br /> def destroy<br /> self.update_attribute( :deleted_at, Time.now ) <br /> end <br />end<br /></pre><br /><br /><b>OK ... but what's it do?</b><br /><ul><br /><li>Validation that plays nice with form view helpers:<br /><br /><br />>> u = User.new( :first_name => 'Noel', :last_name => 'Geren' )<br />=> #<user nil=""><br />>> u.valid?<br />=> false<br />>> u.errors.full_messages.join(", ")<br />=> "Cell phone can't be blank"<br /></li> <br /><li>Direct access to underlying has-one (cell phone record):<br /><br /><br />u = User.new( :first_name => 'Noel', :last_name => 'Geren' )<br />=> #<user nil=""><br />>> u.cell_phone = '123-123-1234'<br />=> "123-123-1234"<br />>> u.cell_phone<br />=> "123-123-1234"<br /></li><br /></ul>/dev/noelhttp://www.blogger.com/profile/03017211122191024916noreply@blogger.com0tag:blogger.com,1999:blog-17595736.post-52628495026725999812011-02-13T18:17:00.007-06:002011-02-13T19:12:37.942-06:00MySQL Gem and “uninitialized constant MysqlCompat::MysqlRes” on LinuxStumbled across the same MySQL Gem error (uninitialized constant MysqlCompat::MysqlRes) that I ran into recently on OSX/Snow Leopard when upgrading/building the MySQL 2.8.11 Gem against MySQL 5.5 client libraries on Linux. <br /><br />Steps to fix this are below:<br /><br />... assuming you've already unpackaged the mysql source into a directory (my steps assume it's in /usr/local/mysql) ...<br /><br /><ol><br /><li>Install the MySQL Ruby gem w/ the correct architecture (-arch i386 for 32bit or -arch x86_64 for 64bit): env ARCHFLAGS="-arch x86_64" gem install --no-rdoc --no-ri mysql -- --with-mysql-dir=/usr/local/mysql --with-mysql-config=/usr/local/mysql/bin/mysql_config</li><br /><li>Check if an existing mysql library configuration file exists for the linux shared library (ld) in /etc/ld.so.conf.d directory.</li><br /><li>If the library exists, edit it and update the path to your source (/usr/local/mysql/lib)</li><br /><li>If the library DOES NOT exist, create a new file named "mysql.conf" containing "/usr/local/mysql/lib" (echo "/usr/local/mysql/lib" > /etc/ld.so.conf.d/mysql.conf).<br /></li><br /><li>run "ldconfig"</li><br /></ol><br /><br />You can verify your MySQL gem's library references by using "ldd" on the "mysql_api.so" file within the gem's installation directory:<br /><br />BEFORE (w/out update):<br /><br />ngeren@....:/usr/local/lib/ruby/gems/1.8/gems/mysql-2.8.1/lib# ldd mysql_api.so <br /> linux-gate.so.1 => (0xb7f50000)<br /> <b>libmysqlclient.so.16 => not found</b><br /> libpthread.so.0 => /lib/tls/i686/cmov/libpthread.so.0 (0xb7f15000)<br /> libm.so.6 => /lib/tls/i686/cmov/libm.so.6 (0xb7eee000)<br /> librt.so.1 => /lib/tls/i686/cmov/librt.so.1 (0xb7ee5000)<br /> libdl.so.2 => /lib/tls/i686/cmov/libdl.so.2 (0xb7ee1000)<br /> libcrypt.so.1 => /lib/tls/i686/cmov/libcrypt.so.1 (0xb7eaf000)<br /> libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7d51000)<br /> /lib/ld-linux.so.2 (0xb7f51000)<br /><br />AFTER:<br /><br />ngeren@.....:/usr/local/lib/ruby/gems/1.8/gems/mysql-2.8.1/lib# ldd mysql_api.so <br /> linux-gate.so.1 => (0xb809a000)<br /> <b>libmysqlclient.so.16 => /usr/local/mysql/lib/libmysqlclient.so.16 (0xb7d47000)</b><br /> libpthread.so.0 => /lib/tls/i686/cmov/libpthread.so.0 (0xb7d2e000)<br /> libm.so.6 => /lib/tls/i686/cmov/libm.so.6 (0xb7d07000)<br /> librt.so.1 => /lib/tls/i686/cmov/librt.so.1 (0xb7cfe000)<br /> libdl.so.2 => /lib/tls/i686/cmov/libdl.so.2 (0xb7cfa000)<br /> libcrypt.so.1 => /lib/tls/i686/cmov/libcrypt.so.1 (0xb7cc8000)<br /> libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7b6a000)<br /> /lib/ld-linux.so.2 (0xb809b000)/dev/noelhttp://www.blogger.com/profile/03017211122191024916noreply@blogger.com2tag:blogger.com,1999:blog-17595736.post-73747883007557085432011-02-11T11:07:00.000-06:002011-02-11T11:08:33.949-06:00AuthorizeNetCimGateway create_customer_profile and update_customer_payment_profile not supporting validation modeActiveMerchant::Billing::AuthorizeNetCimGateway "create_customer_profile" and "update_customer_payment_profile" method does not support the "validation_mode" option, which tells Authorize.net how to perform validations against the optionally provided payment profile(s) (See bottom of page 14 of CIM XML implementation guide - "validationMode"). The patch below implements the support for the missing option in both methods.<br /><br /><pre><br />module ActiveMerchant<br />module Billing<br />class AuthorizeNetCimGateway < Gateway<br /><br /> alias :original_build_create_customer_profile_request :build_create_customer_profile_request<br /> def build_create_customer_profile_request(xml, options)<br /> add_profile( xml, options[:profile] )<br /> xml.tag!( 'validationMode', CIM_VALIDATION_MODES[ options[:validation_mode] ] ) if options[:validation_mode]<br /> xml.target!<br /> end<br /><br /> alias :original_build_update_customer_payment_profile_request :build_update_customer_payment_profile_request <br /> def build_update_customer_payment_profile_request(xml, options)<br /> xml.tag!('customerProfileId', options[:customer_profile_id])<br /> xml.tag!('paymentProfile') do<br /> add_payment_profile(xml, options[:payment_profile]) <br /> end<br /> xml.tag!( 'validationMode', CIM_VALIDATION_MODES[ options[:validation_mode] ] ) if options[:validation_mode]<br /> xml.target!<br /> end<br />end<br />end<br />end<br /></pre>/dev/noelhttp://www.blogger.com/profile/03017211122191024916noreply@blogger.com0tag:blogger.com,1999:blog-17595736.post-37775600444453328852011-02-09T13:51:00.006-06:002011-02-09T14:12:27.028-06:00Ruby, Rails and MySQL 5.5 Oh my!I've seen many postings regarding issues with running 64bit Ruby, Rails and MySQL 5.5 in Leopard/Snow Leopard, especially regarding the missing const error "MysqlCompat::MysqlRes" and the mysql.bundle library issues. After investing about an hour, I had an upgraded MySQL 5.5 and MySQL gem 2.8.1 installation, and I did it like this ...<br /><br /><ol><br /><li>Download and install MySQL 5.5 (I untar it in /usr/local and create a "msyql" symlink to ease upgrades) - configure your /etc/my.cnf as necessary.</li><br /><li>Fire up your new MySQL installation to make sure it works (/usr/local/mysql/bin/mysqld_safe ...) will work for now, or you can go ahead and enable startup via launchctl.</li><br /><li>Uninstall all mysql gems (root and individual user level gems).</li><br /><li>Install the new gem for root:<br /> <ol><br /> <li>sudo su - (if you're not already root)</li><br /> <li>env ARCHFLAGS="-arch x86_64" gem install --no-rdoc --no-ri mysql -- --with-mysql-dir=/usr/local/mysql --with-mysql-config=/usr/local/mysql/bin/mysql_config</li><br /> <li>install_name_tool -change libmysqlclient.16.dylib /usr/local/mysql/lib/libmysqlclient.16.dylib /Library/Ruby/Gems/1.8/gems/mysql-2.8.1/lib/mysql_api.bundle</li><br /> <li>vi (or mate) /Library/Ruby/Gems/1.8/gems/mysql-2.8.1/test/test_mysql.rb - add a require "rubygems"</li><br /> <li>ruby test_mysql.rb - see if everything passes:<br /> (115 tests, 391 assertions, 0 failures, 0 errors)</li><br /> </ol><br /></li><br /><li>For user installed gem, do the same as you did for the root user, except update your paths accordingly.</li><br /></ol><br /><br />--Noel (ngeren)/dev/noelhttp://www.blogger.com/profile/03017211122191024916noreply@blogger.com0tag:blogger.com,1999:blog-17595736.post-12745794311547623912009-01-02T08:42:00.002-06:002009-01-02T08:47:19.998-06:00OSX java.lang.ClassNotFoundException: com.mysql.jdbc.DriverWhile testing a Java package (Jar) that connects to a MySQL instance on my Macbook Pro, I was continuously getting com.mysql.jdbc.Driver errors, regardless of how I configured my classpath. The funny thing is, a simple Java application (not packaged within a Jar) worked fine. <br /><br />Searching through forums, I finally came across a posting that mentioned placing the jar within /Library/Java/Extensions. Sure enough, this fixed the issue! Not sure why this differs from other environments, but it does.<br /><br />--Noel/dev/noelhttp://www.blogger.com/profile/03017211122191024916noreply@blogger.com0tag:blogger.com,1999:blog-17595736.post-78933023716285581552008-06-10T14:00:00.003-05:002008-06-10T14:07:43.180-05:00XSLT transformation for removing a single element/nodeFor some reason this took me a while to figure out. If you define an empty "template", the processing will be skipped.<br /><xsl:stylesheet version="1.0" xsl="http://www.w3.org/1999/XSL/Transform"><xsl:template match="ElementOrNodeToSkip"><xsl:template match="*"><xsl:copy><br /> </xsl:copy><xsl:stylesheet version='1.0' <br/><br />xmlns:xsl='http://www.w3.org/1999/XSL/Transform'> <br/><br /><xsl:template match='ElementToSkip'/> <br/><br /><xsl:template match='*'> <br/><br /><xsl:copy> <br/><br /><xsl:apply-templates select='@*|node()'/> <br/><br /></xsl:copy> <br/><br /></xsl:template> <br/><br /></xsl:stylesheet> <br/><br /></xsl:template></xsl:template></xsl:stylesheet>/dev/noelhttp://www.blogger.com/profile/03017211122191024916noreply@blogger.com0