<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-10247947</id><updated>2011-11-30T08:53:45.193-08:00</updated><category term='Ruby Rails Databases Enterprise CEO CTO Migration'/><category term='rails ruby migrations rake'/><category term='ruby rails rubyonrails class tutorial unify'/><category term='ruby rails centos redhat nginx'/><category term='ruby rails activerecord'/><category term='ruby phillipines'/><category term='ruby rails rubyonrails security logs'/><category term='ruby iseries rails ibm as400'/><category term='Rails'/><category term='Ruby Rails ActiveRecord SQL'/><category term='activejquery'/><category term='ruby rails migrations content management sqlite3'/><category term='ruby dotr graphviz network mapping'/><category term='rubyonrails rails ror Authentication'/><category term='ruby webscrapping RubyfulSoup'/><category term='ruby servicetag wmi'/><category term='ruby fmq message queue rails'/><category term='rails activerecord associations'/><category term='Rails user authentication'/><category term='ruby gem image'/><category term='ruby rails legacyapps activerecord rake'/><category term='RubyOnRails Rails Ruby Jquery JqueryUI JqGrid REST XML'/><category term='rails authenticatedsystem ntlm windows login'/><category term='rubyonrails ruby oracle tablespace'/><category term='HTML Javascript Rails ActiveJquery'/><category term='rails ruby gem runonrails 2.0.2'/><category term='Voice Voip Rails Ruby Call Center'/><category term='ruby windows service network scanning'/><category term='photo recovery fat32 nikon flash memory cards'/><category term='ruby backup utility data deplication'/><category term='jdgrid'/><category term='fusion magnets'/><category term='ruby rails'/><category term='vmware vsphere esx esxi iscsi'/><category term='rails activerecord widgets'/><category term='ruby rubyonrails rake database activerecord'/><title type='text'>Mental Paging Space</title><subtitle type='html'>A place to park ideas, inspire suggestions and makes notes for the future.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default?start-index=101&amp;max-results=100'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>125</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-10247947.post-5175425827486382311</id><published>2011-08-28T01:12:00.000-07:00</published><updated>2011-08-28T01:12:29.943-07:00</updated><title type='text'>RealTime and Rails</title><content type='html'>Sometimes you have a need to process things in real-time. Stock trading apps for example,&lt;br /&gt;or real-time video. EventMachine, in Ruby is great. On top of this you want a gui or a &lt;br /&gt;web page, so Rails naturally fits in. The problem is trying to do Real-Time and Rails in&lt;br /&gt;the same sentence is not quite there. In a application I've done, I had exactly that,&lt;br /&gt;I receive multiple HD cctv feeds in UDP, and handled the whole RTSP protocol using eventmachine.&lt;br /&gt;The problem was every 5 minutes I wanted to save the current file information into&lt;br /&gt;the database. I tried a few methods, but the most reliable turned out to use a em_http request.&lt;br /&gt;This allows you to do async http in eventmachine. I of course targeted my rails stack that&lt;br /&gt;was already running the application. &lt;br /&gt;&lt;br /&gt;So this way, my realtime work can continue (async), and the rails stack gets a tickle &lt;br /&gt;every 5 minutes to stay alert. Result: No more dropped packets.&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;EventMachine.run {&lt;br /&gt;      http = EventMachine::HttpRequest.new('http://gshift-app/').get :query =&amp;gt; {'keyname' =&amp;gt; 'value'}&lt;br /&gt;&lt;br /&gt;      http.errback { p 'Uh oh'; EM.stop }&lt;br /&gt;      http.callback {&lt;br /&gt;        p http.response_header.status&lt;br /&gt;        p http.response_header&lt;br /&gt;        p http.response&lt;br /&gt;&lt;br /&gt;        EventMachine.stop&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-5175425827486382311?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='https://github.com/igrigorik/em-http-request/wiki/Issuing-Requests' title='RealTime and Rails'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/5175425827486382311/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=5175425827486382311' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/5175425827486382311'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/5175425827486382311'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2011/08/realtime-and-rails.html' title='RealTime and Rails'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-5308366262236642312</id><published>2011-03-24T23:14:00.000-07:00</published><updated>2011-03-24T23:16:20.023-07:00</updated><title type='text'>Saving My Bacon when things go Wrong - Veeam Backup In Action</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-1Lphxo9PoYw/TYwyxqT5wyI/AAAAAAAAACY/ycrMB0KH0cc/s1600/VeeamInAction.JPG" imageanchor="1" style="clear:right; float:right; margin-left:1em; margin-bottom:1em"&gt;&lt;img border="0" height="275" width="400" src="http://2.bp.blogspot.com/-1Lphxo9PoYw/TYwyxqT5wyI/AAAAAAAAACY/ycrMB0KH0cc/s400/VeeamInAction.JPG" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Sometimes you click something inoculus, and the world ends.&lt;br /&gt;The button was not red, and it didnt have a safety cover.&lt;br /&gt;Yet it did something really bad, and totally unexpected.&lt;br /&gt;&lt;br /&gt;Had that happen to me this morning. Shutdown a file server,&lt;br /&gt;and the datastore was gone. I understand why, as I was moving data&lt;br /&gt;off the datastore, but I didnt expect it to go at that point.&lt;br /&gt;&lt;br /&gt;What to do Now !?!?!&lt;br /&gt;&lt;br /&gt;We had updated to Veeam 5.0 Vmware backup few months ago.&lt;br /&gt;I decided to give it a try, as I had a backup from just hours ago&lt;br /&gt;and no data had been updated.&lt;br /&gt;&lt;br /&gt;I traditional tape, a restore is a multi-day affair with logs of downtime&lt;br /&gt;and other unplesant activity.&lt;br /&gt;&lt;br /&gt;With Veeam I still expected a 5-8 hour downtime as veeam did the restore.&lt;br /&gt;&lt;br /&gt;Instead I decided to use the Instant Recover Mode. From start to having the&lt;br /&gt;server running again was 2 minutes counting boot time. The Restore only took a minute and a half. At that point the server was running over a &lt;br /&gt;virtulized nfs server automatically attached to the blade of my choice,&lt;br /&gt;automatically added to my vcenter, and automatically started. &lt;br /&gt;&lt;br /&gt;For the non-believers I've included a screen shot just to prove the point.&lt;br /&gt;The server in question has been running now most of the day without issue&lt;br /&gt;and its 60% migrated back to production storage using Storage vMotion.&lt;br /&gt;&lt;br /&gt;This is really unbeliveable how well and easy it worked.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-5308366262236642312?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.veeam.com/' title='Saving My Bacon when things go Wrong - Veeam Backup In Action'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/5308366262236642312/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=5308366262236642312' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/5308366262236642312'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/5308366262236642312'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2011/03/saving-my-bacon-when-things-go-wrong.html' title='Saving My Bacon when things go Wrong - Veeam Backup In Action'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-1Lphxo9PoYw/TYwyxqT5wyI/AAAAAAAAACY/ycrMB0KH0cc/s72-c/VeeamInAction.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-8667991064349327899</id><published>2011-03-16T17:46:00.000-07:00</published><updated>2011-03-16T18:02:31.513-07:00</updated><title type='text'>Parsing dates and times in english free form</title><content type='html'>I've been looking for this a while. I want to be able to take &lt;br /&gt;something like "Every tuesday, starting on the 5th of april" and&lt;br /&gt;convert it to computer readable form. Now in Ruby, you there is a&lt;br /&gt;library to do it.&lt;br /&gt;&lt;br /&gt;Its a ruby gem/add-on called Nickel by Natural Inputs.&lt;br /&gt;&lt;br /&gt;Nickel is an API that extracts date, time, and message information from naturally worded text.&lt;br /&gt;Why you should use it.&lt;br /&gt;&lt;br /&gt;Simplify any form with date and time inputs&lt;br /&gt;Increase your website's usability&lt;br /&gt;Handles recurring date and time information&lt;br /&gt;&lt;br /&gt;In my case I wanted to create calendar entries via a email message. &lt;br /&gt;&lt;br /&gt;This way the subject line alone can give me alot of information.&lt;br /&gt;&lt;br /&gt;http://naturalinputs.com/&lt;br /&gt;https://github.com/lzell/nickel&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-8667991064349327899?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://naturalinputs.com/' title='Parsing dates and times in english free form'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/8667991064349327899/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=8667991064349327899' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/8667991064349327899'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/8667991064349327899'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2011/03/parsing-dates-and-times-in-english-free.html' title='Parsing dates and times in english free form'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-5199701579058748332</id><published>2011-02-27T00:01:00.000-08:00</published><updated>2011-02-27T00:01:53.479-08:00</updated><title type='text'>A Example of _BeforeDataInitialize for Microsoft Lightswitch Collections</title><content type='html'>When you have a Lightswitch edit screen, its not clear from the doc what&lt;br /&gt;you need to do to init data. You have to create a instance of the item,&lt;br /&gt;and put it into the collections selected item field.&lt;br /&gt;Like So.&lt;br /&gt;&lt;br /&gt;partial void PurchaseRequests_BeforeDataInitialize()&lt;br /&gt;        {&lt;br /&gt;            // Write your code here.&lt;br /&gt;            PurchaseRequest theitem = new Portal.PurchaseRequest();&lt;br /&gt;            theitem.PrState = "Unsubmitted";&lt;br /&gt;            theitem.Requestor = Application.Current.User.Name;&lt;br /&gt;            theitem.Subtotal = 0;&lt;br /&gt;            theitem.Total = 0;&lt;br /&gt;            theitem.CurrentcyType = "SGD";&lt;br /&gt;            theitem.DateCreated = DateTime.Now;&lt;br /&gt;            theitem.DateUpdated = DateTime.Now;&lt;br /&gt;            PurchaseRequestCollection.SelectedItem = theitem;&lt;br /&gt;        }&lt;br /&gt;    }&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-5199701579058748332?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/5199701579058748332/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=5199701579058748332' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/5199701579058748332'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/5199701579058748332'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2011/02/example-of-beforedatainitialize-for.html' title='A Example of _BeforeDataInitialize for Microsoft Lightswitch Collections'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-498166274784059630</id><published>2011-02-11T01:57:00.000-08:00</published><updated>2011-02-11T01:57:41.474-08:00</updated><title type='text'>End of Nokia</title><content type='html'>Sometimes I really wonder if people understand the market. While generally I agree in most areas Microsoft does a great job, mobile devices as in phones is not one of them. Windows phone 7,has died to a large degree, even close partners are not happy by the market reality of windows 7. The market share for Windows mobile/windows CE continues to fall, with the iphone and android winning fast. &lt;br /&gt;&lt;br /&gt;Actually palms offering/hp is far stronger than windows 7, and its the "third" choice as it is for the consumer. Android phones are cheap, and getting cheaper, with a wealth of applications, and reasonably quick software updates. &lt;br /&gt;&lt;br /&gt;Nokia hardware and design is not bad, the problem is one of a company being in the business for too long a time, too many models, to many different os's &lt;br /&gt;To the point that change management is just broken. (Try doing application development in Nokia space, its a nightmare of screen sizes and versions)&lt;br /&gt;&lt;br /&gt;So the choice Nokia had were:&lt;br /&gt;1. There new Linux based in-house effort, to long in coming, that its dead&lt;br /&gt;2. Use android/google and have a close partnership with the other giant. &lt;br /&gt;3. Use Microsoft - The underdog.&lt;br /&gt;&lt;br /&gt;I can understand Nokia does not want to compete with HTC, but the reality they are.&lt;br /&gt;HTC produces both Windows as well as android models. The android ones are incredible popular. So Nokia thinks they can make windows mobile better? After how many versions? Please, dont waste your money. Even on my industrial environment devices (Bar code scanners) I'd prefer to have android, it would be easier to develop.&lt;br /&gt;&lt;br /&gt;I really feel nokia is missing the boat. Them joining the Android universe would be a smart move, it would put them in the game. Even offering ports to the existing hardware platforms(phones) would allow them quick entry into the market, without big retootling on the factory side. Newer versions of android really dont need big skinning jobs, so very quick to see a result. &lt;br /&gt;&lt;br /&gt;I love nokia hardware, till iphones came, every phone I bought was a Nokia. Solid&lt;br /&gt;hardware, cost effective, great ability to customize the products. The iphone changed&lt;br /&gt;the game. Android changed it again. With android you can compete with iphone, with windows 7 dont bother to try. &lt;br /&gt;&lt;br /&gt;Attention Nokia Board, u need to wake up. I agree that the "house" is on fire, and you have to take action, but dont use gasoline to put out the fire. Windows Mobile/Windows CE has not delivered, and really dont see it delivering. It had years, and never even touch much of your symbian market share. Look at what android has done? &lt;br /&gt;&lt;br /&gt;I hope I'm wrong and your going to do both android and windows, and windows came first. If so. They you have a chance. But dont make windows mobile your final eulogy.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-498166274784059630?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/498166274784059630/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=498166274784059630' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/498166274784059630'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/498166274784059630'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2011/02/end-of-nokia.html' title='End of Nokia'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-6905204767741899510</id><published>2010-12-07T23:49:00.000-08:00</published><updated>2010-12-07T23:49:40.988-08:00</updated><title type='text'>New widgets for rails 3</title><content type='html'>I'm used activescaffold in countless rails projects. Rails 3, resets the clock a bit. &lt;br /&gt;With each major revision of the framework, I always re-eval my toolkit to see what is a better or more up to date fix. &lt;br /&gt;&lt;br /&gt;While I'm happy with the work I've done combining rails and silverlight, and I've also tried some Silverlight WCF RIA projects, a pure rails project has some appeal.&lt;br /&gt;&lt;br /&gt;Looks like there is another choice. Instead of using activescaffold, look at NetZke.&lt;br /&gt;It leverages ExtJs, and gives very nice gui, with better look and feel than activescaffold plus widgets. Overall, I'd say the base site for a business app in Rails 3 plus NetZke will look so much better than AS plus Widgets Menu I've been using a while for backend ops. &lt;br /&gt;&lt;br /&gt;Of course if you want smooth, go silverlight for the Gui with REST interface.&lt;br /&gt;&lt;br /&gt;http://netzke.org/&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-6905204767741899510?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.railsinside.com/misc/454-netzke-rich-internet-apps-with-ext-js-and-rails.html' title='New widgets for rails 3'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/6905204767741899510/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=6905204767741899510' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/6905204767741899510'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/6905204767741899510'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2010/12/new-widgets-for-rails-3.html' title='New widgets for rails 3'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-6354956665259619729</id><published>2010-10-19T17:13:00.000-07:00</published><updated>2010-10-19T17:13:57.746-07:00</updated><title type='text'>Returning to Roots - Comparison of Ruby and C-Sharp</title><content type='html'>Ran into this while doing my morning reading.&lt;br /&gt;This is a great video that compares C-Sharp and Ruby.&lt;br /&gt;As I'm currently doing both side by side, this is really great review&lt;br /&gt;of the plus and minus of each.&lt;br /&gt;&lt;br /&gt;The presenter is great, and there lots of code.&lt;br /&gt;&lt;br /&gt;http://vimeo.com/12803005&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-6354956665259619729?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://vimeo.com/12803005' title='Returning to Roots - Comparison of Ruby and C-Sharp'/><link rel='enclosure' type='' href='http://vimeo.com/12803005' length='0'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/6354956665259619729/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=6354956665259619729' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/6354956665259619729'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/6354956665259619729'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2010/10/returning-to-roots-comparison-of-ruby.html' title='Returning to Roots - Comparison of Ruby and C-Sharp'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-6853007707537848150</id><published>2010-10-13T03:17:00.000-07:00</published><updated>2010-10-13T03:17:41.236-07:00</updated><title type='text'>Limiting Data by User In Microsoft LightSwitch</title><content type='html'>I wanted to be able to limit my queries by user. In order to do this you need to add additional query code. This can only be done, if you create the query under the datasource. So for example, say I have a table, called&lt;br /&gt;appointments, and the table also has a relationship to users. Right Click on Appointments, and Add A Query. If you try to do this under the screen, you will not be able to add the code.&lt;br /&gt;&lt;br /&gt;Once you have the query, and rename it, you can click the Edit Additional Query Code button, on Properties.&lt;br /&gt;&lt;br /&gt;The gorgous part of this, you can have a complex query, in my case there are three groups or'd togeather, and then on top of that we limit by user.&lt;br /&gt;&lt;br /&gt;And it only takes a couple of lines. &lt;br /&gt;&lt;br /&gt;&lt;pre  style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt; partial void MyTodaysAppointments_PreprocessQuery(ref IQueryable&amp;lt;Appointment&amp;gt; query)&lt;br /&gt;  &lt;br /&gt;     {&lt;br /&gt;  &lt;br /&gt;       query = from Appointments in query&lt;br /&gt;  &lt;br /&gt;           where Appointments.User.Name == Application.Current.User.Name&lt;br /&gt;  &lt;br /&gt;           select Appointments;&lt;br /&gt;  &lt;br /&gt;     }  &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-6853007707537848150?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/6853007707537848150/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=6853007707537848150' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/6853007707537848150'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/6853007707537848150'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2010/10/limiting-data-by-user-in-microsoft.html' title='Limiting Data by User In Microsoft LightSwitch'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-7392320200242315822</id><published>2010-10-06T19:52:00.000-07:00</published><updated>2010-10-06T19:52:16.276-07:00</updated><title type='text'>Minimal Telnet Parsing in C#</title><content type='html'>Ever wonder what the minimal parsing is needed to do a telnet server?&lt;br /&gt;While the socket/listen is easy stuff, and life for low session counts &lt;br /&gt;is easy using a thread per session, the issue is, what do I need to do&lt;br /&gt;to get to the point I can talk to my device. In this case a scangun&lt;br /&gt;with a telnet client.&lt;br /&gt;&lt;br /&gt;Telnet actually is a protocol. The PC Micro link is a good write-up&lt;br /&gt;which wikipedia was so nice to provide a link to.&lt;br /&gt;&lt;br /&gt;I google for a while, and could not find anything other than expensive .net libraries, or basic protocol documentation.&lt;br /&gt;&lt;br /&gt;Here is the code, so you dont have to search any longer.&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;private void HandleClientComm(object client)&lt;br /&gt;        {&lt;br /&gt;            TcpClient tcpClient = (TcpClient)client;&lt;br /&gt;            NetworkStream clientStream = tcpClient.GetStream();&lt;br /&gt;&lt;br /&gt;            byte[] message = new byte[4096];&lt;br /&gt;            byte[] cmd = new byte[4096];&lt;br /&gt;            int cmdcnt;&lt;br /&gt;            int bpos;&lt;br /&gt;            int bytesRead;&lt;br /&gt;           &lt;br /&gt;            const int tmode_normal = 0;&lt;br /&gt;            const int tmode_iac = 1;&lt;br /&gt;            const int tmode_option = 2;&lt;br /&gt;            const int tmode_do = 3;&lt;br /&gt;            const int tmode_will = 4;&lt;br /&gt;            int mode;&lt;br /&gt;            byte thebyte;&lt;br /&gt;            BarCodeClient bci;&lt;br /&gt;            &lt;br /&gt;            cmdcnt = 0;&lt;br /&gt;            bpos = 0;&lt;br /&gt;            mode = tmode_normal;&lt;br /&gt;&lt;br /&gt;           bci = new BarCodeClient(client);&lt;br /&gt;       &lt;br /&gt;            while (true)&lt;br /&gt;            {&lt;br /&gt;                bytesRead = 0;&lt;br /&gt;&lt;br /&gt;                try&lt;br /&gt;                {&lt;br /&gt;                    //blocks until a client sends a message&lt;br /&gt;                    bytesRead = clientStream.Read(message, 0, 4096);&lt;br /&gt;                }&lt;br /&gt;                catch&lt;br /&gt;                {&lt;br /&gt;                    //a socket error has occured&lt;br /&gt;                    break;&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;                if (bytesRead == 0)&lt;br /&gt;                {&lt;br /&gt;                    //the client has disconnected from the server&lt;br /&gt;                    break;&lt;br /&gt;                }&lt;br /&gt;               &lt;br /&gt;                bpos = 0;&lt;br /&gt;                while( (cmdcnt &amp;lt; 4096) &amp;amp;&amp;amp; (bpos &amp;lt; bytesRead)){&lt;br /&gt;                    thebyte = message[bpos++];&lt;br /&gt;                    switch (mode)&lt;br /&gt;                    {&lt;br /&gt;                        case tmode_normal:&lt;br /&gt;                            switch (thebyte)&lt;br /&gt;                            {&lt;br /&gt;                                case telnet_iac:&lt;br /&gt;                                    mode = tmode_iac;&lt;br /&gt;                                    continue;&lt;br /&gt;                                case 0x0a: // LineFeed&lt;br /&gt;                                    break;&lt;br /&gt;                                case 0x0d:&lt;br /&gt;                                    string thecmd = Encoding.ASCII.GetString(cmd,0,cmdcnt);&lt;br /&gt;                                    if (thecmd.Length &amp;gt; 0)&lt;br /&gt;                                    {&lt;br /&gt;                                        bci.Cmd(thecmd);&lt;br /&gt;                                    }&lt;br /&gt;                                    cmdcnt = 0;&lt;br /&gt;                                    continue;&lt;br /&gt;                                default:&lt;br /&gt;                                    break;&lt;br /&gt;                            }&lt;br /&gt;                            cmd[cmdcnt++] = thebyte; &lt;br /&gt;                            break;&lt;br /&gt;                        case tmode_iac:&lt;br /&gt;                            switch (thebyte)&lt;br /&gt;                            {&lt;br /&gt;                                case telnet_do:&lt;br /&gt;                                     mode = tmode_do;&lt;br /&gt;                                     break;&lt;br /&gt;                                case telnet_se:  // End Subnegotiation&lt;br /&gt;                                     mode = tmode_normal;&lt;br /&gt;                                     bci.Cmd(&amp;quot;&amp;quot;); // Let the lower level know to force a screen refresh&lt;br /&gt;                                     break;&lt;br /&gt;                                case telnet_sb:&lt;br /&gt;                                    mode = tmode_option;&lt;br /&gt;                                    break;&lt;br /&gt;                                case telnet_will:&lt;br /&gt;                                    mode = tmode_will;&lt;br /&gt;                                    break;&lt;br /&gt;                                default:&lt;br /&gt;                                    mode = tmode_normal;&lt;br /&gt;                                    break;&lt;br /&gt;                            }&lt;br /&gt;                            break;&lt;br /&gt;                        case tmode_do:&lt;br /&gt;                            switch (thebyte)&lt;br /&gt;                            {&lt;br /&gt;                                default:&lt;br /&gt;                                    mode = tmode_normal;&lt;br /&gt;                                    break;&lt;br /&gt;                            }&lt;br /&gt;                            break;&lt;br /&gt;                        case tmode_will:&lt;br /&gt;                            switch (thebyte)&lt;br /&gt;                             {&lt;br /&gt;                                 default:&lt;br /&gt;                                     mode = tmode_normal;&lt;br /&gt;                                     break;&lt;br /&gt;                             }&lt;br /&gt;                            break;&lt;br /&gt;                        case tmode_option:&lt;br /&gt;                            switch (thebyte)&lt;br /&gt;                            {&lt;br /&gt;                                default:&lt;br /&gt;                                    mode = tmode_normal;&lt;br /&gt;                                    break;&lt;br /&gt;                            }&lt;br /&gt;                            break;&lt;br /&gt;                        }&lt;br /&gt;                    }&lt;br /&gt;                &lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            tcpClient.Close();&lt;br /&gt;        }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-7392320200242315822?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.pcmicro.com/netfoss/telnet.html' title='Minimal Telnet Parsing in C#'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/7392320200242315822/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=7392320200242315822' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/7392320200242315822'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/7392320200242315822'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2010/10/minimal-telnet-parsing-in-c.html' title='Minimal Telnet Parsing in C#'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-6537006193992360831</id><published>2010-10-05T02:35:00.000-07:00</published><updated>2010-10-05T02:35:59.915-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vmware vsphere esx esxi iscsi'/><title type='text'>Creating a debian iscsi shared raid for backup of vmware esx systems</title><content type='html'>I usually keep a backup image on one of my test boxes for the production&lt;br /&gt;systems, so I can have a easy way of recoverying in event of disaster.&lt;br /&gt;This previous was a openfiler but found it managed to lose its disk.&lt;br /&gt;So I decided to setup a equivlent system using debian. So using&lt;br /&gt;the minimal network install, I setup a base debian, then added software raid, and finally iscsi target support. Note this is all running as a VM on top of esxi, with raw disks mapped to local sata drives.&lt;br /&gt;&lt;br /&gt;First, map your raw disk using vmkfstools&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;vmkfstools -r /vmfs/devices/disks/vml.0100000000202020202020202020202020395653334e595335535433313530 disk1.vmdk&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Next you need to go into the vm, and add the raw vmdk into the vm's config&lt;br /&gt;&lt;br /&gt;Now in debian, you will see the raw devices at boot&lt;br /&gt;&lt;br /&gt;Next install mdadm&lt;br /&gt;&lt;br /&gt;apt-get install mdadm&lt;br /&gt;&lt;br /&gt;and you need to install the iscsi target kernel modules&lt;br /&gt;&lt;br /&gt;apt-get install iscsitarget-modules-2.6.26-2-686&lt;br /&gt;&lt;br /&gt;Now setup the raid&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;mdadm --create /dev/md0 --level=5 --raid-devices=5 /dev/sdb /dev/sdc /dev/sdd /dev/sde /dev/sdf&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;To check the status:&lt;br /&gt;mdadm --detail /dev/md0&lt;br /&gt;&lt;br /&gt;Now add the disk into the /etc/ietd.conf&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Change the following:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;#Assuming you want some security, a chap password on incoming user is useful&lt;br /&gt;IncomingUser sinadmin xxyyzz&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Target iqn.2001-04.com.rutledge:storage.disk0.sys1.md0&lt;br /&gt;        # Fixup the security  &lt;br /&gt;         IncomingUser sinadmin xxyyzz&lt;br /&gt;        # Block devices, regular files, LVM, and RAID can be offered&lt;br /&gt;        # to the initiators as a block device.&lt;br /&gt;        Lun 0 Path=/dev/md0,Type=fileio&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And finally:&lt;br /&gt;invoke-rc.d iscsitarget restart&lt;br /&gt;&lt;br /&gt;The get everything using our new config.&lt;br /&gt;&lt;br /&gt;Surprisingly I found this no worse than using openfiler, and I know what is happening&lt;br /&gt;behind the covers.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-6537006193992360831?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/6537006193992360831/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=6537006193992360831' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/6537006193992360831'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/6537006193992360831'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2010/10/creating-debian-iscsi-shared-raid-for.html' title='Creating a debian iscsi shared raid for backup of vmware esx systems'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-9008457559325092081</id><published>2010-09-30T01:35:00.000-07:00</published><updated>2010-09-30T01:35:44.574-07:00</updated><title type='text'>A Debuggable Windows Service in Csharp</title><content type='html'>This is a great example of a windows service. I use it in a app that reads email from pop, and updates a database/webapp written in SilverLight for the FrontEnd.&lt;br /&gt;&lt;br /&gt;One note, this uses a Timer Approach to initiate the check. I found unless I put a lock around the worker class,I would see the timer fire again, and I get get a breakpoint in another "thread", while debugging the first. The lock fixed the issue. But take note if you using this or something similar.&lt;br /&gt;&lt;br /&gt;&lt;pre  style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt; using System;&lt;br /&gt;  &lt;br /&gt; using System.Collections;&lt;br /&gt;  &lt;br /&gt; using System.ComponentModel;&lt;br /&gt;  &lt;br /&gt; using System.Configuration.Install;&lt;br /&gt;  &lt;br /&gt; using System.Reflection;&lt;br /&gt;  &lt;br /&gt; using System.ServiceProcess;&lt;br /&gt;  &lt;br /&gt; using System.Threading;&lt;br /&gt;  &lt;br /&gt; using System.Management;&lt;br /&gt;  &lt;br /&gt; using Microsoft.Practices.EnterpriseLibrary.Logging;&lt;br /&gt;  &lt;br /&gt; namespace WhereAmIEmail&lt;br /&gt;  &lt;br /&gt; {&lt;br /&gt;  &lt;br /&gt;   public class WhereAmIEmail : ServiceBase&lt;br /&gt;  &lt;br /&gt;   {&lt;br /&gt;  &lt;br /&gt;     private Worker myworker;&lt;br /&gt;  &lt;br /&gt;     private Timer serviceTimer;&lt;br /&gt;  &lt;br /&gt;     private Container components = null;&lt;br /&gt;  &lt;br /&gt;     public WhereAmIEmail()&lt;br /&gt;  &lt;br /&gt;     {      &lt;br /&gt;  &lt;br /&gt;       InitializeComponent();     &lt;br /&gt;  &lt;br /&gt;     }&lt;br /&gt;  &lt;br /&gt;     // The main entry point for the process&lt;br /&gt;  &lt;br /&gt;     private static void Main(string[] args)&lt;br /&gt;  &lt;br /&gt;     {&lt;br /&gt;  &lt;br /&gt;       string opt = null;&lt;br /&gt;  &lt;br /&gt;       // check for arguments&lt;br /&gt;  &lt;br /&gt;       if (args.Length &amp;gt; 0)&lt;br /&gt;  &lt;br /&gt;       {&lt;br /&gt;  &lt;br /&gt;         opt = args[0];&lt;br /&gt;  &lt;br /&gt;         if (opt != null &amp;amp;&amp;amp; opt.ToLower() == "/install")&lt;br /&gt;  &lt;br /&gt;         {&lt;br /&gt;  &lt;br /&gt;           TransactedInstaller ti = new TransactedInstaller();&lt;br /&gt;  &lt;br /&gt;           ProjectInstaller pi = new ProjectInstaller();&lt;br /&gt;  &lt;br /&gt;           ti.Installers.Add(pi);&lt;br /&gt;  &lt;br /&gt;           String path = String.Format("/assemblypath={0}",&lt;br /&gt;  &lt;br /&gt;                         Assembly.GetExecutingAssembly().Location);&lt;br /&gt;  &lt;br /&gt;           String[] cmdline = {path};&lt;br /&gt;  &lt;br /&gt;           InstallContext ctx = new InstallContext("", cmdline);&lt;br /&gt;  &lt;br /&gt;           ti.Context = ctx;&lt;br /&gt;  &lt;br /&gt;           ti.Install(new Hashtable());&lt;br /&gt;  &lt;br /&gt;         }&lt;br /&gt;  &lt;br /&gt;         else if (opt != null &amp;amp;&amp;amp; opt.ToLower() == "/uninstall")&lt;br /&gt;  &lt;br /&gt;         {&lt;br /&gt;  &lt;br /&gt;           TransactedInstaller ti = new TransactedInstaller();&lt;br /&gt;  &lt;br /&gt;           ProjectInstaller mi = new ProjectInstaller();&lt;br /&gt;  &lt;br /&gt;           ti.Installers.Add(mi);&lt;br /&gt;  &lt;br /&gt;           String path = String.Format("/assemblypath={0}",&lt;br /&gt;  &lt;br /&gt;                         Assembly.GetExecutingAssembly().Location);&lt;br /&gt;  &lt;br /&gt;           String[] cmdline = {path};&lt;br /&gt;  &lt;br /&gt;           InstallContext ctx = new InstallContext("", cmdline);&lt;br /&gt;  &lt;br /&gt;           ti.Context = ctx;&lt;br /&gt;  &lt;br /&gt;           ti.Uninstall(null);&lt;br /&gt;  &lt;br /&gt;         }&lt;br /&gt;  &lt;br /&gt;       }&lt;br /&gt;  &lt;br /&gt;       if (opt == null) // e.g. ,nothing on the command line&lt;br /&gt;  &lt;br /&gt;       {&lt;br /&gt;  &lt;br /&gt; #if ( ! DEBUG )&lt;br /&gt;  &lt;br /&gt;         ServiceBase[] ServicesToRun;&lt;br /&gt;  &lt;br /&gt;         ServicesToRun = new ServiceBase[] {new WhereAmIEmail()};&lt;br /&gt;  &lt;br /&gt;         ServiceBase.Run(ServicesToRun);&lt;br /&gt;  &lt;br /&gt; #else&lt;br /&gt;  &lt;br /&gt;         // debug code: allows the process to run as a non-service&lt;br /&gt;  &lt;br /&gt;         // will kick off the service start point, but never kill it&lt;br /&gt;  &lt;br /&gt;         // shut down the debugger to exit&lt;br /&gt;  &lt;br /&gt;         WhereAmIEmail service = new WhereAmIEmail();&lt;br /&gt;  &lt;br /&gt;         service.OnStart(null);&lt;br /&gt;  &lt;br /&gt;         Thread.Sleep(Timeout.Infinite);&lt;br /&gt;  &lt;br /&gt; #endif &lt;br /&gt;  &lt;br /&gt;       }&lt;br /&gt;  &lt;br /&gt;     }&lt;br /&gt;  &lt;br /&gt;     /// &amp;lt;summary&amp;gt; &lt;br /&gt;  &lt;br /&gt;     /// Required method for Designer support - do not modify &lt;br /&gt;  &lt;br /&gt;     /// the contents of this method with the code editor.&lt;br /&gt;  &lt;br /&gt;     /// &amp;lt;/summary&amp;gt;&lt;br /&gt;  &lt;br /&gt;     private void InitializeComponent()&lt;br /&gt;  &lt;br /&gt;     {&lt;br /&gt;  &lt;br /&gt;       components = new Container();&lt;br /&gt;  &lt;br /&gt;       this.ServiceName = "WhereAmIEmail";&lt;br /&gt;  &lt;br /&gt;     }&lt;br /&gt;  &lt;br /&gt;     /// &amp;lt;summary&amp;gt;&lt;br /&gt;  &lt;br /&gt;     /// Clean up any resources being used.&lt;br /&gt;  &lt;br /&gt;     /// &amp;lt;/summary&amp;gt;&lt;br /&gt;  &lt;br /&gt;     protected override void Dispose(bool disposing)&lt;br /&gt;  &lt;br /&gt;     {&lt;br /&gt;  &lt;br /&gt;       if (disposing)&lt;br /&gt;  &lt;br /&gt;       {&lt;br /&gt;  &lt;br /&gt;         if (components != null)&lt;br /&gt;  &lt;br /&gt;         {&lt;br /&gt;  &lt;br /&gt;           components.Dispose();&lt;br /&gt;  &lt;br /&gt;         }&lt;br /&gt;  &lt;br /&gt;       }&lt;br /&gt;  &lt;br /&gt;       base.Dispose(disposing);&lt;br /&gt;  &lt;br /&gt;     }&lt;br /&gt;  &lt;br /&gt;     /// &amp;lt;summary&amp;gt;&lt;br /&gt;  &lt;br /&gt;     /// Set things in motion so your service can do its work.&lt;br /&gt;  &lt;br /&gt;     /// &amp;lt;/summary&amp;gt;&lt;br /&gt;  &lt;br /&gt;     protected override void OnStart(string[] args)&lt;br /&gt;  &lt;br /&gt;     {&lt;br /&gt;  &lt;br /&gt;       myworker = new Worker();&lt;br /&gt;  &lt;br /&gt;       TimerCallback timerDelegate = new TimerCallback(myworker.DoWork);&lt;br /&gt;  &lt;br /&gt;       serviceTimer = new Timer(timerDelegate, null, 10000, 10000);&lt;br /&gt;  &lt;br /&gt;     }&lt;br /&gt;  &lt;br /&gt;     /// &amp;lt;summary&amp;gt;&lt;br /&gt;  &lt;br /&gt;     /// Stop this service.&lt;br /&gt;  &lt;br /&gt;     /// &amp;lt;/summary&amp;gt;&lt;br /&gt;  &lt;br /&gt;     protected override void OnStop()&lt;br /&gt;  &lt;br /&gt;     {&lt;br /&gt;  &lt;br /&gt;       // test.Stop() ;&lt;br /&gt;  &lt;br /&gt;     }&lt;br /&gt;  &lt;br /&gt;   }&lt;br /&gt;  &lt;br /&gt; }&lt;br /&gt;  &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-9008457559325092081?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/9008457559325092081/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=9008457559325092081' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/9008457559325092081'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/9008457559325092081'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2010/09/debuggable-windows-service-in-csharp.html' title='A Debuggable Windows Service in Csharp'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-863003405967451538</id><published>2010-09-30T01:28:00.000-07:00</published><updated>2010-09-30T01:28:09.635-07:00</updated><title type='text'>Hacking LightSwitch User Database Entry using Csharp .net and LinqToSQL</title><content type='html'>I want to be able to dynamically create Users in my Microsoft Ligthswitch applications. One of the issues is they use a spearate database. &lt;br /&gt;&lt;br /&gt;Since my app accepts email messges, and creates records for the users, it rather important they exist in the system.&lt;br /&gt;&lt;br /&gt;So the background Windows service uses LinqToSql to update the tables.&lt;br /&gt;&lt;br /&gt;Each user in Lightswitch is in the aspnet_table, there is a record for each application sharing the same database. So if your creating a user, you also need to know which application guid you need to connect the user too.&lt;br /&gt;&lt;br /&gt;&lt;pre  style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt;  public int CreateUser(string UserName)&lt;br /&gt;  &lt;br /&gt;   {&lt;br /&gt;  &lt;br /&gt;     User myUser = new User();&lt;br /&gt;  &lt;br /&gt;     myUser.Name = UserName;&lt;br /&gt;  &lt;br /&gt;     db.Users.InsertOnSubmit(myUser);&lt;br /&gt;  &lt;br /&gt;     db.SubmitChanges();&lt;br /&gt;  &lt;br /&gt;     return (myUser.Id);&lt;br /&gt;  &lt;br /&gt;   }&lt;br /&gt;  &lt;br /&gt;   public Guid CreateAspUser(string UserName)&lt;br /&gt;  &lt;br /&gt;   {&lt;br /&gt;  &lt;br /&gt;     aspnet_User myUser = new aspnet_User();&lt;br /&gt;  &lt;br /&gt;     myUser.ApplicationId = MyAppId;&lt;br /&gt;  &lt;br /&gt;     myUser.UserId = Guid.NewGuid();&lt;br /&gt;  &lt;br /&gt;     myUser.UserName = UserName;&lt;br /&gt;  &lt;br /&gt;     myUser.LoweredUserName = UserName.ToLower();&lt;br /&gt;  &lt;br /&gt;     myUser.IsAnonymous = false;&lt;br /&gt;  &lt;br /&gt;     myUser.LastActivityDate = System.DateTime.Now;&lt;br /&gt;  &lt;br /&gt;     db.aspnet_Users.InsertOnSubmit(myUser);&lt;br /&gt;  &lt;br /&gt;     db.SubmitChanges();&lt;br /&gt;  &lt;br /&gt;     return (myUser.UserId);&lt;br /&gt;  &lt;br /&gt;   }&lt;br /&gt;  &lt;br /&gt;   public Guid GetMyAppId(string appName)&lt;br /&gt;  &lt;br /&gt;   {&lt;br /&gt;  &lt;br /&gt;     var query = from aApp in db.aspnet_Applications where aApp.ApplicationName == appName select aApp;&lt;br /&gt;  &lt;br /&gt;     return (query.First().ApplicationId);&lt;br /&gt;  &lt;br /&gt;   }&lt;br /&gt;  &lt;br /&gt;   public Guid GetUserID(String UserName)&lt;br /&gt;  &lt;br /&gt;   {&lt;br /&gt;  &lt;br /&gt;     var query = from aUser in db.aspnet_Users where aUser.UserName == UserName where aUser.ApplicationId == MyAppId select aUser;&lt;br /&gt;  &lt;br /&gt;     if (query.Count&amp;lt;aspnet_User&amp;gt;() == 0)&lt;br /&gt;  &lt;br /&gt;     {&lt;br /&gt;  &lt;br /&gt;       return (Guid.Empty);&lt;br /&gt;  &lt;br /&gt;     }&lt;br /&gt;  &lt;br /&gt;     return (query.First().UserId);&lt;br /&gt;  &lt;br /&gt;   }&lt;br /&gt;  &lt;br /&gt;   public int GetPortalUserID(String UserName)&lt;br /&gt;  &lt;br /&gt;   {&lt;br /&gt;  &lt;br /&gt;     var query = from aUser in db.Users where aUser.Name == UserName select aUser;&lt;br /&gt;  &lt;br /&gt;     if (query.Count&amp;lt;User&amp;gt;() == 0)&lt;br /&gt;  &lt;br /&gt;     {&lt;br /&gt;  &lt;br /&gt;       return (0);&lt;br /&gt;  &lt;br /&gt;     }&lt;br /&gt;  &lt;br /&gt;     return (query.First().Id);&lt;br /&gt;  &lt;br /&gt;   }  &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;So then it just a matter of calling the code:&lt;br /&gt;&lt;br /&gt;&lt;pre  style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt; Guid theUserID = GetUserID(UserName);&lt;br /&gt;  &lt;br /&gt;          if (theUserID == Guid.Empty)&lt;br /&gt;  &lt;br /&gt;          { // No Such User&lt;br /&gt;  &lt;br /&gt;            theUserID = CreateAspUser(UserName);&lt;br /&gt;  &lt;br /&gt;          }&lt;br /&gt;  &lt;br /&gt;          int thePortalID = GetPortalUserID(UserName);&lt;br /&gt;  &lt;br /&gt;          if (thePortalID == 0)&lt;br /&gt;  &lt;br /&gt;          {&lt;br /&gt;  &lt;br /&gt;            // Need to create local user&lt;br /&gt;  &lt;br /&gt;            thePortalID = CreateUser(UserName);&lt;br /&gt;  &lt;br /&gt;          }&lt;br /&gt;  &lt;br /&gt;          CreateAppointment(theUserID, thePortalID, Email.Subject, theMessage);  &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-863003405967451538?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/863003405967451538/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=863003405967451538' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/863003405967451538'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/863003405967451538'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2010/09/hacking-lightswitch-user-database-entry.html' title='Hacking LightSwitch User Database Entry using Csharp .net and LinqToSQL'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-1636488657575338633</id><published>2010-09-30T01:09:00.000-07:00</published><updated>2010-09-30T01:10:19.086-07:00</updated><title type='text'>ActiveDirectory and Csharp - Finding the domain user via email</title><content type='html'>Sometimes, how many examples, and none seem to work.&lt;br /&gt;&lt;br /&gt;I wanted to lookup and verify a user exists via email, in a process that reads email via pop, and then creates records in Silverlight/Lightswitch application. &lt;br /&gt;&lt;br /&gt;So how do it?&lt;br /&gt;&lt;br /&gt;I've included the code below. Not that a normal user is fine for the username and password, and you must supply the domain controller. I used the IP of mine.&lt;br /&gt;&lt;br /&gt;&lt;pre  style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt;1:  public DirectoryEntry find_by_email(string email)&lt;br /&gt;  &lt;br /&gt;2:    {&lt;br /&gt;  &lt;br /&gt;3:      DirectoryEntry dirEntry = new DirectoryEntry("LDAP://10.0.7.100","ausername","apassword",AuthenticationTypes.Secure);&lt;br /&gt;  &lt;br /&gt;4:      DirectorySearcher Dsearch = new DirectorySearcher(dirEntry);&lt;br /&gt;  &lt;br /&gt;5:      Dsearch.Filter = "(&amp;amp;(objectCategory=person)(sAMAccountName=*)(mail="+email+"))";&lt;br /&gt;  &lt;br /&gt;6:      SearchResult sResult = Dsearch.FindOne();&lt;br /&gt;  &lt;br /&gt;7:      if (sResult == null)&lt;br /&gt;  &lt;br /&gt;8:      {&lt;br /&gt;  &lt;br /&gt;9:        return null;&lt;br /&gt;  &lt;br /&gt;10:      }&lt;br /&gt;  &lt;br /&gt;11:      EventLog.WriteEntry("DoneEmailLookup");&lt;br /&gt;  &lt;br /&gt;12:      DirectoryEntry user = sResult.GetDirectoryEntry();&lt;br /&gt;  &lt;br /&gt;13:      return (user);&lt;br /&gt;  &lt;br /&gt;14:    }&lt;br /&gt;  &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-1636488657575338633?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/1636488657575338633/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=1636488657575338633' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/1636488657575338633'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/1636488657575338633'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2010/09/activedirectory-and-csharp.html' title='ActiveDirectory and Csharp - Finding the domain user via email'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-6201303171483752390</id><published>2010-08-26T19:53:00.000-07:00</published><updated>2010-08-26T19:53:25.127-07:00</updated><title type='text'>Doing a Offline Client Using Silverlight 4 and Rails Backend</title><content type='html'>I've prevously did a MultiMedia Silverlight app for a Video.&lt;br /&gt;Now I'm doing a data driven app, more in line with Rails.&lt;br /&gt;The issue with any web app is no internet = no work. &lt;br /&gt;But how to have a nice web client and have a local database?&lt;br /&gt;Espesially that can operate with Rails backend?&lt;br /&gt;&lt;br /&gt;I Found a Great Solution for Doing this,in the form of a Database Product&lt;br /&gt;called Siaqodb. I managed create a web app, with a datagrid in silverlight&lt;br /&gt;that can run on the web or as a local app, and have local tables, and did it in a few hours. &lt;br /&gt;&lt;br /&gt;For your local tables you can create a model in silverlight such as:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;SendItAttachment.cs&lt;/b&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Linq;&lt;br /&gt;using System.Text;&lt;br /&gt;using Sqo;&lt;br /&gt;&lt;br /&gt;namespace SendIt&lt;br /&gt;{&lt;br /&gt;    public class SendItAttachment : ISqoDataObject &lt;br /&gt;    {&lt;br /&gt;        public string Name { get; set; }&lt;br /&gt;        public string Path { get; set; }&lt;br /&gt;        public DateTime StartTime { get; set; }&lt;br /&gt;        public DateTime EndTime { get; set; }&lt;br /&gt;        public int TransferTime { get; set; }&lt;br /&gt;        public Boolean Done { get; set; }&lt;br /&gt;        public Boolean Failed { get; set; }&lt;br /&gt;        public string Hash { get; set; }&lt;br /&gt;        public int FileSize { get; set; }&lt;br /&gt;        public int OID { get; set; }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        public object GetValue(System.Reflection.FieldInfo field)&lt;br /&gt;        {&lt;br /&gt;            return field.GetValue(this);&lt;br /&gt;        }&lt;br /&gt;        public void SetValue(System.Reflection.FieldInfo field, object value)&lt;br /&gt;        {&lt;br /&gt;&lt;br /&gt;            field.SetValue(this, value);&lt;br /&gt;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Its Important that you make sure your grid is set to autogenerate the columns&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt; &amp;lt;sdk:DataGrid AutoGenerateColumns=&amp;quot;True&amp;quot; Height=&amp;quot;273&amp;quot; HorizontalAlignment=&amp;quot;Left&amp;quot; Margin=&amp;quot;13,321,0,0&amp;quot; Name=&amp;quot;SendingGrid&amp;quot; VerticalAlignment=&amp;quot;Top&amp;quot; Width=&amp;quot;780&amp;quot; /&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Add a reference to SiaqodbSL so that you can use the database.&lt;br /&gt;&lt;br /&gt;Next thing is to Instance the database, and load your data&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;       public MainPage()&lt;br /&gt;        {&lt;br /&gt;            InitializeComponent();&lt;br /&gt;            this.loginContainer.Child = new LoginStatus();&lt;br /&gt;            this.Loaded += new RoutedEventHandler(MainPage_Loaded);&lt;br /&gt;        }&lt;br /&gt;        Siaqodb siaqodb;&lt;br /&gt;        void MainPage_Loaded(object sender, RoutedEventArgs e)&lt;br /&gt;        {&lt;br /&gt;&lt;br /&gt;            if (Application.Current.IsRunningOutOfBrowser &amp;amp;&amp;amp; Application.Current.HasElevatedPermissions)&lt;br /&gt;            {&lt;br /&gt;                //use MyDocuments folder on client machine to store data&lt;br /&gt;                siaqodb = new Siaqodb(&amp;quot;siaqodb&amp;quot;,Environment.SpecialFolder.MyDocuments);&lt;br /&gt;            }&lt;br /&gt;            else&lt;br /&gt;            {&lt;br /&gt;                //use IsolatedStorage to store data&lt;br /&gt;                siaqodb = new Siaqodb(&amp;quot;siaqodb&amp;quot;);&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            SendItAttachment attachment = new SendItAttachment();&lt;br /&gt;            attachment.Name = &amp;quot;&amp;quot;;&lt;br /&gt;            attachment.StartTime = new DateTime(2010,1,1);&lt;br /&gt;            attachment.EndTime = new DateTime(2010,1,1);&lt;br /&gt;            siaqodb.StoreObject(attachment);&lt;br /&gt;            siaqodb.Flush();&lt;br /&gt;&lt;br /&gt;            IObjectList&amp;lt;SendItAttachment&amp;gt; senditattachments = siaqodb.LoadAll&amp;lt;SendItAttachment&amp;gt;();&lt;br /&gt;            this.SendingGrid.ItemsSource = senditattachments;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Thats the basics, we will get a bit facier in new articles coming soon.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-6201303171483752390?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://siaqodb.com/?page_id=6' title='Doing a Offline Client Using Silverlight 4 and Rails Backend'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/6201303171483752390/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=6201303171483752390' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/6201303171483752390'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/6201303171483752390'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2010/08/doing-offline-client-using-silverlight.html' title='Doing a Offline Client Using Silverlight 4 and Rails Backend'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-2855231325178043997</id><published>2010-07-12T23:20:00.000-07:00</published><updated>2010-07-12T23:20:01.219-07:00</updated><title type='text'>ESXi - Resizing Disk</title><content type='html'>Wow, I was running in circles. I needed to resize a system disk on&lt;br /&gt;one of my development machines, that running on the HA ESX/Vsphere &lt;br /&gt;cluster. It was "grayed" out, and I could not change it.&lt;br /&gt;&lt;br /&gt;It puzzled me, as I've resized dozens of times on other machines.&lt;br /&gt;All my machines were created using the latest VM spec, but yet&lt;br /&gt;no resize. I even pushed the disk back and forth between datastores&lt;br /&gt;and it didnt come back.&lt;br /&gt;&lt;br /&gt;What was the problem?&lt;br /&gt;&lt;br /&gt;If you resize, you can have no snapshots.&lt;br /&gt;&lt;br /&gt;Sure enough, deleted my snapshots, and everything was good.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-2855231325178043997?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/2855231325178043997/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=2855231325178043997' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/2855231325178043997'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/2855231325178043997'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2010/07/esxi-resizing-disk.html' title='ESXi - Resizing Disk'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-865601964758088031</id><published>2010-07-08T17:59:00.000-07:00</published><updated>2010-07-08T17:59:55.690-07:00</updated><title type='text'>Vmware - Leasons Learned - View ESX vs ESXi ISCSI Backup</title><content type='html'>Wow, Its been interesting.&lt;br /&gt;&lt;br /&gt;Designing and Deployment of a fully virtualized enterprise.&lt;br /&gt;&lt;br /&gt;This includes:&lt;br /&gt;1. Replacement of all desktops with thin clients.&lt;br /&gt;2. Move from hosted email to a virtulized exchange environment.&lt;br /&gt;3. iscsi based storage for everthing.&lt;br /&gt;4. Blade Based Servers&lt;br /&gt;&lt;br /&gt;Leasons Learned:&lt;br /&gt;1. When your designing your blades, use at least a single SSD&lt;br /&gt;drive to host ESX hypervisor. Yes, you can boot iScsi, yes you can&lt;br /&gt;use a SD card. &lt;br /&gt;&lt;br /&gt;But: &lt;br /&gt;   a. A SD Card means your running ESXi, your updates consists of re-installating. I've had to do it three times. Vs ESX on a SSD drive you&lt;br /&gt;can use update manager.&lt;br /&gt;&lt;br /&gt;   b. iscsi boot - Its a rather "flakey" feature. I put some time on this&lt;br /&gt;      there are two problems &lt;br /&gt;          1) Only a select number of iscsi HBA are supported.&lt;br /&gt;          2) It consumes a LUN on your raid for each blade.&lt;br /&gt;   c. If I use SSD, I can even ghost one to another using FOG. &lt;br /&gt;&lt;br /&gt;2. Storage&lt;br /&gt;   My primary storage is a Dell Equal Logic Raid. A PS4000 to be &lt;br /&gt;   exact. &lt;br /&gt;       Leasons: &lt;br /&gt;           a) Get the biggest that will not get you ask to leave :)&lt;br /&gt;              I'm buying my second one, people tend to keep a lot of garbage&lt;br /&gt;           b) Make sure you put the latest firmware on the device Day 1&lt;br /&gt;           c) Be very careful about your storage Design. The EqualLogic&lt;br /&gt;              has great features. Such as overcommit at the LUN level.&lt;br /&gt;              The problem is when the Volume/LUN gets full, its gets marked&lt;br /&gt;              offline. And any VM's in the VMFS associated are pretty much&lt;br /&gt;              dead. So you key servers put in separate LUN's. A DC, and &lt;br /&gt;              exchange for example in my case should be allocated a dedicated volume. Then you dont have to worry that one overcommit takes out all. I would not recommend you do it for everything but some good division can save your bacon.&lt;br /&gt;           d) I would recommend for key servers, Domain Controller,  Exchange, your Vcenter you dont thin provision them. You make sure space&lt;br /&gt;is allocated all the way down. In that way you know there is not a lurking storage outage waiting.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3. Memory - Get lots, 8 x what you need. Blads + Vmware is not cheap, the&lt;br /&gt;reality is vmware on the CPU side is great and pretty good on the memory side as well. What I found on the blades, is I could put 10x more vm's from a cpu point of view, but memory was red-lined. So I could get more value buying more memory than buy cpu's. So when I expand, I'll up my memory from 12G per blade to at least 48G.&lt;br /&gt;&lt;br /&gt;4. Backup - Vreeam Rocks - Make sure you setup jumbo packets, and be a bit &lt;br /&gt;patient on setup to learn the product. But it really works quite well. You need scratch space to dump the backup file. And use Yosemite to write the backup image to the tape library. Make sure the NICs can run jumbo frames it make a big difference, and get you a nice quad port gig-e card or a 10g interface. &lt;br /&gt;&lt;br /&gt;5. What not to buy - Dont use a Dell R200 for anything for a couple of reasons. No Jumbo Frames, and second the CPU is just under powered.&lt;br /&gt;Also it would not leat me use some ESX features, so ended up uses native.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-865601964758088031?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/865601964758088031/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=865601964758088031' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/865601964758088031'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/865601964758088031'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2010/07/vmware-leasons-learned-view-esx-vs-esxi.html' title='Vmware - Leasons Learned - View ESX vs ESXi ISCSI Backup'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-7092692669697326829</id><published>2010-06-11T21:11:00.000-07:00</published><updated>2010-06-11T21:11:52.763-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby gem image'/><title type='text'>Finding Identical and Different Images</title><content type='html'>Its a common problem to have lots of images, and when you do, it even more common to&lt;br /&gt;have lots of duplicates. The problem with images, is they can be the same to the eye, but vastly different at the binary level. Different resolutions, slightly different cropping, but yet at a glance the same. In IT its common to calculate a hash, or magic number that changes radically for slight difference. What more useful in imaging duplication is changing slightly with near identical images.&lt;br /&gt;&lt;br /&gt;This ruby plugin, does exactly that. I'm looking at using in a upcoming project, and will update the article as I go forward. What's even more exciting is the ability to do the same in video.&lt;br /&gt;&lt;br /&gt;http://github.com/mperham/phashion&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-7092692669697326829?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://github.com/mperham/phashion' title='Finding Identical and Different Images'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/7092692669697326829/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=7092692669697326829' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/7092692669697326829'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/7092692669697326829'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2010/06/finding-identical-and-different-images.html' title='Finding Identical and Different Images'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-4511772476874476359</id><published>2010-05-27T01:29:00.000-07:00</published><updated>2010-05-27T01:29:28.894-07:00</updated><title type='text'>Moving thin vm's between datastores on esxi</title><content type='html'>Wow, I wanted to move my vm's from testbed running on esx-i 4.0 to my production servers, which support iscsi. &lt;br /&gt;&lt;br /&gt;The trick is to move them quick, without letting them ballon.&lt;br /&gt;&lt;br /&gt;To do this you have to move the disk images: *.vmdk and the snapshots using&lt;br /&gt;vmkfstools, plus the .vmx file and the .nvram file.&lt;br /&gt;&lt;br /&gt;So as a example:&lt;br /&gt;&lt;br /&gt;The original directory:&lt;br /&gt;/vmfs/volumes/4bbda047-6fa7b452-4280-6cf049e2d29a/sin-fs-1 # ls -l -h&lt;br /&gt;-rw-------    1 root     root        80.0G May 27 01:37 sin-fs-1-flat.vmdk&lt;br /&gt;-rw-------    1 root     root         8.5k May 27 01:37 sin-fs-1.nvram&lt;br /&gt;-rw-------    1 root     root          501 May 26 07:14 sin-fs-1.vmdk&lt;br /&gt;-rw-------    1 root     root            0 Apr 30 10:07 sin-fs-1.vmsd&lt;br /&gt;-rwxr-xr-x    1 root     root         3.2k May 27 01:37 sin-fs-1.vmx&lt;br /&gt;-rw-------    1 root     root          263 May  5 01:33 sin-fs-1.vmxf&lt;br /&gt;-rw-------    1 root     root       600.0G May 27 01:37 sin-fs-1_1-flat.vmdk&lt;br /&gt;-rw-------    1 root     root          504 May 26 07:15 sin-fs-1_1.vmdk&lt;br /&gt;-rw-r--r--    1 root     root       234.7k May 11 09:21 vmware-2.log&lt;br /&gt;-rw-r--r--    1 root     root       135.3k May 12 06:29 vmware-3.log&lt;br /&gt;-rw-r--r--    1 root     root       135.3k May 13 02:55 vmware-4.log&lt;br /&gt;-rw-r--r--    1 root     root       135.3k May 25 04:03 vmware-5.log&lt;br /&gt;-rw-r--r--    1 root     root       132.5k May 25 04:14 vmware-6.log&lt;br /&gt;-rw-r--r--    1 root     root       135.2k May 26 07:07 vmware-7.log&lt;br /&gt;-rw-r--r--    1 root     root       136.5k May 27 01:37 vmware.log&lt;br /&gt;/vmfs/volumes/4bbda047-6fa7b452-4280-6cf049e2d29a/sin-fs-1 # &lt;br /&gt;&lt;br /&gt;Note the disk image is 600G. Its actually a sparse file, that is very "thin". So we only want to copy the data, not the empty space. Also VM can have snapshot disk images, so you also have to copy them.&lt;br /&gt;&lt;br /&gt;So in this case lets first copy the disk images:&lt;br /&gt;&lt;br /&gt;vmkfstools -i /vmfs/volumes/datastore1/sin-fs-1/sin-fs-1.vmdk -d thin sin-fs-1.vmdk&lt;br /&gt;vmkfstools -i /vmfs/volumes/datastore1/sin-fs-1/sin-fs-1_1.vmdk -d thin sin-fs-1_1.vmdk&lt;br /&gt;&lt;br /&gt;Now we copy the vmx files:&lt;br /&gt;cp /vmfs/volumes/datastore1/sin-fs-1/sin-fs-1.vmx .&lt;br /&gt;cp /vmfs/volumes/datastore1/sin-fs-1/sin-fs-1.nvram .&lt;br /&gt;&lt;br /&gt;You can now use the vSphere client datastore browser to import, or import at the command line.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-4511772476874476359?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/4511772476874476359/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=4511772476874476359' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/4511772476874476359'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/4511772476874476359'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2010/05/moving-thin-vms-between-datastores-on.html' title='Moving thin vm&apos;s between datastores on esxi'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-1683969654916010284</id><published>2010-04-15T01:51:00.000-07:00</published><updated>2010-04-15T01:51:00.737-07:00</updated><title type='text'>Reverting a Cisco LAP1142N to Atonomyous Mode</title><content type='html'>Wow, this was fun.&lt;br /&gt;&lt;br /&gt;A friend of mine got in half-a-dozen Cisco AP's, and they all came with the wrong firmware. These are nice, slim flying saucers Wifi AP's with 2 radios supporting&lt;br /&gt;2.4G and 5.0G operation. The focus of the line is to use a controller, my friend&lt;br /&gt;chose to not buy a controller, but to buy autonomous units. &lt;br /&gt;&lt;br /&gt;So when they came in. IOS was missing in action.&lt;br /&gt;&lt;br /&gt;While there are notes on the web to do this, not appeared to work.&lt;br /&gt;&lt;br /&gt;The basics is, to setup a tftp server at a magic address (10.0.0.2),&lt;br /&gt;the ap will boot, setting it self to 10.0.0.1, and check for a default image&lt;br /&gt;based on model. &lt;br /&gt;&lt;br /&gt;Didnt work at all, despite shooting a day.&lt;br /&gt;&lt;br /&gt;I tried several different tftp implementions, including linux tftp, atftpd, and &lt;br /&gt;finally two different ones on windows.&lt;br /&gt;&lt;br /&gt;So after two days of pain, and some inspiration from one of my friends, I figured out&lt;br /&gt;the secret sause.&lt;br /&gt;&lt;br /&gt;1. Press and hold the mode button&lt;br /&gt;2. Let it boot till it notices (You can see the messages if you plug in the cisco cable) It will say the mode button is pressed in the logs&lt;br /&gt;3. It will fail to find the image need and dump you to the bootloader&lt;br /&gt;4. At the bootloader erase the flash - format flash:&lt;br /&gt;5. Reboot&lt;br /&gt;6. set the IP address, network mask, and router, as the instructions are given in the log&lt;br /&gt;7. tftp_init&lt;br /&gt;8. tar -xtract tftp://thefirmwarefilename.tar flash:&lt;br /&gt;&lt;br /&gt;If you mess up start back at 1&lt;br /&gt;&lt;br /&gt;tftp is very sensitive to traffic, and to extra overhead in the server side,&lt;br /&gt;so be careful about switches.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-1683969654916010284?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/1683969654916010284/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=1683969654916010284' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/1683969654916010284'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/1683969654916010284'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2010/04/reverting-cisco-lap1142n-to-atonomyous.html' title='Reverting a Cisco LAP1142N to Atonomyous Mode'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-3904608673015786648</id><published>2010-01-17T17:44:00.000-08:00</published><updated>2010-01-17T18:22:17.631-08:00</updated><title type='text'>Mac Printing - Getting Color to PCL Printers</title><content type='html'>Wow, what a pain. My friend has a couple of Docucentre III printers, and now they&lt;br /&gt;have a quite a few macs in the office. Getting black and white printing is easy.&lt;br /&gt;Just use the generic Black and white driver, and your printing. Now of course they&lt;br /&gt;want to print color. &lt;br /&gt;&lt;br /&gt;So after trying everything I can think I come to find out the standard printing subsystem, which uses Gutenprint. I upgraded to the latest, which is version 5.2.4,&lt;br /&gt;and still no-soap. Just black and white printing. After reading the forums, seems like the generic Gutenprint 5.2.4 cannot print color.&lt;br /&gt;&lt;br /&gt;So the choice is to add the second printing subsystem.&lt;br /&gt;Its called foomatic, plus you need the RIP(RasterImageProcessor) which is a version&lt;br /&gt;of ghostscript, and finally the print driver which is called pxmono.&lt;br /&gt;&lt;br /&gt;For my case I downloaded the following:&lt;br /&gt;foomatic-rip-4.02.211.dmg&lt;br /&gt;gplgs-8.64so-ub.dmg&lt;br /&gt;pxlmono-1.6.dmg&lt;br /&gt;&lt;br /&gt;The url for getting foomatic and gplg is:&lt;br /&gt;http://www.linuxfoundation.org/collaborate/workgroups/openprinting/macosx/foomatic&lt;br /&gt;&lt;br /&gt;The driver you need is pxlcolor, and its contained in pxlmono installer.&lt;br /&gt;http://www.linuxfoundation.org/collaborate/workgroups/openprinting/macosx/pxlmono&lt;br /&gt;&lt;br /&gt;You must install all three, start with the gplgs, which is a shared ghostscript,&lt;br /&gt;followed by foomatic, and finally by pxmono.&lt;br /&gt;&lt;br /&gt;In your printer settings you now will have a printdriver for:&lt;br /&gt;Generic PCL6/PCL XL Printer Foomatic/pxlcolor&lt;br /&gt;&lt;br /&gt;After you added the printer, if it does not print, you must go to the web interface&lt;br /&gt;and change the print-out-mode setting. To do that, you must go to set-printer-options, using http://localhost:631 &lt;br /&gt;&lt;br /&gt;Select your printer, the set printer option tab and change the printout mode from normal-graysacle to normal.&lt;br /&gt;using your&lt;br /&gt;&lt;br /&gt;This will print nicely on docucentre in color, and I suspect most PCL capable printers.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-3904608673015786648?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.linuxfoundation.org/collaborate/workgroups/openprinting/macosx/foomatic' title='Mac Printing - Getting Color to PCL Printers'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/3904608673015786648/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=3904608673015786648' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/3904608673015786648'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/3904608673015786648'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2010/01/mac-printing-getting-color-to-pcl.html' title='Mac Printing - Getting Color to PCL Printers'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-3736152301927192828</id><published>2010-01-10T17:38:00.000-08:00</published><updated>2010-01-10T17:38:44.866-08:00</updated><title type='text'>Finding missing controllers and models</title><content type='html'>Ever get aggravated you didn't create a model or a base controller for your rails app.&lt;br /&gt;I find its a common issue when large changes are afoot. Like when I create dozens&lt;br /&gt;of tables at a sitting. &lt;br /&gt;&lt;br /&gt;For those wondeful times, I've created a rake take that checks my models and controllers, and creates basic versions of the code.&lt;br /&gt;&lt;br /&gt;&lt;pre  style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt; require 'rubygems'  &lt;br /&gt; require 'pp'  &lt;br /&gt; require 'find'  &lt;br /&gt; def controller_exists?(thefilename)  &lt;br /&gt;   Find.find("./app/controllers") do |path|  &lt;br /&gt;      if FileTest.directory?(path)  &lt;br /&gt;       if File.basename(path)[0] == ?.  &lt;br /&gt;         Find.prune  &lt;br /&gt;        else  &lt;br /&gt;         next  &lt;br /&gt;       end  &lt;br /&gt;      else  &lt;br /&gt;       if path.include?(thefilename)  &lt;br /&gt;         return TRUE  &lt;br /&gt;         end  &lt;br /&gt;        end  &lt;br /&gt;      end  &lt;br /&gt;   return FALSE  &lt;br /&gt; end  &lt;br /&gt; namespace :check do  &lt;br /&gt;      desc "Check Model, and create missing ones"  &lt;br /&gt;      task :modelfile =&amp;gt; :environment do  &lt;br /&gt;           pp ActiveRecord::Base.connection.tables  &lt;br /&gt;           ActiveRecord::Base.connection.tables.each do |tname|  &lt;br /&gt;               begin  &lt;br /&gt;                themodel = tname.classify.constantize  &lt;br /&gt;                model_exists = TRUE  &lt;br /&gt;               rescue  &lt;br /&gt;                model_exists = FALSE  &lt;br /&gt;                end  &lt;br /&gt;               case tname  &lt;br /&gt;                when "schema_migrations"  &lt;br /&gt;                   model_exists = TRUE # Special table  &lt;br /&gt;                when "tag_cross_ref"  &lt;br /&gt;                   model_exists = TRUE # Special table  &lt;br /&gt;                end  &lt;br /&gt;            if model_exists == FALSE # Dont exist  &lt;br /&gt;             model_name = tname.classify  &lt;br /&gt;             puts "Missing #{model_name} for table #{tname} - created\n"  &lt;br /&gt;             mfilename = "./app/models/" + tname.singularize + ".rb"  &lt;br /&gt;             if File.exists?(mfilename)  &lt;br /&gt;               puts "#{mfilename} exists - Bad NEWS\n"  &lt;br /&gt;               raise  &lt;br /&gt;               end  &lt;br /&gt;             mfile = open(mfilename,"w")  &lt;br /&gt;             mfile.puts "class #{model_name} &amp;lt; ActiveRecord::Base\n"  &lt;br /&gt;             mfile.puts "end\n"  &lt;br /&gt;             mfile.close  &lt;br /&gt;             else  &lt;br /&gt;             puts "Exists #{model_name}(#{tname})\n"  &lt;br /&gt;             end  &lt;br /&gt;        end  &lt;br /&gt;     end  &lt;br /&gt;  desc "Check Controllers, and create missing ones"  &lt;br /&gt;  task :controllerfile =&amp;gt; :environment do  &lt;br /&gt;           ActiveRecord::Base.connection.tables.each do |tname|  &lt;br /&gt;               controller_file_name = tname.singularize + "_controller.rb"  &lt;br /&gt;               ctl_missing = !controller_exists?(controller_file_name)  &lt;br /&gt;               case tname  &lt;br /&gt;                when "schema_migrations"  &lt;br /&gt;                   ctl_missing = FALSE #Special Table  &lt;br /&gt;                when "tag_cross_ref"  &lt;br /&gt;                   ctl_missing = FALSE # Special table  &lt;br /&gt;                end  &lt;br /&gt;               if ctl_missing  &lt;br /&gt;             controller_name = (tname.singularize + "_controller").camelize  &lt;br /&gt;             puts "Missing #{controller_name} for table #{tname} - created\n"  &lt;br /&gt;             cfilename = "./app/controllers/adminspace/" + controller_file_name  &lt;br /&gt;             if File.exists?(cfilename)  &lt;br /&gt;               puts "#{cfilename} exists - Bad NEWS\n"  &lt;br /&gt;               raise  &lt;br /&gt;               end  &lt;br /&gt;             cfile = open(cfilename,"w")  &lt;br /&gt;             cfile.puts "#generated by checker\n"  &lt;br /&gt;             cfile.puts "class Adminspace::#{controller_name} &amp;lt; ApplicationController\n"  &lt;br /&gt;             cfile.puts "layout 'tier1admin'\n"  &lt;br /&gt;             cfile.puts "before_filter :login_required\n"  &lt;br /&gt;             cfile.puts 'require_role "admin"' + "\n"  &lt;br /&gt;             cfile.puts "\n"  &lt;br /&gt;             cfile.puts "   active_scaffold :#{tname.singularize} do |config|\n"  &lt;br /&gt;             cfile.puts "       config.actions = [:nested, :create, :update, :show, :list, :search]\n"  &lt;br /&gt;             cfile.puts "       end\n"  &lt;br /&gt;             cfile.puts "\n"  &lt;br /&gt;             cfile.puts "end\n"  &lt;br /&gt;             cfile.close  &lt;br /&gt;             else  &lt;br /&gt;             #puts "Exists #{controller_name}(#{tname})\n"  &lt;br /&gt;             end  &lt;br /&gt;        end  &lt;br /&gt;     end  &lt;br /&gt; end  &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-3736152301927192828?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.pastie.org/773072' title='Finding missing controllers and models'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/3736152301927192828/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=3736152301927192828' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/3736152301927192828'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/3736152301927192828'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2010/01/finding-missing-controllers-and-models.html' title='Finding missing controllers and models'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-8095186007257986102</id><published>2009-10-12T17:15:00.000-07:00</published><updated>2009-10-12T18:06:51.334-07:00</updated><title type='text'>Virtual Models and Parsing in Ruby</title><content type='html'>Ever want to process something external to your database or your rails app, such&lt;br /&gt;as the contents of files. But you think rails is only good for database items?&lt;br /&gt;Actually rails can easily adapt to handle any kind of data.&lt;br /&gt;&lt;br /&gt;In these examples, I process all my controllers, to give a view and a RESTful interface&lt;br /&gt;for testing of my controllers. I also do the same for the menus. All without a database &lt;br /&gt;table in sight.&lt;br /&gt;&lt;br /&gt;First, lets take a look at the controllers "model".&lt;br /&gt;&lt;script src='http://pastie.org/652328.js'&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;This allows us to view our controllers from within rails, useful if you want to know what code is running, or&lt;br /&gt;in my case to use watir to test. The lovely part is I can actually RESTfully pull the list of controllers, and make&lt;br /&gt;sure each is hit in watir.&lt;br /&gt;&lt;br /&gt;The next problem is menu's, how do I validate that each menu does something, a little of the same&lt;br /&gt;technique. Here is a bit more advanced, we actually build a parent menu table, and a child menu item table.&lt;br /&gt;&lt;br /&gt;Here is the menu model. The Menu Model actually creates all the child menu items at startup. It does this by &lt;br /&gt;parsing tabnav/widget format menus. While I was looking at a way of using erb to do this for me, I ended up just&lt;br /&gt;doing the parsing myself. &lt;br /&gt;&lt;br /&gt;&lt;script src='http://pastie.org/652332.js'&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;And finally the MenuItem Model&lt;br /&gt;&lt;script src='http://pastie.org/652341.js'&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;After this I do simple activescaffold based controllers, and more importantly add routes so I can pull xml files&lt;br /&gt;for testing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-8095186007257986102?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/8095186007257986102/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=8095186007257986102' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/8095186007257986102'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/8095186007257986102'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2009/10/virtual-models-and-parsing-in-ruby.html' title='Virtual Models and Parsing in Ruby'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-5341935609119933639</id><published>2009-08-21T05:09:00.000-07:00</published><updated>2009-08-21T05:14:20.414-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='activejquery'/><title type='text'>ActiveJquery - Without git</title><content type='html'>If you pull the files, and install them without using rails plugin code, there&lt;br /&gt;is a "install" script that copies things into the right place.&lt;br /&gt;&lt;br /&gt;The file will be in: #{projectroot}/vendor/plugins/activejquery&lt;br /&gt;&lt;br /&gt;So for me, its in the following directory:&lt;br /&gt;/Users/gwest/mymrp2/vendor/plugins/activejquery&lt;br /&gt;&lt;br /&gt;As you can see it, actually copies a few files into the right place in your project.&lt;br /&gt;&lt;br /&gt;directory = File.dirname(__FILE__)&lt;br /&gt;copy_files("/public/css", "/public/css", directory)&lt;br /&gt;copy_files("/public/javascripts", "/public/javascripts", directory)&lt;br /&gt;copy_files("/app/views/activejquery", "/app/views/activejquery", directory)&lt;br /&gt;&lt;br /&gt;I love to help, so if you have questions, feel free to email me. &lt;br /&gt;or if your commenting, please give me your email, as when you comment on the&lt;br /&gt;blog, the system does not give me a email to respond.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-5341935609119933639?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/5341935609119933639/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=5341935609119933639' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/5341935609119933639'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/5341935609119933639'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2009/08/activejquery-without-git.html' title='ActiveJquery - Without git'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-180667117743622293</id><published>2009-06-15T00:22:00.000-07:00</published><updated>2009-06-15T00:45:50.410-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Voice Voip Rails Ruby Call Center'/><title type='text'>Call Center Voice Recording</title><content type='html'>Ever wonder how you do audit in a large call center?&lt;br /&gt;&lt;br /&gt;Here's the basics:&lt;br /&gt;&lt;br /&gt;First, most modern call centers are using Voip. It makes it easy to setup, and even better&lt;br /&gt;makes it easy to monitor. Also call-centers tend to be in places like india, or phillipines&lt;br /&gt;serving the US or Europe markets. So VoIp plays a role in getting the traffic from one&lt;br /&gt;country to another. &lt;br /&gt;&lt;br /&gt;There are several pieces to this puzzle:&lt;br /&gt;&lt;br /&gt;First, you need to capture the raw data:&lt;br /&gt;So to do that, we need a "tee" off the ethernet channel that is connecting to the VoIP gateway.&lt;br /&gt;This will allow us to see all the VoIP IP Traffic that is going back and forth. &lt;br /&gt;&lt;br /&gt; It's sometimes called 'port mirroring', 'port monitoring', 'Roving Analysis' (3Com), or 'Switched Port Analyzer' or 'SPAN' (Cisco).&lt;br /&gt;&lt;br /&gt;http://wiki.wireshark.org/CaptureSetup/Ethernet&lt;br /&gt;http://www.cisco.com/en/US/products/hw/switches/ps708/products_tech_note09186a008015c612.shtml#descp&lt;br /&gt;&lt;br /&gt;Now that we have traffic, a good way to "capture" the voice is Oreka&lt;br /&gt;http://oreka.sourceforge.net/&lt;br /&gt;&lt;br /&gt;Oreka lets you capture the packets, and convert them to audio files. It actually consists&lt;br /&gt;of three parts. &lt;br /&gt;&lt;br /&gt;- OrkAudio: This is the workhorse that processes the calls and does the actual recording&lt;br /&gt;- OrkWeb: This is the XML based Web U/I to access and manage the system&lt;br /&gt;- OrkTrack: This is the master database (MySQL) that records the call records, metadata, etc.&lt;br /&gt;&lt;br /&gt;Oreka lets you get a basic system up quickly.&lt;br /&gt;&lt;br /&gt;The next issue, is setting up a system of audit, and to connect and understand the calls into transactions,&lt;br /&gt;customers, call-agents, and supervisors. &lt;br /&gt;&lt;br /&gt;For a good GUI on top, I'd switch to a Rails App. This lets me do several things:&lt;br /&gt;&lt;br /&gt;1. I can tie agents to calls&lt;br /&gt;2. I can allow agents access to review there own calls&lt;br /&gt;3. I can allow supervisors to view/listen to calls for agents reporting to them&lt;br /&gt;4. I can let audit department audit calls as appriate.&lt;br /&gt;5. Ease of interfacing existing call center apps togeather&lt;br /&gt;&lt;br /&gt;Now that we have a phase 1, and phase 2 completed, lets add a phase 3.&lt;br /&gt;One of the emerging technologies is Speach to text.&lt;br /&gt;Using the latest SDK's from Dragon Speaking, we can get very high 99% plus on our agents,&lt;br /&gt;and not bad recognition on our clients/customers calling in. This will allow audit to search&lt;br /&gt;for key words, such as scam, theft, etc that would audit to be better aware of things going&lt;br /&gt;on.&lt;br /&gt;&lt;br /&gt;The idea way of implementing the whole system is break things down to separate VM's in a VmWare system.&lt;br /&gt;&lt;br /&gt;1. OakCapture - 1 VM per major Trunk (One Per - Multiple DS1, One DS3)&lt;br /&gt;2. OakGui - 1 VM For system - For reference/admin control only&lt;br /&gt;3. Database - In a call center, a Oracle or DB2 may be better suited, depending on the company&lt;br /&gt;4. VoiceCenterManager - A Rails Server using Nginx/Passenger that provides interfaces to agents, supervisors, audit,&lt;br /&gt;                                             and managers. Number of VM determine by staff size&lt;br /&gt;5. Recognition Engines - A separate VM that is running a Ruby Agent tied to a Dragon Speaking SDK allowing speaker dependent and Speaker Independent Speech to text conversion. This allow for the creation of easily searchable as well&lt;br /&gt;as readable results of the calls in text form. Using a rack of blades, and VmWare we can realtime convert all calls to text&lt;br /&gt;index them, and make them searchable.&lt;br /&gt;&lt;br /&gt;Note that each call center is different but leveraging Rails, and Ruby a AGILE and fast solution can be combined that&lt;br /&gt;gives the best in Audit and accountability.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-180667117743622293?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/180667117743622293/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=180667117743622293' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/180667117743622293'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/180667117743622293'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2009/06/call-center-voice-recording.html' title='Call Center Voice Recording'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-8770573540513896458</id><published>2009-06-11T07:43:00.000-07:00</published><updated>2009-06-11T08:04:43.352-07:00</updated><title type='text'>Ghosting NTFS/Windows using Knoxppix</title><content type='html'>I have a USB 1 Gig stick that is on my key ring.&lt;br /&gt;Its really handy, as I have a complete copy of Knoxppix.&lt;br /&gt;Knoxpix is a Linux Distribution designed to boot and run&lt;br /&gt;from CDROM or DVD. It can also run from a handy USB stick.&lt;br /&gt;With the right options it can also in "RAM", which is handly if you want to &lt;br /&gt;run a few parallel operations, and only need one usb stick.&lt;br /&gt;&lt;br /&gt;While you can use clonezilla, if you want something more packaged,&lt;br /&gt;but in a shop that is windows centric, ghosting to a windows server&lt;br /&gt;may make more sense. &lt;br /&gt;&lt;br /&gt;Boot your usb stick, then at the bash shell, mount your server:&lt;br /&gt;&lt;br /&gt;mount -t cifs //server-name/share-name /mnt/cifs -o username=shareuser,password=sharepassword,domain=nixcraft&lt;br /&gt;&lt;br /&gt;On the share, I usually will the have my ntfscloning scripts&lt;br /&gt;&lt;br /&gt;On a dell machine, there is really only one partition that has "data",&lt;br /&gt;&lt;br /&gt;So to the "dobackup" script is very trival.&lt;br /&gt;This takes the OS partition, in most of the environments I was working in this&lt;br /&gt;would have been /dev/sda2 and uses ntfsclone, which takes only the in-use &lt;br /&gt;sectors, compresses them, and put them in a file on the server.&lt;br /&gt;&lt;br /&gt;dobackup script&lt;br /&gt;&lt;br /&gt;echo backup $1 to $2&lt;br /&gt;mkdir $2&lt;br /&gt;ntfsclone -s -o - /dev/$1 | gzip &gt; $2/$1.ntfsclone.gzip&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The reverse, to restore is:&lt;br /&gt;&lt;br /&gt;dorestore script&lt;br /&gt;&lt;br /&gt;echo restore $1 to $2&lt;br /&gt;cd $1&lt;br /&gt;cat $2.ntfsclone.gzip | gunzip - | ntfsclone --restore-image --overwrite /dev/$2 -&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The only other madatory item is the partition table:&lt;br /&gt;&lt;br /&gt;doptablebackup script&lt;br /&gt;&lt;br /&gt;echo partion backup $1 to $2&lt;br /&gt;sfdisk -d /dev/$1 &gt; $2/ptable.doc&lt;br /&gt;dd if=/dev/$1 bs=512 count=1 of=$2/ptable.sector&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;doptablerestore script&lt;br /&gt;&lt;br /&gt;echo partion restore $1 to $2&lt;br /&gt;dd of=/dev/$2 bs=512 count=1 if=$1/ptable.sector&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-8770573540513896458?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/8770573540513896458/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=8770573540513896458' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/8770573540513896458'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/8770573540513896458'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2009/06/ghosting-ntfswindows-using-knoxppix.html' title='Ghosting NTFS/Windows using Knoxppix'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-2106094109423082342</id><published>2009-06-07T22:07:00.000-07:00</published><updated>2009-06-07T22:15:20.198-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='HTML Javascript Rails ActiveJquery'/><title type='text'>Dynamically Generating Javascript using Parameters</title><content type='html'>I love re-using code, and really believe in DRY. &lt;br /&gt;In doing ActiveJquery, I want my grids to be very re-usable.&lt;br /&gt;For one, I need to use multiple grid/sub-grids to handle Rails&lt;br /&gt;relationships, second I need to be able to have multiple grids&lt;br /&gt;in one page. And want to do all of this with the least amount of code.&lt;br /&gt;&lt;br /&gt;In ActiveJquery, the Grid code, is generated on the fly. While it looks like a normal&lt;br /&gt;call, its actually hitting controller code tucked inside the plugin. &lt;br /&gt;&lt;br /&gt;So when we request the javascript code for a particular controller, the ActiveJquery&lt;br /&gt;code generates the appropriate javascript on the fly.&lt;br /&gt;&lt;br /&gt;In doing, the sub-table, I need to have parameters passed in, so I rely on standard&lt;br /&gt;Rails Semantics when handling HTML. &lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;lt;script src=&amp;quot;location.js?subof=Company&amp;amp;div=Company_Location&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This technique lets me generate customized javascript on the fly, making the generator re-usable, and&lt;br /&gt;the grid re-usable any number of times in the same application.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-2106094109423082342?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/2106094109423082342/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=2106094109423082342' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/2106094109423082342'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/2106094109423082342'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2009/06/dynamically-generating-javascript-using.html' title='Dynamically Generating Javascript using Parameters'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-6007170539492902635</id><published>2009-06-06T00:08:00.001-07:00</published><updated>2009-06-06T00:21:50.373-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails activerecord associations'/><title type='text'>Finding ActiveRecord Associations</title><content type='html'>Im working away on ActiveJquery, and the next thing on the list, is to add support for relationships. This gets to be really interesting, because your Inside the box, in a plugin, and you need to know what associations the user has&lt;br /&gt;defined.&lt;br /&gt;&lt;br /&gt;I was scanning the documentation, and looking around for the api to find the information.&lt;br /&gt;&lt;br /&gt;After searching for a while, I discovered railway, a gem for rails that does diagraming of rails models using dot. So grab the gem, and look thru the source. &lt;br /&gt;&lt;br /&gt;So the key to finding associations is:&lt;br /&gt;&lt;br /&gt;@associations = table.reflect_on_all_associations&lt;br /&gt;&lt;br /&gt;This results in:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;@associations=&lt;br /&gt;  [#ActiveRecord::Reflection::AssociationReflection:0x26305cc&lt;br /&gt;    @active_record=&lt;br /&gt;     Company(id: integer, name: string, location_id: integer, created_at: datetime, updated_at: datetime),&lt;br /&gt;    @macro=:has_many,&lt;br /&gt;    @name=:user,&lt;br /&gt;    @options={:extend=&amp;gt;[]}&amp;gt;,&lt;br /&gt;   #&amp;lt;ActiveRecord::Reflection::AssociationReflection:0x262faa0&lt;br /&gt;    @active_record=&lt;br /&gt;     Company(id: integer, name: string, location_id: integer, created_at: datetime, updated_at: datetime),&lt;br /&gt;    @macro=:has_many,&lt;br /&gt;    @name=:location,&lt;br /&gt;    @options={:extend=&amp;gt;[]}&amp;gt;,&lt;br /&gt;   #&amp;lt;ActiveRecord::Reflection::AssociationReflection:0x262f0c8&lt;br /&gt;    @active_record=&lt;br /&gt;     Company(id: integer, name: string, location_id: integer, created_at: datetime, updated_at: datetime),&lt;br /&gt;    @macro=:has_many,&lt;br /&gt;    @name=:division,&lt;br /&gt;    @options={:extend=&amp;gt;[]}&amp;gt;],&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;From my models:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;class Company &amp;lt; ActiveRecord::Base&lt;br /&gt;  has_many :user&lt;br /&gt;  has_many :location&lt;br /&gt;  has_many :division&lt;br /&gt;  &lt;br /&gt;end&lt;br /&gt;class Department &amp;lt; ActiveRecord::Base&lt;br /&gt;      belongs_to :division&lt;br /&gt;end&lt;br /&gt;class Division &amp;lt; ActiveRecord::Base&lt;br /&gt;belongs_to :company&lt;br /&gt;end&lt;br /&gt;class Location &amp;lt; ActiveRecord::Base&lt;br /&gt;end&lt;br /&gt;class User &amp;lt; ActiveRecord::Base&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-6007170539492902635?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/6007170539492902635/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=6007170539492902635' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/6007170539492902635'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/6007170539492902635'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2009/06/finding-activerecord-associations.html' title='Finding ActiveRecord Associations'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-197756361998860592</id><published>2009-05-14T21:30:00.001-07:00</published><updated>2009-05-14T21:30:46.309-07:00</updated><title type='text'>ruby script/plugin git does not work in Rails 2.3.2 and Ruby 1.9</title><content type='html'>&lt;p&gt;Lots of people are scratching there head over why they cannot&lt;br /&gt;install rails plugins using git.&lt;br /&gt;&lt;br /&gt;I'm working with Ruby 1.9.1 and Rails 2.3.2. And git is a pretty natural&lt;br /&gt;for working with version control. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;So I wanted to pull from my own respository, but kept getting &lt;br /&gt;a error on tryping to do the install.&lt;br /&gt;&lt;br /&gt;sin-gwest-laptop:testjq gwest$ ruby script/plugin --verbose install git://github.com/glennswest/activejquery.git &lt;br /&gt;Plugins will be installed using http&lt;br /&gt;Plugin not found: [&amp;quot;git://github.com/glennswest/activejquery.git&amp;quot;]&lt;br /&gt;#&amp;lt;TypeError: can't convert Array into String&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Come to find out, this is a known but as the mkdir_p call has changed its&lt;br /&gt;return parameter in Ruby 1.9 and that messes up the install of git plugins&lt;br /&gt;unless you do the patch&lt;br /&gt;&lt;br /&gt;https://rails.lighthouseapp.com/attachments/90768/plugin_mkdir_p.diff&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-197756361998860592?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/197756361998860592/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=197756361998860592' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/197756361998860592'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/197756361998860592'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2009/05/ruby-scriptplugin-git-does-not-work-in.html' title='ruby script/plugin git does not work in Rails 2.3.2 and Ruby 1.9'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-3703933840959366805</id><published>2009-05-14T19:57:00.001-07:00</published><updated>2009-05-14T19:57:55.044-07:00</updated><title type='text'>ActiveJquery Goes to version .011</title><content type='html'>&lt;p&gt;I've updated ActiveJquery on github to .011&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;That was fun. I thought I'd put the authtoken issue to bed.&lt;br /&gt;On doing test for delete and add, found I still was getting authtoken&lt;br /&gt;issues. So I moved from using editData jqgrid parameters to adding&lt;br /&gt;it to the editurl.&lt;br /&gt;&lt;br /&gt;Also found a bug in the page based xml pull of the controller component.&lt;br /&gt;This would result in you not seeing the last 10 records. (You notice that&lt;br /&gt;when your adding records and they dont show up).&lt;br /&gt;&lt;br /&gt;ActiveJquery consists of:&lt;br /&gt;&lt;br /&gt;1. active_jquery               - The controller plugin&lt;br /&gt;2. active_jquery_runtime - Generates the dynamic jqgrid javascript &lt;br /&gt;3. Dynamic Javascript      - The code that runs in the browser&lt;br /&gt;4. jQuery/Jquery UI/jqGrid&lt;br /&gt;&lt;br /&gt;I've also combined all the needed public css and javascript into the plugin.&lt;br /&gt;&lt;br /&gt;Need to add a rake task and init that makes sure they get copied.&lt;br /&gt;&lt;br /&gt; &lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-3703933840959366805?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/3703933840959366805/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=3703933840959366805' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/3703933840959366805'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/3703933840959366805'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2009/05/activejquery-goes-to-version-011.html' title='ActiveJquery Goes to version .011'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-3549003076896050119</id><published>2009-05-14T02:20:00.001-07:00</published><updated>2009-05-14T02:20:14.695-07:00</updated><title type='text'>ActiveJquery Reaches Version .010</title><content type='html'>&lt;p&gt;ActiveJquery, which is designed to integrate Jqgrid, Jquery UI into rails, is&lt;br /&gt;now at Version 0.010.&lt;br /&gt;&lt;br /&gt;It now is a Rails 2.3.3 Controller Plugin. You can invoke it in a single&lt;br /&gt;line in your controller. &lt;br /&gt;&lt;br /&gt;The plugin automatically generates javascript for the grid, based on your table,&lt;br /&gt;with inline editing. As well as a full REST server to serve the data to the browswer. &lt;br /&gt;&lt;br /&gt;I've implemented the ForgeryProtection on Posts, and that is working. Seems like a bit of comfusion in BLogSpere about weather the URI Components need to be encoded or not. Least in Ruby 1.9.1 and Rails 2.3.2 They do NOT need to be encoded. &lt;br /&gt;&lt;br /&gt;Todo:&lt;br /&gt;1. Allow Customizations&lt;br /&gt;2. Allow Relationships and SubTables&lt;br /&gt;3. JQuery UI Menus&lt;br /&gt;&lt;br /&gt;Test and More TEst&lt;br /&gt;&lt;br /&gt;Also I will implement a rails DEMO app that is based on data from the JQGRID site.&lt;br /&gt;&lt;br /&gt;I'll make a separate git repository for the demo.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-3549003076896050119?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/3549003076896050119/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=3549003076896050119' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/3549003076896050119'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/3549003076896050119'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2009/05/activejquery-reaches-version-010.html' title='ActiveJquery Reaches Version .010'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-5370003914103856451</id><published>2009-04-29T18:58:00.000-07:00</published><updated>2009-04-29T19:10:41.044-07:00</updated><title type='text'>ActiveJquery - Status</title><content type='html'>Current Things That Are Working:&lt;br /&gt;&lt;br /&gt;Controller/Server&lt;br /&gt;1. Can read full table&lt;br /&gt;2. Can read using JqGrid Pager&lt;br /&gt;3. Added Sort support, so server will honor the grid sort request&lt;br /&gt;4. Added Delete,Add and Update support.&lt;br /&gt;5. Auto Generates JqGrid Javascript from ActiveRecord&lt;br /&gt;6 Added Total Records to XML so Pager works properly.&lt;br /&gt;&lt;br /&gt;ActiveJquery Library/Client&lt;br /&gt;1. Added support for string, integer, date.&lt;br /&gt;2. Generates JSON Based Reader compatible with Rails JSON Format&lt;br /&gt;3.  Uses Humanize to handle automatic column names. &lt;br /&gt;4. Uses JqueryUI for theming&lt;br /&gt;5. InLine Edit Support&lt;br /&gt;&lt;br /&gt;Things to Do:&lt;br /&gt;1. Paste Controller code into prepared plugin &lt;br /&gt;2. Add static data support&lt;br /&gt;3. Add a bit of DSL(Domain Specific Language) to allow easy configuration&lt;br /&gt;4. Add Master/Detail Support&lt;br /&gt;5. Add Date Picker Plugin&lt;br /&gt;6. Add Parent Table Dynamic Data Selector&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-5370003914103856451?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/5370003914103856451/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=5370003914103856451' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/5370003914103856451'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/5370003914103856451'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2009/04/activejquery-status.html' title='ActiveJquery - Status'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-923449731917145756</id><published>2009-04-29T18:05:00.000-07:00</published><updated>2009-04-29T18:57:02.023-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='RubyOnRails Rails Ruby Jquery JqueryUI JqGrid REST XML'/><title type='text'>ActiveJquery - Features</title><content type='html'>ActiveJquery is a Rails Plugin that combines the goodness of Jquery, Jquery UI, and JqGrid.&lt;br /&gt;&lt;style type="text/css"&gt;.nobrtable br { display: none }&lt;/style&gt;&lt;br /&gt;&lt;div class="nobrtable"&gt;&lt;br /&gt;&lt;table border="2"&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;th&gt;Feature&lt;/th&gt;&lt;br /&gt;&lt;th&gt;Description&lt;/th&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;REST&lt;/td&gt;&lt;br /&gt;&lt;td&gt;ActiveJquery breaks your GUI into a javascript REST Client, and a Rails based REST JSON Server. This reduces&lt;br /&gt;the overhead of our web app, and gives you better expandability, and better response time&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;DRY&lt;/td&gt;&lt;br /&gt;&lt;td&gt;Tired of repeating yourself, dont. ActiveJquery will find your Field Name, and configure the Grid for you.&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;Customizable&lt;/td&gt;&lt;br /&gt;&lt;td&gt;You can configure grids in countless ways, allowing you easy control over what you want to see.&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;td&gt;MultiGrid&lt;/td&gt;&lt;br /&gt;&lt;td&gt;Need a butch of grids on one page? Not a problem. You can have any number of grids in one page. Each is named automatically for you.&lt;/td&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;Master/Detail&lt;/td&gt;&lt;br /&gt;&lt;td&gt;You Rails Associations are used to generate sub-grids or master-detail views of your data.&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;Theming&lt;/td&gt;&lt;br /&gt;&lt;td&gt;ActiveJquery uses Jquery UI themes, so you can easily customize the look and color scheme of the grid&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;td&gt;Menu's/Tabs&lt;/td&gt;&lt;br /&gt;&lt;td&gt;Want to have a easy to use menu system. ActiveJquery supports JqueryUI tabs, so you can do complex, but&lt;br /&gt;easy to use apps.&lt;/td&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;Dynamic Data&lt;/td&gt;&lt;br /&gt;&lt;td&gt;By default data is read a screenful at a time, using the grid pager. This reduces the need to read large amounts of a big table. Also makes loading multiple grids very fast.&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;Static Data&lt;/td&gt;&lt;br /&gt;&lt;td&gt;ActiveJavascript can embed the table data directly in the javascript. This is great for tables that 1000 rows or less, and are read-only.&lt;/td&gt;&lt;br /&gt;&lt;/table&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-923449731917145756?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/923449731917145756/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=923449731917145756' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/923449731917145756'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/923449731917145756'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2009/04/activejquery-features.html' title='ActiveJquery - Features'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-7308098319759601219</id><published>2009-04-29T04:47:00.000-07:00</published><updated>2009-04-29T18:56:13.254-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='jdgrid'/><title type='text'>Jdgrid Pager Problem</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/__O7-qQKRRFU/Sfg_F9j7F-I/AAAAAAAAAA8/OKV71mTHd50/s1600-h/Picture+3.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 158px;" src="http://1.bp.blogspot.com/__O7-qQKRRFU/Sfg_F9j7F-I/AAAAAAAAAA8/OKV71mTHd50/s320/Picture+3.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5330079530650114018" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Trying out the latest versions of jquery/jquery ui/jqgrid, and just cannot get the formatting right.&lt;br /&gt;&lt;br /&gt;Lets see if we can figure out whats going on.&lt;br /&gt;&lt;br /&gt;The html for the grid:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt;  &amp;lt;title&amp;gt; Airstate &amp;lt;/title&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;&amp;lt;h2&amp;gt; Airstate &amp;lt;/h2&amp;gt;&lt;br /&gt;&amp;lt;script src=&amp;quot;javascripts/jquery-1.3.2.min.js&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script src=&amp;quot;javascripts/jquery-ui-1.7.1.custom.min.js&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script src=&amp;quot;javascripts/jquery.layout.js&amp;quot; text=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script src=&amp;quot;javascripts/jqModal.js&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script src=&amp;quot;javascripts/jqDnR.js&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script src=&amp;quot;javascripts/jquery.jqGrid.js&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;link rel=&amp;quot;stylesheet&amp;quot; type=&amp;quot;text/css&amp;quot; media=&amp;quot;screen&amp;quot; href=&amp;quot;themes/redmond/jquery-ui-1.7.1.custom.css&amp;quot; /&amp;gt;&lt;br /&gt;&amp;lt;link rel=&amp;quot;stylesheet&amp;quot; type=&amp;quot;text/css&amp;quot; media=&amp;quot;screen&amp;quot; href=&amp;quot;themes/ui.jqgrid.css&amp;quot; /&amp;gt;&lt;br /&gt;&amp;lt;style&amp;gt;&lt;br /&gt;html, body {&lt;br /&gt;    margin: 0;            /* Remove body margin/padding */&lt;br /&gt;    padding: 0;&lt;br /&gt;    overflow: hidden;    /* Remove scroll bars on browser window */    &lt;br /&gt;    font-size: 75%;&lt;br /&gt;}&lt;br /&gt;/*Splitter style */&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#LeftPane {&lt;br /&gt;    /* optional, initial splitbar position */&lt;br /&gt;    overflow: auto;&lt;br /&gt;}&lt;br /&gt;/*&lt;br /&gt; * Right-side element of the splitter.&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;#RightPane {&lt;br /&gt;    padding: 2px;&lt;br /&gt;    overflow: auto;&lt;br /&gt;}&lt;br /&gt;.ui-tabs-nav li {position: relative;}&lt;br /&gt;.ui-tabs-selected a span {padding-right: 10px;}&lt;br /&gt;.ui-tabs-close {display: none;position: absolute;top: 3px;right: 0px;z-index: 800;width: 16px;height: 14px;font-size: 10px; font-style: normal;cursor: pointer;}&lt;br /&gt;.ui-tabs-selected .ui-tabs-close {display: block;}&lt;br /&gt;.ui-layout-west .ui-jqgrid tr.jqgrow td { border-bottom: 0px none;}&lt;br /&gt;.ui-datepicker {z-index:1200;}&lt;br /&gt;&amp;lt;/style&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;var listlastsel;jQuery(document).ready(function(){&lt;br /&gt;jQuery(&amp;quot;#list&amp;quot;).jqGrid({&lt;br /&gt;   url:'airstate.xml',&lt;br /&gt;   editurl:'airstate',&lt;br /&gt;   datatype: 'xml', &lt;br /&gt;   mtype: 'GET',&lt;br /&gt;   colNames:['Id','Created on','Whom','Logmessage'],&lt;br /&gt;   colModel :[&lt;br /&gt;      {name: 'id',index:'id',key:true,width:80,align:'right'},&lt;br /&gt;      {name: 'created_on',index:'created_on',key:false,width:90},&lt;br /&gt;      {name: 'whom',index:'whom',key:false,width:300,align:'left',editable:true},&lt;br /&gt;      {name: 'logmessage',index:'logmessage',key:false,width:300,align:'left',editable:true}],&lt;br /&gt;   pager: jQuery('#list-pager'),&lt;br /&gt;   onSelectRow: function(id){&lt;br /&gt;     if(id &amp;amp;&amp;amp; id!==listlastsel){&lt;br /&gt;        jQuery('#list').restoreRow(listlastsel);&lt;br /&gt;        jQuery('#list').editRow(id,true);&lt;br /&gt;         listlastsel=id;&lt;br /&gt;         }&lt;br /&gt;      },&lt;br /&gt;   autowidth: true,&lt;br /&gt;   rowNum:10,&lt;br /&gt;   rowList:[10,20,30],&lt;br /&gt;   sortname: 'id',&lt;br /&gt;   sortorder: &amp;quot;desc&amp;quot;,&lt;br /&gt;   viewrecords: true,&lt;br /&gt;   imgpath: 'themes/basic/images',&lt;br /&gt;   caption: 'Airstate',&lt;br /&gt;   xmlReader: {root: &amp;quot;root&amp;quot;,&lt;br /&gt;                row: &amp;quot;syslog&amp;quot;,&lt;br /&gt;                page:&amp;quot;root&amp;gt;page&amp;quot;,&lt;br /&gt;                total:&amp;quot;root&amp;gt;total&amp;quot;,&lt;br /&gt;                records:&amp;quot;root&amp;gt;records&amp;quot;,&lt;br /&gt;                repeatitems:false&lt;br /&gt;},&lt;br /&gt;  });&lt;br /&gt;jQuery(&amp;quot;#list&amp;quot;).navGrid('#list-pager',{ edit:true,add:true,del:true,search:true });&lt;br /&gt;});&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;div id=&amp;quot;list-pager&amp;quot; class=&amp;quot;scroll&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;table id=&amp;quot;list&amp;quot; class=&amp;quot;scroll&amp;quot;&amp;gt;&amp;lt;/table&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now lets see if we can figure out whats going on.&lt;br /&gt;&lt;br /&gt;Ok, Great support from jdquery. Seems like its a a bug in the latest v2 alfa test.&lt;br /&gt;Alfa 3 should solve the problem.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-7308098319759601219?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/7308098319759601219/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=7308098319759601219' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/7308098319759601219'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/7308098319759601219'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2009/04/trying-out-latest-versions-of.html' title='Jdgrid Pager Problem'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/__O7-qQKRRFU/Sfg_F9j7F-I/AAAAAAAAAA8/OKV71mTHd50/s72-c/Picture+3.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-7916879514738890657</id><published>2009-04-07T05:25:00.000-07:00</published><updated>2009-04-07T05:30:35.131-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby Rails ActiveRecord SQL'/><title type='text'>Getting only the columns you want in Rails</title><content type='html'>A thing that is often missed when your doing a web service or a rails app is selecting only&lt;br /&gt;the columns you need.&lt;br /&gt;&lt;br /&gt;A traditional find:&lt;br /&gt;&lt;br /&gt;user = User.find :all &lt;br /&gt;render :xml =&gt; user.to_xml &lt;br /&gt;&lt;br /&gt;Will give you the bloat of the whole user table. &lt;br /&gt;If you only hae a few small columns then thats not so bad,&lt;br /&gt;but I've seen legacy apps that have very large number of columns,&lt;br /&gt;so it makes since then to control this better.&lt;br /&gt;&lt;br /&gt;user = User.find(:all, :select = 'email') &lt;br /&gt;render :xml =&gt; user&lt;br /&gt;&lt;br /&gt;This also will make your resulting xml file alot more managable.&lt;br /&gt;And since bandwidth is not free, it will help you handle more users&lt;br /&gt;for less money.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-7916879514738890657?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/7916879514738890657/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=7916879514738890657' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/7916879514738890657'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/7916879514738890657'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2009/04/getting-only-columns-you-want-in-rails.html' title='Getting only the columns you want in Rails'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-809803710345998408</id><published>2009-04-07T00:56:00.000-07:00</published><updated>2009-04-07T01:05:15.856-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby windows service network scanning'/><title type='text'>Network Monitor as a Windows Service in Ruby</title><content type='html'>In reading thru the Ruby Google Group, there seems to be a lot of misconceptions about what should be done inside&lt;br /&gt;of a Rails process and what should be done outside it. Generally if it take any time at all, you should be it outside&lt;br /&gt;the Rails Web Server. In windows you can do a Windows Service, in Linux/Unix you would do a daemon.&lt;br /&gt;&lt;br /&gt;This is a example of a windows service that scans cisco switches, finds new nodes, and keep track of there mac&lt;br /&gt;address and there port. Even builds a network map. &lt;br /&gt;&lt;br /&gt;The app consists of a Rails app to display the data, and take in configuration information. Which is put in a database,&lt;br /&gt;such as sqlite3, and updated by this Windows Service. &lt;br /&gt;&lt;br /&gt;As long as the Service is running, the data will be updated. If I was doing it again, I'd use rufus-scheduler to&lt;br /&gt;wrap the scanning and the mapping.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;br /&gt;require 'rubygems'&lt;br /&gt;require 'win32/daemon'&lt;br /&gt;include Win32&lt;br /&gt;require 'logger'&lt;br /&gt;require 'win32/process'&lt;br /&gt;require 'net/ping'&lt;br /&gt;#Note that most of your requires need to go in the service init&lt;br /&gt;&lt;br /&gt;class IPAddr&lt;br /&gt;   def succ()&lt;br /&gt;       return self.clone.set(@addr + 1)&lt;br /&gt;       end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;class AirstateDiscovery&lt;br /&gt;&lt;br /&gt;def doscan()&lt;br /&gt;    ProcessNetworks()&lt;br /&gt;    ProcessDiscovery()&lt;br /&gt;    return&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def ProcessDiscovery()&lt;br /&gt;    Mac.find(:all).each do &amp;#124;mymac&amp;#124;&lt;br /&gt;          mydevice = mymac.device&lt;br /&gt;          if mydevice&lt;br /&gt;             mynet = Network.find_network_by_ip(mymac.ip)&lt;br /&gt;             if mynet #Ok we have a valid network&lt;br /&gt;                Device.find_device_type(mymac.ip,mydevice)&lt;br /&gt;             end&lt;br /&gt;          end&lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def ProcessSwitches()&lt;br /&gt;    Switch.find(:all).each do &amp;#124;myswitch&amp;#124;&lt;br /&gt;            if myswitch.enabled&lt;br /&gt;               if myswitch.switch_type == &amp;quot;cisco&amp;quot;&lt;br /&gt;                     cisco = CiscoSwitch.new(myswitch)&lt;br /&gt;                     #begin&lt;br /&gt;                       cisco.update_macs()&lt;br /&gt;                     #rescue&lt;br /&gt;                     #  end # Rescue&lt;br /&gt;                     cisco = nil&lt;br /&gt;                  end #if myswitch.switch_type == &amp;quot;cisco&amp;quot;&lt;br /&gt;               end # myswitch.enabled&lt;br /&gt;            thegraph = SwitchGraph.new(myswitch)&lt;br /&gt;            thegraph.graph()&lt;br /&gt;            thegraph = nil&lt;br /&gt;            end # find do&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def ProcessNetworks()&lt;br /&gt;  ProcessSwitches()&lt;br /&gt;  return&lt;br /&gt;  &lt;br /&gt;  # Brute Force Scan&lt;br /&gt;    Network.find(:all).each do &amp;#124;mynet&amp;#124;&lt;br /&gt;            ProcessSwitches() # Networks is &amp;quot;long&amp;quot; running, Switch is &amp;quot;fast&amp;quot;&lt;br /&gt;            if mynet.enable&lt;br /&gt;               startip = mynet.ip_start&lt;br /&gt;               endip   = mynet.ip_end&lt;br /&gt;               ip = IPAddr.new(startip)&lt;br /&gt;               while ip.to_s != endip &lt;br /&gt;                  ProcessWmi(mynet,ip.to_s)&lt;br /&gt;                  ip = ip.succ()&lt;br /&gt;                  end&lt;br /&gt;               end&lt;br /&gt;            end&lt;br /&gt;end # def Process Networks&lt;br /&gt;&lt;br /&gt;end # class AirStateDiscovery &lt;br /&gt;   &lt;br /&gt;class Daemon&lt;br /&gt;      def service_init&lt;br /&gt;          end&lt;br /&gt;&lt;br /&gt;      def service_main&lt;br /&gt;     &lt;br /&gt;         require 'ipaddr'&lt;br /&gt;          Dir.chdir(&amp;quot;\\projects\\airstate&amp;quot;)&lt;br /&gt;          require File.dirname(__FILE__) + '/../config/environment.rb'&lt;br /&gt;          require 'lib/cisco_phone'&lt;br /&gt;          require 'lib/managepc'&lt;br /&gt;          require 'lib/switchgraph'&lt;br /&gt;          @mywork = AirstateDiscovery.new&lt;br /&gt;          mylog = Syslog.new&lt;br /&gt;          mylog.whom = &amp;quot;AirStateDiscovery&amp;quot;&lt;br /&gt;          mylog.logmessage = &amp;quot;Discovery Starting&amp;quot;&lt;br /&gt;          mylog.save&lt;br /&gt;         while running?&lt;br /&gt;            @mywork.doscan()&lt;br /&gt;            sleep 3&lt;br /&gt;         end&lt;br /&gt;      end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# Test Code&lt;br /&gt;#          require 'ipaddr'&lt;br /&gt;#          Dir.chdir(&amp;quot;\\projects\\airstate&amp;quot;)&lt;br /&gt;#          require File.dirname(__FILE__) + '/../config/environment.rb'   &lt;br /&gt;#          require 'lib/managepc'&lt;br /&gt;#          require 'lib/cisco'&lt;br /&gt;#          require 'lib/switchgraph'&lt;br /&gt;#          require 'lib/cisco_phone'&lt;br /&gt;#          @mywork = AirstateDiscovery.new&lt;br /&gt;#          while 1&lt;br /&gt;#            @mywork.doscan()&lt;br /&gt;#            end&lt;br /&gt;#          exit&lt;br /&gt;&lt;br /&gt;Daemon.mainloop&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-809803710345998408?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/809803710345998408/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=809803710345998408' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/809803710345998408'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/809803710345998408'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2009/04/network-monitor-as-windows-service-in.html' title='Network Monitor as a Windows Service in Ruby'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-8195826556981371963</id><published>2009-04-05T18:21:00.001-07:00</published><updated>2009-04-05T18:21:31.190-07:00</updated><title type='text'>Rails - Useful Plugins</title><content type='html'>&lt;p&gt;In updating myself I found some really useful Rals plugins for my next project.&lt;br /&gt;&lt;br /&gt;Hoptoad Notifier&lt;br /&gt;A Rails app is a very dynamic thing. Finding out when your users have errors, and what the pattern of errors is a must have. The traditional approach is to view the log files from time to time, or use a notifier that sends the errors to your email. Then go thru it as they come in. First, it not uncommon for a error to repeat. So you get log of junk in your email. A better approach is to use the hoptoad service/plugin. This way, you get nice reporting and analysis, and for a single project, its free. It consists of a hosted site web gui, and a rails plugin, and a optional local mac gui to show your croak's, ie the errors in your apps.&lt;br /&gt;&lt;br /&gt;http://www.hoptoadapp.com/welcome&lt;br /&gt;http://blog.railsrumble.com/2008/10/6/hoptoad&lt;br /&gt;http://github.com/thoughtbot/hoptoad_notifier/tree/master&lt;br /&gt;http://github.com/bricooke/croak-app/tree/master&lt;br /&gt;&lt;br /&gt;Simple Ruby Rest Client&lt;br /&gt;REST is a lovely way of doing Remote Procedure Calls. It the rails way of creating web services. Sometime its handy to have a simple REST-client.&lt;br /&gt;There is a simple to Rest client done by Adam Wiggins &lt;br /&gt;&lt;br /&gt;http://github.com/adamwiggins/rest-client/tree/master&lt;br /&gt;http://rest-client.heroku.com/rdoc/&lt;br /&gt;&lt;br /&gt;Now you can call a REST api even from IRC or rails console&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-8195826556981371963?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/8195826556981371963/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=8195826556981371963' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/8195826556981371963'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/8195826556981371963'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2009/04/rails-useful-plugins.html' title='Rails - Useful Plugins'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-5138429063147338365</id><published>2009-03-21T20:38:00.001-07:00</published><updated>2009-03-21T20:43:27.375-07:00</updated><title type='text'>C Code - Bucket Based Allocator</title><content type='html'>In realtime systems, malloc/free/garbage collection can take a very long time.&lt;br /&gt;&lt;br /&gt;For a real-time system I'm doing, I want to have very fast response time, I call malloc/free often. &lt;br /&gt;Traditional malloc/free will fragment memory quickly, and garbage collection will just take&lt;br /&gt;forever. &lt;br /&gt;&lt;br /&gt;The solution I've used many times is a bucket allocator, setting pre-defined sizes of memory, and putting them in a queue, or in this case a "bucket". The idea being find the bucket, pull out a entry and return it.&lt;br /&gt;&lt;br /&gt;Also something I've found useful is to keep track of busy memory elements as well. That way if I suspect that memory is getting corrupted, I can easily add a tag at the end of the allocation, and run thru the busy memory looking for the corruption. Very useful in debug.&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;#include &amp;quot;include/queue.h&amp;quot;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;struct bucket_struct {&lt;br /&gt;       struct entry_struct entry;&lt;br /&gt;       struct queue_struct free_q;&lt;br /&gt;       struct queue_struct busy_q;&lt;br /&gt;       int    size;&lt;br /&gt;       };&lt;br /&gt;&lt;br /&gt;struct alloc_struct {&lt;br /&gt;       struct entry_struct entry;&lt;br /&gt;       struct bucket_struct *bucket;&lt;br /&gt;       };&lt;br /&gt;&lt;br /&gt;struct queue_struct buckets;&lt;br /&gt;&lt;br /&gt;int gkmalloc_init_needed = 1;&lt;br /&gt;&lt;br /&gt;void gkmalloc_newbucket(thesize)&lt;br /&gt;int thesize;&lt;br /&gt;{&lt;br /&gt;struct bucket_struct *mybucket;&lt;br /&gt;&lt;br /&gt;     mybucket = malloc(sizeof(struct bucket_struct));&lt;br /&gt;     mybucket-&amp;gt;free_q.head = NULL;&lt;br /&gt;     mybucket-&amp;gt;free_q.tail = NULL;&lt;br /&gt;     mybucket-&amp;gt;busy_q.head = NULL;&lt;br /&gt;     mybucket-&amp;gt;busy_q.tail = NULL;&lt;br /&gt;     mybucket-&amp;gt;entry.next = NULL;&lt;br /&gt;     mybucket-&amp;gt;entry.prev = NULL;&lt;br /&gt;     mybucket-&amp;gt;size = thesize;&lt;br /&gt;     queue(&amp;amp;buckets, &amp;amp;mybucket-&amp;gt;entry);&lt;br /&gt;     return;&lt;br /&gt;}    &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;void gkmalloc_init(void)&lt;br /&gt;{&lt;br /&gt;    gkmalloc_init_needed = 0;&lt;br /&gt;    buckets.head = NULL;&lt;br /&gt;    buckets.tail = NULL;&lt;br /&gt;    gkmalloc_newbucket(32);&lt;br /&gt;    gkmalloc_newbucket(64);&lt;br /&gt;    gkmalloc_newbucket(128);&lt;br /&gt;    gkmalloc_newbucket(256);&lt;br /&gt;    gkmalloc_newbucket(512);&lt;br /&gt;    gkmalloc_newbucket(1024);&lt;br /&gt;    gkmalloc_newbucket(2048);&lt;br /&gt;    gkmalloc_newbucket(4096);&lt;br /&gt;    gkmalloc_newbucket(8192);&lt;br /&gt;    gkmalloc_newbucket(32768);&lt;br /&gt;    gkmalloc_newbucket(12000000); // Big Buf for jpegs&lt;br /&gt;    return;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;char *gkmalloc(thesize)&lt;br /&gt;int thesize;&lt;br /&gt;{&lt;br /&gt;struct bucket_struct *mybucket;&lt;br /&gt;struct alloc_struct  *myalloc;&lt;br /&gt;void *ptr;&lt;br /&gt;&lt;br /&gt;     if (thesize == 0)&lt;br /&gt;        return(NULL);&lt;br /&gt;     if (gkmalloc_init_needed){&lt;br /&gt;        gkmalloc_init();&lt;br /&gt;        gkmalloc_init_needed = 0;&lt;br /&gt;        }&lt;br /&gt;     mybucket = (struct bucket_struct *)buckets.head;&lt;br /&gt;     while(mybucket-&amp;gt;size &amp;lt; thesize){&lt;br /&gt;          if (mybucket == NULL){ // Should never happen&lt;br /&gt;              gkfatal(&amp;quot;gkmalloc: Allocation bigger than max bucket&amp;quot;);&lt;br /&gt;              return(NULL);&lt;br /&gt;              }&lt;br /&gt;          mybucket = (struct bucket_struct *)mybucket-&amp;gt;entry.next;&lt;br /&gt;          }&lt;br /&gt;     myalloc = (struct alloc_struct *)unqueue(&amp;amp;mybucket-&amp;gt;free_q);&lt;br /&gt;     if (myalloc == NULL){ // The allocation queue is empty&lt;br /&gt;         // Dynamically allocate from the system&lt;br /&gt;         myalloc = malloc(sizeof(struct alloc_struct) + mybucket-&amp;gt;size);&lt;br /&gt;         if (myalloc == NULL){&lt;br /&gt;            gkfatal(&amp;quot;gkmalloc: Cannot malloc new buffer&amp;quot;);&lt;br /&gt;            return(NULL);&lt;br /&gt;            }&lt;br /&gt;         myalloc-&amp;gt;bucket = mybucket;&lt;br /&gt;         }&lt;br /&gt;           &lt;br /&gt;      queue(&amp;amp;mybucket-&amp;gt;busy_q, &amp;amp;myalloc-&amp;gt;entry);&lt;br /&gt;      ptr = (void *)(myalloc + 1); // Add the size of the header to get Memory After&lt;br /&gt;      return(ptr);&lt;br /&gt;}&lt;br /&gt;       &lt;br /&gt;void gkfree(ptr)&lt;br /&gt;void *ptr;&lt;br /&gt;{&lt;br /&gt;struct bucket_struct *mybucket;&lt;br /&gt;struct alloc_struct  *myalloc;&lt;br /&gt;&lt;br /&gt;      if (ptr == NULL){&lt;br /&gt;         gkfatal(&amp;quot;gkfree: Bad Free - Null Ptr Passed&amp;quot;);&lt;br /&gt;         return;&lt;br /&gt;         }&lt;br /&gt;      myalloc = (struct alloc_struct *)ptr;&lt;br /&gt;      myalloc = myalloc - 1; // Go back to the header info&lt;br /&gt;      mybucket = myalloc-&amp;gt;bucket;&lt;br /&gt;      if (mybucket == NULL){&lt;br /&gt;         gkfatal(&amp;quot;gkfree: Bad Bucket&amp;quot;);&lt;br /&gt;         return;&lt;br /&gt;         }&lt;br /&gt;      queue(&amp;amp;mybucket-&amp;gt;free_q,&amp;amp;myalloc-&amp;gt;entry);&lt;br /&gt;      return;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-5138429063147338365?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/5138429063147338365/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=5138429063147338365' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/5138429063147338365'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/5138429063147338365'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2009/03/c-code-bucket-based-allocator.html' title='C Code - Bucket Based Allocator'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-4005154392350124532</id><published>2009-03-18T19:45:00.001-07:00</published><updated>2009-03-18T19:56:23.607-07:00</updated><title type='text'>C Code - Link List or Queues</title><content type='html'>One of my favorite real-time system tricks is to use queues, or linked-list&lt;br /&gt;to handle message passing. Then the whole system can be lots of small co-routines, without the overhead of task-switching. Small and tight code really can run fast. Usually the problem you get with this is malloc/free overhead.&lt;br /&gt;&lt;br /&gt;A pre-allocated chunk based system solves that. I'll post it to a future blog.&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;## queue.c&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;&lt;br /&gt;#include &amp;quot;include/queue.h&amp;quot;&lt;br /&gt;/*&lt;br /&gt;** Queue.c&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;struct entry_struct *unqueue(q)&lt;br /&gt;struct queue_struct *q;&lt;br /&gt;{&lt;br /&gt;struct entry_struct *entry;&lt;br /&gt;&lt;br /&gt;  if (q==NULL)         return(NULL);&lt;br /&gt;  if (q-&amp;gt;head == NULL) return(NULL);&lt;br /&gt;  entry = q-&amp;gt;head;&lt;br /&gt;  q-&amp;gt;head = entry-&amp;gt;next;&lt;br /&gt;  if (q-&amp;gt;head == NULL) q-&amp;gt;tail = NULL;&lt;br /&gt;  entry-&amp;gt;next = NULL;&lt;br /&gt;  entry-&amp;gt;prev = NULL;&lt;br /&gt;  return(entry);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void queue(q,entry)&lt;br /&gt;struct queue_struct *q; &lt;br /&gt;struct entry_struct *entry;&lt;br /&gt;{&lt;br /&gt;  if (q==NULL) return;&lt;br /&gt;  if (entry == NULL) return;&lt;br /&gt;  entry-&amp;gt;next = NULL;&lt;br /&gt;  entry-&amp;gt;prev = NULL;&lt;br /&gt;  if (q-&amp;gt;head == NULL){&lt;br /&gt;     q-&amp;gt;head = entry;&lt;br /&gt;     q-&amp;gt;tail = entry;&lt;br /&gt;    return;&lt;br /&gt;    }&lt;br /&gt;  entry-&amp;gt;prev = q-&amp;gt;tail;&lt;br /&gt;  q-&amp;gt;tail-&amp;gt;next = entry;&lt;br /&gt;  q-&amp;gt;tail = entry;&lt;br /&gt; return;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;struct queue_struct *init_queue(void)&lt;br /&gt;{&lt;br /&gt;struct queue_struct *q;&lt;br /&gt;&lt;br /&gt;    q = (struct queue_struct *)malloc(sizeof(struct queue_struct *));&lt;br /&gt;        q-&amp;gt;head = NULL;&lt;br /&gt;        q-&amp;gt;tail = NULL;&lt;br /&gt;        return(q);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;## queue.h&lt;br /&gt;/*&lt;br /&gt;** Queue.h&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;struct entry_struct {&lt;br /&gt;       struct entry_struct *next;&lt;br /&gt;       struct entry_struct *prev;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;struct queue_struct {&lt;br /&gt;     struct entry_struct  *head;&lt;br /&gt;     struct entry_struct *tail;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;struct entry_struct *unqueue(struct queue_struct *);&lt;br /&gt;void queue(struct queue_struct *, struct entry_struct *);&lt;br /&gt;struct queue_struct *init_queue(void);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-4005154392350124532?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.pastie.org/420503' title='C Code - Link List or Queues'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/4005154392350124532/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=4005154392350124532' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/4005154392350124532'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/4005154392350124532'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2009/03/c-code-link-list-or-queues.html' title='C Code - Link List or Queues'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-1287409161781273755</id><published>2009-02-25T04:36:00.001-08:00</published><updated>2009-02-25T04:36:05.509-08:00</updated><title type='text'>Scraping Digikey using Ruby and ScRUBYt</title><content type='html'>&lt;p&gt;Sometimes the information you need in your application is already out there on a web site. In a BOM (Bill-of-Materials) app I'm doing, I want to be able&lt;br /&gt;to lookup distributor part numbers from a manufacture part number.&lt;br /&gt;&lt;br /&gt;In this example I use Digikey, as they have the vast majority of parts I use in projects.&lt;br /&gt;&lt;br /&gt;I use Scrubyt, a ruby library, by Peter Szinek, and Glenn Gillen.&lt;br /&gt;It does the heavy lifting.&lt;br /&gt;&lt;br /&gt;The data returned in this example, is in the form of a table. ScRUBYt makes&lt;br /&gt;parsing the table straight forward. You can use firebug in firebird to find your&lt;br /&gt;data if your doing a different website.&lt;br /&gt;&lt;br /&gt; Here is the base code&lt;br /&gt;&lt;br /&gt;require 'rubygems'&lt;br /&gt;require 'scrubyt'&lt;br /&gt;require 'pp'&lt;br /&gt;digikey_data = Scrubyt::Extractor.define do&lt;br /&gt; thepartnumber ='C0805C104K3RACTU'&lt;br /&gt; thesearch = 'http://search.digikey.com/scripts/DkSearch/dksus.dll?&lt;br /&gt;lang=en&amp;amp;site=US&amp;amp;x=0&amp;amp;y=0&amp;amp;keywords=' + thepartnumber&lt;br /&gt; fetch thesearch&lt;br /&gt; table &amp;quot;/html/body/div[2]/table&amp;quot; do&lt;br /&gt; row &amp;quot;//tr&amp;quot; do&lt;br /&gt; dist_pn &amp;quot;/td[1]&amp;quot;&lt;br /&gt; manuf_pn &amp;quot;/td[2]&amp;quot;&lt;br /&gt; pn_description &amp;quot;/td[3]&amp;quot;&lt;br /&gt; pn_oem &amp;quot;/td[5]&amp;quot;&lt;br /&gt; end&lt;br /&gt; end&lt;br /&gt;#&lt;br /&gt;end&lt;br /&gt;part_data = digikey_data.to_flat_hash&lt;br /&gt;pp part_data&lt;br /&gt;&lt;br /&gt;The result:&lt;br /&gt;sin-gwest-laptop:digikey gwest$ ruby digikey.rb&lt;br /&gt;[{:pn_oem=&amp;gt;&amp;quot;Kemet&amp;quot;,&lt;br /&gt; :dist_pn=&amp;gt;&amp;quot;399-1168-2-ND&amp;quot;,&lt;br /&gt; :manuf_pn=&amp;gt;&amp;quot;C0805C104K3RACTU&amp;quot;,&lt;br /&gt; :pn_description=&amp;gt;&amp;quot;CAP .10UF 25V CERAMIC X7R 0805&amp;quot;},&lt;br /&gt; {:pn_oem=&amp;gt;&amp;quot;Kemet&amp;quot;,&lt;br /&gt; :dist_pn=&amp;gt;&amp;quot;399-1168-1-ND&amp;quot;,&lt;br /&gt; :manuf_pn=&amp;gt;&amp;quot;C0805C104K3RACTU&amp;quot;,&lt;br /&gt; :pn_description=&amp;gt;&amp;quot;CAP .10UF 25V CERAMIC X7R 0805&amp;quot;},&lt;br /&gt; {:pn_oem=&amp;gt;&amp;quot;Kemet&amp;quot;,&lt;br /&gt; :dist_pn=&amp;gt;&amp;quot;399-1168-6-ND&amp;quot;,&lt;br /&gt; :manuf_pn=&amp;gt;&amp;quot;C0805C104K3RACTU&amp;quot;,&lt;br /&gt; :pn_description=&amp;gt;&amp;quot;CAP .10UF 25V CERAMIC X7R 0805&amp;quot;}]&lt;br /&gt;sin-gwest-laptop:digikey gwest$      &lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-1287409161781273755?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/1287409161781273755/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=1287409161781273755' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/1287409161781273755'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/1287409161781273755'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2009/02/scraping-digikey-using-ruby-and-scrubyt.html' title='Scraping Digikey using Ruby and ScRUBYt'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-9070756072519691309</id><published>2009-02-19T17:44:00.001-08:00</published><updated>2009-02-19T17:44:10.213-08:00</updated><title type='text'>ActiveScaffold - Example of using Roles for security</title><content type='html'>&lt;p&gt;Recently I was ask for examples of using rolerequirement with activescaffod,&lt;br /&gt;so here is the examples.&lt;br /&gt;&lt;br /&gt;For security, two areas to consider. &lt;br /&gt;&lt;br /&gt;1. Manage what menus appear.&lt;br /&gt;2. Verify access in controllers.&lt;br /&gt;&lt;br /&gt;You can also control what columns appear, and what actions are available as well.  While I have done this all in one controller, to follow DRY, I find that having a adminspace controller, and a userspace controller a bit cleaner. &lt;br /&gt;&lt;br /&gt;Note if you want to configure activescaffold dynamically, AS does some caching, and you need to specifically reconfigure AS each time, to make sure&lt;br /&gt;of cache consistency. &lt;br /&gt;&lt;br /&gt;For menus, I use widgets/tabnav&lt;br /&gt;&lt;br /&gt;&amp;lt;% &lt;br /&gt;# this partial renders a tabnav, you can call it in your views with:&lt;br /&gt;# &amp;lt;%= tabnav :admin % &amp;gt; (just the tabnav) &lt;br /&gt;# or, if you want a boxed tabnav:&lt;br /&gt;# &amp;lt;% tabnav :admin do % &amp;gt;&lt;br /&gt;# your html here&lt;br /&gt;# &amp;lt;% end % &amp;gt;&lt;br /&gt;# (remove the space between % and &amp;gt;, we don't want to mess up your brand new tabnav :-))&lt;br /&gt;#&lt;br /&gt;# you can pass render_tabnav a few options:&lt;br /&gt;# :generate_css =&amp;gt; true|false #=&amp;gt; generates a default inline css for the tabnav, defaults to false&lt;br /&gt;# :html =&amp;gt; aHash #=&amp;gt; sets html options for the tabnav's div (es :html =&amp;gt; {:class=&amp;gt; 'myCssClass', :id=&amp;gt;'myCssId'}) &lt;br /&gt;# &lt;br /&gt;render_tabnav :admin, &lt;br /&gt; :generate_css =&amp;gt; true do &lt;br /&gt; if @current_user.has_role?('admin')&lt;br /&gt; add_tab do |t|&lt;br /&gt; t.named 'Admin'&lt;br /&gt; t.titled 'Administration'&lt;br /&gt; t.links_to :controller =&amp;gt; 'adminspace/admin'&lt;br /&gt; end &lt;br /&gt; add_tab do |t|&lt;br /&gt; t.named 'Users'&lt;br /&gt; t.titled 'Users'&lt;br /&gt; t.links_to :controller =&amp;gt; 'adminspace/user'&lt;br /&gt; end &lt;br /&gt; add_tab do |t|&lt;br /&gt; t.named 'Roles'&lt;br /&gt; t.titled 'Roles'&lt;br /&gt; t.links_to :controller =&amp;gt; 'adminspace/role'&lt;br /&gt; end&lt;br /&gt; end&lt;br /&gt; end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2. For the controllers:&lt;br /&gt;&lt;br /&gt;class Adminspace::AdminController &amp;lt; ApplicationController&lt;br /&gt; layout 'tier2admin'&lt;br /&gt; before_filter :login_required&lt;br /&gt; require_role &amp;quot;admin&amp;quot;&lt;br /&gt;# &lt;br /&gt;# Generated by GenRails&lt;br /&gt;# &lt;br /&gt; &lt;br /&gt;active_scaffold :Logmsg do |config|&lt;br /&gt; config.label = 'AdminMessages'&lt;br /&gt; config.actions = [:search, :show, :list]&lt;br /&gt; end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-9070756072519691309?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/9070756072519691309/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=9070756072519691309' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/9070756072519691309'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/9070756072519691309'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2009/02/activescaffold-example-of-using-roles.html' title='ActiveScaffold - Example of using Roles for security'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-3175352871863626771</id><published>2009-02-08T00:28:00.001-08:00</published><updated>2009-02-08T00:28:37.011-08:00</updated><title type='text'>Converting a rails app to db2</title><content type='html'>&lt;p&gt;DB2 has a long history, having ran on IBM mainframes, and mid-range for decades. Now it easy to move your rails app using it.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The lovely thing about the latest version 9.5 DB2 is that you can use&lt;br /&gt;it for free, if your using the DB2-ExpressC version. It has most all the features you will need, and the database size is not limited. You can add support, or add-ons easily.&lt;br /&gt;&lt;br /&gt;The issue you will have, if you have a existing rails app, is moving your data from mysql, or other rails database into db2.&lt;br /&gt;&lt;br /&gt;The idea solution for this is a rails plugin, called YamlDb.&lt;br /&gt;&lt;br /&gt;In Rails 2.1 its as easy as:&lt;br /&gt;script/plugin install git://github.com/adamwiggins/yaml_db.git&lt;br /&gt;&lt;br /&gt;rake db:data:dump&lt;br /&gt;rake db:schema:dump&lt;br /&gt;&lt;br /&gt;then update your database config file to point to db2:&lt;br /&gt;&lt;br /&gt;development:&lt;br /&gt; adapter: ibm_db&lt;br /&gt; database: baseapp&lt;br /&gt; username: gwest&lt;br /&gt; password: xxxxxxxx&lt;br /&gt;&lt;br /&gt;The rake db:create does not work in db2, so:&lt;br /&gt;db2 create database baseapp&lt;br /&gt;&lt;br /&gt;Then:&lt;br /&gt;rake db:schema:load&lt;br /&gt;rake db:data:load&lt;br /&gt;&lt;br /&gt;And your ready to go.&lt;br /&gt;&lt;br /&gt;Not that database names can only be 8 characters, and underlines and spaces may cause you problems. Otherwise, its painless.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-3175352871863626771?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/3175352871863626771/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=3175352871863626771' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/3175352871863626771'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/3175352871863626771'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2009/02/converting-rails-app-to-db2.html' title='Converting a rails app to db2'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-7255647210032744242</id><published>2009-02-01T19:27:00.001-08:00</published><updated>2009-02-01T19:27:30.168-08:00</updated><title type='text'>Mac DBI - dbi binary will not list gem drivers but will work</title><content type='html'>&lt;p&gt;Thanks to the creator of DBI, I found out that if you install gem based dbi drivers, that the dbi command will not list them, but they will work properly in your ruby code.&lt;br /&gt;&lt;br /&gt;So to list tables in our sqlite3 development database.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;require 'rubygems'&lt;br /&gt;gem 'dbi'&lt;br /&gt;require 'dbi'&lt;br /&gt;require 'pp'&lt;br /&gt;&lt;br /&gt;# Assume dbd-sqlite3 is installed&lt;br /&gt;# sudo gem install dbd-sqlite3&lt;br /&gt;# Assumes we are in our project directory&lt;br /&gt;&lt;br /&gt;fromdb = DBI.connect('dbi:SQLite3:db/development.sqlite3', nil, nil)&lt;br /&gt;&lt;br /&gt;tables = fromdb.tables&lt;br /&gt;tables.each { |tablename|&lt;br /&gt; pp tablename&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;I tend to use DBI in migrating from foreign environments into a rails app.&lt;br /&gt;I also use DBI to write automatic generators for controllers, models, and &lt;br /&gt;menus. It really makes getting going on a legacy app very fast.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-7255647210032744242?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/7255647210032744242/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=7255647210032744242' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/7255647210032744242'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/7255647210032744242'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2009/02/mac-dbi-dbi-binary-will-not-list-gem.html' title='Mac DBI - dbi binary will not list gem drivers but will work'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-3736489501795507422</id><published>2009-01-25T02:08:00.000-08:00</published><updated>2009-01-25T02:19:24.787-08:00</updated><title type='text'>Ruby DBI does find DBD drivers on Mac when using Gem</title><content type='html'>I found a very nice problem when trying to use DBI on a mac, with the sqlite3 driver&lt;br /&gt;I've been a avid your of dbi, which is a direct database API in Ruby, that allow&lt;br /&gt;low level access to databases.&lt;br /&gt;&lt;br /&gt;I've used it on Linux, and Windows against Oracle extensively, and several other databases.&lt;br /&gt;&lt;br /&gt;So expected it to work the same. Seems like I hit a small problem in that oh.&lt;br /&gt;&lt;br /&gt;My script was telling me no driver. When I ran the dbi command, it showed there was no drivers.&lt;br /&gt;If I used irb, and did a DBI.drivers_available, it told me none.&lt;br /&gt;&lt;br /&gt;First, a quick review of the installed gems:&lt;br /&gt;&lt;br /&gt;sh-3.2# gem list&lt;br /&gt;&lt;br /&gt;*** LOCAL GEMS ***&lt;br /&gt;&lt;br /&gt;actionmailer (2.2.2)&lt;br /&gt;actionpack (2.2.2)&lt;br /&gt;activerecord (2.2.2)&lt;br /&gt;activeresource (2.2.2)&lt;br /&gt;activesupport (2.2.2)&lt;br /&gt;dbd-sqlite3 (1.2.4)&lt;br /&gt;dbi (0.4.1)&lt;br /&gt;deprecated (2.0.1)&lt;br /&gt;gem_plugin (0.2.3)&lt;br /&gt;hpricot (0.6.164)&lt;br /&gt;mechanize (0.9.0)&lt;br /&gt;nokogiri (1.1.1)&lt;br /&gt;rails (2.2.2)&lt;br /&gt;rake (0.8.3)&lt;br /&gt;scrubyt (0.4.06)&lt;br /&gt;sqlite3-ruby (1.2.4)&lt;br /&gt;wxruby (1.9.9)&lt;br /&gt;&lt;br /&gt;Yep, Its there, everything looks ok.&lt;br /&gt;&lt;br /&gt;Now lets track down the source to find out what is going on.&lt;br /&gt;# Returns a list (of String) of the currently available drivers on your system in&lt;br /&gt;        # 'dbi:driver:' format.&lt;br /&gt;        #&lt;br /&gt;        # This currently does not work for rubygems installations, please see&lt;br /&gt;        # DBI.collect_drivers for reasons.&lt;br /&gt;        def available_drivers&lt;br /&gt;            drivers = []&lt;br /&gt;            collect_drivers.each do |key, value|&lt;br /&gt;                drivers.push("dbi:#{key}:")&lt;br /&gt;            end&lt;br /&gt;            return drivers&lt;br /&gt;        end&lt;br /&gt;That looks ok.&lt;br /&gt;&lt;br /&gt;Lets go and see what collect_drivers()&lt;br /&gt; #&lt;br /&gt;        # Return a list (of String) of the available drivers.&lt;br /&gt;        #&lt;br /&gt;        # NOTE:: This is non-functional for gem installations, due to the&lt;br /&gt;        #        nature of how it currently works. A better solution for&lt;br /&gt;        #        this will be provided in DBI 0.6.0.&lt;br /&gt;        def collect_drivers&lt;br /&gt;            drivers = { }&lt;br /&gt;            # FIXME rewrite this to leverage require and be more intelligent&lt;br /&gt;            path = File.join(File.dirname(__FILE__), "dbd", "*.rb")&lt;br /&gt;            Dir[path].each do |f|&lt;br /&gt;                if File.file?(f)&lt;br /&gt;                    driver = File.basename(f, ".rb")&lt;br /&gt;                    drivers[driver] = f&lt;br /&gt;                end&lt;br /&gt;            end&lt;br /&gt;&lt;br /&gt;Ok, the FIXME gives us the clue.&lt;br /&gt;Looks like it does not bother to search thru rubygems.&lt;br /&gt;You must manually copy the dbd drivers into dbi.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The Solution:&lt;br /&gt;Copy the drivers into the dbi gem.&lt;br /&gt;cd /opt/local/lib/ruby/gems/1.8/gems/dbi-0.4.1/lib&lt;br /&gt;cp -r ../../dbd-sqlite3-1.2.4/lib/dbd dbd&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-3736489501795507422?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/3736489501795507422/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=3736489501795507422' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/3736489501795507422'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/3736489501795507422'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2009/01/ruby-dbi-does-find-dbd-drivers-on-mac.html' title='Ruby DBI does find DBD drivers on Mac when using Gem'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-8763020266679635733</id><published>2009-01-24T17:37:00.001-08:00</published><updated>2009-01-24T17:38:24.312-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rubyonrails rails ror Authentication'/><title type='text'>A Review of Authentication and Access Control for Ruby On Rails</title><content type='html'>A review of Authentication and Access Control for Ruby On Rails&lt;br /&gt;&lt;br /&gt;Previous Articles That Are Related&lt;br /&gt;http://mentalpagingspace.blogspot.com/2007/11/getting-started-faster-in-rails.html&lt;br /&gt;http://mentalpagingspace.blogspot.com/2008/12/rails-to-windows-integration-single.html&lt;br /&gt;&lt;br /&gt;First, to give some context, when building Rails apps, its common practice to use&lt;br /&gt;a common set of plugins. In "EDGE" rails, there is even a template system so that&lt;br /&gt;when you create a rails apps, it can load your standard plugins. &lt;br /&gt;&lt;br /&gt;For my basic set, I use the following:&lt;br /&gt;&lt;br /&gt;My base set is:&lt;br /&gt;ActsAsAuthenticated (Login)&lt;br /&gt;http://www.railslodge.com/plugins/1-acts-as-authenticated&lt;br /&gt;RestfulAuthentication (The Replacement for the above)&lt;br /&gt;http://github.com/technoweenie/restful-authentication/tree/master&lt;br /&gt;RoleRequirement (Access Control in controllers and menus)&lt;br /&gt;http://code.google.com/p/rolerequirement/&lt;br /&gt;Tabnav/Widgets (Menus)&lt;br /&gt;http://wiki.github.com/paolodona/rails-widgets&lt;br /&gt;ActiveScaffold (Controller/View for CRUD)&lt;br /&gt;http://activescaffold.com/&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In rails there are "two" different problems, first there is authentication, then there is access control.&lt;br /&gt;&lt;br /&gt;Authentication is:&lt;br /&gt;1. How do we login to the app&lt;br /&gt;2. User Model&lt;br /&gt;   a. User Name&lt;br /&gt;   b. Email Address&lt;br /&gt;3. What Access do we have? (Roles)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Do do the heavy lifting for this, we use a plugin&lt;br /&gt;&lt;br /&gt;There are several different plugs for authentication:&lt;br /&gt;1. ActsAsAuthenticated (The original)&lt;br /&gt;3. RestfulAuthentication (The new "standard")&lt;br /&gt;2. OpenId&lt;br /&gt;3. NTLM (Use this when your app is only in a ActiveDirectory environment)&lt;br /&gt;&lt;br /&gt;So once your logged in, using one of the above, we ad the rolerequirement plugin.&lt;br /&gt;&lt;br /&gt;I find RoleRequirement handles my access control very nicely. It enhances your user model, with the ability to have&lt;br /&gt;multiple role. You can then use the "role" to verify in your menus and controllers if a user can perform or use&lt;br /&gt;certain actions. &lt;br /&gt;&lt;br /&gt;If you look at rolerequirement, in your code, you can do something like the following:&lt;br /&gt;&lt;br /&gt;class Adminspace::AdminController &lt; ApplicationController&lt;br /&gt;  before_filter :login_required&lt;br /&gt;  require_role "admin"&lt;br /&gt;  &lt;br /&gt; layout 'basic'  &lt;br /&gt;  def index&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;Notice the require_role above.&lt;br /&gt;When you setup rolerequirement, You can login to your app, and add additional roles.&lt;br /&gt;You can also add a migration to add these roles. (Useful in a empty database setting.&lt;br /&gt;&lt;br /&gt;Also notice the before filter. This makes sure the user is logged in.&lt;br /&gt;&lt;br /&gt;The next issue you will get is, updating menus on the fly.&lt;br /&gt;I use tabnav typically for my menus.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So in order to make menus come and go based on roles, you can check roles in tabnav.&lt;br /&gt;&lt;br /&gt;&lt;%  &lt;br /&gt;# this partial renders a tabnav    &lt;br /&gt;render_tabnav :aircenter, &lt;br /&gt;              :generate_css =&gt; true do &lt;br /&gt; &lt;br /&gt;  add_tab do |t|&lt;br /&gt;    t.named 'ReqCenter'&lt;br /&gt;    t.titled 'ReqCenter'&lt;br /&gt;    t.links_to :controller =&gt; '/reqcenter'&lt;br /&gt;   end &lt;br /&gt;  if @current_user.has_role?('admin')&lt;br /&gt;   add_tab do |t|&lt;br /&gt;    t.named 'Admin'&lt;br /&gt;    t.titled 'admin'&lt;br /&gt;    t.links_to :controller =&gt; 'adminspace/admin'&lt;br /&gt;   end &lt;br /&gt;   end&lt;br /&gt;  add_tab do |t|&lt;br /&gt;    t.named 'Requests'&lt;br /&gt;    t.titled 'Requests'&lt;br /&gt;    t.links_to :controller =&gt; 'requestspace/requesthome'&lt;br /&gt;   end &lt;br /&gt;  add_tab do |t|&lt;br /&gt;    t.named 'Logout'&lt;br /&gt;    t.titled 'Logout'&lt;br /&gt;    t.links_to :controller =&gt; 'adminspace/account', :action =&gt; 'logout'&lt;br /&gt;   end &lt;br /&gt;end &lt;br /&gt;%&gt;&lt;br /&gt;&lt;br /&gt;A example of a Admin CRUD, using ActiveScaffold:&lt;br /&gt;&lt;br /&gt;class Adminspace::UserController &lt; ApplicationController&lt;br /&gt;  layout 'tier1admin'&lt;br /&gt;  before_filter :login_required&lt;br /&gt;  require_role "admin"&lt;br /&gt;  &lt;br /&gt;  active_scaffold :users do |config|&lt;br /&gt;    config.list.columns = [:id,:display_name,:businessunit,:department,:location]&lt;br /&gt;    config.columns[:businessunit].ui_type = :select&lt;br /&gt;    config.columns[:location].ui_type = :select&lt;br /&gt;    config.columns[:department].ui_type = :select&lt;br /&gt;    config.columns[:roles].ui_type = :select&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;So now, using namespaces, we can have a admin controller, with a role of admin for access, that allows the admin&lt;br /&gt;to change anything in all users, and another controller, that allows only the user to change his own fields.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-8763020266679635733?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/8763020266679635733/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=8763020266679635733' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/8763020266679635733'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/8763020266679635733'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2009/01/review-of-authentication-and-access.html' title='A Review of Authentication and Access Control for Ruby On Rails'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-8050188017443219499</id><published>2009-01-19T05:33:00.000-08:00</published><updated>2009-01-19T05:48:59.488-08:00</updated><title type='text'>Rails verse Microsoft Access</title><content type='html'>Like everyone with significant Microsoft experience I've done some Access Applications.&lt;br /&gt;The reality is, I'd prefer to do it in Rails. Ruby on Rails let me gain the power of using&lt;br /&gt;any ruby gem or rails plug-in. I have access to practically every database in Rails.&lt;br /&gt;And I have access to nice Menus as well. Plus the ability to define a web api,&lt;br /&gt;using REST. &lt;br /&gt;&lt;br /&gt;For me, for a small app, I can host it as a windows service directly on Windows with Mongrel. I can&lt;br /&gt;use single sign-on, so if your in the domain, your automatically authenticated. Using role-requirement,&lt;br /&gt;I can define user roles, and even have dynamic menus.&lt;br /&gt;&lt;br /&gt;Even better I can use PRAWN or Pdf::Writer to directly generate reports. Or Scruby to scrape web pages.&lt;br /&gt;And Add to the Data on the fly.&lt;br /&gt;&lt;br /&gt;The other thing I've seen with Access applications, it too easy to get the file locked by one user, and&lt;br /&gt;no one else able to access it. Scaling on Rails is Easy compared to Access. And on top of all of this is&lt;br /&gt;easy cross platform functionality. &lt;br /&gt;&lt;br /&gt;The nice thing is that the language of Rails is Ruby. And Ruby is significantly easier and faster to develop on than VBA.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-8050188017443219499?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/8050188017443219499/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=8050188017443219499' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/8050188017443219499'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/8050188017443219499'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2009/01/rails-verse-microsoft-access.html' title='Rails verse Microsoft Access'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-4995816838112529906</id><published>2009-01-15T22:21:00.000-08:00</published><updated>2009-01-15T22:37:42.945-08:00</updated><title type='text'>Windows 7 - The Bleeding Edge</title><content type='html'>Well I finally bit the bullet. While I had tried vista on my work laptop, and after sweeting it for 3 months, went back to xp.&lt;br /&gt;Microsoft Windows 7 seemed to be the answer to what I was looking for. &lt;br /&gt;&lt;br /&gt;So I finally decided to use the Beta on my main gaming machine. My main work machine is a MAC.&lt;br /&gt;&lt;br /&gt;First, Lets see how well the beta behaves. So I created a new VM on my Mac, and did the install from the ISO.&lt;br /&gt;Wow, it went smooth and easy. Very fast install compared to XP. And so much better than Vista.&lt;br /&gt;&lt;br /&gt;So after playing a bit with that, I decided that my gaming machine needs a cleanup. So its  a great time to&lt;br /&gt;give Windows 7 a try. In my house I currently support 2 desktop for my kids under Vista, another of the same desktop for my wife, and a desktop for myself, plus a laptop. I've migrated most things to my MAC. &lt;br /&gt;&lt;br /&gt;For me on the Gaming Machine, WOW is very important. Vista generally left something to be desired on Gaming performance.&lt;br /&gt;So Windows 7, I thought there was hope. &lt;br /&gt;&lt;br /&gt;So first making sure that I had copies of everything, I decided to do a "new" install without formating the disk. &lt;br /&gt;(Not something I generally like doing by the way). Windows 7, renamed the windows folder, and moved the Document and Users, as well as the Program files under the Windows.old. I like that implementation. I then went into the Windows.old, and dragged the documents folder back to the Windows 7 location. Wow, it noticed and put the photos in the right place.&lt;br /&gt;&lt;br /&gt;I then turned on my Pixma 5000 USB printer, and Windows 7, went out and grabbed the right printer driver and installed that as well. Nice.&lt;br /&gt;&lt;br /&gt;Now to do a first go/no-go test. I sent a shortcut from my WOW.exe to the desktop. And ran it. It worked right out of the box.&lt;br /&gt;WOW client is actually very good at copy and go. And with Windows 7 it was no different. Good job Microsoft. I'll do some detailed testing tonight, but so far the performance and drivers look good&lt;br /&gt;&lt;br /&gt;Now lets move on and try a older version of office. Installed was clean.&lt;br /&gt;And to my shock, the old version of Office was FAST. Now that is a improvement.&lt;br /&gt;&lt;br /&gt;So I'll update the post over the next few days. I really want to try some of the new VM offerings from VMware,&lt;br /&gt;and Microsoft.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-4995816838112529906?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/4995816838112529906/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=4995816838112529906' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/4995816838112529906'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/4995816838112529906'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2009/01/windows-7-bleeding-edge.html' title='Windows 7 - The Bleeding Edge'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-5563829811321485160</id><published>2009-01-08T22:46:00.000-08:00</published><updated>2009-01-08T22:58:02.351-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Rails user authentication'/><title type='text'>And Max ask how to find the user name? (Automatic Logon)</title><content type='html'>This answer varies depending on if you doing linux or windows. &lt;br /&gt;The key is NTLM. If the client is coming from the local net, and part of a domain,&lt;br /&gt;you can use NTLM based login, this is also know as Integrated Windows Authentication.&lt;br /&gt;&lt;br /&gt;If you using NTLM to automatically logon, there is a nice plugin you can using with&lt;br /&gt;mongrel on windows. &lt;br /&gt;&lt;br /&gt;See my post &lt;br /&gt;http://mentalpagingspace.blogspot.com/2008/12/rails-to-windows-integration-single.html&lt;br /&gt;&lt;br /&gt;This is idea for light-duty applications hosted on a windows machine or vm. I use this when my&lt;br /&gt;application needs to make WMI or other windows specific calls. Your application login&lt;br /&gt;is automatic if the user is coming from the local network and part of a domain. The mongrel&lt;br /&gt;can run as a service that auto starts at boot time.&lt;br /&gt;&lt;br /&gt;In Linux you can also do the same trick, there is a apache plugin to allow you to use NTLM.&lt;br /&gt;Since I've seen apache articles on using NTLM in a domain, then I'll leave those to the reader.&lt;br /&gt;&lt;br /&gt;And as a note, I prefer LINUX for applications that do not need significant usage of Window API.&lt;br /&gt;Its faster and more stable than running it on XP. My fav at the moment is to use Passenger to manage &lt;br /&gt;linux hosting of Rails&lt;br /&gt;&lt;br /&gt;On the other hand, If you have a app a handful of people are going to use sporadically, which&lt;br /&gt;is common in the enterprise. A XP based Implementation has been problem free for me.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-5563829811321485160?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://en.wikipedia.org/wiki/Integrated_Windows_Authentication' title='And Max ask how to find the user name? (Automatic Logon)'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/5563829811321485160/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=5563829811321485160' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/5563829811321485160'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/5563829811321485160'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2009/01/and-max-ask-how-to-find-user-name.html' title='And Max ask how to find the user name? (Automatic Logon)'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-3813562011846420447</id><published>2008-12-30T04:19:00.001-08:00</published><updated>2008-12-30T04:57:33.132-08:00</updated><title type='text'>Virtual Manufacturing Control - VmWare To the Factory Floor</title><content type='html'>In the industry, VmWare has taken over the Data Center. Server Consolidation has been going on for a while. Multiple servers&lt;br /&gt;that used to run on dedicated hardware, are now Virtual Machines, multiple setting on one rack or blade server. Its not uncommon to see 10's to 100's of virtual server running on one physical server. This has resulted in great cost saving, easy upgrades, easier provisioning, and a reduction of power consumption. This technology is proven, and works. &lt;br /&gt;&lt;br /&gt;To give you a example, before VmWare, it would take a week to get a quote, get the approvals for purchase, then another week for delivery, and then a day to set it up, install the OS, and then your ready to start thinking about putting a application on the server. You also had to worry about backup, and KVM (Keyboard and monitor switching). &lt;br /&gt;&lt;br /&gt;With VmWare, I log into VmCenter, create a new Virtual machine, selecting how much memory and CPU I need, and pointing it to a ISO image of the OS. And Say Go. The new machine "boots" up, and starts installing the OS. Since a Dell Blade, or 1U server could support upwards of 32 machine, the physical act of buying hardware is reduced significantly. The reality is, most servers are under-utilized, and VmWare lets us use these otherwise wasted resources better.&lt;br /&gt;&lt;br /&gt;Another layer of this puzzle is high-availability. We really dont want our applications to go down. It doent matter if its a DHCP server, or a Oracle Database, being up means people are working, and having a hardware issue can really spoil your day when you manage 100's of servers, and almost as many applications. The answer to this is has a few components.&lt;br /&gt;&lt;br /&gt;First, we break the Storage component using iSCSI into a separate device. The RAID is now a external device we talk to over TCP/IP using SCSI over our ethernet connections. With 10Gig Ethernet, and hardware based switching, IP is the fastest SAN. Most blade give us 4 1-Gig links which allows 512Megabytes a second of capacity for getting data in and out. This concept means our blades or rack based servers now have no disk locally. &lt;br /&gt;&lt;br /&gt;This separation means we can now migrate any virtual machine into any physical cpu, using what VmWare calls vMotion. So if you want to pull a blade server, and replace memory, or reprogram its bios, you can use VmCenter to move a running virtual machine to another physical cpu, without the application even knowing it. In the event of a failure the VM can be run on any physical CPU available. Also Snapshots can be taken, and the allows a virtual ghost type functionality where we can take a virtual photo of what is running, and go back to it at any time. &lt;br /&gt;&lt;br /&gt;In the above example, it could have been even easier. In that you load your server-os into a VM, do your patching and updates, then convert it into a template. After you have a template, you can then create more servers using it by just cloning it, and giving it a new name.&lt;br /&gt;&lt;br /&gt;None of this so far is new. I've been doing this for a whle. The next step is called VmView.&lt;br /&gt;&lt;br /&gt;In manufacturing for example, its not uncommon that you need PC near or in the production areas. So for example lets say we need 320 PC to handle our ERP or SAP type application. These would be scattered over a large area of factory floor. The condition in a factory are not office environment. Heat, Temp, and Humidity are not comfortable for the workers, and worse for the equipment. There are other problems with this approach. 1) Updates - While WSUS and Microsoft tries to automate this, all to often you end up walking to every pc. 2) Security - USB Drives, Thumb Drives, CD-ROM, Phones, and Ipod are all avenues for data leakage, as well as virus to come into the system. The solution is a thin-terminal. &lt;br /&gt;&lt;br /&gt;Traditionally with thin-terminals, you need a terminal-server. A terminal server gives you a shared environment to run your applications. This works reasonably well, but not every application can install in such a shared environment. Forcing us back to the common pc approach. With VmView, we can now apply the same technology from the DataCenter to the desktop. &lt;br /&gt;&lt;br /&gt;We can create one or more template machines, that are automatically created, re-used, removed or restored that run in the data-center. We can choose what USB devices are connected to the VM on the fly. This allows us to support scanners, barcode guns, rfid readers, and printers that are connected via thin-terminals to the VM in the data-center. &lt;br /&gt;&lt;br /&gt;To give a example. For 320 Users we could put those on six M905 Dell Blades. Each user would be allocated a 20Gig Virtual hard disk. Using templates, the OS and common apps could be shared. We would customize AD to do small roaming profiles to avoide any corruption issue, and re-direct MyDocuments etc to proper file server. Now we can "install" a new pc for a new staff in a minute instead of hours. We can snapshot, audit, and reboot all centrally. We can update and touch every pc in the shop with a script easily. And we can deploy new patches, even change from XP to Vista in minutes.&lt;br /&gt;&lt;br /&gt;Even changing the desktop hardware is easy. We buy new servers for VmView. Mount them in the data center, and vMotion them over to the new servers. &lt;br /&gt;&lt;br /&gt;Using proper network design, we can have a high-availability redundant solution from server to desktop onto the factory floor that is secure and easy to maintain.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-3813562011846420447?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/3813562011846420447/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=3813562011846420447' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/3813562011846420447'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/3813562011846420447'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/12/virtual-manufacturing-control-vmware-to.html' title='Virtual Manufacturing Control - VmWare To the Factory Floor'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-6766995927178053342</id><published>2008-12-10T23:51:00.001-08:00</published><updated>2008-12-11T00:00:08.426-08:00</updated><title type='text'>Ruby on Rails - Are you a Member?</title><content type='html'>Large Enterprises that use Windows are typically in a Domain environment.&lt;br /&gt;Often application access is controlled by group membership in ActiveDirectory.&lt;br /&gt;&lt;br /&gt;The easy and fast way of finding this out, is via ruby-net-ldap, a native ruby implmenation.&lt;br /&gt;&lt;br /&gt;So first install ruby-net-ldap&lt;br /&gt;gem install ruby-net-ldap&lt;br /&gt;&lt;br /&gt;You will get:&lt;br /&gt;&lt;br /&gt;C:\&gt;gem install ruby-net-ldap&lt;br /&gt;Successfully installed ruby-net-ldap-0.0.4&lt;br /&gt;1 gem installed&lt;br /&gt;Installing ri documentation for ruby-net-ldap-0.0.4...&lt;br /&gt;Installing RDoc documentation for ruby-net-ldap-0.0.4...&lt;br /&gt;&lt;br /&gt;Example:&lt;br /&gt;ad = ActiveDirectory.new('user','password','server','dc=company,dc=com')&lt;br /&gt;pp ad.GetMembers('user1')&lt;br /&gt;pp ad.GetMembers('user2')&lt;br /&gt;if ad.MemberOf?("user1","myappgroup")&lt;br /&gt;   puts "YES We can do work"&lt;br /&gt;   end&lt;br /&gt;&lt;br /&gt;You will need the following library:&lt;br /&gt;&lt;br /&gt;#lib\active_directory.rb&lt;br /&gt;require 'rubygems'&lt;br /&gt;require 'net/ldap'&lt;br /&gt;require 'pp'&lt;br /&gt;&lt;br /&gt;class ActiveDirectory&lt;br /&gt;&lt;br /&gt;#server has to be full name.domain.com&lt;br /&gt;#treebase is dc=domain,dc=com&lt;br /&gt;def initialize(username,password,server,treebase)&lt;br /&gt; @username = username&lt;br /&gt;        @password = password&lt;br /&gt;        @server   = server&lt;br /&gt;        @treebase = treebase&lt;br /&gt;        @ldap_con = Net::LDAP.new( {:host =&gt; @server, :port =&gt; 389, :auth =&gt;&lt;br /&gt;                                  { :method =&gt; :simple, :username =&gt; @username, :password =&gt; @password}})&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def cleanup_members(members)&lt;br /&gt; mymembers = Array.new&lt;br /&gt;        mymembers &lt;&lt; '-none'&lt;br /&gt;        members.each do |member|&lt;br /&gt;              cmc = member[3,64]&lt;br /&gt;              cmcs = cmc.split(',')&lt;br /&gt;              mymembers &lt;&lt; String.new(cmcs[0].delete(' '))&lt;br /&gt;              end&lt;br /&gt;        return(mymembers)&lt;br /&gt;end&lt;br /&gt;              &lt;br /&gt;&lt;br /&gt; &lt;br /&gt;def GetEmail(username)&lt;br /&gt;        op_filter = Net::LDAP::Filter.eq( "samaccountname", username)&lt;br /&gt;&lt;br /&gt;        entries = @ldap_con.search( :base =&gt; @treebase, :filter =&gt; op_filter,:attributes=&gt;&lt;br /&gt;                        ['samaccountname','mail'])&lt;br /&gt;        entry = entries[0]&lt;br /&gt;        emailaddress = entry.mail&lt;br /&gt;        return(emailaddress)&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def GetMembers(username)&lt;br /&gt;        op_filter = Net::LDAP::Filter.eq( "samaccountname", username)&lt;br /&gt;&lt;br /&gt;        entries = @ldap_con.search( :base =&gt; @treebase, :filter =&gt; op_filter,:attributes=&gt;&lt;br /&gt;                        ['samaccountname','memberof'])&lt;br /&gt;        entry = entries[0]&lt;br /&gt;        begin&lt;br /&gt;          themembers = entry.memberof&lt;br /&gt;        rescue&lt;br /&gt;          themembers = Array.new&lt;br /&gt;          end&lt;br /&gt;        membership = cleanup_members(themembers)&lt;br /&gt;        return(membership)&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def MemberOf?(username,thegroup)&lt;br /&gt;    groups = GetMembers(username)&lt;br /&gt;    return groups.include?(thegroup)&lt;br /&gt;end&lt;br /&gt;end #ActiveDirectory&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-6766995927178053342?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/6766995927178053342/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=6766995927178053342' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/6766995927178053342'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/6766995927178053342'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/12/ruby-on-rails-are-you-member.html' title='Ruby on Rails - Are you a Member?'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-1688061052890169626</id><published>2008-12-10T18:18:00.000-08:00</published><updated>2008-12-10T18:37:43.782-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails authenticatedsystem ntlm windows login'/><title type='text'>Rails to Windows Integration - Single Signon with NTLM and Mongrel</title><content type='html'>I was moving a application for network management in Rails into a production environment.&lt;br /&gt;It had originally started out as something for my own use.&lt;br /&gt;Of course I did not do security for a single user app. &lt;br /&gt;&lt;br /&gt;In previous apps I'd used authenticated system with ldap to give a sign-on. &lt;br /&gt;I wanted easier and tighter integration. NTLM comes to mind, as you can just clink a link,&lt;br /&gt;and your windows login is re-used for your web application.&lt;br /&gt;&lt;br /&gt;The problem has always been that mongrel does not support NTLM.&lt;br /&gt;Well that solved now. Thanks to the work of Seggy Umboh, there is a new&lt;br /&gt;NTLM filter for mongrel. &lt;br /&gt;&lt;br /&gt;http://github.com/secobarbital/mongrel-ntlm/tree/master&lt;br /&gt;&lt;br /&gt;This actually passes you the windows domain user name &lt;br /&gt;directly into your controller.&lt;br /&gt;&lt;br /&gt;To get mongrel to use the filter, you must pass a config file, as&lt;br /&gt;documented in the readme.&lt;br /&gt;&lt;br /&gt;Then you need a few things in your app:&lt;br /&gt;&lt;br /&gt;First in your routes:&lt;br /&gt;&lt;br /&gt;map.connect 'ntlm/login', :controller =&gt; 'account', :action =&gt; 'login'&lt;br /&gt;&lt;br /&gt;I added this so the ntlm mongrel filter will chain to my account controller. That way&lt;br /&gt;your "user" controller can remain unchanged. I just prefer to keep them separate.&lt;br /&gt;Easier to add into existing systems that way.&lt;br /&gt;&lt;br /&gt;The in the account controller you need the following:&lt;br /&gt;class AccountController &lt; ApplicationController&lt;br /&gt;layout 'tier1'&lt;br /&gt;&lt;br /&gt;def login&lt;br /&gt;     my_user_name = request.env['REMOTE_USER']&lt;br /&gt;     if my_user_name.nil?&lt;br /&gt;        session[:logged_in] = :false&lt;br /&gt;        return&lt;br /&gt;        end&lt;br /&gt;     myuser = User.find(:first, :conditions =&gt; ["name = ?", my_user_name])&lt;br /&gt;     if myuser.nil?&lt;br /&gt;        myuser = User.new&lt;br /&gt;        myuser.name = my_user_name&lt;br /&gt;        myuser.save&lt;br /&gt;        end&lt;br /&gt;     session[:current_user] = my_user_name&lt;br /&gt;     session[:user_id] = myuser.id  &lt;br /&gt;     session[:logged_in] = :true&lt;br /&gt;     redirect_back_or_default('/myapp')&lt;br /&gt;     end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;Then you need a little helper lib. This one is cut down from authenticated system.&lt;br /&gt;This should be in you lib directory.&lt;br /&gt;&lt;br /&gt;#ntlm_system.rb&lt;br /&gt;module NtlmSystem&lt;br /&gt;  protected&lt;br /&gt;    # Returns true or false if the user is logged in.&lt;br /&gt;    # Preloads @current_user with the user model if they're logged in.&lt;br /&gt;    def logged_in?&lt;br /&gt;      if session[:logged_in].nil?&lt;br /&gt;         return false&lt;br /&gt;         end&lt;br /&gt;      if session[:logged_in] == :false&lt;br /&gt;         return false&lt;br /&gt;         end&lt;br /&gt;      return true&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    def login_required&lt;br /&gt;      if logged_in?()&lt;br /&gt;         return&lt;br /&gt;         end&lt;br /&gt;        pp "Access Denied"&lt;br /&gt;        access_denied()&lt;br /&gt;    end&lt;br /&gt;    &lt;br /&gt;    # Redirect as appropriate when an access request fails.&lt;br /&gt;    # Our application only uses ntlm based login - you must be part of the domain&lt;br /&gt;    def access_denied&lt;br /&gt;      redirect_to('/ntlm/login')&lt;br /&gt;    end  &lt;br /&gt;    &lt;br /&gt;    # Store the URI of the current request in the session.&lt;br /&gt;    #&lt;br /&gt;    # We can return to this location by calling #redirect_back_or_default.&lt;br /&gt;    def store_location&lt;br /&gt;      session[:return_to] = request.request_uri&lt;br /&gt;    end&lt;br /&gt;    &lt;br /&gt;    # Redirect to the URI stored by the most recent store_location call or&lt;br /&gt;    # to the passed default.&lt;br /&gt;    def redirect_back_or_default(default)&lt;br /&gt;      session[:return_to] ? redirect_to(session[:return_to]) : redirect_to(default)&lt;br /&gt;      session[:return_to] = nil&lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;Finally in your application.rb&lt;br /&gt;# Filters added to this controller apply to all controllers in the application.&lt;br /&gt;# Likewise, all the methods added will be available for all controllers.&lt;br /&gt;&lt;br /&gt;class ApplicationController &lt; ActionController::Base&lt;br /&gt;  helper :all # include all helpers, all the time&lt;br /&gt;  include NtlmSystem  # Add this for NTLM to work&lt;br /&gt;  # See ActionController::RequestForgeryProtection for details&lt;br /&gt;  # Uncomment the :secret if you're not using the cookie session store&lt;br /&gt;  protect_from_forgery  :secret =&gt; '6e2f000403020a0d9041a7bfb069239d'&lt;br /&gt;  &lt;br /&gt;  # See ActionController::Base for details &lt;br /&gt;  # Uncomment this to filter the contents of submitted sensitive data parameters&lt;br /&gt;  # from your application log (in this case, all fields with names like "password"). &lt;br /&gt;  filter_parameter_logging :password&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;When you start your application, make sure you do it like this:&lt;br /&gt;mongrel_rails start -S config\mongrel_ntlm.conf&lt;br /&gt;&lt;br /&gt;After reading, on NTLM, and playing with it, I found the URL are a bit picky, if you&lt;br /&gt;want to use the app, without needing to key your username and password&lt;br /&gt;&lt;br /&gt;http://servername:3000/ work perfectly fine.&lt;br /&gt;&lt;br /&gt;If you put the whole name, it tends to ask you the user name and password&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-1688061052890169626?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://github.com/secobarbital/mongrel-ntlm/tree/master' title='Rails to Windows Integration - Single Signon with NTLM and Mongrel'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/1688061052890169626/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=1688061052890169626' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/1688061052890169626'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/1688061052890169626'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/12/rails-to-windows-integration-single.html' title='Rails to Windows Integration - Single Signon with NTLM and Mongrel'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-3301770482845412865</id><published>2008-12-08T16:28:00.000-08:00</published><updated>2008-12-08T16:35:31.745-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby rails activerecord'/><title type='text'>Simple Rails Goodness - Annotate_Model</title><content type='html'>Ever have trouble remembering the fields in your rails models?&lt;br /&gt;Now you dont have too.&lt;br /&gt;&lt;br /&gt;This is really great time saver. Used to I'd keep up a SQL query windows&lt;br /&gt;just to be able to look at fields. Now with this plugin I dont have too.&lt;br /&gt;&lt;br /&gt;gem install annotate-models&lt;br /&gt;&lt;br /&gt;Will get you the gem version.&lt;br /&gt;&lt;br /&gt;Usage:&lt;br /&gt;&lt;br /&gt;cd [your project]&lt;br /&gt;annotate&lt;br /&gt;&lt;br /&gt;And you will get something like:&lt;br /&gt;&lt;br /&gt;  # == Schema Information&lt;br /&gt;  #&lt;br /&gt;  #  id                  :integer(11)   not null&lt;br /&gt;  #  quantity            :integer(11)   &lt;br /&gt;  #  product_id          :integer(11)   &lt;br /&gt;  #  unit_price          :float         &lt;br /&gt;  #  order_id            :integer(11)   &lt;br /&gt;  #&lt;br /&gt;&lt;br /&gt;  class LineItem &lt; ActiveRecord::Base &lt;br /&gt;    belongs_to :product&lt;br /&gt;  &lt;br /&gt;   end&lt;br /&gt;  &lt;br /&gt;This is so Useful when your writing model code&lt;br /&gt;&lt;br /&gt;http://github.com/ctran/annotate_models/tree/master&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-3301770482845412865?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://github.com/ctran/annotate_models/tree/master' title='Simple Rails Goodness - Annotate_Model'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/3301770482845412865/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=3301770482845412865' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/3301770482845412865'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/3301770482845412865'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/12/simple-rails-goodness-annotatemodel.html' title='Simple Rails Goodness - Annotate_Model'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-4663512243781842983</id><published>2008-11-23T19:54:00.001-08:00</published><updated>2008-11-23T23:32:01.248-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby iseries rails ibm as400'/><title type='text'>RPG really still exists</title><content type='html'>I was looking thru some surveys and surprised that in hometown of Cleveland/Chattanoga TN, one of the more common environments is AS/400&lt;br /&gt;or iSeries midrange machines. And the language of choice is RPG. &lt;br /&gt;&lt;br /&gt;I've done a few projects in my early years with RPG, find it incredible that&lt;br /&gt;its still alive and kicking. &lt;br /&gt;&lt;br /&gt;The nice thing is now, there is ruby support on AS/400(iSeries) as well as&lt;br /&gt;database support.&lt;br /&gt;&lt;br /&gt;Using this, new applications can be developed rapidly. They can be viewed from standard pc, or mac, inside or if you choose outside the company. One of the &lt;br /&gt;the truely powerful elements is creating Iphone applications, that can be access in a mobile environment. Using the DB2 adapter, exiting applications can be enhanced&lt;br /&gt;or new functionality added, without changing the core infrastruture.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;http://www.ibmsystemsmag.com/i5/july07/tipstechniques/16330p1.aspx&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-4663512243781842983?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.ibmsystemsmag.com/i5/july07/tipstechniques/16330p1.aspx' title='RPG really still exists'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/4663512243781842983/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=4663512243781842983' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/4663512243781842983'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/4663512243781842983'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/11/rpg-really-still-exists.html' title='RPG really still exists'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-6011463946998202936</id><published>2008-11-03T17:09:00.001-08:00</published><updated>2008-11-03T17:18:49.413-08:00</updated><title type='text'>Why Use Ruby? Why Not Java? Why Not C?</title><content type='html'>Its a common question, that is always ask when you start a project. What &lt;br /&gt;tool to use. Having long experience, with all languages practically, I've programmed&lt;br /&gt;in multiple assemblers, Basic, Pascal, Cobol, Fortran, RPG, VB, C, C++, Java Python, VHDL, Veriflog, and Ruby.&lt;br /&gt;&lt;br /&gt;I agree with the comment that CPU get cheaper, and people get more expensive. &lt;br /&gt;Also timelines are decreasing. Market timeframes get smaller. Also for me, as a &lt;br /&gt;senior manager of technology, I have no time for the likes of C. (Yes I need&lt;br /&gt;to go back and do a project just to keep the skill, that is coming soon)&lt;br /&gt;But if I want a functioning prototype system, and I need it in a day, even&lt;br /&gt;at my best I cannot do it in C. I can do it in Ruby ( on Rails).&lt;br /&gt;&lt;br /&gt;Then I can go in the meeting with my programming staff, and tell them, ok this&lt;br /&gt;is how I expect it to work. At that point, little room for discussion. With Ruby&lt;br /&gt;you can do a system in the time it takes to do the powerpoint to describe it. Thats&lt;br /&gt;a major statement as I eat and breath powerpoint.&lt;br /&gt;&lt;br /&gt;The other thing that people know ruby for is perfomance, but to a large degree that is just startup time. With the new implementations using VM based technology there is no reason ruby cannot run on a 8 bit processor, and now we have 64bit ones almost for free.&lt;br /&gt;&lt;br /&gt;So next time you need to fix 20 year old code, consider using Ruby, some nice plugin and gems, and a few days of your time. Its a lot better than spending 5-10 man years in java.&lt;br /&gt;&lt;br /&gt;Reference:&lt;br /&gt;http://engineroom.mixx.com/2008/08/10/ruby-on-rails-vs-java-vs-c-vs-assembler/&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-6011463946998202936?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://engineroom.mixx.com/2008/08/10/ruby-on-rails-vs-java-vs-c-vs-assembler/' title='Why Use Ruby? Why Not Java? Why Not C?'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/6011463946998202936/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=6011463946998202936' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/6011463946998202936'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/6011463946998202936'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/11/why-use-ruby-why-not-java-why-not-c.html' title='Why Use Ruby? Why Not Java? Why Not C?'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-5848500948025655226</id><published>2008-11-02T17:24:00.000-08:00</published><updated>2008-11-02T17:33:58.325-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby phillipines'/><title type='text'>Solving Large Scale Company Software Issues</title><content type='html'>What to do when your dealing with complex enterprise issues,&lt;br /&gt;with multiple legacy systems?&lt;br /&gt;&lt;br /&gt;If you look at most large companies today, you find a long organic history&lt;br /&gt;of IT software and hardware.&lt;br /&gt;&lt;br /&gt;The hardware side of things is easy enough to fix over time. I find that&lt;br /&gt;DELL has fastastic warranty, and great service, and moderate price. Get a&lt;br /&gt;five year warranty, and forget about hardware problems for your servers and&lt;br /&gt;pc's. Likewise on your network gear, Cisco does a great job.&lt;br /&gt;&lt;br /&gt;That solves infrasturure, but not the complexity of software.&lt;br /&gt;Some have current investment in java, some even in cobol still. &lt;br /&gt;I could write a 100 page essay on the wide variety of systems in&lt;br /&gt;large companies.&lt;br /&gt;&lt;br /&gt;Going forward, what you want is the ability to integrate and have a standard&lt;br /&gt;across the enterpise. As CTO and Technology managers, we need something that&lt;br /&gt;will tie everything togeather. Something that will last, and has good performance&lt;br /&gt;and that we will not have to spend 100Million on just to get thing consistent.&lt;br /&gt;&lt;br /&gt;For this "glue" consider using Ruby on Rails. Its mature, It fast, and its efficient.&lt;br /&gt;It can scale from 1 User to Millions of users. And it can be developmed in small&lt;br /&gt;to large teams.&lt;br /&gt;&lt;br /&gt;Add to this a development center in the phillipines for even more cost effective solution. The cost of english speaking staff in Manilla is 1/3 that of the US.&lt;br /&gt;The people are smart, and hard workers. With good video conferencing, and &lt;br /&gt;VOIP telephony they can be virtually down the hall from you. And my experience&lt;br /&gt;they can work on US timezone allowing for no time lag.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-5848500948025655226?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/5848500948025655226/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=5848500948025655226' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/5848500948025655226'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/5848500948025655226'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/11/solving-large-scale-company-software.html' title='Solving Large Scale Company Software Issues'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-6412584334912887261</id><published>2008-09-22T17:07:00.000-07:00</published><updated>2008-09-23T01:53:41.467-07:00</updated><title type='text'>Be Gentle Admins(Gods) - Be slow to judge</title><content type='html'>I recently tried the site getacoder.com The site offers contractors/programmer/engineers for work-for-hire, at good rates.&lt;br /&gt;Thats the good news. The bad news, is there administration is heavy&lt;br /&gt;handed to say the least. &lt;br /&gt;&lt;br /&gt;I posted a request, and having done lots of outsourcing gave as much&lt;br /&gt;information as I could, even siting the a open-source reference board.&lt;br /&gt;&lt;br /&gt;Seems like the terms of service specify that you cannot provide contact info,&lt;br /&gt;which I'm perfectly fine with. But the Open Source project has contact info for there project. And within a hour of posting, my account was suspended, for violation of terms-of-service. &lt;br /&gt;&lt;br /&gt;I've done no violation of terms of service. As my contact details were not included.&lt;br /&gt;&lt;br /&gt;-----------------------------------------------&lt;br /&gt;Dear Glenn, &lt;br /&gt;&lt;br /&gt;Your account was suspended due to the fact that you have provided contact information in a project page; Please be reminded that this is not allowed by GetACoder. &lt;br /&gt;&lt;br /&gt;Statements like: \"For any questions, concerns, or issues submit them to gerald@BeagleBoard.org\"- Will not be tolerated. &lt;br /&gt;&lt;br /&gt;If you wish to reactivate your account send us an email, informing that you understand our Terms of Use agreeing to abide by them at all times. &lt;br /&gt;&lt;br /&gt;--------------------------------------------------&lt;br /&gt;&lt;br /&gt;Funny dont you think that the person knows my name is Glenn, yet she suspended my&lt;br /&gt;account for a unrelated person called gerald.&lt;br /&gt;&lt;br /&gt;I've withheld her name to protect the guilty.&lt;br /&gt;&lt;br /&gt;Its now been more than 16 hours, account suspended, with no response.&lt;br /&gt;&lt;br /&gt;So just to make sure.&lt;br /&gt;&lt;br /&gt;I Am Informing Getacoder.com that I AGREE TO THE TERMS OF SERVICE, HAVE NOT, NOR WILL EVER VIOLATE THEM IN THE FUTURE.&lt;br /&gt;&lt;br /&gt;Finally I get a response:&lt;br /&gt;---------------------------------------------------------------------------------&lt;br /&gt;Dear Glenn, &lt;br /&gt;&lt;br /&gt;Glad to know that you are aware of the situation and plan to follow a professional conduct with GetACoder. We have reopened your account. &lt;br /&gt;&lt;br /&gt;Feel free to contact us if you have further questions. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;NOTE: If you wish to send additional information regarding this ticket, please do not create a new email. Instead, reply to this one and do not change subject line. &lt;br /&gt;&lt;br /&gt;Sincerely, &lt;br /&gt;Anna Kesel     &lt;br /&gt;---------------------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;I really dont know about these people. The quality of responses is 4 so far, 2 of &lt;br /&gt;which were proposing web designs for a hardware design, ie they dont have a clue&lt;br /&gt;of what is being talked about. Waiting on the other two to "bid" and see what the price is. Since this is a hobby project, cannot be so high.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-6412584334912887261?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/6412584334912887261/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=6412584334912887261' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/6412584334912887261'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/6412584334912887261'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/09/be-gentle-adminsgods-be-slow-to-judge.html' title='Be Gentle Admins(Gods) - Be slow to judge'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-6021866257535388569</id><published>2008-09-14T00:30:00.000-07:00</published><updated>2008-09-14T00:42:36.524-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fusion magnets'/><title type='text'>Making Polywell Magnets Using Ceramics and Liquid Metals</title><content type='html'>One of my areas of interest is fusion. Since tradition tokamak fusion devices dont seem to have a future. I tend torwards the Inertial Confinement Fusion Camp, with&lt;br /&gt;Polywell based technology being the area I believe would work the best with the lowest cost.&lt;br /&gt;&lt;br /&gt;One of the cost issues of polywell that needs to be solved from engineering point of view is the magnet design. In polywell you use a sperical array of magnets to create a virtual grid. &lt;br /&gt;&lt;br /&gt;The magnets needless to say need to create a strong magnetic field. So for continious operation you really need cooling. Water does not work because its going to flash to steam way to easily. &lt;br /&gt;&lt;br /&gt;The concept I had was to use EoPlex Technologies (http://www.eoplex.com/index.html) to create a ceramic layered magnetic structure combining the magnet and a integrated channel for ibm's liquid metal as well as the copper magnetic wire. The magnets mounted in the reator chanber would connect to a liquid metal circulation system, carrying the liquid metal to a large heat exchanger capable of 1600 degree's C down to 85 degree C, as stated the IBM article.&lt;br /&gt;&lt;br /&gt;Since the liquid metal has magnetic properties we may even be able to get rid of the copper conducter and have a liquid conductor. Need a bit more research, but believe this may offer the ability to produce 100Megawatt plants without the need to have cryo cooling.&lt;br /&gt;&lt;br /&gt;http://www.nextenergynews.com/news1/next-energy-news5.16.08d.html&lt;br /&gt;http://www.eoplex.com/index.html&lt;br /&gt;http://www.talk-polywell.org/bb/index.php&lt;br /&gt;http://en.wikipedia.org/wiki/Polywell&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-6021866257535388569?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.eoplex.com' title='Making Polywell Magnets Using Ceramics and Liquid Metals'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/6021866257535388569/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=6021866257535388569' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/6021866257535388569'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/6021866257535388569'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/09/making-polywell-magnets-using-ceramics.html' title='Making Polywell Magnets Using Ceramics and Liquid Metals'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-8137398110483445902</id><published>2008-09-09T00:15:00.000-07:00</published><updated>2008-09-09T00:37:35.883-07:00</updated><title type='text'>Questons Questions Questions - A meme inspired by David Mohundro</title><content type='html'>&lt;strong&gt;How old were you when you started programming?&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;15 Years old.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;How did you get started in programming?&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;After following many articles in Byte Magazine. (Where I learned electronics&lt;br /&gt;from the wondering writing of Steve Ciarcia (http://www.circellar.com/)&lt;br /&gt;I saved my pennies and got me the first TRS80 PC from Radio Shack.&lt;br /&gt;&lt;br /&gt;I did lots of small apps, like programs to teach me primary school spelling. Speach Output. Light Pen Input.&lt;br /&gt;&lt;br /&gt;Then started doing commercial projects around 16 years old&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;What was your first language?&lt;/strong&gt;&lt;br /&gt;BASIC (Microsoft Basic)&lt;br /&gt;Z80 Assembler&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;What was the first real program that you wrote?&lt;/strong&gt;&lt;br /&gt;Real Program, means I got paid for it.&lt;br /&gt;First paying job was a mail-merge program for the TRS80 Word Processor&lt;br /&gt;Followed by a automation system for a beer disti.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;What languages have you used since you started programming?&lt;/strong&gt;&lt;br /&gt;Cobol&lt;br /&gt;Fortran&lt;br /&gt;RPG&lt;br /&gt;C&lt;br /&gt;TurboPascal&lt;br /&gt;8086 Assembler&lt;br /&gt;68K Assembler&lt;br /&gt;8031/8051 Assembler&lt;br /&gt;VB&lt;br /&gt;C++&lt;br /&gt;Java&lt;br /&gt;Python&lt;br /&gt;Ruby&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;If you knew what you know now, would you have started programming?&lt;/strong&gt;&lt;br /&gt;Absolutely. But I'd skip down to ruby.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;What's the most fun you've ever had... programming?&lt;/strong&gt;&lt;br /&gt;Several that come to mind.&lt;br /&gt;1. LightPen App for the TRS80.&lt;br /&gt;2. Banking Analysis APP - Took it from a month of run-time to a weekend.&lt;br /&gt;3. PDFtoRuby - A Ruby Gem to create ruby code from pdf files&lt;br /&gt;4. Network Monitor APP I did recently in Ruby/Rails&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I can’t think of any one specific instance, but I think one of the best feelings is, after having spent literally hours trying to debug some problem and then giving up and going home, waking up the next day and having the light bulb come on with the solution to this problem. I love solving problems with software.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Tag, you’re it!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-8137398110483445902?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.mohundro.com/blog/2008/07/15/HowIGotStartedInProgramming.aspx' title='Questons Questions Questions - A meme inspired by David Mohundro'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/8137398110483445902/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=8137398110483445902' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/8137398110483445902'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/8137398110483445902'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/09/questons-questions-questions-meme.html' title='Questons Questions Questions - A meme inspired by David Mohundro'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-7870305122605198852</id><published>2008-08-21T16:55:00.000-07:00</published><updated>2008-08-21T16:59:19.970-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby rails'/><title type='text'>Ruby and Rails can do almost anything</title><content type='html'>I'd like to expose a few things that Rails is not just for Web Applications.&lt;br /&gt;&lt;br /&gt;By definitions of traditional web applications I mean, your traditional shopping cart, or social networking sites.&lt;br /&gt;&lt;br /&gt;Applications I've done with Rails&lt;br /&gt;&lt;br /&gt;Network Management - This maps all nodes in a network, grabs there macs, find what ports they are on switches, gets there service tag, and even for phones find outs there extensions. Yes you use a IE or Firefox to access it, but its not a social networking site&lt;br /&gt;&lt;br /&gt;Regional Aviation Maint. Mangament Applicaton&lt;br /&gt;This manages the overhaul process for a company that repair aircraft components and does the regulatory paperwork. Its a very controlled environment. Again not your normal shopping cart&lt;br /&gt;&lt;br /&gt;A Proof-of-concept Data Deduplication Backup system&lt;br /&gt;This uses ActiveRecord and sqlite3 to do the tracking part of the backup. And Rails to be a GUI for the server.&lt;br /&gt;&lt;br /&gt;Embedded Device Managment.&lt;br /&gt;In my hobby, I'm building a 360 degree camera.&lt;br /&gt;All the device management, and the gui code is done using ruby and&lt;br /&gt;rails, running on a tiny avr32 cpu.&lt;br /&gt;&lt;br /&gt;Database Conversion(s) - More than I care to count&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Thing I could do with Rails&lt;br /&gt;Any Commecial Program that you can think of. From Cash Registers in food courts, to Factory Management applications&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So you see, Rails is not just about yet-another-web-site. Its a GUI for any application you want to write.&lt;br /&gt;&lt;br /&gt;WIth Ruby maning the heavy-lifting, and Rails handling the GUI, there very few things that cannot be done with the combination.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-7870305122605198852?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/7870305122605198852/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=7870305122605198852' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/7870305122605198852'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/7870305122605198852'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/08/ruby-and-rails-can-do-almost-anything.html' title='Ruby and Rails can do almost anything'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-5009018432124606273</id><published>2008-08-21T00:48:00.000-07:00</published><updated>2008-08-21T00:55:38.888-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby dotr graphviz network mapping'/><title type='text'>dotr - drawing network maps</title><content type='html'>Ever want to draw a network map.&lt;br /&gt;Seems like there is a "great" way to do this.&lt;br /&gt;The ruby 'dotr" library. It can be used for diagraming code, to diagramming&lt;br /&gt;the whole internet.&lt;br /&gt;&lt;br /&gt;DotR provides a simple Ruby interface for contructing directed graphs in a natural syntax and plotting them via the 'dot' utility to PNG, PS and other graphic formats.&lt;br /&gt;&lt;br /&gt;the ruby dotr drives Graphviz &lt;http://www.graphviz.org/&gt; Which is a mapping&lt;br /&gt;application done by ATT. Its open source, and you can "write" dot files using&lt;br /&gt;the dotr gem.&lt;br /&gt;&lt;br /&gt;I call the SwitchGraph in the "background" of a "rails" app, generating "maps" of all my network switches. In my rails app, they appear to "update" by themselves.&lt;br /&gt;I use Rmagick to create smaller thumbnails, that can be "clicked" to a large version.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Example of driving dotr/graphviz&lt;br /&gt;&lt;br /&gt;#switchgraph.rb&lt;br /&gt;require 'tempfile'&lt;br /&gt;require 'dotr'&lt;br /&gt;require 'RMagick'&lt;br /&gt;include Magick&lt;br /&gt;&lt;br /&gt;class SwitchGraph&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def initialize(theswitch)&lt;br /&gt;    @me = theswitch&lt;br /&gt;end #init&lt;br /&gt;&lt;br /&gt;def graph()&lt;br /&gt;     d = DotR::Digraph.new(@me.name,:rankdir=&gt;"LR",:ranksep=&gt;"2.75") do |g|&lt;br /&gt;        switchname = @me.name&lt;br /&gt;        switchlabel = @me.site.name + "/" + @me.name&lt;br /&gt;        g.node(switchname, :label =&gt; switchlabel)&lt;br /&gt;        @me.switch_ports.each do |port|&lt;br /&gt;             port.macs.each do |mac|&lt;br /&gt;                 if Device.exists?(mac.device_id)&lt;br /&gt;                   begin &lt;br /&gt;                    nodename = mac.device.name&lt;br /&gt;                    nodelabel = mac.device.name + "(" + mac.ip + ")"&lt;br /&gt;                   rescue&lt;br /&gt;                    nodename = "-Unknown-"&lt;br /&gt;                    nodelabel = "(" + mac.ip + ")"&lt;br /&gt;                    end&lt;br /&gt;                  g.node(nodename,:label =&gt; nodelabel) do |n|&lt;br /&gt;                       portlabel = port.name&lt;br /&gt;                       n.connection(switchname, :label =&gt; portlabel)&lt;br /&gt;                       if mac.device.user&lt;br /&gt;                          username = mac.device.user.name&lt;br /&gt;                          userlabel = username&lt;br /&gt;                          g.node(username, :label =&gt; userlabel) do |u|&lt;br /&gt;                            u.connection(nodename)&lt;br /&gt;                            end # do u&lt;br /&gt;                          end #mac.device.user&lt;br /&gt;                       end #g.node mac&lt;br /&gt;                    end #if mac.device&lt;br /&gt;                 end #port.macs.each&lt;br /&gt;             end #@me.switch_ports&lt;br /&gt;        end #DotR&lt;br /&gt;&lt;br /&gt;    #C:\projects\airstate\public\switch\graph\4&lt;br /&gt;    thebase = 'public/switch/graph/' + @me.id.to_s + "/" &lt;br /&gt;    thefilename = thebase + @me.name + ".png"&lt;br /&gt;    thumbdir = thebase + "thumb"&lt;br /&gt;    FileUtils.mkdir_p thumbdir&lt;br /&gt;&lt;br /&gt;    File.open(thefilename, 'wb') { |f| f.write(d.diagram(:png)) }&lt;br /&gt;    img = Magick::Image::read(thefilename).first&lt;br /&gt;    thumb = img.resize(250,250) &lt;br /&gt;    thumb.write thumbdir + '/' + @me.name + ".png"&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;end #class switchgraph&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-5009018432124606273?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/5009018432124606273/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=5009018432124606273' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/5009018432124606273'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/5009018432124606273'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/08/dotr-draing-network-maps.html' title='dotr - drawing network maps'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-3008739657902973742</id><published>2008-08-21T00:41:00.001-07:00</published><updated>2008-08-21T00:56:17.813-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby webscrapping RubyfulSoup'/><title type='text'>Scraping Web Pages with Soup</title><content type='html'>I wanted to "grab" the contents of a "management" web page off a cisco 7941 phone.&lt;br /&gt;&lt;br /&gt;After reading up on the variety of ruby gems to use for scrapping.&lt;br /&gt;My choice was "soup".&lt;br /&gt;&lt;br /&gt;http://www.crummy.com/software/RubyfulSoup/&lt;br /&gt;&lt;br /&gt;This seems to work nice. I've managed to pull serial numbers, extensions, and&lt;br /&gt;phone names as well as models from close to 100 phones this way.&lt;br /&gt;&lt;br /&gt;This is a "class" for getting the phone information.&lt;br /&gt;&lt;br /&gt;#cisco_phone.rb - Class to "Scrap" Cisco Phone&lt;br /&gt;class CiscoPhone&lt;br /&gt;require 'rubygems'&lt;br /&gt;require 'open-uri'&lt;br /&gt;require 'rubyful_soup'&lt;br /&gt;require 'cgi'&lt;br /&gt;require "pp"&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def initialize(theip)&lt;br /&gt;    valuestack = Array.new&lt;br /&gt;    @values = Hash.new&lt;br /&gt;    url = "http://#{theip}"&lt;br /&gt;     &lt;br /&gt;   begin&lt;br /&gt;     open(url) {&lt;br /&gt;       |page| page_content = page.read()&lt;br /&gt;       soup = BeautifulSoup.new(page_content)&lt;br /&gt;       result = soup.find_all('td')&lt;br /&gt;       valuename = nil&lt;br /&gt;       result.each do |item|&lt;br /&gt;           content= item.b&lt;br /&gt;           if content&lt;br /&gt;              value = content.string&lt;br /&gt;              if value&lt;br /&gt;                 value.strip!&lt;br /&gt;                 if !valuestack.include?(value)&lt;br /&gt;                    valuestack.push(value)&lt;br /&gt;                    end&lt;br /&gt;                 end&lt;br /&gt;             end&lt;br /&gt;         end    &lt;br /&gt;       }&lt;br /&gt;  rescue&lt;br /&gt;      @values = nil&lt;br /&gt;      return nil&lt;br /&gt;      end&lt;br /&gt; thename = nil&lt;br /&gt; thevalue = nil&lt;br /&gt; valuestack.each do |content|&lt;br /&gt;      if thename.nil?&lt;br /&gt;         thename = content&lt;br /&gt;       else&lt;br /&gt;         thevalue = content&lt;br /&gt;         @values[thename] = thevalue&lt;br /&gt;         thename = nil&lt;br /&gt;        end &lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;br /&gt;  # Validations  &lt;br /&gt;  if !@values.has_key?('Model Number')&lt;br /&gt;     @values = nil&lt;br /&gt;     return nil&lt;br /&gt;     end&lt;br /&gt;  if !@values.has_key?('Phone DN')&lt;br /&gt;     @values = nil&lt;br /&gt;     return nil&lt;br /&gt;     end&lt;br /&gt;  return self&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def isphone?()&lt;br /&gt;    if @values.nil?&lt;br /&gt;       return false&lt;br /&gt;     else&lt;br /&gt;       return true &lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def getvalue(thename)&lt;br /&gt;    if !@values.include?(thename)&lt;br /&gt;       return nil&lt;br /&gt;       end&lt;br /&gt;    return @values[thename].downcase&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;#Test Cases&lt;br /&gt;#thetest = CiscoPhone.new("192.168.1.20")&lt;br /&gt;#pp thetest&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-3008739657902973742?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.crummy.com/software/RubyfulSoup/' title='Scraping Web Pages with Soup'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/3008739657902973742/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=3008739657902973742' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/3008739657902973742'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/3008739657902973742'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/08/scraping-web-pages-with-soup.html' title='Scraping Web Pages with Soup'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-2244183195724159416</id><published>2008-08-21T00:15:00.000-07:00</published><updated>2008-08-21T00:56:52.835-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby backup utility data deplication'/><title type='text'>Data Deplucation In Ruby - Backup Terabytes In Minutes</title><content type='html'>Recently I went looking at the "perpetual" problem of "backups".&lt;br /&gt;&lt;br /&gt;I wanted to "know" how some of the commerical products, do there "magic".&lt;br /&gt;&lt;br /&gt;So I wrote a "simulation", in ruby, with activerecord for my data storage.&lt;br /&gt;&lt;br /&gt;The theory of this, is your "average" server/workstation has "lots" of duplicated files. They may have "different" names, and be in "different" directories, but the &lt;br /&gt;contents is the same.&lt;br /&gt;&lt;br /&gt;This is even more the case spread over multiple machines, or for machines that have been around for a while.&lt;br /&gt;&lt;br /&gt;I created the following script to "explore" dedup backup.&lt;br /&gt;&lt;br /&gt;First, terminology explained:&lt;br /&gt;&lt;br /&gt;1. Chunk is a "unique" file, as indentified by a "hash" - In my case a SHA-512 hash.&lt;br /&gt;2. Backup is a "typical" full "backup" of everything on my workstation.&lt;br /&gt;&lt;br /&gt;Logic Flow:&lt;br /&gt;1. Loop Thru All Available Files.&lt;br /&gt;2. Compute a SHA-512 for the current file&lt;br /&gt;3. Look up the hash, do we have a "chunk" that exists.&lt;br /&gt;4. If we do, "connect" the file record to the chunk.&lt;br /&gt;5.    else create a new chunk, and link the file record&lt;br /&gt;&lt;br /&gt;The first run, without "compression" we get a 15% saving&lt;br /&gt;If you run this a second time, the second backup will go be reduced from 37+ gig&lt;br /&gt;to 200Meg or less. Resulting in a deduplication ration of 99%+ &lt;br /&gt;&lt;br /&gt;The nice "tricks" that can be done with this, is to reduce your "backups" from days to "minutes", since the "normal" rotation of "removable" backups already have "data" that we can delta.&lt;br /&gt;&lt;br /&gt;In addition we could keep 2 years of backup at a cheap price.&lt;br /&gt;And a slew of other features.&lt;br /&gt;&lt;br /&gt;Stats of the "backup" actually done on my workstation.&lt;br /&gt;&lt;br /&gt;Chunks 382899&lt;br /&gt;Backups 1&lt;br /&gt;Backup Files 510960&lt;br /&gt;Total Backup Size 40031553419 = 37.28G&lt;br /&gt;Total Chunk Size 33727083825 = 31.41G&lt;br /&gt;Savings 6304469594 = 5.87G = 15% for first backup&lt;br /&gt;&lt;br /&gt;Second Backup would have a savings of 99%&lt;br /&gt;&lt;br /&gt;Now the code:&lt;br /&gt;&lt;br /&gt;First we need a "place" to track our progress.&lt;br /&gt;&lt;br /&gt;#migration&lt;br /&gt;class CreateChunks &lt; ActiveRecord::Migration&lt;br /&gt;  def self.up&lt;br /&gt;      create_table "backupchunks", :force =&gt; true do |t|&lt;br /&gt;          t.string   :filehash&lt;br /&gt;          t.integer  :filesize&lt;br /&gt;          t.string   :ctype&lt;br /&gt;          t.datetime :created_at&lt;br /&gt;          end&lt;br /&gt;      create_table "backups", :force =&gt; true do |t|&lt;br /&gt;          t.string   :host&lt;br /&gt;          t.string   :description&lt;br /&gt;          t.datetime :created_at   &lt;br /&gt;          end&lt;br /&gt;      create_table "backupfiles", :force =&gt; true do |t|&lt;br /&gt;          t.integer  :backup_id&lt;br /&gt;          t.string   :filename&lt;br /&gt;          t.integer  :filesize&lt;br /&gt;          t.integer  :backupchunk_id&lt;br /&gt;          end&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def self.down&lt;br /&gt;         drop_table :backupchunks&lt;br /&gt;         drop_table :backups&lt;br /&gt;         drop_table :backupfiles&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;Now our "agent"&lt;br /&gt;&lt;br /&gt;#scandisk.rb&lt;br /&gt;#---------------&lt;br /&gt;require 'digest'&lt;br /&gt;require 'find'&lt;br /&gt;require 'pp'&lt;br /&gt;require "rubygems"&lt;br /&gt;require "activerecord"&lt;br /&gt;&lt;br /&gt;ActiveRecord::Base.establish_connection(&lt;br /&gt;  :adapter  =&gt; "sqlite3",&lt;br /&gt;  :database =&gt;  "db/development.sqlite3"&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;class Backupchunk &lt; ActiveRecord::Base&lt;br /&gt;has_many :Files&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;class Backup &lt; ActiveRecord::Base&lt;br /&gt;has_many :Files&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;class Backupfile &lt; ActiveRecord::Base&lt;br /&gt;belongs_to :Backupchunk&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def hash_file(file, hash_kind)&lt;br /&gt;  digest, chunk = hash_kind.new, ''&lt;br /&gt;  open(file, 'rb') do |f|&lt;br /&gt;    digest &lt;&lt; chunk while f.read(4096, chunk)&lt;br /&gt;  end&lt;br /&gt;  digest&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def handlebackup(f)&lt;br /&gt;&lt;br /&gt;         begin&lt;br /&gt;          thehash = hash_file(f, Digest::SHA512).to_s&lt;br /&gt;         rescue&lt;br /&gt;          puts "Cannot read #{f}"&lt;br /&gt;          return&lt;br /&gt;          end&lt;br /&gt;&lt;br /&gt;        thechunk = Backupchunk.find(:first,:conditions =&gt; {:filehash =&gt; thehash})&lt;br /&gt;        if thechunk.nil?&lt;br /&gt;           thechunk = Backupchunk.new&lt;br /&gt;           thechunk.filehash = thehash&lt;br /&gt;           thechunk.filesize = File.size(f)&lt;br /&gt;           thechunk.save&lt;br /&gt;          else &lt;br /&gt;           pp f&lt;br /&gt;          end&lt;br /&gt;        thefile = Backupfile.new&lt;br /&gt;        thefile.filename = f&lt;br /&gt;        thefile.filesize = File.size(f)&lt;br /&gt;        thefile.backupchunk_id = thechunk.id&lt;br /&gt;        thefile.save&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;target_dir = "h:/dedup/store/"&lt;br /&gt;&lt;br /&gt;mybackup = Backup.new&lt;br /&gt;mybackup.host = "sinub-glenn2"&lt;br /&gt;mybackup.save&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Find.find('/') do |f|&lt;br /&gt;     if File.file?(f)&lt;br /&gt;        handlebackup(f)&lt;br /&gt;        end&lt;br /&gt;     end&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-2244183195724159416?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/2244183195724159416/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=2244183195724159416' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/2244183195724159416'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/2244183195724159416'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/08/data-deplucation-in-ruby-backup.html' title='Data Deplucation In Ruby - Backup Terabytes In Minutes'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-836151862024991248</id><published>2008-07-27T06:03:00.000-07:00</published><updated>2008-07-27T06:07:57.819-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='photo recovery fat32 nikon flash memory cards'/><title type='text'>Corrupted Flash Card - Recovery of FAT32 Files</title><content type='html'>Recently, I was getting ready to copy some images from a "full" memory card, to my pc for archive. Somewhere during the process, the fat32 file system on the card, got confused, and the directory where the images were simply disappeared. &lt;br /&gt;&lt;br /&gt;What to do now? I tried chkdsk? Nothing&lt;br /&gt;I tried the "Trash" folder, Again nothing.&lt;br /&gt;Over 540+ irreplaceable photos from my Nikon D70 were&lt;br /&gt;gone.&lt;br /&gt;&lt;br /&gt;So doing some research, I found many a "pay" solutions.&lt;br /&gt;But not really wanting to pay, I wanted to find a "free"&lt;br /&gt;solution, without running into a virus, spyware, etc.&lt;br /&gt;&lt;br /&gt;After looking at three or four, I found my solution.&lt;br /&gt;&lt;br /&gt;PhotoRec. &lt;br /&gt;The interface is a bit primative, but it worked perfectly.&lt;br /&gt;The first time. Every photo was recovered.&lt;br /&gt;&lt;br /&gt;So if you hit that problem, give it a try.&lt;br /&gt;Cost is $0.00. Very good perfomance for the price.&lt;br /&gt;&lt;br /&gt;http://www.cgsecurity.org/wiki/PhotoRec&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-836151862024991248?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.cgsecurity.org/wiki/PhotoRec' title='Corrupted Flash Card - Recovery of FAT32 Files'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/836151862024991248/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=836151862024991248' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/836151862024991248'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/836151862024991248'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/07/corrupted-flash-card-recovery-of-fat32.html' title='Corrupted Flash Card - Recovery of FAT32 Files'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-2849868929140441802</id><published>2008-07-10T23:28:00.000-07:00</published><updated>2008-07-11T03:20:54.224-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails activerecord widgets'/><title type='text'>Dynamic Tabnav Widget menus</title><content type='html'>I wanted to do a "dynamic" menu that is filled from data in my Rails Application.&lt;br /&gt;I have a "table" (Model in rails speak) that has the values. Then I can "overload"&lt;br /&gt;the controller to add more functionality. &lt;br /&gt;&lt;br /&gt;The "gotcha" in coding this is, there is "no" each method for activerecord. &lt;br /&gt;&lt;br /&gt;The other "gotcha" is a "site" can have mutliple networks, so since we are selecting my "site", and network does not have it, we do a lookup in the conditions_for_collections code. Note that active_scaffold can also "view" the devices via the site controller. But I find having "buttons" on the device controller a nice interface.&lt;br /&gt;&lt;br /&gt;Using this technique, I can "dry" up the controller, and reuse it for several "purposes". No need to repeat the "controller". &lt;br /&gt;&lt;br /&gt;Note that we have to "pass" the level3 status up thru the controller, and then back down thru the partials.&lt;br /&gt;&lt;br /&gt;First the widgets for tabnav&lt;br /&gt;&lt;br /&gt;File: app\views\widgets\_device_tier2_tabnav.rhtml&lt;br /&gt;&lt;%  &lt;br /&gt;level3 = nil&lt;br /&gt;render_tabnav :device_tier2, &lt;br /&gt;              :generate_css =&gt; true do &lt;br /&gt; &lt;br /&gt;   add_tab do |t|&lt;br /&gt;    t.named 'All'&lt;br /&gt;    t.titled 'All'&lt;br /&gt;    t.links_to :controller =&gt; 'device'&lt;br /&gt;    end &lt;br /&gt;   add_tab do |t|&lt;br /&gt;    t.named 'Sites'&lt;br /&gt;    t.named 'Sites'&lt;br /&gt;    t.links_to :controller =&gt; 'device?level3=device_sites_tier3'&lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;%&gt;&lt;br /&gt;&lt;br /&gt;File: app/views/widgets/_device_sites_tier3_tabnav.rhtml&lt;br /&gt;&lt;%&lt;br /&gt;render_tabnav :device_sites_tier3,&lt;br /&gt;              :generate_css =&gt; true do&lt;br /&gt;           Site.find(:all).each do |thesite|&lt;br /&gt;              add_tab do |t|&lt;br /&gt;                 t.named thesite.name&lt;br /&gt;                 t.links_to :controller =&gt; "device?site=#{thesite.id}&amp;level3=device_sites_tier3"&lt;br /&gt;                 end&lt;br /&gt;              end&lt;br /&gt;end&lt;br /&gt;%&gt;&lt;br /&gt;&lt;br /&gt;File app\views\layouts\tier2device.rhtml&lt;br /&gt;&amp;lt;html&gt;&lt;br /&gt;&amp;lt;%= javascript_include_tag :defaults %&gt;&lt;br /&gt;&amp;lt;%= active_scaffold_includes %&gt;&lt;br /&gt;&amp;lt;%= stylesheet_link_tag "/javascripts/jscalendar-1.0/calendar-win2k-cold-1.css" %&gt;&lt;br /&gt;&amp;lt;%= javascript_include_tag "jscalendar-1.0/calendar.js" %&gt;&lt;br /&gt;&amp;lt;%= javascript_include_tag "jscalendar-1.0/lang/calendar-en.js" %&gt;&lt;br /&gt;&amp;lt;%= javascript_include_tag "jscalendar-1.0/calendar-setup.js" %&gt;&lt;br /&gt;&amp;lt;head&gt;&lt;br /&gt;  &amp;lt;title&gt;AppName&amp;lt;/title&gt;&lt;br /&gt;&amp;lt;/head&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;body&gt;&lt;br /&gt;&amp;lt;br&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;%= tabnav :airstate %&gt; &lt;br /&gt;&amp;lt;%= tabnav :device_tier2 %&gt;&lt;br /&gt;&amp;lt;% if @level3 %&gt;&lt;br /&gt;&amp;lt;%= tabnav  @level3 %&gt;&lt;br /&gt;&amp;lt;% end %&gt;&lt;br /&gt;&amp;lt;%= @content_for_layout %&gt;&lt;br /&gt;&amp;lt;/body&gt;&lt;br /&gt;&amp;lt;/html&gt;&lt;br /&gt;&lt;br /&gt;The controller, which is using activescaffold looks like this:&lt;br /&gt;class DeviceController &lt; ApplicationController&lt;br /&gt;  layout 'tier2device'&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  active_scaffold :device do |config|&lt;br /&gt;    config.actions = [:delete,:show, :list, :nested, :search]&lt;br /&gt;    config.list.columns = [:network, :name, :serialnum, :model, :macs, :purchase_date, :warranty_end]&lt;br /&gt;    config.columns[:macs].ui_type = :select&lt;br /&gt;    config.columns[:network].ui_type = :select&lt;br /&gt;    config.columns[:user].ui_type = :select&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;def conditions_for_collection&lt;br /&gt;       &lt;br /&gt;  @level3 = nil&lt;br /&gt;  if params.include?("level3")&lt;br /&gt;     @level3 = params.delete("level3")&lt;br /&gt;     end&lt;br /&gt;  if params.include?("site")&lt;br /&gt;     mysite = params.delete("site")&lt;br /&gt;     mynets = Network.find(:all,:conditions =&gt; "site_id = #{mysite}")&lt;br /&gt;     mywhere = ['network_id IN (?)', mynets]&lt;br /&gt;     end&lt;br /&gt;&lt;br /&gt;return mywhere&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;References - No .each in active record&lt;br /&gt;http://weblog.jamisbuck.org/2007/4/6/faking-cursors-in-activerecord&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-2849868929140441802?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/2849868929140441802/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=2849868929140441802' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/2849868929140441802'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/2849868929140441802'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/07/dynamic-tabnav-widget-menus.html' title='Dynamic Tabnav Widget menus'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-1753924392459444585</id><published>2008-07-06T17:20:00.000-07:00</published><updated>2008-07-06T17:26:23.593-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby servicetag wmi'/><title type='text'>Reading the Service Tag or Serial Number in Ruby</title><content type='html'>I want to "do" a inventory of "all" my equipment. (Yes It will eventually be a Rails app), but the first issue is gettig all the "service" tags, and updating them on the fly. If you search, you'll find plenty of examples in vb or python, but not very many. (Read none) in ruby. So I decided to see if I could do it.&lt;br /&gt;&lt;br /&gt;First I liked the ruby-wmi package, that gives a activerecord flavor to wmi. WMI is windows standard "Instrumentation" library, where you can find out all too many facts about a windows system. &lt;br /&gt;&lt;br /&gt;Next a little "code" of my own to show "how" to do it. Implemented as a class on top of ruby-wmi, with some basic "caching" to make the overhead smaller.&lt;br /&gt;&lt;br /&gt;require 'ruby-wmi'&lt;br /&gt;require 'pp'&lt;br /&gt;&lt;br /&gt;# Reference URL's&lt;br /&gt;# http://www.vbforums.com/showthread.php?t=326425&lt;br /&gt;# http://ruby-wmi.rubyforge.org/doc/classes/WMI/Base.html&lt;br /&gt;# http://mentalpagingspace.blogspot.com/2008/01/ruby-class-tutorial-using-unify-dbi.html&lt;br /&gt;&lt;br /&gt;class ManagePC&lt;br /&gt;&lt;br /&gt;def initialize(ipaddress)&lt;br /&gt;&lt;br /&gt;@myip = ipaddress&lt;br /&gt;@biosv = WMI::Win32_BIOS.find(:all,:host=&gt;@myip)&lt;br /&gt;@csysv  = WMI::Win32_ComputerSystem.find(:all,:host=&gt;@myip)&lt;br /&gt;@netv   = WMI::Win32_NetworkAdapterConfiguration.find(:all,&lt;br /&gt;                          :conditions =&gt; 'IPEnabled = True')&lt;br /&gt;return&lt;br /&gt;&lt;br /&gt;end #initialize&lt;br /&gt;&lt;br /&gt;def prtnetvalues()   &lt;br /&gt;    @netv.each do |netx|&lt;br /&gt;      netx.properties_.each do |p|&lt;br /&gt;        value = netx[p.name]&lt;br /&gt;        if value&lt;br /&gt;           if value.class == Fixnum&lt;br /&gt;              value = value.to_s&lt;br /&gt;              end&lt;br /&gt;           if value.class == Array&lt;br /&gt;              value = value.to_s&lt;br /&gt;              end&lt;br /&gt;           if value.class == TrueClass&lt;br /&gt;              if value&lt;br /&gt;                 value = "True"&lt;br /&gt;                else&lt;br /&gt;                 value = "False"&lt;br /&gt;                end&lt;br /&gt;              end&lt;br /&gt;           theprop = p.name + "="&lt;br /&gt;           theprop &lt;&lt; value&lt;br /&gt;           puts theprop&lt;br /&gt;           end&lt;br /&gt;        end&lt;br /&gt;     end&lt;br /&gt;end # prtnetvalues()&lt;br /&gt;&lt;br /&gt;def prtcsysvalues()   &lt;br /&gt;    @csysv.each do |csys|&lt;br /&gt;      csys.properties_.each do |p|&lt;br /&gt;        printf "#{p.name} = #{csys[p.name]}\n"&lt;br /&gt;        end&lt;br /&gt;     end&lt;br /&gt;end # prtcsysvalues()&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def netvalue(name)&lt;br /&gt;    @netv.each do |netx|&lt;br /&gt;      netx.properties_.each do |p|&lt;br /&gt;        if p.name == name&lt;br /&gt;           return netx[name]&lt;br /&gt;           end&lt;br /&gt;        end&lt;br /&gt;     end    &lt;br /&gt;   return nil&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def csysvalue(name)&lt;br /&gt;    @csysv.each do |csys|&lt;br /&gt;      csys.properties_.each do |p|&lt;br /&gt;        if p.name == name&lt;br /&gt;           return csys[name]&lt;br /&gt;           end&lt;br /&gt;        end&lt;br /&gt;     end    &lt;br /&gt;   return nil&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def macs()&lt;br /&gt;    mymacs = Array.new&lt;br /&gt;    current_mac = nil&lt;br /&gt;    @netv.each do |netx|&lt;br /&gt;      netx.properties_.each do |p|&lt;br /&gt;        if p.name == "IPAddress"&lt;br /&gt;           current_mac &lt;&lt; netx[p.name].to_s&lt;br /&gt;           end&lt;br /&gt;        if p.name == "MACAddress"&lt;br /&gt;           current_mac &lt;&lt; netx[p.name]&lt;br /&gt;           end&lt;br /&gt;        if p.name == "Caption" # A new network interface&lt;br /&gt;           if current_mac&lt;br /&gt;              mymacs &lt;&lt; current_mac&lt;br /&gt;              end&lt;br /&gt;           current_mac = Array.new&lt;br /&gt;           end&lt;br /&gt;        end&lt;br /&gt;     end    &lt;br /&gt;   mymacs &lt;&lt; current_mac&lt;br /&gt;   return(mymacs)&lt;br /&gt;end&lt;br /&gt;       &lt;br /&gt;&lt;br /&gt;def domain()&lt;br /&gt;    return csysvalue("Domain")&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def model()&lt;br /&gt;    return csysvalue("Model")&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def name()&lt;br /&gt;    return csysvalue("Name")&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def domain?()&lt;br /&gt;    return csysvalue("PartOfDomain")&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def username()&lt;br /&gt;    return csysvalue("UserName")&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def memory()&lt;br /&gt;    return csysvalue("TotalPhysicalMemory")&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def servicetag()&lt;br /&gt;@biosv.each do |bios|&lt;br /&gt; bios.properties_.each do |p|&lt;br /&gt;    if p.name == "SerialNumber"&lt;br /&gt;       return(bios[p.name])&lt;br /&gt;       end&lt;br /&gt;      end&lt;br /&gt;   end&lt;br /&gt;  return(nill)&lt;br /&gt;end #GetServiceTag&lt;br /&gt;&lt;br /&gt;end #ManagePC&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;mypc = ManagePC.new("127.0.0.1")&lt;br /&gt;puts mypc.servicetag&lt;br /&gt;puts mypc.domain&lt;br /&gt;puts mypc.model&lt;br /&gt;puts mypc.name&lt;br /&gt;puts mypc.username&lt;br /&gt;puts mypc.memory&lt;br /&gt;pp mypc.macs&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-1753924392459444585?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.vbforums.com/showthread.php?t=326425' title='Reading the Service Tag or Serial Number in Ruby'/><link rel='enclosure' type='' href='http://www.vbforums.com/showthread.php?t=326425' length='0'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/1753924392459444585/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=1753924392459444585' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/1753924392459444585'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/1753924392459444585'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/07/reading-service-tag-or-serial-number-in.html' title='Reading the Service Tag or Serial Number in Ruby'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-9078826064747366806</id><published>2008-07-01T17:33:00.000-07:00</published><updated>2008-07-01T17:37:55.957-07:00</updated><title type='text'>Annoucing PDFTORUBY Support Forum</title><content type='html'>PDFtoRuby now has a support "forum" hosted via Google Groups.&lt;br /&gt;If your having issues or problems with PDFtoRuby, or its "just" working&lt;br /&gt;please feel free to drop a message on the board.&lt;br /&gt;&lt;br /&gt;I'll be glad to help "resolve" any issues you have&lt;br /&gt;&lt;br /&gt;http://groups.google.com/group/pdftoruby?hl=en&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-9078826064747366806?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://groups.google.com/group/pdftoruby?hl=en' title='Annoucing PDFTORUBY Support Forum'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/9078826064747366806/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=9078826064747366806' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/9078826064747366806'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/9078826064747366806'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/07/annoucing-pdftoruby-support-forum.html' title='Annoucing PDFTORUBY Support Forum'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-4380730119199146632</id><published>2008-06-25T23:25:00.000-07:00</published><updated>2008-06-25T23:35:41.898-07:00</updated><title type='text'>Rapid easy loading of CSV data in a Rails migration</title><content type='html'>Well, it had to happen sometimes.&lt;br /&gt;I was sent some nice "huge" database tables, that&lt;br /&gt;had been exported as "csv" files. So new there&lt;br /&gt;were several "ways" of handling this in ruby,&lt;br /&gt;so I wanted to do it in a migration, and since the&lt;br /&gt;tables have "lots" of columns, didnt want to have to "write" them&lt;br /&gt;out.&lt;br /&gt;&lt;br /&gt;I use both "fastercsv" in combination with ar_extensions&lt;br /&gt;I could not find a "blog" article that had a "simple" migration using&lt;br /&gt;the combination.&lt;br /&gt;&lt;br /&gt;Not that I load "ar_extensions" in my enviornment.rb&lt;br /&gt;Also note that the table is "created" in another migration.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# 099_load_myrecipes.rb&lt;br /&gt;require 'fastercsv'&lt;br /&gt;&lt;br /&gt;class LoadRecipes &lt; ActiveRecord::Migration&lt;br /&gt;  def self.up&lt;br /&gt;      mycnames = Recipes.columns.map{ |column| column.name }&lt;br /&gt;      mycnames.delete("id")&lt;br /&gt;      value_sets = FasterCSV.read("#{RAILS_ROOT}/mdata/Recipes.csv", :col_sep =&gt; ",", &lt;br /&gt;                                   :row_sep =&gt; "\n")&lt;br /&gt;      options = { :validate =&gt; false } &lt;br /&gt;      Recipes.import( mycnames, value_sets, options)&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def self.down&lt;br /&gt;      Recipes.delete_all()&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;Resources:&lt;br /&gt;FasterCSV Doc               - http://fastercsv.rubyforge.org/&lt;br /&gt;FasterCSV and arext article - http://www.jobwd.com/article/show/31&lt;br /&gt;AR Extention                - http://www.continuousthinking.com/tags/arext&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-4380730119199146632?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/4380730119199146632/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=4380730119199146632' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/4380730119199146632'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/4380730119199146632'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/06/rapid-easy-loading-of-csv-data-in-rails.html' title='Rapid easy loading of CSV data in a Rails migration'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-899433899649938002</id><published>2008-06-24T17:21:00.000-07:00</published><updated>2008-06-24T17:29:34.480-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby fmq message queue rails'/><title type='text'>Great new ruby "tool" - Free Message queue</title><content type='html'>Wow, now this is something that is easy to use, and works out of the "can".&lt;br /&gt;&lt;br /&gt;gem install fmq &lt;br /&gt;&lt;br /&gt;Gets you started. This is a "message" queue system. It lets you implement a "fire" and forget type messaging system. (In my old Stratus or VOS days, we called them "server" queues.)&lt;br /&gt;&lt;br /&gt;So you set up a "server", which in this can is a "mongrel" rails application, that manages multiple "server" queues. The communications method is "http", which means it will go thru firewalls easy. Your "client", which could be a pc, or a "ruby" capable device then can "fire" work to be done at the server, such as request a report, or perform some "action". &lt;br /&gt;&lt;br /&gt;For example, in "device" management, it could be to "get" outstanding commands, or "update" status. The work is "queued" and processed as quick as possible.&lt;br /&gt;&lt;br /&gt;The nice thing about fmq that I can see is the "dependencies" are "tiny" to "none". There's a cute little demo/management system that lets you create "queues", and fire messages, and receive messages. &lt;br /&gt;&lt;br /&gt;In doing a lot of "missing" critical applications I find a good message system is critical. I've even coded my own "system" to extend "server/message" queues to a pc. &lt;br /&gt;This looks "simple" and "good".&lt;br /&gt;&lt;br /&gt;So I'll give this a spin in a "real" project, and see how it flies. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;http://fmq.rubyforge.org&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-899433899649938002?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://fmq.rubyforge.org/' title='Great new ruby &quot;tool&quot; - Free Message queue'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/899433899649938002/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=899433899649938002' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/899433899649938002'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/899433899649938002'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/06/great-new-ruby-tool-free-message-queue.html' title='Great new ruby &quot;tool&quot; - Free Message queue'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-7553959858833743465</id><published>2008-05-20T00:12:00.000-07:00</published><updated>2008-05-20T00:15:50.051-07:00</updated><title type='text'>Annoucing pdftoruby</title><content type='html'>Did you ever need to "modify" pdf files, or "recreate" them with&lt;br /&gt;fields changed or added. Do you ever want to generate nice "invoices"&lt;br /&gt;or other "forms" documents, but dont want to break out the ruler to &lt;br /&gt;"recreate" the form. &lt;br /&gt;&lt;br /&gt;Now there's a tool that can take a pdf form, and convert it to ruby code.&lt;br /&gt;This "unifies" pdf::reader and pdf::writer libraries. &lt;br /&gt;&lt;br /&gt;pdftoruby generates ruby code from a supplied pdf.&lt;br /&gt;You can then "edit" the ruby code to add/delete/modfiy and run the code,&lt;br /&gt;it will generate the pdf file using pdf::writer.&lt;br /&gt;&lt;br /&gt;I've used the result code in a rails production application for months now, without issue.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;http://code.google.com/p/pdftoruby/&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-7553959858833743465?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://code.google.com/p/pdftoruby/' title='Annoucing pdftoruby'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/7553959858833743465/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=7553959858833743465' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/7553959858833743465'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/7553959858833743465'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/05/annoucing-pdftoruby.html' title='Annoucing pdftoruby'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-8991965217804371588</id><published>2008-05-20T00:07:00.000-07:00</published><updated>2008-05-20T00:12:01.914-07:00</updated><title type='text'>Creating PDF::Writer Compatible PNG Files</title><content type='html'>I've fought PNG for a while. Scanning google countless times to&lt;br /&gt;figure out how to get a PNG to write, in as few as lines of possible.&lt;br /&gt;&lt;br /&gt;So my final choice is to use a "clone" of png gem, with a few changes.&lt;br /&gt;&lt;br /&gt;One, make sure to write in "binary", so your file opens in the library must&lt;br /&gt;be in a "b" option. The default install of PNG, does not have the "b" option,&lt;br /&gt;which means it will work perfectly fine on linux/unix, and not at all in windows.&lt;br /&gt;&lt;br /&gt;The second problem is the "color" space type. The default is 6, which means there&lt;br /&gt;is a transparency byte per pixel. This of course does not work with PDF::writer.&lt;br /&gt;So My version uses "2", which drops the transparency byte, and writes 3 bytes.&lt;br /&gt;&lt;br /&gt;The later versions of png gem, switch to using inline, which require a compiler to work. Since it makes installing pdftoruby a pain, I wanted something simple.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;class String # :nodoc:&lt;br /&gt;  ##&lt;br /&gt;  # Calculates a CRC using the algorithm in the PNG specification.&lt;br /&gt;  def png_crc&lt;br /&gt;    unless defined? @@crc then&lt;br /&gt;      @@crc = Array.new(256)&lt;br /&gt;      256.times do |n|&lt;br /&gt;        c = n&lt;br /&gt;        8.times do&lt;br /&gt;          c = (c &amp; 1 == 1) ? 0xedb88320 ^ (c &gt;&gt; 1) : c &gt;&gt; 1&lt;br /&gt;        end&lt;br /&gt;        @@crc[n] = c&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    c = 0xffffffff&lt;br /&gt;    each_byte do |b|&lt;br /&gt;      c = @@crc[(c^b) &amp; 0xff] ^ (c &gt;&gt; 8)&lt;br /&gt;    end&lt;br /&gt;    return c ^ 0xffffffff&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;## gsw - Make sure we have version 1 - as version 2 will require major havoc - also fix the "binary" issue&lt;br /&gt;# A pure Ruby Portable Network Graphics (PNG) writer.&lt;br /&gt;#&lt;br /&gt;# http://www.libpng.org/pub/png/spec/1.2/&lt;br /&gt;#&lt;br /&gt;# PNG supports:&lt;br /&gt;# + 8 bit truecolor PNGs&lt;br /&gt;#&lt;br /&gt;# PNG does not support:&lt;br /&gt;# + any other color depth&lt;br /&gt;# + extra data chunks&lt;br /&gt;# + filters&lt;br /&gt;#&lt;br /&gt;# = Example&lt;br /&gt;#&lt;br /&gt;#   require 'png'&lt;br /&gt;#   &lt;br /&gt;#   canvas = PNG::Canvas.new 200, 200&lt;br /&gt;#   canvas[100, 100] = PNG::Color::Black&lt;br /&gt;#   canvas.line 50, 50, 100, 50, PNG::Color::Blue&lt;br /&gt;#   png = PNG.new canvas&lt;br /&gt;#   png.save 'blah.png'&lt;br /&gt;&lt;br /&gt;class PNG&lt;br /&gt;&lt;br /&gt;  ##&lt;br /&gt;  # Creates a PNG chunk of type +type+ that contains +data+.&lt;br /&gt;&lt;br /&gt;  def self.chunk(type, data="")&lt;br /&gt;    [data.size, type, data, (type + data).png_crc].pack("Na*a*N")&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  ##&lt;br /&gt;  # Creates a new PNG object using +canvas+&lt;br /&gt;&lt;br /&gt;  def initialize(canvas)&lt;br /&gt;    @height = canvas.height&lt;br /&gt;    @width = canvas.width&lt;br /&gt;    @bits = 8&lt;br /&gt;    @data = canvas.data&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  ##&lt;br /&gt;  # Writes the PNG to +path+.&lt;br /&gt;&lt;br /&gt;  def save(path)&lt;br /&gt;    File.open(path, "wb") do |f|&lt;br /&gt;      f.write [137, 80, 78, 71, 13, 10, 26, 10].pack("C*") # PNG signature&lt;br /&gt;      f.write PNG.chunk('IHDR',&lt;br /&gt;                        [ @height, @width, @bits, 2, 0, 0, 0 ].pack("N2C5"))&lt;br /&gt;      # 0 == filter type code "none"&lt;br /&gt;      data = @data.map { |row| [0] + row.map { |p| [p.values[0], p.values[1], p.values[2]] } }.flatten&lt;br /&gt;      #data = @data.map { |row| [0] + row.map { |p| p.values } }.flatten&lt;br /&gt;      f.write PNG.chunk('IDAT', Zlib::Deflate.deflate(data.pack("C*"), 9))&lt;br /&gt;      f.write PNG.chunk('IEND', '')&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  ##&lt;br /&gt;  # RGBA colors&lt;br /&gt;&lt;br /&gt;  class Color&lt;br /&gt;&lt;br /&gt;    attr_reader :values&lt;br /&gt;&lt;br /&gt;    ##&lt;br /&gt;    # Creates a new color with values +red+, +green+, +blue+, and +alpha+.&lt;br /&gt;&lt;br /&gt;    def initialize(red, green, blue, alpha)&lt;br /&gt;      @values = [red, green, blue, alpha]&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    ##&lt;br /&gt;    # Transparent white&lt;br /&gt;&lt;br /&gt;    Background = Color.new 0xFF, 0xFF, 0xFF, 0x00&lt;br /&gt; &lt;br /&gt;    White      = Color.new 0xFF, 0xFF, 0xFF, 0xFF&lt;br /&gt;    Black      = Color.new 0x00, 0x00, 0x00, 0xFF&lt;br /&gt;    Gray       = Color.new 0x7F, 0x7F, 0x7F, 0xFF&lt;br /&gt;&lt;br /&gt;    Red        = Color.new 0xFF, 0x00, 0x00, 0xFF&lt;br /&gt;    Orange     = Color.new 0xFF, 0xA5, 0x00, 0xFF&lt;br /&gt;    Yellow     = Color.new 0xFF, 0xFF, 0x00, 0xFF&lt;br /&gt;    Green      = Color.new 0x00, 0xFF, 0x00, 0xFF&lt;br /&gt;    Blue       = Color.new 0x00, 0x00, 0xFF, 0xFF&lt;br /&gt;    Purple     = Color.new 0XFF, 0x00, 0xFF, 0xFF&lt;br /&gt;&lt;br /&gt;    ##&lt;br /&gt;    # Red component&lt;br /&gt;&lt;br /&gt;    def r; @values[0]; end&lt;br /&gt;&lt;br /&gt;    ##&lt;br /&gt;    # Green component&lt;br /&gt;&lt;br /&gt;    def g; @values[1]; end&lt;br /&gt;&lt;br /&gt;    ##&lt;br /&gt;    # Blue component&lt;br /&gt;&lt;br /&gt;    def b; @values[2]; end&lt;br /&gt;&lt;br /&gt;    ##&lt;br /&gt;    # Alpha transparency component&lt;br /&gt;&lt;br /&gt;    def a; @values[3]; end&lt;br /&gt;&lt;br /&gt;    ##&lt;br /&gt;    # Blends +color+ into this color returning a new blended color.&lt;br /&gt;&lt;br /&gt;    def blend(color)&lt;br /&gt;      return Color.new((r * (0xFF - color.a) + color.r * color.a) &gt;&gt; 8,&lt;br /&gt;                       (g * (0xFF - color.a) + color.g * color.a) &gt;&gt; 8,&lt;br /&gt;                       (b * (0xFF - color.a) + color.b * color.a) &gt;&gt; 8,&lt;br /&gt;                       (a * (0xFF - color.a) + color.a * color.a) &gt;&gt; 8)&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    ##&lt;br /&gt;    # Returns a new color with an alpha value adjusted by +i+.&lt;br /&gt;&lt;br /&gt;    def intensity(i)&lt;br /&gt;      return Color.new(r,b,g,(a*i) &gt;&gt; 8)&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    def inspect # :nodoc:&lt;br /&gt;      "#&lt;%s %02x %02x %02x %02x&gt;" % [self.class, *@values]&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  ##&lt;br /&gt;  # PNG canvas&lt;br /&gt;&lt;br /&gt;  class Canvas&lt;br /&gt;&lt;br /&gt;    ##&lt;br /&gt;    # Height of the canvas&lt;br /&gt;&lt;br /&gt;    attr_reader :height&lt;br /&gt;&lt;br /&gt;    ##&lt;br /&gt;    # Width of the canvas&lt;br /&gt;&lt;br /&gt;    attr_reader :width&lt;br /&gt;&lt;br /&gt;    ##&lt;br /&gt;    # Raw data&lt;br /&gt;&lt;br /&gt;    attr_reader :data&lt;br /&gt;&lt;br /&gt;    def initialize(height, width, background = Color::White)&lt;br /&gt;      @height = height&lt;br /&gt;      @width = width&lt;br /&gt;      @data = Array.new(@width) { |x| Array.new(@height) { background } }&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    ##&lt;br /&gt;    # Retrieves the color of the pixel at (+x+, +y+).&lt;br /&gt;&lt;br /&gt;    def [](x, y)&lt;br /&gt;      raise "bad x value #{x} &gt;= #{@height}" if x &gt;= @height&lt;br /&gt;      raise "bad y value #{y} &gt;= #{@width}" if y &gt;= @width&lt;br /&gt;      @data[y][x]&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    ##&lt;br /&gt;    # Sets the color of the pixel at (+x+, +y+) to +color+.&lt;br /&gt;&lt;br /&gt;    def []=(x, y, color)&lt;br /&gt;      raise "bad x value #{x} &gt;= #{@height}" if x &gt;= @height&lt;br /&gt;      raise "bad y value #{y} &gt;= #{@width}"  if y &gt;= @width&lt;br /&gt;      @data[y][x] = color&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    ##&lt;br /&gt;    # Iterates over each pixel in the canvas.&lt;br /&gt;&lt;br /&gt;    def each&lt;br /&gt;      @data.each_with_index do |row, y|&lt;br /&gt;        row.each_with_index do |pixel, x|&lt;br /&gt;          yield x, y, color&lt;br /&gt;        end&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    ##&lt;br /&gt;    # Blends +color+ onto the color at point (+x+, +y+).&lt;br /&gt;&lt;br /&gt;    def point(x, y, color)&lt;br /&gt;      self[x,y] = self[x,y].blend(color)&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    ##&lt;br /&gt;    # Draws a line using Xiaolin Wu's antialiasing technique.&lt;br /&gt;    #&lt;br /&gt;    # http://en.wikipedia.org/wiki/Xiaolin_Wu's_line_algorithm&lt;br /&gt;&lt;br /&gt;    def line(x0, y0, x1, y1, color)&lt;br /&gt;      dx = x1 - x0&lt;br /&gt;      sx = dx &lt; 0 ? -1 : 1&lt;br /&gt;      dx *= sx # TODO: abs?&lt;br /&gt;      dy = y1 - y0&lt;br /&gt;&lt;br /&gt;      # 'easy' cases&lt;br /&gt;      if dy == 0 then&lt;br /&gt;        Range.new(*[x0,x1].sort).each do |x|&lt;br /&gt;          point(x, y0, color)&lt;br /&gt;        end&lt;br /&gt;        return&lt;br /&gt;      end&lt;br /&gt;&lt;br /&gt;      if dx == 0 then&lt;br /&gt;        (y0..y1).each do |y|&lt;br /&gt;          point(x0, y, color)&lt;br /&gt;        end&lt;br /&gt;        return&lt;br /&gt;      end&lt;br /&gt;&lt;br /&gt;      if dx == dy then&lt;br /&gt;        Range.new(*[x0,x1].sort).each do |x|&lt;br /&gt;          point(x, y0, color)&lt;br /&gt;          y0 += 1&lt;br /&gt;        end&lt;br /&gt;        return&lt;br /&gt;      end&lt;br /&gt;&lt;br /&gt;      # main loop&lt;br /&gt;      point(x0, y0, color)&lt;br /&gt;      e_acc = 0&lt;br /&gt;      if dy &gt; dx then # vertical displacement&lt;br /&gt;        e = (dx &lt;&lt; 16) / dy&lt;br /&gt;        (y0...y1-1).each do |i|&lt;br /&gt;          e_acc_temp, e_acc = e_acc, (e_acc + e) &amp; 0xFFFF&lt;br /&gt;          x0 = x0 + sx if (e_acc &lt;= e_acc_temp) &lt;br /&gt;          w = 0xFF-(e_acc &gt;&gt; 8)&lt;br /&gt;          point(x0, y0, color.intensity(w))&lt;br /&gt;          y0 = y0 + 1&lt;br /&gt;          point(x0 + sx, y0, color.intensity(0xFF-w))&lt;br /&gt;        end&lt;br /&gt;        point(x1, y1, color)&lt;br /&gt;        return&lt;br /&gt;      end&lt;br /&gt;&lt;br /&gt;      # horizontal displacement&lt;br /&gt;      e = (dy &lt;&lt; 16) / dx&lt;br /&gt;      (x0...(x1-sx)).each do |i|&lt;br /&gt;        e_acc_temp, e_acc = e_acc, (e_acc + e) &amp; 0xFFFF&lt;br /&gt;        y0 += 1 if (e_acc &lt;= e_acc_temp)&lt;br /&gt;        w = 0xFF-(e_acc &gt;&gt; 8)&lt;br /&gt;        point(x0, y0, color.intensity(w))&lt;br /&gt;        x0 += sx&lt;br /&gt;        point(x0, y0 + 1, color.intensity(0xFF-w))&lt;br /&gt;      end&lt;br /&gt;      point(x1, y1, color)&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;end&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-8991965217804371588?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/8991965217804371588/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=8991965217804371588' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/8991965217804371588'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/8991965217804371588'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/05/creating-pdfwriter-compatible-png-files.html' title='Creating PDF::Writer Compatible PNG Files'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-4619279187084562958</id><published>2008-04-23T20:04:00.000-07:00</published><updated>2008-04-23T20:19:58.695-07:00</updated><title type='text'>Ruby Png Gem - Getting Rid of Inline</title><content type='html'>Hmm, I know I grew up cutting teeth on C, but the "overhead" of getting &lt;br /&gt;decent development environment, and "syncing" your compiler version&lt;br /&gt;to that of who-ever wrote the code originally gets to be fun.&lt;br /&gt;&lt;br /&gt;Its even worse when your going cross platform. (Yes I now prefer to&lt;br /&gt;do my coding in ruby whenever possible).&lt;br /&gt;&lt;br /&gt;I was reading thru ruby group on goole, about how to speed up the "png"&lt;br /&gt;gem without using inline. I'm going to give that a try. Then I can use&lt;br /&gt;the resolve in my pdftoruby tool. &lt;br /&gt;&lt;br /&gt;Should be interesting, will update the article after I finish.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-4619279187084562958?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://groups.google.com/group/ruby-talk-google/browse_thread/thread/4c965de1ccb7e69c/4e588177392adbf3?lnk=gst&amp;q=png#4e588177392adbf3' title='Ruby Png Gem - Getting Rid of Inline'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/4619279187084562958/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=4619279187084562958' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/4619279187084562958'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/4619279187084562958'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/04/ruby-png-gem-getting-rid-of-inline.html' title='Ruby Png Gem - Getting Rid of Inline'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-749732333279843216</id><published>2008-04-23T02:00:00.000-07:00</published><updated>2008-04-23T02:11:16.857-07:00</updated><title type='text'>Geting Ruby png1.0.0 to work in windows</title><content type='html'>I need to be able to save "png" files out of my pdftoruby application.&lt;br /&gt;My big problem was to take a "rgb" file, and write it, without using something&lt;br /&gt;heave like ImageMagik. (Which seems like everyone complains about)&lt;br /&gt;&lt;br /&gt;So my first choice was "png", but the latest version of png is not "pure" ruby.&lt;br /&gt;Version 1.0.0 is "pure". The reason this is important, is that with the 1.1.0&lt;br /&gt;release of png gem, you have to use "inline" and that then requires you to &lt;br /&gt;use the "latest" compiler.&lt;br /&gt;&lt;br /&gt;I've installed, and reinstalled png several times, but it seems to never work,&lt;br /&gt;then finally I found a "mention" in a old ruby-talk message thread that on windows&lt;br /&gt;you need the "b" open on the open. (A following comment said it had been patched).&lt;br /&gt;&lt;br /&gt;Well decicded to go look at the source, and sure enough, its not got the "b" option&lt;br /&gt;on the open.&lt;br /&gt;&lt;br /&gt;So do the following:&lt;br /&gt;gem install --version 1.0.0 png&lt;br /&gt;&lt;br /&gt;Then go to the png directory&lt;br /&gt;cd \ruby\lib\ruby\gems\1.8\gems\png-1.0.0\lib&lt;br /&gt;&lt;br /&gt;And edit png.rb&lt;br /&gt;&lt;br /&gt;vi png.rb # Use the editor of your choice&lt;br /&gt;&lt;br /&gt; def save(path)&lt;br /&gt;    File.open(path, "wb") do |f| #Must add the "b" next to the "w" &lt;br /&gt;                                 #here for windows to work&lt;br /&gt;      f.write [137, 80, 78, 71, 13, 10, 26, 10].pack("C*") # PNG signature&lt;br /&gt;      f.write PNG.chunk('IHDR',&lt;br /&gt;                        [ @height, @width, @bits, 6, 0, 0, 0 ].pack("N2C5"))&lt;br /&gt;      # 0 == filter type code "none"&lt;br /&gt;      data = @data.map { |row| [0] + row.map { |p| p.values } }.flatten&lt;br /&gt;      f.write PNG.chunk('IDAT', Zlib::Deflate.deflate(data.pack("C*"), 9))&lt;br /&gt;      f.write PNG.chunk('IEND', '')&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;Now png examples will work, and I can get back to business.&lt;br /&gt;&lt;br /&gt;(I've seen some nice pure ruby optizations in the threads, will implemented those in pdfto ruby)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-749732333279843216?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/749732333279843216/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=749732333279843216' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/749732333279843216'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/749732333279843216'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/04/geting-ruby-png100-to-work-in-windows.html' title='Geting Ruby png1.0.0 to work in windows'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-2109560173980995205</id><published>2008-03-30T04:56:00.001-07:00</published><updated>2008-03-31T17:02:13.846-07:00</updated><title type='text'>The Evils of EBAY - Never never never use them</title><content type='html'>Well you know from the title I had a bad experience from ebay.]&lt;br /&gt;Two years ago, I decided to "try" ebay by buying a lens.&lt;br /&gt;The "seller" had a great reputation. (looks like there are tricks&lt;br /&gt;to give you a false "reputation", if anyone know how, feel free to post them to a comment.)&lt;br /&gt;&lt;br /&gt;So after reading the ad, the seller wanted a "money order" or a "cashier" check. Nevermind, I can do that. So I went to the bank, paid the fee, and sent off my check. I "have" a copy of the check laying in my library to prove it. I mailed it off to the individuals address, and waited and waited and after a month got nothing. THe person saying "he" never got the check. Needless to say I complained to ebay. I gave him "negative" reputation. He returned the favor. &lt;br /&gt;&lt;br /&gt;So I havent tried to use ebay from that bad experience for two years. I did write in and ask for help. I always got "wonderfully" worded emails, but no action. Worse come to find out, after two years I want to "try" it again, and guess what, I still have the "-1" reputation from the "bad" seller. And cannot do a transaction.&lt;br /&gt;&lt;br /&gt;So for me, I'me giving up ebay for life, and will tell everyone I know its a untrustworty company, that there not to be trusted. That you will lose your money, that you will get "sweet" email, when you complain from them, and nothing more.&lt;br /&gt;&lt;br /&gt;Well looks like they (Ebay) will not change the post, but if you see the comment,&lt;br /&gt;they gave a nice invitation.&lt;br /&gt;&lt;br /&gt;So any lawyer in california interested in class action lawsuit against ebay?&lt;br /&gt;I'm intersted in joining a class action suit for people abused, and mentally abused by them.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-2109560173980995205?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/2109560173980995205/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=2109560173980995205' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/2109560173980995205'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/2109560173980995205'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/03/evils-of-ebay-never-never-never-use.html' title='The Evils of EBAY - Never never never use them'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-1245521867254977397</id><published>2008-03-24T00:23:00.001-07:00</published><updated>2008-03-24T00:25:49.841-07:00</updated><title type='text'>ICC Profiles - Decoding Using BitStruct And Ruby</title><content type='html'>I wanted to be able to explore ICC Color Profiles.&lt;br /&gt;Since the data is binary, I wanted to be able to define nice "Structures",&lt;br /&gt;and see the data.&lt;br /&gt;&lt;br /&gt;So I disovered "Bitstruct". Its a library that lets you define&lt;br /&gt;binary data easily.&lt;br /&gt;&lt;br /&gt;Example o fdecoding ICC Profiles:&lt;br /&gt;&lt;br /&gt;require 'bit-struct'&lt;br /&gt;require 'pp'&lt;br /&gt;&lt;br /&gt;class IccHeader &lt; BitStruct&lt;br /&gt;    unsigned  :size,        32, "Profile Size"&lt;br /&gt;    char      :type,        32, "CMM Type Signature"&lt;br /&gt;    octets    :version,     32, "Profile Version Number"&lt;br /&gt;    char      :pdclass,     32, "Profile/Device Class"&lt;br /&gt;    text      :colorspace,  32, "Color Space of Data"&lt;br /&gt;    text      :pconnspace,  32, "Profile Connection Space"&lt;br /&gt;    char      :date,        96, "Creation Date"&lt;br /&gt;    text      :sign,        32, "Profile Signature"&lt;br /&gt;    text      :platform,    32, "Primary Platform"&lt;br /&gt;    text      :flags,       32, "CMM Flags"&lt;br /&gt;    text      :devmanuf,    32, "Device Manufacture"&lt;br /&gt;    text      :devmodel,    32, "Device Model"&lt;br /&gt;    text      :devattr,     64, "Device Attributes"&lt;br /&gt;    text      :renderintent,32, "Rendering Intent"&lt;br /&gt;    char      :xyz1,        32, "XYZ Number 1"&lt;br /&gt;    char      :xyz2,        32, "XYZ Number 2"&lt;br /&gt;    char      :xyz3,        32, "XYZ Number 3"&lt;br /&gt;    char      :creator,     32, "Profile Creator"&lt;br /&gt;    text      :id,         128, "Profile ID"&lt;br /&gt;    text      :reserved,   224, "Reserved"&lt;br /&gt;    unsigned  :tagcount,    32, "Tag Count"&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;class TagTableEntry &lt; BitStruct&lt;br /&gt;    text      :sign,        32, "Signature"&lt;br /&gt;    unsigned  :offset,      32, "Offset"&lt;br /&gt;    unsigned  :size,        32, "Size"&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;puts "Dump of ICC Profile"&lt;br /&gt;pfile = File.open("profile","r")&lt;br /&gt;icchdr = IccHeader.new(pfile.read(132))&lt;br /&gt;pp icchdr&lt;br /&gt;cnt = icchdr.tagcount&lt;br /&gt;offset = 133&lt;br /&gt;tags = Array.new&lt;br /&gt;while cnt &gt; 0&lt;br /&gt;    tags &lt;&lt; TagTableEntry.new(pfile.read(12))&lt;br /&gt;    cnt -= 1&lt;br /&gt;    end&lt;br /&gt;pp tags&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-1245521867254977397?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.color.org/newiccspec.pdf' title='ICC Profiles - Decoding Using BitStruct And Ruby'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/1245521867254977397/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=1245521867254977397' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/1245521867254977397'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/1245521867254977397'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/03/icc-profiles-decoding-using-bitstruct.html' title='ICC Profiles - Decoding Using BitStruct And Ruby'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-4181194156861041639</id><published>2008-02-16T23:41:00.001-08:00</published><updated>2008-02-17T00:00:41.174-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby rubyonrails rake database activerecord'/><title type='text'>Rake Script to Load Seed Data or Update Existing Data</title><content type='html'>In the previous blog we descussed loading of seed data using rake/active record.&lt;br /&gt;What was missing was examples.&lt;br /&gt;&lt;br /&gt;So First a example of our "rake" file. &lt;br /&gt;&lt;br /&gt;namespace :project do&lt;br /&gt; desc 'parts_master_load'&lt;br /&gt; task :parts_master_load =&gt; :environment do&lt;br /&gt;  PartsMaster.uoc :pn =&gt; '11-1111-11',&lt;br /&gt;     :description =&gt; 'Part description for part 11-111-11',&lt;br /&gt;     :application_code =&gt; ApplicationCode.foc('appcode1'),&lt;br /&gt;     :pn_type_code =&gt; PnTypeCode.foc('REF')&lt;br /&gt;  PartsMaster.uoc :pn =&gt; '22-2222-22',&lt;br /&gt;     :description =&gt; 'Part Description for part 22-222-22',&lt;br /&gt;     :application_code =&gt; ApplicationCode.foc('apcode2'),&lt;br /&gt;     :pn_type_code =&gt; PnTypeCode.foc('REF')&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;Rake has the advantage in that it runs with all of rails environment, and for us that means activerecord, so we can use our "models". Another advantage is if there is a error, if you have the rake trace option, you get exactly the line of "data" that caused the issue. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In the above example, there are "three" models that are directly mentioned.&lt;br /&gt;One is the PartsMaster, Two is the ApplicationCode, and the Third is the PnTypeCode.&lt;br /&gt;&lt;br /&gt;The "method" foc is one of my own, that means "find" or "create". Very handly for those "simple" tables that are used for "catagories".&lt;br /&gt;&lt;br /&gt;So as a example of "foc" as used in the "application" code module.&lt;br /&gt;&lt;br /&gt;class ApplicationCode &lt; ActiveRecord::Base&lt;br /&gt;   set_table_name "APPLICATION_CODES"&lt;br /&gt;&lt;br /&gt;   defaults :application_code =&gt; "",&lt;br /&gt;            :cannot_modify   =&gt; "F",&lt;br /&gt;            :converted       =&gt; "F",&lt;br /&gt;         &lt;br /&gt;public&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def self.foc(thevalue) #find_or_create&lt;br /&gt;    if thevalue.nil?&lt;br /&gt;       thevalue = "_"&lt;br /&gt;    end&lt;br /&gt;    if thevalue == ""&lt;br /&gt;       thevalue = "_"&lt;br /&gt;    end&lt;br /&gt;    therecord = find(:first,:conditions =&gt; "application_code = '#{thevalue}'")&lt;br /&gt;    if therecord&lt;br /&gt;        return therecord&lt;br /&gt;        end&lt;br /&gt;    therecord = self.new&lt;br /&gt;    therecord.application_code = thevalue&lt;br /&gt;    therecord.description      = thevalue&lt;br /&gt;    therecord.save&lt;br /&gt;    return therecord&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;Here you can see the power of "foc". We actually use the "application" key to do a "lookup", on existing data. We can "also" cleanup any "issues" with the "incoming" data, to make it more "consistent".  If the record "does" not exist, then the record is created. This also is good illustration of "default" values to make usage of the model "easier".&lt;br /&gt;&lt;br /&gt;Now lets look at a "stippet" of the "update or create" or uoc method. For the main&lt;br /&gt;table in the application, we need to update existing records, since the file has constraints, so we cannot "truncate" the table, and aways do a "create".&lt;br /&gt;&lt;br /&gt;def self.uoc(options = {}) # update or create&lt;br /&gt;    thevalue = options[:pn] #fixme - Need to also look at manufactuer&lt;br /&gt;    record = find(:first,:conditions =&gt; "pn = '#{thevalue}'")&lt;br /&gt;    if record.nil?&lt;br /&gt;      record = new&lt;br /&gt;    end&lt;br /&gt;    record.attributes = options&lt;br /&gt;    record.save!&lt;br /&gt;    &lt;br /&gt;    record&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;This illustrates a lovely "concept" in ruby of allowing us to use a hash, allowing us to take variable arguments in, and pass those variable arguments down. Code looks simple. I could code the same in "C" and it would be rather ugly.&lt;br /&gt;&lt;br /&gt;In this code, the "new" will create a record, and establish defaults (The record has a couple hundred fields, so defaults is "not" small.) and then "update" it with what we pass. That allows the "create" rake script to be very small.&lt;br /&gt;  &lt;br /&gt;So there you have it. From now own, I'm going to use active record to do my data load and migration. It works very nice.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-4181194156861041639?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/4181194156861041639/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=4181194156861041639' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/4181194156861041639'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/4181194156861041639'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/02/rake-script-to-load-seed-data-or-update.html' title='Rake Script to Load Seed Data or Update Existing Data'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-800385385261639632</id><published>2008-02-15T19:00:00.001-08:00</published><updated>2008-02-16T23:41:08.750-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby rails legacyapps activerecord rake'/><title type='text'>Integrating Legacy Applications with Rails</title><content type='html'>I'm current involved in a large software project which is taking a "legacy" applicaton to a "new" generation application. Of course for me, ruby is my "main" tool. So I'm doing the migration with ruby, and looking to use rails to "expand" the canned application with rails functionality.&lt;br /&gt;&lt;br /&gt;So the issues are many, and countless.&lt;br /&gt;&lt;br /&gt;1. Schema - While the database is oracle, the schema of the new system is "huge", 400+ tables is nothing to sneeze at. So first we need some good documentation of it. Does it come with the system? Nope, no schema documentation, so lets create some documentation for easy reference. &lt;br /&gt;&lt;br /&gt;http://schemaspy.sourceforge.net/&lt;br /&gt;&lt;br /&gt;Schemaspy will let us "create" a map of existing schema, so we can explore it, and get familiar with internal standards.&lt;br /&gt;&lt;br /&gt;2. Walking around the data. Next we need to "explore" the data of the new system. For this in a oracle environment, Oracle Sql Developer is free, and lets us look at the data easily.&lt;br /&gt;&lt;br /&gt;3. Write a "script" in ruby to create models automatically. Typing any normal of models, getting plurization right, and creating controllers is not for the faint of heart. I create a "gen" script that generates "missing" models, and controllers. (I use activescaffold plugin for handling the controller side, and models can be started without relationships if you wish. (If I do this a second time, I'll have the relationships also done by the script. Not much fun doing tables that have 20 relationships, where the keyname does not match the tablename.) (Now you know why you need schemaspy).&lt;br /&gt;&lt;br /&gt;4. For importing your "existing data, assuming its not terabytes, I find that it works best in a "two" step process. In previous projects I would write a "dbi" ruby script taking one table to the "new" rails table. That works fine, but now I have destination tables that have "rich" relationships, writing dbi is no fun. ActiveRecord can save the day. &lt;br /&gt;     a. Step 1 - dbi process - Read existing table, and generate a rake script, calling active record "models"&lt;br /&gt;&lt;br /&gt;Reference: http://railspikes.com/2008/2/1/loading-seed-data&lt;br /&gt;&lt;br /&gt;     b. Step 2 - Run your rake script&lt;br /&gt;&lt;br /&gt;Reference:&lt;br /&gt;http://www.slashdotdash.net/articles/2007/01/18/using-activerecord-outside-rails-part-ii&lt;br /&gt;&lt;br /&gt;I find that this gives you the easy ability to handle the multi-tier adds&lt;br /&gt;while keeping things simple.&lt;br /&gt;&lt;br /&gt;When your creating your models, I find that often in "large" applicatons the tables from tradiitional applications can be "huge" number of fields. Of course the reality is that the majority of fields are always" default" values. To keep your create and update clean, use a "defalts" plugin. This will allow you to write you "create" or "create-and-update" call in your rake script to be "very" small, while all the flags and other values get set to the right values.&lt;br /&gt;&lt;br /&gt;Reference:&lt;br /&gt;http://agilewebdevelopment.com/plugins/activerecord_defaults&lt;br /&gt;&lt;br /&gt;This makes my "rake" task incrediably small.&lt;br /&gt;&lt;br /&gt;Finally consider in your models adding a method of either:&lt;br /&gt;&lt;br /&gt;1. uoc - Update or Create - This will let you take a hash, and find a existing record and update it, or create a new one based on the "primary" key that is "application" specific. While my target application does have a numeric primary key, the "real" key is two other fields. using uoc allows me to do a find on the record and update it. (Yes I could "truncate" the table and always do creates, but remmeber its a complex app with a spiderweb of connections, updates work better)&lt;br /&gt;&lt;br /&gt;2. foc - Find or create - This is great for those "simple" tables like unit of measure, or other tables that typically reasly are for "catorgories". It simply "finds" the right record or "create" a new one and returns it for the relationship your building.&lt;br /&gt;&lt;br /&gt;This also makes the rake script re-usable. And the code in your modeles can also be used in "expansion" applications.&lt;br /&gt;&lt;br /&gt;Next week I'll add a few examples.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-800385385261639632?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/800385385261639632/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=800385385261639632' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/800385385261639632'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/800385385261639632'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/02/integrating-legacy-applications-with.html' title='Integrating Legacy Applications with Rails'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-7946165425455216523</id><published>2008-02-05T21:50:00.000-08:00</published><updated>2008-02-05T23:16:40.938-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby rails migrations content management sqlite3'/><title type='text'>Rails - The Menu Problem - Handling Large Scale Applications moving to Rails</title><content type='html'>It was interesting. I'm doing a large progject, and there are 500+ tables to deal with. This is my first "legacy" as it is project. And of course the "same" old tricks dont always work. &lt;br /&gt;&lt;br /&gt;One of the problems, to check my models, of course I generate activescaffold controllers.&lt;br /&gt;&lt;br /&gt;If your've read my previous post, my converts/imports usually do the following:&lt;br /&gt;&lt;br /&gt;1. Move the table.&lt;br /&gt;   a. grab the schema&lt;br /&gt;   b. add missing fields&lt;br /&gt;   c. fix field names and table names for destination database&lt;br /&gt;   d. create the sequence number&lt;br /&gt;   e. create the table in the new schema&lt;br /&gt;2. Create a model&lt;br /&gt;3. Create a controller&lt;br /&gt;4. Update the menu&lt;br /&gt;&lt;br /&gt;This strategy has worked great. You get a reasobly native rails app,&lt;br /&gt;and cleanup some of the database/schmema issues in the process.&lt;br /&gt;&lt;br /&gt;New project is a bit different. Its all in oracle all ready. And its a "off-the-shelf" application.&lt;br /&gt;&lt;br /&gt;So now I need to not "touch" the database schema, but man, I need a extra table, and&lt;br /&gt;how to do menus etc when the functionality is so "rich".&lt;br /&gt;&lt;br /&gt;So I decided to create a separate sqlite3 database just to do menus and functions.&lt;br /&gt;(and maybe some other things along the way).&lt;br /&gt;&lt;br /&gt;So first, need a do a migration (001_system_menu.rb). This will create our new&lt;br /&gt;sqlite3 database, not touching our oracle database that is already working.&lt;br /&gt;I did a trick to get this to work, I created a "empty" sqlite3 database file,&lt;br /&gt;so the schema_version table would already exist, otherwise you get a "nice" error message saying you "cannot" create it.&lt;br /&gt;&lt;br /&gt;Next wanted to get some data "into" the tables, so I created a second migration&lt;br /&gt;(002_add_base_menus.rb) that creates some data so the menu system can be tweaked further. &lt;br /&gt;&lt;br /&gt;So now how to "fill" up the tables in the operating "application"?&lt;br /&gt;So in the models, I added the ability to "walk" the "controller" directory,&lt;br /&gt;and any associated namespaces, and create entries. This will allow you then&lt;br /&gt;to "play" them into the "menu" tree and "treak" the names, and the roles.&lt;br /&gt;&lt;br /&gt;The "update_functions" method does a few things:&lt;br /&gt;1. Verify "functions(controllers)" actually exist, &lt;br /&gt;   then enable or disable as appropriate &lt;br /&gt;   (If we delete we loose the custimization)&lt;br /&gt;2. Find any new controllers and "add" them into the system&lt;br /&gt;&lt;br /&gt;For now thats what we got, next will be to automatically generation of&lt;br /&gt;menu (tabnav) partials for each level of the menu, and arrange for "hooks" in&lt;br /&gt;the application to "know" what his menu is.&lt;br /&gt;&lt;br /&gt;The system_function model has a very good example of "walking" directories.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#-----------------------001_system_menu.rb ------------------------&lt;br /&gt;class SystemMenu &lt; ActiveRecord::Migration&lt;br /&gt;&lt;br /&gt;class SystemMenu &lt; ActiveRecord::Base&lt;br /&gt;  ActiveRecord::Base.establish_connection(&lt;br /&gt;         :adapter =&gt; "sqlite3",&lt;br /&gt;         :database  =&gt; "db/system.sqlite3"&lt;br /&gt;         )&lt;br /&gt;  acts_as_tree&lt;br /&gt;  has_many :SystemFunction &lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;class SystemFunction &lt; ActiveRecord::Base&lt;br /&gt;  ActiveRecord::Base.establish_connection(&lt;br /&gt;         :adapter =&gt; "sqlite3",&lt;br /&gt;         :database  =&gt; "db/system.sqlite3"&lt;br /&gt;         )&lt;br /&gt;  belongs_to :SystemMenu&lt;br /&gt;end&lt;br /&gt;  &lt;br /&gt;  def self.up&lt;br /&gt;    create_table :system_functions do |t|&lt;br /&gt;                 t.column :system_menu_id,  :number&lt;br /&gt;                 t.column :present,         :boolean&lt;br /&gt;                 t.column :enable,          :boolean&lt;br /&gt;                 t.column :name,  :string,  :limit =&gt;32, :null =&gt; false&lt;br /&gt;                 t.column :title, :string,  :limit =&gt;64, :null =&gt; false&lt;br /&gt;                 t.column :controller,      :string,  :limit =&gt;128&lt;br /&gt;                 t.column :role,            :string&lt;br /&gt;                 t.column :created_at,      :datetime&lt;br /&gt;                 t.column :updated_at,      :datetime&lt;br /&gt;                 end&lt;br /&gt;    create_table :system_menus do |t|&lt;br /&gt;                 t.column :name,            :string,  :limit =&gt;32, :null =&gt; false&lt;br /&gt;                 t.column :title,           :string,  :limit =&gt;64, :null =&gt; false&lt;br /&gt;                 t.column :role,            :string,  :limit =&gt;32&lt;br /&gt;                 t.column :enable,          :boolean&lt;br /&gt;                 t.column :parent_id,       :number&lt;br /&gt;                 t.column :created_at,      :datetime&lt;br /&gt;                 t.column :updated_at,      :datetime&lt;br /&gt;                 end&lt;br /&gt;    &lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;  def self.down&lt;br /&gt;      drop_table :system_menus&lt;br /&gt;      drop_table :system_functions&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;class AddBaseMenus &lt; ActiveRecord::Migration&lt;br /&gt;class SystemMenu &lt; ActiveRecord::Base&lt;br /&gt;establish_connection :adapter =&gt; "sqlite3", :database  =&gt; "db/system.sqlite3"&lt;br /&gt;acts_as_tree&lt;br /&gt;has_many :system_function&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;#-------------------- 002_add_base_menus.rb ------------------------&lt;br /&gt;class SystemFunction &lt; ActiveRecord::Base&lt;br /&gt;  establish_connection :adapter =&gt; "sqlite3", :database  =&gt; "db/system.sqlite3"&lt;br /&gt;  belongs_to :system_menu&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;  def self.up&lt;br /&gt;    homemenu = SystemMenu.create :name =&gt; "home", :title =&gt; "Home" &lt;br /&gt;    adminmenu = SystemMenu.create :name =&gt; "admin", :title =&gt; "Admin", :role =&gt; "Admin", :parent_id =&gt; homemenu.id&lt;br /&gt;    SystemFunction.create :system_menu_id =&gt; adminmenu.id, :name =&gt; "Menus", :title =&gt; "System Menus", :controller =&gt; "adminspace/system_menu", :role =&gt; "admin", :present =&gt; TRUE, :enable =&gt; TRUE&lt;br /&gt;    SystemFunction.create :system_menu_id =&gt; adminmenu.id, :name =&gt; "Functions", :title =&gt; "System Functions", :controller =&gt; "adminspace/system_function", :role =&gt; "admin", :present =&gt; TRUE, :enable =&gt; TRUE&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;  def self.down&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;#----------------------- system_menu.rb ----------------------&lt;br /&gt;class SystemMenu &lt; ActiveRecord::Base&lt;br /&gt;establish_connection :adapter =&gt; "sqlite3", :database  =&gt; "db/system.sqlite3"&lt;br /&gt;acts_as_tree&lt;br /&gt;has_many :system_function&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;#---------------------- system_function.rb -------------------&lt;br /&gt;class SystemFunction &lt; ActiveRecord::Base&lt;br /&gt;  establish_connection :adapter =&gt; "sqlite3", :database  =&gt; "db/system.sqlite3"&lt;br /&gt;  belongs_to :system_menu&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;public &lt;br /&gt;def self.update_functions&lt;br /&gt;      app_directory = "./app/controllers"&lt;br /&gt;      verify_functions(app_directory)&lt;br /&gt;      system_function_process_dir(app_directory,"")&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def self.verify_functions(thedir)&lt;br /&gt;         SystemFunction.find(:all).each do |record|&lt;br /&gt;             thepath = thedir + "/" + record.controller + "_controller.rb"&lt;br /&gt;             if File.exists?(thepath)&lt;br /&gt;                if record.present == FALSE&lt;br /&gt;                   record.present = TRUE&lt;br /&gt;                   record.save&lt;br /&gt;                   end&lt;br /&gt;               else&lt;br /&gt;                 if record.present == TRUE&lt;br /&gt;                    record.present = FALSE&lt;br /&gt;                    record.save&lt;br /&gt;                    end&lt;br /&gt;                 end&lt;br /&gt;             end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def self.system_function_process_entry(theparent,thedir, theentry)&lt;br /&gt;    if theentry == "."&lt;br /&gt;        return&lt;br /&gt;        end&lt;br /&gt;    if theentry == ".."&lt;br /&gt;       return&lt;br /&gt;       end&lt;br /&gt;    if theentry == "archive"&lt;br /&gt;       return&lt;br /&gt;       end&lt;br /&gt;    fullpath = thedir + "/" + theentry&lt;br /&gt;    if File.directory?(fullpath)&lt;br /&gt;       system_function_process_dir(fullpath,theentry)&lt;br /&gt;       return&lt;br /&gt;     end&lt;br /&gt;    if theentry.include? "_controller.rb"&lt;br /&gt;       thelen = theentry.index('_controller.rb')&lt;br /&gt;       thename = theentry[0,thelen]&lt;br /&gt;       if theparent == ""&lt;br /&gt;             mycontroller = thename&lt;br /&gt;           else&lt;br /&gt;             mycontroller = theparent + "/" + thename&lt;br /&gt;           end&lt;br /&gt;       myfunction = SystemFunction.find(:first, :conditions =&gt; "controller = '#{mycontroller}'")&lt;br /&gt;       if myfunction == nil # We dont exist&lt;br /&gt;          myfunction = SystemFunction.new&lt;br /&gt;          myfunction.name = thename&lt;br /&gt;          myfunction.system_menu_id = nil&lt;br /&gt;          myfunction.title = thename&lt;br /&gt;          myfunction.controller = mycontroller&lt;br /&gt;          myfunction.enable = FALSE&lt;br /&gt;          myfunction.present = TRUE&lt;br /&gt;          myfunction.role = ''&lt;br /&gt;          myfunction.save&lt;br /&gt;          return&lt;br /&gt;       end&lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def self.system_function_process_dir(thedir,theparent)&lt;br /&gt;    Dir.foreach(thedir){ |theentry| system_function_process_entry(theparent,thedir,theentry)}&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;end&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-7946165425455216523?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://groups.google.com/group/rails-widgets/browse_thread/thread/4fd650a9321054d6' title='Rails - The Menu Problem - Handling Large Scale Applications moving to Rails'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/7946165425455216523/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=7946165425455216523' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/7946165425455216523'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/7946165425455216523'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/02/rails-menu-problem-handling-large-scale.html' title='Rails - The Menu Problem - Handling Large Scale Applications moving to Rails'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-5449386159612821943</id><published>2008-01-30T21:18:00.000-08:00</published><updated>2008-01-30T21:35:06.267-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby rails rubyonrails security logs'/><title type='text'>Rails Security - Is there passwords waiting for the world to read</title><content type='html'>Recently I was promoting a "Rails" app, that was going to be used by another division. And was asking my "boss" to login, and it got me thinking about log file "security". One of the things that has been bothering me for a while was when I was running a app, and looking at the log, either in production or development I would always "say" a few words when a user was loggin in while I was watching. One of my hero's has a favorite saying, "To much information".&lt;br /&gt;&lt;br /&gt;To illustrate:&lt;br /&gt;Processing AccountController#login (for 127.0.0.1 at 2008-01-31 13:10:58) [POST]&lt;br /&gt;  Session ID: 9a85051d00c5aee3dc20305ac0dd315e&lt;br /&gt;  Parameters: {"commit"=&gt;"Log in", "action"=&gt;"login", "controller"=&gt;"adminspace/account", "login"=&gt;"user", "password"=&gt;"secret"}&lt;br /&gt;&lt;br /&gt;And you wll see this in both production and development.&lt;br /&gt;&lt;br /&gt;No there was a few solutions when I was googling:&lt;br /&gt;&lt;br /&gt;1. Turn the logging to warning&lt;br /&gt;in config/environments/production.rb&lt;br /&gt;# Fix the logging so sensitive information is not logged&lt;br /&gt;config.log_level = :warn&lt;br /&gt;&lt;br /&gt;Cons: You loose all your request, now you log analyser and you have very little information on what is going on in your application.&lt;br /&gt;&lt;br /&gt;2. "Filtering"&lt;br /&gt;Now this is "nice". And is good even in development side. (ie I use ldap based authentication, so in development the account and password is REAL). So it&lt;br /&gt;lets me still see whats going on, without printing out the password (My password)&lt;br /&gt;1000 plus times.&lt;br /&gt;&lt;br /&gt;The fix:&lt;br /&gt;in app/controllers/application.rb&lt;br /&gt;&lt;br /&gt;filter_parameter_logging "password"&lt;br /&gt;&lt;br /&gt;This will get rid of any filtered parameter.&lt;br /&gt;&lt;br /&gt;The result (in the development log):&lt;br /&gt;&lt;br /&gt;Processing AccountController#login (for 127.0.0.1 at 2008-01-31 13:10:58) [POST]&lt;br /&gt;  Session ID: 9a85051d00c5aee3dc20305ac0dd315e&lt;br /&gt;  Parameters: {"commit"=&gt;"Log in", "action"=&gt;"login", "controller"=&gt;"adminspace/account", "login"=&gt;"user", "password"=&gt;"[FILTERED]"}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Lovely.&lt;br /&gt;&lt;br /&gt;You can also hide other things as well if you want to keep them secure, credit card numbers etc are good examples.&lt;br /&gt;&lt;br /&gt;I tend to think this should be your "default" setting in any application.&lt;br /&gt;It will be in mine from now on.&lt;br /&gt;&lt;br /&gt;This works in 2.0.2 rails very nicely. (It was actually added quite a while back)&lt;br /&gt;&lt;br /&gt;If you ask me it should be the "default" in the template when generating a rails applicaton.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-5449386159612821943?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://weblog.rubyonrails.org/2006/8/21/filtered-parameter-logging' title='Rails Security - Is there passwords waiting for the world to read'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/5449386159612821943/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=5449386159612821943' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/5449386159612821943'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/5449386159612821943'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/01/rails-security-is-there-passwords.html' title='Rails Security - Is there passwords waiting for the world to read'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-6617913877547885734</id><published>2008-01-27T18:32:00.000-08:00</published><updated>2008-01-27T21:53:56.332-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rubyonrails ruby oracle tablespace'/><title type='text'>Oracle and Rails - Moving tables to new tablespaces</title><content type='html'>Hmmm. Things are growing in my oracle tables, and I really want to&lt;br /&gt;move things around a bit. So moving a "application" or "user" to a new&lt;br /&gt;tablespace is resonably common. &lt;br /&gt;&lt;br /&gt;For me, language for first resort is ruby, so I have quite&lt;br /&gt;a few "little" scripts to do oracle tasks.&lt;br /&gt;&lt;br /&gt;Here's today's, move all of a users tables to a new tablespace.&lt;br /&gt;&lt;br /&gt;require 'DBI'&lt;br /&gt;require 'pp'&lt;br /&gt;#movetablepace.rb &lt;br /&gt;#***************************************&lt;br /&gt;#make a Oracle Connection&lt;br /&gt;&lt;br /&gt;fromdbconstr  = ARGV[0]  # For example - DBI:OCI8://myoracleserver/oracleinstance&lt;br /&gt;fromdbconuser = ARGV[1]  # MYRAILSDBUSER-DEVELOP&lt;br /&gt;fromdbconpass = ARGV[2]  # MYRAILSDBUSER-PASSWORD&lt;br /&gt;dataspacename = ARGV[3]  # APPLICATION-DATASPACE&lt;br /&gt;&lt;br /&gt;fromdb = DBI.connect(fromdbconstr, fromdbconuser, fromdbconpass)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;tables = fromdb.tables&lt;br /&gt;tables.each do |tablename|&lt;br /&gt;   tablename = tablename.strip&lt;br /&gt;   if tablename.length == 0&lt;br /&gt;      next&lt;br /&gt;      end&lt;br /&gt;   if tablename.length &gt; 4&lt;br /&gt;      if tablename[0,4] == "BIN$"&lt;br /&gt;         next&lt;br /&gt;         end&lt;br /&gt;      end&lt;br /&gt;   puts "Move Table [#{tablename}] to new tablespace"&lt;br /&gt;   sqlmove = "alter table " + '"' + tablename + '" move tablespace "' + dataspacename + '"' &lt;br /&gt;   puts sqlmove&lt;br /&gt;   begin&lt;br /&gt;      result = fromdb.execute(sqlmove)&lt;br /&gt;   rescue&lt;br /&gt;      puts "Table [#{tablename}] not moved"&lt;br /&gt;      end&lt;br /&gt;   &lt;br /&gt;   end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;And after you do that, you need to "rebuild" the indexes into the new tablespace&lt;br /&gt;&lt;br /&gt;require 'DBI'&lt;br /&gt;require 'pp'&lt;br /&gt;&lt;br /&gt;#make a Oracle Connection&lt;br /&gt;&lt;br /&gt;fromdbconstr  = ARGV[0]  # For example - DBI:OCI8://myoracleserver/oracleinstance&lt;br /&gt;fromdbconuser = ARGV[1]  # MYRAILSDBUSER-DEVELOP&lt;br /&gt;fromdbconpass = ARGV[2]  # MYRAILSDBUSER-PASSWORD&lt;br /&gt;dataspacename = ARGV[3]  # APPLICATION-DATASPACE&lt;br /&gt;&lt;br /&gt;fromdb = DBI.connect(fromdbconstr, fromdbconuser, fromdbconpass)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;tables = fromdb.tables&lt;br /&gt;sqlget = "select index_name from user_indexes"&lt;br /&gt;indexs = fromdb.execute(sqlget)&lt;br /&gt;indexs.each do |theindex|&lt;br /&gt;   indexname = theindex[0]&lt;br /&gt;   printf "Rebuilding Index %s\n", indexname&lt;br /&gt;   sqlrebuild = 'alter index "' + indexname + '" rebuild tablespace "' + dataspacename + '"'&lt;br /&gt;   begin &lt;br /&gt;      result = fromdb.execute(sqlrebuild)&lt;br /&gt;   rescue&lt;br /&gt;      printf "[%s] Index not rebult\n", indexname&lt;br /&gt;      end&lt;br /&gt;   end&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-6617913877547885734?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/6617913877547885734/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=6617913877547885734' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/6617913877547885734'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/6617913877547885734'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/01/oracle-and-rails-moving-tables-to-new.html' title='Oracle and Rails - Moving tables to new tablespaces'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-8816503325447103225</id><published>2008-01-25T21:57:00.000-08:00</published><updated>2008-01-25T22:06:13.115-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby Rails Databases Enterprise CEO CTO Migration'/><title type='text'>When the C-LEVEL(CTO,CEO,CFO) ask so why should we use Rails</title><content type='html'>Ok Mr. Big CTO, why shuld we use RAILS? &lt;br /&gt;A question that was recently asked in the Ruby forums.&lt;br /&gt;&lt;br /&gt;So having done a few C-Level jobs, I thought I'd answer.&lt;br /&gt;&lt;br /&gt;1. Is it going to be around a long time - Yes - Ruby itself has, and &lt;br /&gt;Rails has hit 2. Plus recognition from &lt;br /&gt;major software firms. (Oracle offered class on it on the Shanghai &lt;br /&gt;Training Session,), oracle has support. &lt;br /&gt;Major media companies are using it. Other MNC are using. Trading(As in &lt;br /&gt;stock, on wallstreet) are using it. &lt;br /&gt;Look at the "books" available. Need one every week. Look at the number &lt;br /&gt;of web articles. By every metric its &lt;br /&gt;everywhere. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2. Is training available? Yes, on multiple fronts. Also fresh java &lt;br /&gt;grads tend to pick it up easier. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3. Does it marry with my "enterprise" systems. Now this one is &lt;br /&gt;interesting. Ruby can marry to just &lt;br /&gt;about anything, so thus "rails" can. I am just finishing a "marriage" &lt;br /&gt;between Unify and Rails. The original &lt;br /&gt;applicaiton is over 15 years old, and the data is still worth &lt;br /&gt;millions. Of course I "moved" the data over to &lt;br /&gt;oracle. (With ruby). I've also did "bridges" between applications. &lt;br /&gt;&lt;br /&gt;3. Is it secure? If its running on "Linux" would be my answer. Look at &lt;br /&gt;the security guide. Put a https proxy(Nginx) &lt;br /&gt;in fromt. 100x more secure than windows. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;4. Is it scalable. Big question. But in a short answer, yes yes yes. &lt;br /&gt;For our users, 3000-4000 is max user count. &lt;br /&gt;I even was helping a friend with handling million plus user bases. &lt;br /&gt;Hardware is cheap, with nginx, mongrel clusters, and &lt;br /&gt;good hardware its falling off a log. (If your public hosting, even a &lt;br /&gt;single server can handle your average load"). &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;5. Can I get consultants? Yes. Look at the tavnav guys for one. There &lt;br /&gt;great. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;6. But does it take "long" to do the job? &lt;br /&gt;Its the "fastest" system I've found to get thing done fast, neat, and quick.&lt;br /&gt;Look up "DRY" under Rails. It stands for "Dont Repeat Yourself".&lt;br /&gt;&lt;br /&gt;7. Does it do "Windows"&lt;br /&gt;Yes very well. How about a "Applicatoin-to-Application" Bridge done&lt;br /&gt;in a week as a Windows "Service"&lt;br /&gt;&lt;br /&gt;8. Does it do "Clusters" &lt;br /&gt;Yes&lt;br /&gt;&lt;br /&gt;9. Does it do "Linux"&lt;br /&gt;Yes&lt;br /&gt;&lt;br /&gt;10. Is it better than Java&lt;br /&gt;Yes - very. So much more concise.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-8816503325447103225?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/3cc03379af01bc38' title='When the C-LEVEL(CTO,CEO,CFO) ask so why should we use Rails'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/8816503325447103225/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=8816503325447103225' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/8816503325447103225'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/8816503325447103225'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/01/when-c-levelctoceocfo-ask-so-why-should.html' title='When the C-LEVEL(CTO,CEO,CFO) ask so why should we use Rails'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-5447790931616456533</id><published>2008-01-22T18:49:00.001-08:00</published><updated>2008-01-22T18:58:29.504-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails ruby migrations rake'/><title type='text'>Advanced Rails Migrations - Adding and Updating Related Table ID's</title><content type='html'>Ever have that "rails" problem.&lt;br /&gt;You imported a butch of "existing" tables to create a rails application,&lt;br /&gt;and you dont have appropriate index/id's to help with your belong_to, and&lt;br /&gt;associated tables?&lt;br /&gt;&lt;br /&gt;Well Migrations can do it for you.&lt;br /&gt;&lt;br /&gt;Example migration using two tables that are in ActiveRecord.&lt;br /&gt;&lt;br /&gt;This one builds a link between a inventory table, and a customer table.&lt;br /&gt;&lt;br /&gt;class UpdateXco &lt; ActiveRecord::Migration&lt;br /&gt;  def self.up&lt;br /&gt;      add_column :REG_INV_SERS, :REG_CUST_ID, :integer&lt;br /&gt;      RegInvSer.reset_column_information&lt;br /&gt;      RegInvSer.find(:all).each do |record|&lt;br /&gt;         regcustomer = RegCust.find(:first, :conditions =&gt; "CUST_NBR = '#{record.cust_nbr}'")&lt;br /&gt;         if not regcustomer.nil?&lt;br /&gt;           record.reg_cust_id = regcustomer.id&lt;br /&gt;           record.save&lt;br /&gt;         end&lt;br /&gt;         end&lt;br /&gt;    end   &lt;br /&gt;def self.down&lt;br /&gt;     remove_column "REG_INV_SERS", "REG_CUST_ID"&lt;br /&gt; end    &lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;Another one, that illustrates doing a table import from a dbase/foxpro table, with a id update as well.&lt;br /&gt;&lt;br /&gt;class Updatesalesorder &lt; ActiveRecord::Migration&lt;br /&gt;  def self.up&lt;br /&gt;  &lt;br /&gt;      thepathname = "h:xxxxx.DBF"&lt;br /&gt;      table = DBF::Table.new(thepathname)&lt;br /&gt;      table.records.each do |record|&lt;br /&gt;         mysalesorder = salesorder.create(record.attributes)&lt;br /&gt;         mycustomer = customer.find(:first, :conditions =&gt; "custno = '#{record.custno}'")&lt;br /&gt;         if not mycustomer.nil?&lt;br /&gt;           mysalesorder.customer_id = mycustomer.id&lt;br /&gt;           mysalesorder.save&lt;br /&gt;         end&lt;br /&gt;         end&lt;br /&gt;    end   &lt;br /&gt;def self.down&lt;br /&gt;   drop_table "salesorders"&lt;br /&gt; end    &lt;br /&gt;end&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-5447790931616456533?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/5447790931616456533/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=5447790931616456533' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/5447790931616456533'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/5447790931616456533'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/01/advanced-rails-migrations-adding-and.html' title='Advanced Rails Migrations - Adding and Updating Related Table ID&apos;s'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-904371067335280641</id><published>2008-01-21T23:02:00.001-08:00</published><updated>2008-01-22T00:44:05.388-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby rails rubyonrails class tutorial unify'/><title type='text'>Ruby - A "class" tutorial using a Unify DBI interface as a example</title><content type='html'>This is a "good" example of a "class".&lt;br /&gt;It implemnets a simple "dbi" like interface to a unify IDS database.&lt;br /&gt;(This is a embedded database used in linux, and embedded devices)&lt;br /&gt;&lt;br /&gt;Recently needed to access data from a unify database in "rails".&lt;br /&gt;&lt;br /&gt;So of course, needed a "dbi" like layer to work with one of my scripts to&lt;br /&gt;pull the data. (See previous posts on data conversion and migrations).&lt;br /&gt;&lt;br /&gt;So it was natural to create a "class". A class is a "object" consisting of code,&lt;br /&gt;or methods, and "data". The data can come in two types "instance" and class data.&lt;br /&gt;Here everything is "instance" data. So when we create a new "Unify" object, we&lt;br /&gt;get another set of "data" for that instance.&lt;br /&gt;&lt;br /&gt;In our example, we use two temp files per instance to communication to Unify sql command via a "shell" command. One is for the SQL statement, and one is for the "results".&lt;br /&gt;&lt;br /&gt;Also the lovely thing about "instances" is it makes it easy to see all your "instance" data, simply by doing a "pp" (Pretty Print) on the "instance" variable.&lt;br /&gt;&lt;br /&gt;So:&lt;br /&gt;     mydb = Unify.new(database,user,password)&lt;br /&gt;     pp mydb (Will let you see what going on with the instance)&lt;br /&gt;&lt;br /&gt;Note that all the "@" instance varibles are recreated on each "new".&lt;br /&gt;&lt;br /&gt;This allows this simple example to have multiple outstanding "queries", without&lt;br /&gt;getting confused.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;class Unify&lt;br /&gt;def make_tmpname(type,instance)&lt;br /&gt;    return 'unify-' + type + '-' + instance + '.tmp'&lt;br /&gt;    end &lt;br /&gt;def execute_unify_sql(thesql)&lt;br /&gt;    thequery = File.open(@uqueryfilename,"w")&lt;br /&gt;    thequery.puts "lines 0"&lt;br /&gt;    # thequery.puts "separator ','&lt;br /&gt;    thequery.puts thesql&lt;br /&gt;    thequery.close&lt;br /&gt;    thecommand = 'SQL ' + @uqueryfilename + '&gt; ' + @udatafilename&lt;br /&gt;    result = system(thecommand)&lt;br /&gt;    if result == false&lt;br /&gt;       sleep(10)&lt;br /&gt;       result = system(thecommand)&lt;br /&gt;       end&lt;br /&gt;    theresult = File.open(@udatafilename)&lt;br /&gt;    @udatafile = theresult&lt;br /&gt;    return theresult&lt;br /&gt;    end&lt;br /&gt;def initialize(database,user,password)&lt;br /&gt;    @udatabase = database&lt;br /&gt;    @uuser = user&lt;br /&gt;    @upassword = password&lt;br /&gt;    @udatafile = nil&lt;br /&gt;    @udatafilename = nil&lt;br /&gt;    @uqueryfilename = nil&lt;br /&gt;    queryinstance = rand(10000).to_s&lt;br /&gt;    @udatafilename = make_tmpname('result',queryinstance)&lt;br /&gt;    @uqueryfilename  = make_tmpname('query',queryinstance)&lt;br /&gt;    end&lt;br /&gt;def fields(tablename)&lt;br /&gt;    thesql = 'fields ' + tablename&lt;br /&gt;    thedata = execute_unify_sql(thesql)&lt;br /&gt;    header = thedata.gets&lt;br /&gt;    header = thedata.gets #throw away the two header lines&lt;br /&gt;    result = Array.new&lt;br /&gt;    thedata.readlines.each { |line|&lt;br /&gt;       theline = line.chomp!&lt;br /&gt;       # theline &lt;= '|' # last element does not terminate with |&lt;br /&gt;       element = theline.split&lt;br /&gt;       result &lt;&lt; element&lt;br /&gt;       }&lt;br /&gt;    self.finish()&lt;br /&gt;    return result&lt;br /&gt;    end&lt;br /&gt;def tables&lt;br /&gt;    thedata = execute_unify_sql("tables")&lt;br /&gt;    thecontents = thedata.read&lt;br /&gt;    self.finish&lt;br /&gt;    mytables = thecontents.split&lt;br /&gt;    return mytables&lt;br /&gt;    end&lt;br /&gt;def execute(sql) &lt;br /&gt;    #For execute create a new "instance"&lt;br /&gt;    unifyinstance = Unify.new(@udatabase,@uuser,@upassword)&lt;br /&gt;    if sql[-1,1] == ';'&lt;br /&gt;       sql[-1,1] = '/'&lt;br /&gt;       end&lt;br /&gt;    theresultfile = unifyinstance.execute_unify_sql(sql)&lt;br /&gt;    return unifyinstance&lt;br /&gt;    end&lt;br /&gt;def fetch()&lt;br /&gt;    @udatafile.pos = 0  #Make sure we are at the beginning&lt;br /&gt;    thetable = Array.new&lt;br /&gt;    while thedata = @udatafile.gets&lt;br /&gt;         thedata.chomp!&lt;br /&gt;         therow = thedata.split('|',-1) # No supressed fields&lt;br /&gt;         thetable &lt;&lt; therow&lt;br /&gt;         end&lt;br /&gt;    return thetable&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;def finish()&lt;br /&gt;    @udatafile.close&lt;br /&gt;    File.delete(@udatafilename)&lt;br /&gt;    File.delete(@uqueryfilename)&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;end&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-904371067335280641?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/904371067335280641/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=904371067335280641' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/904371067335280641'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/904371067335280641'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/01/ruby-class-tutorial-using-unify-dbi.html' title='Ruby - A &quot;class&quot; tutorial using a Unify DBI interface as a example'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-5882122209502995459</id><published>2008-01-21T01:31:00.000-08:00</published><updated>2008-01-21T16:09:23.282-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails ruby gem runonrails 2.0.2'/><title type='text'>Rails 2.0.2 Issues and Problems Resolved</title><content type='html'>Now this was fun, my main Rails box is now running Rails 2.0.2&lt;br /&gt;&lt;br /&gt;First problem, when running Rake task, I get complaints about Active Recrd&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;C:\projects\ror\tempco&gt;rake extract_fixtures&lt;br /&gt;(in C:/projects/ror/tempco)&lt;br /&gt;rake aborted!&lt;br /&gt;can't activate activerecord (= 1.15.3), already activated activerecord-2.0.2]&lt;br /&gt;&lt;br /&gt;This one stumped me for a moment, but then realized that the "old" gems may&lt;br /&gt;be confusing issues. So a little cleanup is in order.&lt;br /&gt;&lt;br /&gt;gem cleanup&lt;br /&gt;&lt;br /&gt;This command cleans up all "the" old gems.&lt;br /&gt;And solved my problems&lt;br /&gt;&lt;br /&gt;The next problem I had, was:&lt;br /&gt;&lt;br /&gt;C:\projects\ror\tempco&gt;rake extract_fixtures&lt;br /&gt;(in C:/projects/ror/tempco)&lt;br /&gt;rake aborted!&lt;br /&gt;Please install the oracle adapter: `gem install activerecord-oracle-adapter` (no&lt;br /&gt; such file to load -- active_record/connection_adapters/oracle_adapter)&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;Rails 2 does not by default install ActiveRecord adapter for oracle.&lt;br /&gt;Of course if you try the gem install command the error message recommends,&lt;br /&gt;it still does not give you gratification.&lt;br /&gt;&lt;br /&gt;The proper command that works is:&lt;br /&gt;&lt;br /&gt;C:\projects\ror\tempco&gt;gem install activerecord-oracle-adapter &lt;br /&gt;    --source http://gems.rubyonrails.org&lt;br /&gt;Bulk updating Gem source index for: http://gems.rubyonrails.org&lt;br /&gt;Successfully installed activerecord-oracle-adapter-1.0.0&lt;br /&gt;1 gem installed&lt;br /&gt;&lt;br /&gt;And now, I try to do a rake db:schema:dump&lt;br /&gt;And the next problem occurs, seems like there is a "bug" in the &lt;br /&gt;oracle adapter.&lt;br /&gt;&lt;br /&gt;The fix seems to be here:&lt;br /&gt;http://dev.rubyonrails.org/attachment/ticket/9062/fix_oracleadapter_problem_indexes.diff&lt;br /&gt;&lt;br /&gt;But does not match the code in the 1.0 adapter. Hmmm. &lt;br /&gt;&lt;br /&gt;Ok, lets try to setup a "session" migration.&lt;br /&gt;&lt;br /&gt;Hmm same error&lt;br /&gt;&lt;br /&gt;C:\projects\ror\tempco&gt;&lt;br /&gt;C:\projects\ror\tempco&gt;rake db:migrate&lt;br /&gt;(in C:/projects/ror/tempco)&lt;br /&gt;== 1 CreateSessions: migrating ================================================&lt;br /&gt;-- create_table(:sessions)&lt;br /&gt;   -&gt; 38.5940s&lt;br /&gt;-- add_index(:sessions, :session_id)&lt;br /&gt;   -&gt; 0.0930s&lt;br /&gt;-- add_index(:sessions, :updated_at)&lt;br /&gt;   -&gt; 0.0630s&lt;br /&gt;== 1 CreateSessions: migrated (38.7500s) ======================================&lt;br /&gt;&lt;br /&gt;rake aborted!&lt;br /&gt;select_rows is an abstract method&lt;br /&gt;&lt;br /&gt;Ok, do a bit more google work, and what do we find:&lt;br /&gt;&lt;br /&gt;http://dev.rubyonrails.org/ticket/10415&lt;br /&gt;&lt;br /&gt;Insert the code into the oracle adapter, and now no error on our migration.&lt;br /&gt;&lt;br /&gt;And our db:schema:dump works properly.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-5882122209502995459?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/5882122209502995459/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=5882122209502995459' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/5882122209502995459'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/5882122209502995459'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2008/01/oracle-and-rails-202-with-windows-xp.html' title='Rails 2.0.2 Issues and Problems Resolved'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-7562547980322060782</id><published>2007-11-27T18:54:00.000-08:00</published><updated>2007-11-27T19:01:14.338-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby rails centos redhat nginx'/><title type='text'>RedhatOnRails or CentosOnRails</title><content type='html'>Wow, I finally did it. &lt;br /&gt;A automatied script to get NGINX, Mongrel/MongrelCluster, and Rails up on Redhat/Centos.&lt;br /&gt;The gotcha that was bad was I assumed the Centos/Redhat ruby was up to date. Its not.&lt;br /&gt;And causes intersting problems. Even using yum to remove it does not get rid of the old binary.&lt;br /&gt;&lt;br /&gt;So make sure you dont have ruby installed, and if you do you have to go and remove it both with yum and manually. Then you should be fine.&lt;br /&gt;&lt;br /&gt;The script install ruby, ImageMagic, Nginx, and rails, and gem.&lt;br /&gt;I found that gem install for rails was not working for linux. But installing with&lt;br /&gt;the gem manually worked fine.&lt;br /&gt;&lt;br /&gt;#install_rails - dont forget the chmod +x install_rails and run as root&lt;br /&gt;yum install -y gcc&lt;br /&gt;yum install -y buildsys-build&lt;br /&gt;wget ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.6-p110.tar.gz&lt;br /&gt;tar -xzvf ruby-1.8.6-p110.tar.gz&lt;br /&gt;cd ruby-1.8.6-p110&lt;br /&gt;./configure &amp;&amp; make &amp;&amp; make install&lt;br /&gt;cd ..&lt;br /&gt;rm -r -f ruby-1.8.6-p110&lt;br /&gt;rm ruby-1.8.6-p110.tar.gz&lt;br /&gt;yum install -y openssl-devel&lt;br /&gt;wget http://rubyforge.org/frs/download.php/28174/rubygems-0.9.5.tgz&lt;br /&gt;mkdir rubygems&lt;br /&gt;mv rubygems-0.9.5.tgz rubygems&lt;br /&gt;cd rubygems&lt;br /&gt;tar xzvf rubygems-0.9.5.tgz&lt;br /&gt;cd rubygems-0.9.5&lt;br /&gt;ruby setup.rb&lt;br /&gt;cd ..&lt;br /&gt;cd ..&lt;br /&gt;rm -r -f rubygems&lt;br /&gt;yum -y install libpng-devel libjpeg-devel libtiff-devel freetype-devel ghostscript-devel&lt;br /&gt;wget ftp://ftp.imagemagick.org/pub/ImageMagick/ImageMagick.tar.gz&lt;br /&gt;tar -xzvf ImageMagick.tar.gz&lt;br /&gt;cd ImageMagick-6.3.7&lt;br /&gt;./configure&lt;br /&gt;make &amp;&amp; make install&lt;br /&gt;cd ..&lt;br /&gt;rm -rf ImageMagick-6.3.7&lt;br /&gt;cp /etc/ld.so.conf /etc/ld.so.conf.backup&lt;br /&gt;sed '$a\&lt;br /&gt;/usr/local/lib' /etc/ld.so.conf &gt; ld.so.conf.new&lt;br /&gt;mv ld.so.conf.new /etc/ld.so.conf&lt;br /&gt;/sbin/ldconfig -v&lt;br /&gt;/sbin/ldconfig&lt;br /&gt;gem install rmagick&lt;br /&gt;yum -y install pcre pcre-devel&lt;br /&gt;wget http://sysoev.ru/nginx/nginx-0.5.33.tar.gz&lt;br /&gt;tar -xzvf nginx-0.5.33.tar.gz&lt;br /&gt;cd nginx-0.5.33&lt;br /&gt;./configure --with-http_ssl_module&lt;br /&gt;make&lt;br /&gt;make install&lt;br /&gt;cd ..&lt;br /&gt;rm -r -f nginx-0.5.33&lt;br /&gt;rm nginx-0.5.33.tar.gz&lt;br /&gt;wget http://rubyforge.org/frs/download.php/28337/rails-1.2.6.gem&lt;br /&gt;gem install ./rails-1.2.6.gem&lt;br /&gt;gem install mongrel mongrel_cluster&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-7562547980322060782?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/7562547980322060782/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=7562547980322060782' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/7562547980322060782'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/7562547980322060782'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2007/11/redhatonrails-or-centosonrails.html' title='RedhatOnRails or CentosOnRails'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-3808146683449509361</id><published>2007-11-06T01:25:00.000-08:00</published><updated>2007-11-06T01:31:14.488-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby rails'/><title type='text'>Getting started faster in rails</title><content type='html'>Had a comment on my blog for "create xyz application" did not work.&lt;br /&gt;I suspect the cut/paste must of went astray. Just to make sure&lt;br /&gt;your start in rails is a bit faster, I wrote a quick ruby script.&lt;br /&gt;&lt;br /&gt;So install ruby and rails per the previous instructions, then this script&lt;br /&gt;will create your "rails" app tree, and automatically install the three plugins&lt;br /&gt;that I recommend to get started in Rails.&lt;br /&gt;&lt;br /&gt;1. ActiveScaffold&lt;br /&gt;2. RoleRequirement&lt;br /&gt;3. Widgets/Tabnav&lt;br /&gt;&lt;br /&gt;To run the script&lt;br /&gt;&lt;br /&gt;myrails appname&lt;br /&gt;&lt;br /&gt;#myrails.rb&lt;br /&gt;# Usage: myrails appname&lt;br /&gt;myappname = ARGV[0]&lt;br /&gt;puts "Creating Initial App - " + myappname&lt;br /&gt;system ("rails " + myappname)&lt;br /&gt;Dir.chdir(myappname)&lt;br /&gt;#Each of these must be a single line, no returns/newline allowed - Must be 3 system lines&lt;br /&gt;system ('ruby ./script/plugin install http://activescaffold.googlecode.com/svn/tags/active_scaffold')&lt;br /&gt;system ('ruby ./script/plugin install http://rolerequirement.googlecode.com/svn/tags/role_requirement/')&lt;br /&gt;system ('ruby ./script/plugin install svn://svn.seesaw.it/widgets/trunk')&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-3808146683449509361?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/3808146683449509361/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=3808146683449509361' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/3808146683449509361'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/3808146683449509361'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2007/11/getting-started-faster-in-rails.html' title='Getting started faster in rails'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-6707803907777116807</id><published>2007-10-30T20:05:00.000-07:00</published><updated>2007-10-30T20:11:57.485-07:00</updated><title type='text'>Can you create xyz application in rails</title><content type='html'>Yes you can. And its easy.&lt;br /&gt;&lt;br /&gt;First oh, Go to your favorate book seller and buy the following books:&lt;br /&gt;&lt;br /&gt;1. The Ruby Way - Second Edition By Hal Fulton&lt;br /&gt;2. Rails Recipes - Fowler&lt;br /&gt;3. Ruby Cookbook - Lucas Carlson &amp; Leonard Richardson&lt;br /&gt;4. Agile Web Development with Rails - Thomas Heinemeler Hansson&lt;br /&gt;&lt;br /&gt;Then your ready to get started:&lt;br /&gt;&lt;br /&gt;Its very easy.&lt;br /&gt;&lt;br /&gt;1. Install Rails&lt;br /&gt;   gem install rails --include-dependencies&lt;br /&gt;2. Add ActiveScoffold PlugIn (http://activescaffold.com/)&lt;br /&gt;   ./script/plugin install http://activescaffold.googlecode.com/svn/tags/active_scaffold&lt;br /&gt;3. Add RoleRequirement      (http://code.google.com/p/&lt;br /&gt;rolerequirement/)&lt;br /&gt;   ./script/plugin install http://rolerequirement.googlecode.com/svn/tags/role_requirement/&lt;br /&gt;4. Add TabNav/Widgets       (ruby script/plugin install&lt;br /&gt;svn://svn.seesaw.it/widgets/trunk)  (Information: http://www.seesaw.it/en/toolbox/widgets/)&lt;br /&gt;   ruby script/plugin install svn://svn.seesaw.it/widgets/trunk&lt;br /&gt;5. Define your takes in a migration&lt;br /&gt;&lt;br /&gt;6. Build your model files (3-4 lines each)&lt;br /&gt;&lt;br /&gt;7. Buld your controllers (for each table)&lt;br /&gt;&lt;br /&gt;8. Build your menus (using tabnav)&lt;br /&gt;&lt;br /&gt;9. Add your relationships and tweak tabnav.&lt;br /&gt;&lt;br /&gt;10. Add email confirmation, and notification.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-6707803907777116807?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/6707803907777116807/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=6707803907777116807' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/6707803907777116807'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/6707803907777116807'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2007/10/can-you-create-xyz-application-in-rails.html' title='Can you create xyz application in rails'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-4029308639196053470</id><published>2007-10-30T18:13:00.000-07:00</published><updated>2007-10-30T18:41:59.357-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>Rails Tabnav - Fixing Menu Spacing</title><content type='html'>For my applications, I want a good "look" and feel, with standadized menus.&lt;br /&gt;My "menu" of choice is Tabnav/widget done by seesaw.&lt;br /&gt;&lt;br /&gt;In "Enterprise" applications, the number of menus sometimes can be "large".&lt;br /&gt;For example if you want a "menu" per department, there could be 20 departments&lt;br /&gt;in a large company.&lt;br /&gt;&lt;br /&gt;While tabnav does not "limit" you in the number or levels of menus, there&lt;br /&gt;is a minor overlap problem that can occur if the screen is swunken below&lt;br /&gt;a certan point, or you have "to" many menus on one "level.&lt;br /&gt;&lt;br /&gt;There's a "easy" fix for handling this.&lt;br /&gt;&lt;br /&gt;In your project/vendor/plugins/widgets/lib/widgets/tabnav.css.erb file, you&lt;br /&gt;can adjust the overlap.&lt;br /&gt;&lt;br /&gt;If you look at the "top" of the tabnav.css.erb file, you will notice the "line-height", I found by setting this to 170% my overlap problems disappeared.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Modified tabnav.css.erb&lt;/strong&gt;&lt;br /&gt; color: #000;&lt;br /&gt;        line-height: 170%;&lt;br /&gt; border-bottom: 2px solid black;&lt;br /&gt; margin: 13px 0px 0px 0px;&lt;br /&gt; padding: 0px;&lt;br /&gt; z-index: 1;&lt;br /&gt; padding-left: 10px&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Original tabnav.css.erb (First few lines)&lt;/strong&gt;&lt;br /&gt; color: #000;&lt;br /&gt; border-bottom: 2px solid black;&lt;br /&gt; margin: 13px 0px 0px 0px;&lt;br /&gt; padding: 0px;&lt;br /&gt; z-index: 1;&lt;br /&gt; padding-left: 10px&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-4029308639196053470?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.seesaw.it/en/toolbox/widgets/' title='Rails Tabnav - Fixing Menu Spacing'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/4029308639196053470/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=4029308639196053470' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/4029308639196053470'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/4029308639196053470'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2007/10/rails-tabnav-fixing-menu-spacing.html' title='Rails Tabnav - Fixing Menu Spacing'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-4662992050114780108</id><published>2007-10-30T01:38:00.001-07:00</published><updated>2007-10-30T01:42:43.076-07:00</updated><title type='text'>Ruby and ActiveDirectory - Finding Servers and Dead Computer Accounts</title><content type='html'>Lets expand our example to find servers, and dead computers.&lt;br /&gt;One thing, the "servers" dont always appear when we search for "computer" accounts, in AD. Didnt find a known bug for this, but servers I know are "out" there just didnt come back.&lt;br /&gt;&lt;br /&gt;So a few more "gotcha" when using AD from Ruby/LDAP&lt;br /&gt;&lt;br /&gt;1. Servers dont "come-back" from a search of objectype = Computer&lt;br /&gt;2. "Server" objectype does not give you the OS. Must search for server, then find it specifically to get the OS.&lt;br /&gt;3. You might have duplicates if you add these togeather.&lt;br /&gt;4. AD Date and Time is very different format than ruby's, so thanks to google, I found some nice routeines for converting between the two. &lt;br /&gt;&lt;br /&gt;Example code:&lt;br /&gt;&lt;br /&gt;require 'ldap'&lt;br /&gt;require "pp"&lt;br /&gt;&lt;br /&gt;def fetch_computers(domain_controller,the_username, the_password)&lt;br /&gt;  conn = LDAP::Conn.new( domain_controller, 389 )&lt;br /&gt;  conn.set_option( LDAP::LDAP_OPT_PROTOCOL_VERSION, 3 )&lt;br /&gt;  conn.bind( the_username, the_password ) do |conn|&lt;br /&gt;&lt;br /&gt;  base = 'DC=company,DC=com'&lt;br /&gt;&lt;br /&gt;  results = conn.search2(base, LDAP::LDAP_SCOPE_SUBTREE, "objectClass=Computer")&lt;br /&gt;  if results == LDAP::LDAP_SIZELIMIT_EXCEEDED&lt;br /&gt;     printf "To Much Data\n"&lt;br /&gt;     end&lt;br /&gt;  return results&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def fetch_servers(domain_controller,the_username, the_password)&lt;br /&gt;  conn = LDAP::Conn.new( domain_controller, 389 )&lt;br /&gt;  conn.set_option( LDAP::LDAP_OPT_PROTOCOL_VERSION, 3 )&lt;br /&gt;  conn.bind( the_username, the_password ) do |conn|&lt;br /&gt;&lt;br /&gt;  base = 'DC=company,DC=com'&lt;br /&gt;&lt;br /&gt;  results = conn.search2(base, LDAP::LDAP_SCOPE_SUBTREE, "objectClass=Server")&lt;br /&gt;  if results == LDAP::LDAP_SIZELIMIT_EXCEEDED&lt;br /&gt;     printf "To Much Data\n"&lt;br /&gt;     end&lt;br /&gt;  return results&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def fetch_computer(domain_controller,the_username, the_password,thecomputername)&lt;br /&gt;  conn = LDAP::Conn.new( domain_controller, 389 )&lt;br /&gt;  conn.set_option( LDAP::LDAP_OPT_PROTOCOL_VERSION, 3 )&lt;br /&gt;  conn.bind( the_username, the_password )&lt;br /&gt;&lt;br /&gt;  base = 'DC=company,DC=com'&lt;br /&gt;&lt;br /&gt;  results = conn.search2(base, LDAP::LDAP_SCOPE_SUBTREE, "cn=#{thecomputername}")&lt;br /&gt;  return results&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;#[["Windows 2000 Server"],&lt;br /&gt;# ["Windows Server 2003"],&lt;br /&gt;# ["Windows XP Professional"],&lt;br /&gt;# ["Windows 2000 Professional"],&lt;br /&gt;# ["Windows NT"],&lt;br /&gt;# ["Windows Vista\342\204\242 Business"],&lt;br /&gt;# ["Windows XP Tablet PC Edition"]]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;AD_EPOCH      = 116_444_736_000_000_000&lt;br /&gt;AD_MULTIPLIER = 10_000_000&lt;br /&gt;&lt;br /&gt;# convert a Time object to AD's epoch&lt;br /&gt;def time2ad(time)&lt;br /&gt;  (time.to_i * AD_MULTIPLIER) + AD_EPOCH&lt;br /&gt;end&lt;br /&gt;  &lt;br /&gt;# convert from AD's time string to a Time object&lt;br /&gt;def ad2time(time)&lt;br /&gt;  begin&lt;br /&gt;    thetime = Time.at((time.to_i - AD_EPOCH) / AD_MULTIPLIER)&lt;br /&gt;    return thetime&lt;br /&gt;  rescue&lt;br /&gt;    return 0&lt;br /&gt;  end&lt;br /&gt;  &lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;thedc = "myserver"               # The "nearest" domain controler name&lt;br /&gt;theaccount = 'domain\username'   # Change this to your domain and username&lt;br /&gt;thepassword = 'password'         # Gota have a password&lt;br /&gt;&lt;br /&gt;operating_systems = Array.new&lt;br /&gt;w2000servers = Array.new&lt;br /&gt;w2003servers = Array.new&lt;br /&gt;winservers   = Array.new&lt;br /&gt;oldaccounts  = Array.new&lt;br /&gt;&lt;br /&gt;result = fetch_computers(thedc, theaccount, thepassword)&lt;br /&gt;today = Time.now&lt;br /&gt;result.each {|entry| &lt;br /&gt;      #printf "%s - %s\n", entry["cn"], entry["operatingSystem"] &lt;br /&gt;      thePasswordTime = ad2time(entry["pwdLastSet"].to_s)&lt;br /&gt;      theAge = (today - thePasswordTime) /  86400  # Number of days&lt;br /&gt;      if theAge &gt; 90&lt;br /&gt;         oldaccounts &lt;&lt; entry["cn"]&lt;br /&gt;         end&lt;br /&gt;      if entry["operatingSystem"] != nil&lt;br /&gt;         operating_systems &lt;&lt; entry["operatingSystem"]&lt;br /&gt;         operating_systems.uniq!&lt;br /&gt;         if entry["operatingSystem"] == ["Windows 2000 Server"]&lt;br /&gt;            w2000servers &lt;&lt; entry["cn"]&lt;br /&gt;            winservers &lt;&lt; entry["cn"]&lt;br /&gt;            end&lt;br /&gt;         if entry["operatingSystem"] == ["Windows Server 2003"]&lt;br /&gt;            w2003servers &lt;&lt; entry["cn"]&lt;br /&gt;            winservers &lt;&lt; entry["cn"]&lt;br /&gt;            end  &lt;br /&gt;         end&lt;br /&gt;      }&lt;br /&gt;              &lt;br /&gt;&lt;br /&gt;result = fetch_servers(thedc, theaccount, thepassword)&lt;br /&gt;today = Time.now&lt;br /&gt;result.each {|entry| &lt;br /&gt;      winservers &lt;&lt; entry["cn"]&lt;br /&gt;      # The server AD entry does not contain the OS, so fetch the Servers ObjectType = Computer entry&lt;br /&gt;      myservers = fetch_computer(thedc,theaccount,thepassword,entry["cn"].to_s)&lt;br /&gt;      &lt;br /&gt;      myservers.each { |myserver|&lt;br /&gt;         if myserver["operatingSystem"] == ["Windows 2000 Server"]&lt;br /&gt;            w2000servers &lt;&lt; entry["cn"]&lt;br /&gt;            end&lt;br /&gt;         if myserver["operatingSystem"] == ["Windows Server 2003"]&lt;br /&gt;            w2003servers &lt;&lt; entry["cn"]&lt;br /&gt;            end  &lt;br /&gt;&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;w2000servers.uniq!&lt;br /&gt;w2003servers.uniq!&lt;br /&gt;winservers.uniq!&lt;br /&gt;&lt;br /&gt;puts&lt;br /&gt;pp operating_systems&lt;br /&gt;puts&lt;br /&gt;puts "Win2000 Servers "&lt;br /&gt;pp w2000servers.sort!&lt;br /&gt;puts&lt;br /&gt;puts "Win2003 Servers "&lt;br /&gt;pp w2003servers.sort!&lt;br /&gt;&lt;br /&gt;puts "Windows Servers"&lt;br /&gt;pp winservers.sort!&lt;br /&gt;&lt;br /&gt;puts&lt;br /&gt;puts "Old/Unused Computer Accounts"&lt;br /&gt;pp oldaccounts.sort!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-4662992050114780108?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/4662992050114780108/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=4662992050114780108' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/4662992050114780108'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/4662992050114780108'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2007/10/ruby-and-activedirectory-finding.html' title='Ruby and ActiveDirectory - Finding Servers and Dead Computer Accounts'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-4598968418354883662</id><published>2007-10-29T18:19:00.000-07:00</published><updated>2007-10-29T18:24:57.841-07:00</updated><title type='text'>Ruby LDAP Example - How to find Computers</title><content type='html'>Ever want to find "all" your computers in a large "domain".&lt;br /&gt;Having trouble find examples?&lt;br /&gt;&lt;br /&gt;Some gochas from using ruby ldap&lt;br /&gt;&lt;br /&gt;1. Make sure the Active Directory Domain Controller is on the same "network" segment as you. I've seen this not work if your going over a WAN. And no error message is given. This happend when I was doing my first Active Directory login authentication. Once I used a local domain controller everything was fine.&lt;br /&gt;2. On the "ObjectClass" string extra parens and quotes cause it not to work. and no error message is given.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here's a working one&lt;br /&gt;&lt;br /&gt;require 'ldap'&lt;br /&gt;require "pp"&lt;br /&gt;&lt;br /&gt;conn = LDAP::Conn.new( 'sinsiw2k1', 389 )&lt;br /&gt;conn.set_option( LDAP::LDAP_OPT_PROTOCOL_VERSION, 3 )&lt;br /&gt;conn.bind( 'domain\myname', 'mypass' ) do |conn|&lt;br /&gt;&lt;br /&gt;  base = 'DC=company,DC=com'&lt;br /&gt;&lt;br /&gt;  results = conn.search2(base, LDAP::LDAP_SCOPE_SUBTREE, "objectClass=Computer")&lt;br /&gt;  if results == LDAP::LDAP_SIZELIMIT_EXCEEDED&lt;br /&gt;     printf "To Much Data\n"&lt;br /&gt;     end&lt;br /&gt;  pp results&lt;br /&gt;  pp results.controls&lt;br /&gt;  pp results.referrals&lt;br /&gt;&lt;br /&gt;  results.each { |entry| puts entry }&lt;br /&gt;&lt;br /&gt;end&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-4598968418354883662?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://ruby-ldap.sourceforge.net/rdoc/' title='Ruby LDAP Example - How to find Computers'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/4598968418354883662/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=4598968418354883662' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/4598968418354883662'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/4598968418354883662'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2007/10/ruby-ldap-example-how-to-find-computers.html' title='Ruby LDAP Example - How to find Computers'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-7873962073281639669</id><published>2007-10-22T18:37:00.000-07:00</published><updated>2007-10-22T18:42:39.844-07:00</updated><title type='text'>Importing from ODBC sources into Oracle and Rails</title><content type='html'>Having lots of data in a "third" party database, I needed a way of moving it over into a "rails" friendly environment. ODBC provided the "interface". This should work for most odbc/dbi compliant databases.&lt;br /&gt;&lt;br /&gt;Note that you might have to work a bit on "dates".&lt;br /&gt;&lt;br /&gt;require 'DBI'&lt;br /&gt;require 'pp'&lt;br /&gt;require 'active_support'&lt;br /&gt;require 'fileutils'&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def numeric?(thenumber)&lt;br /&gt;  if thenumber =~ /^[0-9]+$/&lt;br /&gt;     return(TRUE)&lt;br /&gt;  else return(FALSE)&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def tableexists?(wantedtablename)&lt;br /&gt;&lt;br /&gt;tables = $existing_tables&lt;br /&gt;tables.each do |tablename|&lt;br /&gt;   if wantedtablename == tablename&lt;br /&gt;      return TRUE&lt;br /&gt;      end&lt;br /&gt;   end&lt;br /&gt;return FALSE&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;def sanitize(thevalue)  &lt;br /&gt;    thevalue.gsub(/[^[:alnum:]]+/, '_')  &lt;br /&gt;end  &lt;br /&gt; &lt;br /&gt;&lt;br /&gt;def XlateColumnName(thename)&lt;br /&gt;    thename = thename.delete(" ")&lt;br /&gt;    thename = thename.upcase&lt;br /&gt;    if numeric?(thename)&lt;br /&gt;       thename = "X" + thename&lt;br /&gt;       end&lt;br /&gt;    thename = sanitize(thename)  # Get rid of / and \ and other goodies&lt;br /&gt;    if thename == "LOCK"&lt;br /&gt;       thename = "XLOCK"&lt;br /&gt;       end&lt;br /&gt;    if thename == "SCOPE"&lt;br /&gt;       thename = "XSCOPE"&lt;br /&gt;       end&lt;br /&gt;    if thename == "TYPE"&lt;br /&gt;       thename = "XTYPE"&lt;br /&gt;       end&lt;br /&gt;    if thename == "CLASS"&lt;br /&gt;       thename = "XCLASS"&lt;br /&gt;       end&lt;br /&gt;    if thename == "COST"&lt;br /&gt;       thename = "XCOST"&lt;br /&gt;       end&lt;br /&gt;    if thename == "FIXED"&lt;br /&gt;       thename = "XFIXED"&lt;br /&gt;       end&lt;br /&gt;    if thename == "CURRENT"&lt;br /&gt;       thename = "XCURRENT"&lt;br /&gt;       end&lt;br /&gt;    if thename == "DATE"&lt;br /&gt;       thename = "XDATE"&lt;br /&gt;       end&lt;br /&gt;    if thename == "TIME"&lt;br /&gt;       thename = "XTIME"&lt;br /&gt;       end&lt;br /&gt;    if thename == "NUMBER"&lt;br /&gt;       thename = "XNUMBER"&lt;br /&gt;       end&lt;br /&gt;    if thename == "CONDITION"&lt;br /&gt;       thename = "XCONDITION"&lt;br /&gt;       end&lt;br /&gt;    if thename == "SEQ"&lt;br /&gt;       thename = "XSEQ"&lt;br /&gt;       end&lt;br /&gt;    if thename == "COMMENT"&lt;br /&gt;       thename = "XCOMMENT"&lt;br /&gt;       end&lt;br /&gt;    return(thename)&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def dotable(fromdb, todb, tablename, prefix)&lt;br /&gt;&lt;br /&gt;   tablename = tablename.strip&lt;br /&gt;   if tablename.length == 0&lt;br /&gt;      return&lt;br /&gt;      end&lt;br /&gt;   stmt = "select * from #{tablename};"&lt;br /&gt;   begin &lt;br /&gt;     tabledata = fromdb.execute(stmt)&lt;br /&gt;   rescue&lt;br /&gt;     return&lt;br /&gt;     end&lt;br /&gt;   row = tabledata.fetch  # Get one&lt;br /&gt;   if row == nil #maybe we dont have data:)&lt;br /&gt;      tabledata.finish  #on empty data dont bother to create it&lt;br /&gt;      return&lt;br /&gt;      end&lt;br /&gt;&lt;br /&gt;   tablename = sanitize(tablename) #Get rid of nasties&lt;br /&gt;   railsname = prefix + "_" + tablename   &lt;br /&gt;   railsname = Inflector.pluralize(railsname)&lt;br /&gt;   railsname = railsname.upcase&lt;br /&gt;   if tableexists?(railsname)&lt;br /&gt;      printf "Exists %s\n",railsname&lt;br /&gt;      tabledata.finish&lt;br /&gt;      return&lt;br /&gt;      end&lt;br /&gt;   puts "Created #{railsname}"&lt;br /&gt;   #sqldrop = "DROP TABLE " + '"' + railsname + '" PURGE' &lt;br /&gt;   #begin&lt;br /&gt;   #   result = todb.execute(sqldrop)&lt;br /&gt;   #rescue&lt;br /&gt;   #   puts "Table [#{railsname}] not dropped"&lt;br /&gt;   #  end&lt;br /&gt;   sqlcreate = String.new()&lt;br /&gt;   sqlcreate = "CREATE TABLE "&lt;br /&gt;   sqlcreate &lt;&lt; '"' &lt;br /&gt;   sqlcreate &lt;&lt; railsname&lt;br /&gt;   sqlcreate &lt;&lt; '" ('&lt;br /&gt;   sqlcreate &lt;&lt; '"ID" NUMBER(38,0) NOT NULL'&lt;br /&gt;   # Good reference for data conversion to oracle types&lt;br /&gt;   # http://www.indiana.edu/~dss/Services/DataWarehouse/Oracle/Sybase/conversion.html&lt;br /&gt;   fieldnames = Array.new&lt;br /&gt;   tabledata.column_info.each_with_index do |info, i|&lt;br /&gt;            sqlcreate &lt;&lt; ", "&lt;br /&gt;            sqlcreate &lt;&lt; '"'&lt;br /&gt;            thename = info["name"]&lt;br /&gt;            thename = XlateColumnName(thename)&lt;br /&gt;            sqlcreate &lt;&lt; thename&lt;br /&gt;            sqlcreate &lt;&lt; '" '&lt;br /&gt;            thetype = info["type_name"]&lt;br /&gt;            theprecision = info["precision"]&lt;br /&gt;            thescale     = info["scale"]&lt;br /&gt;            if thetype == "CHAR"&lt;br /&gt;               thetype = "VARCHAR2(" + theprecision.to_s() + " BYTE)"&lt;br /&gt;               end&lt;br /&gt;            if thetype == "DOUBLE"&lt;br /&gt;               thetype = "NUMBER(38,0)"&lt;br /&gt;               end&lt;br /&gt;            if thetype == "BIT"&lt;br /&gt;               thetype = "CHAR(1)"&lt;br /&gt;               end&lt;br /&gt;            if thetype == "TINYINT"&lt;br /&gt;               thetype = "NUMBER(5,0)"&lt;br /&gt;               end&lt;br /&gt;            sqlcreate &lt;&lt; thetype&lt;br /&gt;            fieldnames &lt;&lt; thename&lt;br /&gt;            end&lt;br /&gt;   sqlcreate &lt;&lt; ', PRIMARY KEY ("ID") '&lt;br /&gt;   sqlcreate &lt;&lt; ")"&lt;br /&gt;   begin &lt;br /&gt;     result = todb.execute(sqlcreate)&lt;br /&gt;   rescue&lt;br /&gt;     puts "convertdata: Cannot create #{railsname}"&lt;br /&gt;     puts sqlcreate&lt;br /&gt;     raise&lt;br /&gt;     end&lt;br /&gt;   &lt;br /&gt;   #Drop any "old" sequence&lt;br /&gt;   sqldrop = "DROP SEQUENCE " + '"' + railsname + '_SEQ"' &lt;br /&gt;   begin&lt;br /&gt;      result = todb.execute(sqldrop)&lt;br /&gt;   rescue&lt;br /&gt;      #puts sqldrop&lt;br /&gt;      #puts "Sequence [#{railsname}] not dropped"&lt;br /&gt;      end&lt;br /&gt;   #Now create the RAILS Sequence number&lt;br /&gt;   #CREATE SEQUENCE  "AIRSTATION-DEVELOP"."BUSINESSUNITS_SEQ"  &lt;br /&gt;   # MINVALUE 1 MAXVALUE 999999999999999999999999999 INCREMENT BY 1 START WITH 10040 CACHE 20 NOORDER  NOCYCLE ;&lt;br /&gt;   sqlseq = String.new()&lt;br /&gt;   sqlseq &lt;&lt; "CREATE SEQUENCE "&lt;br /&gt;   sqlseq &lt;&lt; '"'&lt;br /&gt;   sqlseq &lt;&lt; railsname&lt;br /&gt;   sqlseq &lt;&lt; '_SEQ" ' &lt;br /&gt;   sqlseq &lt;&lt; "MAXVALUE 999999999999999999999999999 INCREMENT BY 1 START WITH 10000 CACHE 20 NOORDER  NOCYCLE"&lt;br /&gt;   begin &lt;br /&gt;      result = todb.execute(sqlseq)&lt;br /&gt;   rescue&lt;br /&gt;      puts sqlseq&lt;br /&gt;      raise&lt;br /&gt;      end&lt;br /&gt;&lt;br /&gt;   if row == nil #maybe we dont have data:)&lt;br /&gt;      tabledata.finish&lt;br /&gt;      return&lt;br /&gt;      end&lt;br /&gt;   doinsert(todb,railsname,fieldnames,row) # We already "Fetched" One&lt;br /&gt;&lt;br /&gt;   tabledata.fetch do |row|&lt;br /&gt;        doinsert(todb,railsname,fieldnames,row)&lt;br /&gt;        end&lt;br /&gt;    &lt;br /&gt;   tabledata.finish&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;#&lt;br /&gt;def doinsert(thedb, tablename, fieldnames, row)&lt;br /&gt;     if row == nil&lt;br /&gt;        return&lt;br /&gt;        end&lt;br /&gt;     sqlinsert = String.new&lt;br /&gt;     sqlinsert = "INSERT INTO "&lt;br /&gt;     sqlinsert &lt;&lt; '"'&lt;br /&gt;     sqlinsert &lt;&lt; tablename&lt;br /&gt;     sqlinsert &lt;&lt; '" ('&lt;br /&gt;     sqlinsert &lt;&lt; "ID,"&lt;br /&gt;     fieldnames.each do |myfield|&lt;br /&gt;         sqlinsert &lt;&lt; myfield + ","&lt;br /&gt;         end&lt;br /&gt;     #Must get rid of trailing comma and space&lt;br /&gt;     sqlinsert = sqlinsert[0,sqlinsert.length - 1]&lt;br /&gt;     sqlinsert &lt;&lt; ') VALUES ('&lt;br /&gt;     sqlinsert &lt;&lt; tablename + '_SEQ.NEXTVAL, '&lt;br /&gt;     row.each_with_name do |val, name|&lt;br /&gt;        val = val.to_s.strip&lt;br /&gt;        if val.length == 0&lt;br /&gt;            sqlinsert &lt;&lt; "NULL,"&lt;br /&gt;          else&lt;br /&gt;            sqlinsert &lt;&lt; thedb.quote(val.to_s.strip)&lt;br /&gt;            sqlinsert &lt;&lt; ","&lt;br /&gt;          end&lt;br /&gt;         end&lt;br /&gt;     #Must get rid of trailing comma and space&lt;br /&gt;     sqlinsert = sqlinsert[0,sqlinsert.length - 1]&lt;br /&gt;     sqlinsert &lt;&lt; ')'&lt;br /&gt;     begin &lt;br /&gt;        result = thedb.execute(sqlinsert)&lt;br /&gt;     rescue&lt;br /&gt;        puts sqlinsert&lt;br /&gt;        raise&lt;br /&gt;        end&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;argcount = ARGV.size&lt;br /&gt;if argcount &lt; 7&lt;br /&gt;   puts "command line is convertdata.rb FromDbDbi Username Password ToDbDbi Username Password Prefix"&lt;br /&gt;   puts "            ie: convertdata.rb DBI:ODBC:PRODDATA . . DBI:OCI8:XE . . MAG"&lt;br /&gt;   puts "             . = a empty string"&lt;br /&gt;   exit&lt;br /&gt;   end&lt;br /&gt;fromdbconstr  = ARGV[0]&lt;br /&gt;fromdbconuser = ARGV[1]&lt;br /&gt;fromdbconpass = ARGV[2]&lt;br /&gt;todbconstr    = ARGV[3]&lt;br /&gt;todbconuser   = ARGV[4]&lt;br /&gt;todbconpass   = ARGV[5]&lt;br /&gt;prefix        = ARGV[6]&lt;br /&gt;&lt;br /&gt;if fromdbconuser == '.'&lt;br /&gt;   fromdbconuser = ''&lt;br /&gt;   end&lt;br /&gt;if fromdbconpass == '.'&lt;br /&gt;   fromdbconpass = ''&lt;br /&gt;   end&lt;br /&gt;if todbconuser == '.'&lt;br /&gt;   todbconuser = ''&lt;br /&gt;   end&lt;br /&gt;if todbconpass == '.'&lt;br /&gt;   todbconpass = ''&lt;br /&gt;   end&lt;br /&gt;&lt;br /&gt;printf "FromDB: [%s] User [%s] Password [%s]\n",fromdbconstr,fromdbconuser,fromdbconpass&lt;br /&gt;printf "ToDB:   [%s] User [%s] Password [%s]\n",todbconstr, todbconuser, todbconpass&lt;br /&gt;printf "Prefix: [%s]\n", prefix&lt;br /&gt;&lt;br /&gt;#make a ODBC Connection&lt;br /&gt;fromdb = DBI.connect(fromdbconstr,fromdbconuser,fromdbconpass);&lt;br /&gt;todb   = DBI.connect(todbconstr,todbconuser,todbconpass)&lt;br /&gt;#fromdb = DBI.connect('DBI:ODBC:PRODDATA','','')&lt;br /&gt;#todb   = DBI.connect('DBI:OCI8:XE', 'AIRSTATION-DEVELOP', 'AIRSTATION-DEVELOP')&lt;br /&gt;#prefix = "MAG"&lt;br /&gt;&lt;br /&gt;tables = fromdb.tables&lt;br /&gt;$existing_tables = todb.tables&lt;br /&gt;&lt;br /&gt;tables.each do |tablename|&lt;br /&gt;   dotable(fromdb, todb, tablename, prefix)&lt;br /&gt;   end&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-7873962073281639669?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/7873962073281639669/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=7873962073281639669' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/7873962073281639669'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/7873962073281639669'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2007/10/importing-from-odbc-sources-into-oracle.html' title='Importing from ODBC sources into Oracle and Rails'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-517382008739625314</id><published>2007-10-18T20:45:00.000-07:00</published><updated>2007-10-18T20:51:06.210-07:00</updated><title type='text'>Import and Cleanup Dbase Files into Rails with Oracle Support</title><content type='html'>Wow, so many files, and how to clean them up.&lt;br /&gt;I can do migrations (See my previous post) with DBF,&lt;br /&gt;and do some nice cleanup as I go, but I really want to "get"&lt;br /&gt;rid of the dbase files, and make them native as fast as possible.&lt;br /&gt;&lt;br /&gt;So finally wrote a dbf-dbi-to-oracle converter.&lt;br /&gt;&lt;br /&gt;The issues you get with dbase files into rails are numerous. Lack&lt;br /&gt;of ID field, and names that are reserved words in SQL.&lt;br /&gt;&lt;br /&gt;Even "splits" of tables into multiple files is resonbly common.&lt;br /&gt;And worse the "schema" could change over the life of the dbf files,&lt;br /&gt;with some "dbf" files having one schema, and newer ones having signficant&lt;br /&gt;new fields.&lt;br /&gt;&lt;br /&gt;So here is the solution to all of this.&lt;br /&gt;&lt;br /&gt;A importdbf script&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;require 'DBI'&lt;br /&gt;require 'pp'&lt;br /&gt;require 'active_support'&lt;br /&gt;require 'fileutils'&lt;br /&gt;require 'dbf'&lt;br /&gt;require 'date'&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def sanitize(thevalue)  &lt;br /&gt;    thevalue.gsub(/[^[:alnum:]]+/, '_')  &lt;br /&gt;end  &lt;br /&gt; &lt;br /&gt;&lt;br /&gt;def numeric?(thenumber)&lt;br /&gt;  if thenumber =~ /^[0-9]+$/&lt;br /&gt;     return(TRUE)&lt;br /&gt;  else return(FALSE)&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def tableexists?(wantedtablename)&lt;br /&gt;&lt;br /&gt;tables = $existing_tables&lt;br /&gt;tables.each do |tablename|&lt;br /&gt;   if wantedtablename == tablename&lt;br /&gt;      return TRUE&lt;br /&gt;      end&lt;br /&gt;   end&lt;br /&gt;return FALSE&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def FileExtension(thepath)&lt;br /&gt;   thedot = thepath.rindex('.')&lt;br /&gt;   thelen = thepath.length - thedot&lt;br /&gt;   theextension = thepath[thedot,thelen]&lt;br /&gt;   theextension = theextension.downcase&lt;br /&gt;   return theextension&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#&lt;br /&gt;def doinsert(fromdb, thedb, tablename, fieldnames, row)&lt;br /&gt;     if row == nil&lt;br /&gt;        return&lt;br /&gt;        end&lt;br /&gt;     sqlinsert = String.new&lt;br /&gt;     sqlinsert = "INSERT INTO "&lt;br /&gt;     sqlinsert &lt;&lt; '"'&lt;br /&gt;     sqlinsert &lt;&lt; tablename&lt;br /&gt;     sqlinsert &lt;&lt; '" ('&lt;br /&gt;     sqlinsert &lt;&lt; "ID,"&lt;br /&gt;     fieldnames.each do |myfield|&lt;br /&gt;         sqlinsert &lt;&lt; myfield + ",\n"&lt;br /&gt;         end&lt;br /&gt;     #Must get rid of trailing comma and space&lt;br /&gt;     sqlinsert = sqlinsert[0,sqlinsert.length - 2]&lt;br /&gt;     sqlinsert &lt;&lt; ') VALUES ('&lt;br /&gt;     sqlinsert &lt;&lt; tablename + '_SEQ.NEXTVAL, '&lt;br /&gt;     fromdb.columns.each_with_index do |info, i|&lt;br /&gt;        val = row.attributes[info.name].to_s&lt;br /&gt;        if info.type == "D" #DATE&lt;br /&gt;           # "Mon Jan 01 00:00:00 UTC 2001" - dbf date&lt;br /&gt;           dbfformat = "%a %b %d %H:%M:%S %Z %Y"&lt;br /&gt;           #to_date('12-31-2007 12:15','MM-DD-YYYY HH:MI)&lt;br /&gt;           if val != ""&lt;br /&gt;             thedate = Date.parse(val)&lt;br /&gt;             val = "to_date('" + thedate.strftime("%m-%d-%Y %H:%M") + "', 'MM-DD-YYYY HH24:MI')"&lt;br /&gt;             sqlinsert &lt;&lt; val&lt;br /&gt;            else &lt;br /&gt;             sqlinsert &lt;&lt; "NULL" &lt;br /&gt;            end&lt;br /&gt;          elsif info.type == "M"&lt;br /&gt;             sqlinsert &lt;&lt; thedb.quote(val.to_s.strip)&lt;br /&gt;          elsif info.type == "L"&lt;br /&gt;           if val == "true"&lt;br /&gt;              val = "Y"&lt;br /&gt;              end&lt;br /&gt;           if val == "false"&lt;br /&gt;              val = "N"&lt;br /&gt;              end&lt;br /&gt;           sqlinsert &lt;&lt; thedb.quote(val.to_s.strip)&lt;br /&gt;          else &lt;br /&gt;           sqlinsert &lt;&lt; thedb.quote(val.to_s.strip)&lt;br /&gt;          end&lt;br /&gt;        # printf "Name = %s Type = %s Value = %s\n", info.name, info.type, val&lt;br /&gt;        sqlinsert &lt;&lt; ",\n"&lt;br /&gt;        end&lt;br /&gt;     #Must get rid of trailing comma and space&lt;br /&gt;     sqlinsert = sqlinsert[0,sqlinsert.length - 2]&lt;br /&gt;     sqlinsert &lt;&lt; ')'&lt;br /&gt;     begin &lt;br /&gt;        # puts sqlinsert&lt;br /&gt;        tabledata = thedb.execute(sqlinsert)&lt;br /&gt;     rescue&lt;br /&gt;        puts sqlinsert&lt;br /&gt;        thesql = File.open("convertdbf.sql","w")&lt;br /&gt;        thesql.puts sqlinsert + ";"&lt;br /&gt;        thesql.close&lt;br /&gt;        raise&lt;br /&gt;        end&lt;br /&gt;    tabledata.finish&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def ImportTable(fromdb,todb,railsname,fieldnames)&lt;br /&gt;&lt;br /&gt;   fromdb.records.each do |record|&lt;br /&gt;      doinsert(fromdb, todb,railsname,fieldnames,record) &lt;br /&gt;      end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def XlateColumnName(thename,thetype)&lt;br /&gt;    thename = thename.delete(" ")&lt;br /&gt;    thename = thename.upcase&lt;br /&gt;    if thetype == "D" #DATE Should have it in the name&lt;br /&gt;       if !thename.include?("DATE")&lt;br /&gt;          thename &lt;&lt; "DATE"&lt;br /&gt;          end&lt;br /&gt;       end&lt;br /&gt;    if numeric?(thename)&lt;br /&gt;       thename = "X" + thename&lt;br /&gt;       end&lt;br /&gt;    if thename == "FILE"&lt;br /&gt;       thename = "XFILE"&lt;br /&gt;       end&lt;br /&gt;    if thename == "LOCK"&lt;br /&gt;       thename = "XLOCK"&lt;br /&gt;       end&lt;br /&gt;    if thename == "SCOPE"&lt;br /&gt;       thename = "XSCOPE"&lt;br /&gt;       end&lt;br /&gt;    if thename == "TYPE"&lt;br /&gt;       thename = "XTYPE"&lt;br /&gt;       end&lt;br /&gt;    if thename == "CLASS"&lt;br /&gt;       thename = "XCLASS"&lt;br /&gt;       end&lt;br /&gt;    if thename == "COST"&lt;br /&gt;       thename = "XCOST"&lt;br /&gt;       end&lt;br /&gt;    if thename == "FIXED"&lt;br /&gt;       thename = "XFIXED"&lt;br /&gt;       end&lt;br /&gt;    if thename == "CURRENT"&lt;br /&gt;       thename = "XCURRENT"&lt;br /&gt;       end&lt;br /&gt;    if thename == "DATE"&lt;br /&gt;       thename = "XDATE"&lt;br /&gt;       end&lt;br /&gt;    if thename == "TIME"&lt;br /&gt;       thename = "XTIME"&lt;br /&gt;       end&lt;br /&gt;    if thename == "NUMBER"&lt;br /&gt;       thename = "XNUMBER"&lt;br /&gt;       end&lt;br /&gt;    if thename == "CONDITION"&lt;br /&gt;       thename = "XCONDITION"&lt;br /&gt;       end&lt;br /&gt;    if thename == "SEQ"&lt;br /&gt;       thename = "XSEQ"&lt;br /&gt;       end&lt;br /&gt;    if thename == "COMMENT"&lt;br /&gt;       thename = "XCOMMENT"&lt;br /&gt;       end&lt;br /&gt;    return(thename)&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def XlateColumntype(thetype, theprecision, thescale)&lt;br /&gt;&lt;br /&gt;   if thetype == "C"&lt;br /&gt;      thetype = "VARCHAR2(" + theprecision.to_s() + " BYTE)"&lt;br /&gt;      end&lt;br /&gt;   if thetype == "L" #Logical - false or true&lt;br /&gt;      thetype = "CHAR(1)"&lt;br /&gt;      end&lt;br /&gt;   if thetype == "N"&lt;br /&gt;      thetype = "NUMBER(38,0)"&lt;br /&gt;      end&lt;br /&gt;   if thetype == "D"&lt;br /&gt;      thetype = "DATE"&lt;br /&gt;      end&lt;br /&gt;   if thetype == "B"&lt;br /&gt;      thetype = "CHAR(1)"&lt;br /&gt;      end&lt;br /&gt;   if thetype == "M"&lt;br /&gt;      thetype = "CLOB"&lt;br /&gt;      end&lt;br /&gt;   return(thetype)&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def CreateTable(fromdb,todb,railsname)&lt;br /&gt;   sqlcreate = String.new()&lt;br /&gt;   sqlcreate = "CREATE TABLE "&lt;br /&gt;   sqlcreate &lt;&lt; '"' &lt;br /&gt;   sqlcreate &lt;&lt; railsname&lt;br /&gt;   sqlcreate &lt;&lt; '" ('&lt;br /&gt;   sqlcreate &lt;&lt; '"ID" NUMBER(38,0) NOT NULL'&lt;br /&gt;   # Good reference for data conversion to oracle types&lt;br /&gt;   # http://www.indiana.edu/~dss/Services/DataWarehouse/Oracle/Sybase/conversion.html&lt;br /&gt;   fieldnames = Array.new&lt;br /&gt;   &lt;br /&gt;   fromdb.columns.each_with_index do |info, i|&lt;br /&gt;            sqlcreate &lt;&lt; ", "&lt;br /&gt;            sqlcreate &lt;&lt; '"'&lt;br /&gt;            thename = XlateColumnName(info.name,info.type)&lt;br /&gt;            sqlcreate &lt;&lt; thename&lt;br /&gt;            sqlcreate &lt;&lt; '" '&lt;br /&gt;            thetype = info.type&lt;br /&gt;            theprecision = info.length&lt;br /&gt;            thescale     = info.decimal&lt;br /&gt;            thetype = XlateColumntype(thetype,theprecision, thescale)&lt;br /&gt;            sqlcreate &lt;&lt; thetype&lt;br /&gt;            fieldnames &lt;&lt; thename&lt;br /&gt;            end&lt;br /&gt;   sqlcreate &lt;&lt; ', PRIMARY KEY ("ID") '&lt;br /&gt;   sqlcreate &lt;&lt; ")"&lt;br /&gt;   begin &lt;br /&gt;     tabledata = todb.execute(sqlcreate)&lt;br /&gt;   rescue&lt;br /&gt;     puts "convertdata: Cannot create #{railsname}"&lt;br /&gt;     thesql = File.open("convertdbf.sql","w")&lt;br /&gt;     thesql.puts sqlcreate + ";"&lt;br /&gt;     thesql.close&lt;br /&gt;     puts sqlcreate&lt;br /&gt;     raise&lt;br /&gt;     end&lt;br /&gt;   tabledata.finish&lt;br /&gt;   #Drop any "old" sequence&lt;br /&gt;   sqldrop = "DROP SEQUENCE " + '"' + railsname + '_SEQ"' &lt;br /&gt;   begin&lt;br /&gt;      tabledata = todb.execute(sqldrop)&lt;br /&gt;      tabledata.finish&lt;br /&gt;   rescue&lt;br /&gt;      #puts sqldrop&lt;br /&gt;      #puts "Sequence [#{railsname}] not dropped"&lt;br /&gt;      end&lt;br /&gt;   #Now create the RAILS Sequence number&lt;br /&gt;   #CREATE SEQUENCE  "AIRSTATION-DEVELOP"."BUSINESSUNITS_SEQ"  &lt;br /&gt;   # MINVALUE 1 MAXVALUE 999999999999999999999999999 INCREMENT BY 1 START WITH 10040 CACHE 20 NOORDER  NOCYCLE ;&lt;br /&gt;   sqlseq = String.new()&lt;br /&gt;   sqlseq &lt;&lt; "CREATE SEQUENCE "&lt;br /&gt;   sqlseq &lt;&lt; '"'&lt;br /&gt;   sqlseq &lt;&lt; railsname&lt;br /&gt;   sqlseq &lt;&lt; '_SEQ" ' &lt;br /&gt;   sqlseq &lt;&lt; "MAXVALUE 999999999999999999999999999 INCREMENT BY 1 START WITH 10000 CACHE 20 NOORDER  NOCYCLE"&lt;br /&gt;   begin &lt;br /&gt;      tabledata = todb.execute(sqlseq)&lt;br /&gt;      tabledata.finish&lt;br /&gt;   rescue&lt;br /&gt;      puts sqlseq&lt;br /&gt;      raise&lt;br /&gt;      end&lt;br /&gt;   $existing_tables &lt;&lt; railsname&lt;br /&gt;   return(fieldnames)&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def create_master_content_table(thedb,mastercontent_table)&lt;br /&gt;    sqlcreate = "CREATE TABLE " + mastercontent_table + "( SUBFILENAME VARCHAR2(32) )"&lt;br /&gt;    begin &lt;br /&gt;      tabledata = thedb.execute(sqlcreate)&lt;br /&gt;    rescue&lt;br /&gt;      puts sqlcreate&lt;br /&gt;      raise&lt;br /&gt;      end  &lt;br /&gt;    tabledata.finish&lt;br /&gt;    $existing_tables &lt;&lt; mastercontent_table&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def is_in_mastertable?(thedb, mastertable,thename)&lt;br /&gt;    mastercontent_table = mastertable + "_FILES"&lt;br /&gt;    if tableexists?(mastercontent_table) == FALSE&lt;br /&gt;       create_master_content_table(thedb,mastercontent_table)&lt;br /&gt;       return(FALSE)&lt;br /&gt;       end&lt;br /&gt;    sqlquery = "SELECT * FROM " + mastercontent_table + &lt;br /&gt;               " WHERE SUBFILENAME = " +  &lt;br /&gt;                thedb.quote(thename.to_s.strip)&lt;br /&gt;    tabledata = thedb.execute(sqlquery)&lt;br /&gt;    row = tabledata.fetch&lt;br /&gt;    if row == nil&lt;br /&gt;       tabledata.finish&lt;br /&gt;       return(FALSE)&lt;br /&gt;       end&lt;br /&gt;    tabledata.finish&lt;br /&gt;    return TRUE&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def add_to_file_table(thedb, mastertable, thefilename )&lt;br /&gt;    sqlinsert = "INSERT INTO " + mastertable + "_FILES " + " (SUBFILENAME) VALUES ("&lt;br /&gt;    sqlinsert &lt;&lt; thedb.quote(thefilename) + ")"&lt;br /&gt;    begin     &lt;br /&gt;      tabledata = thedb.execute(sqlinsert) &lt;br /&gt;    rescue&lt;br /&gt;      puts sqlinsert&lt;br /&gt;      raise&lt;br /&gt;      end&lt;br /&gt;    tabledata.finish&lt;br /&gt;end    &lt;br /&gt;&lt;br /&gt;def DescribeTable(todb,railsname)&lt;br /&gt;    fieldnames = Array.new&lt;br /&gt;    sqlquery = "SELECT * FROM " + railsname&lt;br /&gt;    tabledata = todb.execute(sqlquery)&lt;br /&gt;    for column in tabledata.column_info()&lt;br /&gt;        if column['name'] == "ID" # We "assume" that ID is present&lt;br /&gt;           next&lt;br /&gt;           end&lt;br /&gt;        fieldnames &lt;&lt; column['name']&lt;br /&gt;        end&lt;br /&gt;    tabledata.finish&lt;br /&gt;    return(fieldnames)&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def UpdateTableDef(fieldnames,fromdb,todb,railsname)&lt;br /&gt;&lt;br /&gt;   #alter table author add (author_last_published  date); &lt;br /&gt;   sqlmodify = "ALTER TABLE "&lt;br /&gt;   sqlmodify &lt;&lt; '"' &lt;br /&gt;   sqlmodify &lt;&lt; railsname&lt;br /&gt;   sqlmodify &lt;&lt; '" ADD ('&lt;br /&gt;   thistablefields = Array.new&lt;br /&gt;   newfields = Array.new&lt;br /&gt;   fromdb.columns.each_with_index do |info, index|&lt;br /&gt;            thename = XlateColumnName(info.name,info.type)&lt;br /&gt;            thistablefields &lt;&lt; thename&lt;br /&gt;            if fieldnames.include?(thename)&lt;br /&gt;               next&lt;br /&gt;               end&lt;br /&gt;            newfields &lt;&lt; thename&lt;br /&gt;            sqlmodify &lt;&lt; '"'&lt;br /&gt;            sqlmodify &lt;&lt; thename&lt;br /&gt;            sqlmodify &lt;&lt; '" '&lt;br /&gt;            thetype = info.type&lt;br /&gt;            theprecision = info.length&lt;br /&gt;            thescale     = info.decimal&lt;br /&gt;            thetype = XlateColumntype(thetype,theprecision, thescale)&lt;br /&gt;            sqlmodify &lt;&lt; thetype&lt;br /&gt;            sqlmodify &lt;&lt; ", "&lt;br /&gt;            fieldnames &lt;&lt; thename&lt;br /&gt;            end&lt;br /&gt;   if newfields.empty?    # Table definition is identical&lt;br /&gt;      return(thistablefields)&lt;br /&gt;      end&lt;br /&gt;   # pp newfields&lt;br /&gt;   #Must get rid of trailing comma and space&lt;br /&gt;   sqlmodify = sqlmodify[0,sqlmodify.length - 2]&lt;br /&gt;   sqlmodify &lt;&lt; ")"&lt;br /&gt;   begin &lt;br /&gt;     tabledata = todb.execute(sqlmodify)&lt;br /&gt;   rescue&lt;br /&gt;     puts "convertdata: Cannot modify #{railsname}"&lt;br /&gt;     thesql = File.open("convertdbf.sql","w")&lt;br /&gt;     thesql.puts sqlmodify + ";"&lt;br /&gt;     thesql.close&lt;br /&gt;     puts sqlmodify&lt;br /&gt;     raise&lt;br /&gt;     end    &lt;br /&gt;   tabledata.finish&lt;br /&gt;   return(thistablefields)&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def ProcessFile(thename, thepath,todb,prefix,mastertable)&lt;br /&gt;    filetype = FileExtension(thepath)&lt;br /&gt;    if filetype != ".dbf"&lt;br /&gt;       return&lt;br /&gt;       end&lt;br /&gt;   tablename = thename.slice(0,thename.length - 4)&lt;br /&gt;   tablename = sanitize(tablename) &lt;br /&gt;   if numeric?(tablename)&lt;br /&gt;       tablename = mastertable&lt;br /&gt;       railsname = Inflector.pluralize(tablename)&lt;br /&gt;       railsname = railsname.upcase&lt;br /&gt;       if is_in_mastertable?(todb,mastertable,thename)&lt;br /&gt;          return&lt;br /&gt;          end&lt;br /&gt;       add_to_file_table(todb,mastertable,thename)&lt;br /&gt;       puts "Adding #{thename} to #{railsname}"&lt;br /&gt;      else&lt;br /&gt;       tablename = prefix + '_' + tablename&lt;br /&gt;       tablename = tablename.upcase&lt;br /&gt;       railsname = Inflector.pluralize(tablename)&lt;br /&gt;       railsname = railsname.upcase&lt;br /&gt;       if tableexists?(railsname)&lt;br /&gt;          printf "Exists %s\n",railsname&lt;br /&gt;          return&lt;br /&gt;          end&lt;br /&gt;       end&lt;br /&gt;   fromdb = DBF::Table.new(thepath,:in_memory =&gt; false)&lt;br /&gt;   if tableexists?(railsname) == FALSE&lt;br /&gt;       fieldnames = CreateTable(fromdb,todb,railsname)&lt;br /&gt;       puts "Created #{railsname}"&lt;br /&gt;      else&lt;br /&gt;       fieldnames = DescribeTable(todb,railsname)&lt;br /&gt;       fieldnames = UpdateTableDef(fieldnames,fromdb,todb,railsname)&lt;br /&gt;      end&lt;br /&gt;   ImportTable(fromdb,todb,railsname,fieldnames)&lt;br /&gt;   fromdb = nil&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def DoDir(mydirectory,todb,prefix,mastertable)&lt;br /&gt;  Dir.foreach(mydirectory) do |entry|&lt;br /&gt;   # Dont bother with . and ..&lt;br /&gt;   next if [".",".."].include? entry&lt;br /&gt;   fullname = mydirectory + "\\" + entry&lt;br /&gt;   if FileTest::directory?(fullname)&lt;br /&gt;      DoDir(fullname,todb,prefix)&lt;br /&gt;     elsif FileTest::file?(fullname)&lt;br /&gt;      ProcessFile(entry,fullname,todb,prefix,mastertable)&lt;br /&gt;     else &lt;br /&gt;      puts "Unknown file type - #{fullname}"&lt;br /&gt;      return;&lt;br /&gt;     end&lt;br /&gt;   end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;argcount = ARGV.size&lt;br /&gt;if argcount &lt; 6&lt;br /&gt;   puts "command line is convertdbf.rb FromPath ToDbDbi Username Password Prefix"&lt;br /&gt;   exit&lt;br /&gt;   end&lt;br /&gt;fromdir       = ARGV[0]&lt;br /&gt;todbconstr    = ARGV[1]&lt;br /&gt;todbconuser   = ARGV[2]&lt;br /&gt;todbconpass   = ARGV[3]&lt;br /&gt;prefix        = ARGV[4]&lt;br /&gt;mastertable   = ARGV[5]&lt;br /&gt;&lt;br /&gt;if todbconuser == '*'&lt;br /&gt;   todbconuser = ''&lt;br /&gt;   end&lt;br /&gt;if todbconpass == '*'&lt;br /&gt;   todbconpass = ''&lt;br /&gt;   end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#make a ODBC Connection&lt;br /&gt;todb   = DBI.connect(todbconstr,todbconuser,todbconpass)&lt;br /&gt;&lt;br /&gt;$existing_tables = todb.tables&lt;br /&gt;&lt;br /&gt;DoDir(fromdir,todb,prefix,mastertable)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-517382008739625314?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/517382008739625314/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=517382008739625314' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/517382008739625314'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/517382008739625314'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2007/10/import-and-cleanup-dbase-files-into.html' title='Import and Cleanup Dbase Files into Rails with Oracle Support'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-4026397826291679805</id><published>2007-10-18T20:31:00.000-07:00</published><updated>2007-10-18T20:36:44.833-07:00</updated><title type='text'>A Production generator for Rails</title><content type='html'>As I get into Rails, I'm generating "large" applications, and I really like the RAILS DRY principle. So for production I'm using a variety of "plug-ins"&lt;br /&gt;&lt;br /&gt;ActiveScaffold&lt;br /&gt;RoleRequirement&lt;br /&gt;Widgets/Tabnav&lt;br /&gt;&lt;br /&gt;In addition I'm using a Oracle Database.&lt;br /&gt;&lt;br /&gt;So I wrote a generator that "reads" the Oracle Database, and generates any &lt;br /&gt;"missing" controllers and models. The lovely part is, when I change the basic&lt;br /&gt;controller, I just "erase" the ones I want updated, and fire the script again.&lt;br /&gt;&lt;br /&gt;This also handles the pluraziation, making sure the controllers, models are named the same. Also tries to do some cleanup so the menu names are a little more humanized. In addition good example of using name spaces to help organize a large project better.&lt;br /&gt;&lt;br /&gt;require 'DBI'&lt;br /&gt;require 'pp'&lt;br /&gt;require 'active_support'&lt;br /&gt;require 'fileutils'&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def domodel(tablename)&lt;br /&gt;    modelname = tablename.downcase&lt;br /&gt;    modelname = modelname.singularize&lt;br /&gt;   &lt;br /&gt;    modeldir = "app\\models\\"&lt;br /&gt;    FileUtils.makedirs(modeldir)&lt;br /&gt;    modelpath = modeldir + modelname + ".rb"&lt;br /&gt;    if FileTest::exists?(modelpath)&lt;br /&gt;       printf "exists %s\n", modelpath&lt;br /&gt;       return&lt;br /&gt;       end&lt;br /&gt;    themodel = File.open(modelpath,"w")&lt;br /&gt;&lt;br /&gt;    themodel.puts "class " + modelname.camelize + " &lt; ActiveRecord::Base"&lt;br /&gt;    themodel.puts "# "&lt;br /&gt;    themodel.puts "# Created By GenRails"&lt;br /&gt;    themodel.puts "# "&lt;br /&gt;    themodel.puts "end"&lt;br /&gt;    themodel.close&lt;br /&gt;    printf "create %s\n", modelpath&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def docontroller(thenamespace,tablename, layout, prefix)&lt;br /&gt;    controllername = tablename.downcase&lt;br /&gt;    controllername = controllername.singularize&lt;br /&gt;    controllerfilename = controllername + "_controller.rb"&lt;br /&gt;    controllerdir = "app\\controllers\\" + thenamespace + "\\"&lt;br /&gt;    FileUtils.makedirs(controllerdir)&lt;br /&gt;    controllerpath = controllerdir + controllerfilename&lt;br /&gt;    if FileTest::exists?(controllerpath)&lt;br /&gt;       printf "exists %s\n", controllerpath&lt;br /&gt;       return&lt;br /&gt;       end&lt;br /&gt;    thecontroller = File.open(controllerpath,"w")&lt;br /&gt;    &lt;br /&gt;    thecontroller.puts "class " + thenamespace.camelize + '::' + controllername.camelize + 'Controller &lt; ApplicationController'&lt;br /&gt;    thecontroller.puts " layout '" + layout + "'"&lt;br /&gt;    thecontroller.puts " before_filter :login_required"&lt;br /&gt;    thecontroller.puts "# "&lt;br /&gt;    thecontroller.puts "# Generated by GenRails"&lt;br /&gt;    thecontroller.puts "# "&lt;br /&gt;    thecontroller.puts " "&lt;br /&gt;    thecontroller.puts "active_scaffold :" + controllername.camelize + " do |config|"&lt;br /&gt;    menuname = tablename.slice(prefix.length+1,tablename.length - prefix.length + 1)&lt;br /&gt;    menuname = menuname.camelize&lt;br /&gt;    thecontroller.puts " config.label = '" + menuname + "'"&lt;br /&gt;    thecontroller.puts "        config.actions = [:search, :show, :list, :create, :delete]"&lt;br /&gt;    thecontroller.puts " end"&lt;br /&gt;    thecontroller.puts "end"&lt;br /&gt;    thecontroller.close&lt;br /&gt;    printf "create %s\n", controllerpath&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def dotable(fromdb, namespace, tablename, layout, prefix)&lt;br /&gt;&lt;br /&gt;   tablename = tablename.strip&lt;br /&gt;   if tablename.length == 0&lt;br /&gt;      return&lt;br /&gt;      end&lt;br /&gt;#   begin &lt;br /&gt;#      row = fromdb.select_one("select count(*) from #{tablename}")&lt;br /&gt;#   rescue&lt;br /&gt;#      return&lt;br /&gt;#      end &lt;br /&gt;#   record_count = row[0]&lt;br /&gt;#   if record_count == 0&lt;br /&gt;#      return&lt;br /&gt;#      end&lt;br /&gt; &lt;br /&gt;   domodel(tablename)&lt;br /&gt;   docontroller(namespace,tablename, layout, prefix)&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;#make a ODBC Connection&lt;br /&gt;&lt;br /&gt;fromdb = DBI.connect('DBI:OCI8:XE', 'AIRSTATION-DEVELOP', 'AIRSTATION-DEVELOP')&lt;br /&gt;prefix = "MAG"&lt;br /&gt;appname = 'overhaul'&lt;br /&gt;namespace = appname + "space"&lt;br /&gt;layout    = "tier2" + appname&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;tables = fromdb.tables&lt;br /&gt;&lt;br /&gt;tabnavname = '_' + appname + '_tabnav.rhtml'&lt;br /&gt;tabnavdir  = 'app\\views\\widgets\\'&lt;br /&gt;FileUtils.makedirs(tabnavdir)&lt;br /&gt;tabnavpath = tabnavdir + tabnavname&lt;br /&gt;thetabnav = File.open(tabnavpath,"w")&lt;br /&gt;&lt;br /&gt;thetabnav.puts '&lt;%'&lt;br /&gt;thetabnav.puts '# GenRails - Tabnav based menu'&lt;br /&gt;thetabnav.puts 'render_tabnav :' + appname + ","&lt;br /&gt;thetabnav.puts ' :generate_css =&gt; true do'&lt;br /&gt;thetabnav.puts ' '&lt;br /&gt;thetabnav.puts '  if @current_user.has_role?(' + '\'' + appname + '\')'&lt;br /&gt;thetabnav.puts '     add_tab do |t|'&lt;br /&gt;thetabnav.puts '       t.named ' + '\'' + appname.capitalize + '\''&lt;br /&gt;thetabnav.puts '       t.titled ' + '\'' + appname.capitalize + ' Home\''&lt;br /&gt;thetabnav.puts '       t.links_to :controller =&gt; ' + '\'' + namespace + '/' + appname + 'home' + '\''&lt;br /&gt;thetabnav.puts '       end'&lt;br /&gt;&lt;br /&gt;tables.each do |tablename|&lt;br /&gt;   thetableprefix = tablename.slice(0,prefix.length)&lt;br /&gt;   if thetableprefix == prefix&lt;br /&gt;      dotable(fromdb, namespace, tablename, layout,prefix)&lt;br /&gt;      menuname = tablename.slice(prefix.length+1,tablename.length - prefix.length + 1)&lt;br /&gt;      menuname = menuname.downcase&lt;br /&gt;      menuname = menuname.singularize&lt;br /&gt;      controllername = tablename.downcase&lt;br /&gt;      controllername = controllername.singularize&lt;br /&gt;      thetabnav.puts '     add_tab do |t|'&lt;br /&gt;      thetabnav.puts '       t.named ' + '\'' + menuname.capitalize + '\''&lt;br /&gt;      thetabnav.puts '       t.titled ' + '\'' + menuname.capitalize + '\''&lt;br /&gt;      thetabnav.puts '       t.links_to :controller =&gt; ' + '\'' + namespace + '/' + controllername + '\''&lt;br /&gt;      thetabnav.puts '       end'&lt;br /&gt;      end&lt;br /&gt;   end&lt;br /&gt;&lt;br /&gt;thetabnav.puts '   end'&lt;br /&gt;thetabnav.puts 'end'&lt;br /&gt;thetabnav.puts '%&gt;'&lt;br /&gt;thetabnav.close&lt;br /&gt;printf "updated %s", tabnavpath&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-4026397826291679805?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/4026397826291679805/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=4026397826291679805' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/4026397826291679805'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/4026397826291679805'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2007/10/production-generator-for-rails.html' title='A Production generator for Rails'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-7821910053113152505</id><published>2007-10-04T19:41:00.000-07:00</published><updated>2007-10-04T19:52:15.892-07:00</updated><title type='text'>Ruby Rails - Importorting Dbase and Foxpro  Files</title><content type='html'>Did you have foxprofiles that you just want to move into a rails environment.&lt;br /&gt;Then dbf is your friend.&lt;br /&gt;&lt;br /&gt;It lets you do "mirgrations" that move dbase into the rails database of your choice.&lt;br /&gt;&lt;br /&gt;So for example, one I just did:&lt;br /&gt;&lt;br /&gt;class CreateMrosalesorder &lt; ActiveRecord::Migration&lt;br /&gt;  def self.up&lt;br /&gt;      create_table "mrosalesorders", :force =&gt; true do |t|&lt;br /&gt;        t.column "mrocustomer_id", :integer&lt;br /&gt;        t.column "sono", :string, :limit =&gt; 8&lt;br /&gt;              ....&lt;br /&gt;        t.column "tot_mcmosr", :float&lt;br /&gt;        t.column "tot_labosr", :float&lt;br /&gt;      end&lt;br /&gt;      thepathname = "...\SOMAST01.DBF"&lt;br /&gt;      table = DBF::Table.new(thepathname)&lt;br /&gt;      table.records.each do |record|&lt;br /&gt;         mysalesorder = Mrosalesorder.create(record.attributes)&lt;br /&gt;         mymrocustomer = Mrocustomer.find(:first, :conditions =&gt; "custno = '#{record.custno}'")&lt;br /&gt;         if not mymrocustomer.nil?&lt;br /&gt;           mysalesorder.mrocustomer_id = mymrocustomer.id&lt;br /&gt;           mysalesorder.save&lt;br /&gt;         end&lt;br /&gt;         end&lt;br /&gt;    end   &lt;br /&gt;def self.down&lt;br /&gt;   drop_table "mrosalesorders"&lt;br /&gt; end    &lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;Now the issue will occur that some "field" names in dbase/foxpro may be invalid in your database of choice.&lt;br /&gt;&lt;br /&gt;So its easy to resolve that in your model.&lt;br /&gt;When "fields" are set they call a "method" of varname= in your model.&lt;br /&gt;So take care of your "renames" there. If your a "cobol" programmer this is&lt;br /&gt;like a "move" corresponding, with a "rename" in the middle, without needeing&lt;br /&gt;to handle all the fields that are not renamed.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;class Mrosalesorder &lt; ActiveRecord::Base&lt;br /&gt;belongs_to :customer&lt;br /&gt;belongs_to :mrocustomer&lt;br /&gt;&lt;br /&gt;def comment=(value)&lt;br /&gt;    self.socomment=value&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def current=(value)&lt;br /&gt;    self.curr=value&lt;br /&gt;end&lt;br /&gt;  &lt;br /&gt;def to_label&lt;br /&gt;    "#{sono}"&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;end&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-7821910053113152505?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://rubyforge.org/projects/dbf/' title='Ruby Rails - Importorting Dbase and Foxpro  Files'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/7821910053113152505/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=7821910053113152505' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/7821910053113152505'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/7821910053113152505'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2007/10/ruby-rails-importorting-dbase-and.html' title='Ruby Rails - Importorting Dbase and Foxpro  Files'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-8730086525029419213</id><published>2007-10-02T00:47:00.000-07:00</published><updated>2007-10-02T00:50:35.593-07:00</updated><title type='text'>Fetcher Typos Resolved</title><content type='html'>Well, somehow it happened. A few typo's entered my perfect program. Why did it even work? :) The story of code. The new version starts faster, and more reliable as well.&lt;br /&gt;&lt;br /&gt;Fetch your Exchange Mail, and call recievemail function directy in your ActiveRecord Models.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;require 'rubygems'&lt;br /&gt;require 'win32/service'&lt;br /&gt;require 'logger'&lt;br /&gt;require 'net/imap'&lt;br /&gt;require 'net/pop'&lt;br /&gt;include Win32&lt;br /&gt;&lt;br /&gt;Dir.chdir("\\projects\\ror\\AirCenter")&lt;br /&gt;require File.dirname(__FILE__) + '/../config/environment.rb'   &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SERVICE_NAME = 'AirFetchService'&lt;br /&gt;SERVICE_DISPLAYNAME = 'AirCenterEmailFetcherService'&lt;br /&gt;$logger = Logger.new("c:\\projects\\ror\\AirCenter\\log\\AirFetchService.log")&lt;br /&gt;&lt;br /&gt;class Mailman &lt; ActionMailer::Base&lt;br /&gt;  def receive(email)&lt;br /&gt;    sender = email.from.to_s()&lt;br /&gt;    subject = email.subject.to_s()&lt;br /&gt;    body = email.body.to_s()&lt;br /&gt;    subjectparts = subject.split(/ /)&lt;br /&gt;    classname = subjectparts[0]&lt;br /&gt;    $logger.info("Mailman: Sender = #{sender} Class = #{classname} Subject = #{subject}")&lt;br /&gt;    myclass = Object.const_get(classname)&lt;br /&gt;    if myclass&lt;br /&gt;      myclass.ReceiveEmail(sender,subject,subjectparts,body)&lt;br /&gt;      else $logger.warn("Mailman: Invalid class #{classname}")&lt;br /&gt;    #Request.ReceiveEmail(sender,subject,body)&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end  &lt;br /&gt;&lt;br /&gt;if ARGV[0] == "register"&lt;br /&gt; #Start The Service&lt;br /&gt; svc = Service.new&lt;br /&gt; svc.create_service do |s|&lt;br /&gt;  s.service_name = SERVICE_NAME&lt;br /&gt;  s.display_name = SERVICE_DISPLAYNAME&lt;br /&gt;  s.binary_path_name = "c:\\ruby\\bin\\ruby.exe c:\\projects\\ror\\AirCenter\\script\\AirFetchService.rb"&lt;br /&gt;    # + File.expand_path($0)&lt;br /&gt;  s.dependencies = []&lt;br /&gt;  end&lt;br /&gt; svc.close&lt;br /&gt; puts "Registered Service - " + SERVICE_DISPLAYNAME&lt;br /&gt;elsif ARGV[0] == "test"&lt;br /&gt;     $logger.info "Service Starting"&lt;br /&gt;     $logger.info "Loading EMAIL Config"&lt;br /&gt;     @config = YAML.load_file("#{RAILS_ROOT}/config/mail.yml")&lt;br /&gt;     $logger.info "Setting up config"&lt;br /&gt;     @config = @config[RAILS_ENV].to_options&lt;br /&gt;     $logger.info "Setting up sleep time"&lt;br /&gt;     @sleep_time = @config.delete(:sleep_time) || 60&lt;br /&gt;     $logger.info "Service Init Complete"&lt;br /&gt;     $logger.info "AirFetchService Establish mail processor"&lt;br /&gt;     # Add your own receiver object below&lt;br /&gt;     @fetcher = Fetcher.create({:receiver =&gt; Mailman}.merge(@config))&lt;br /&gt;     @fetcher.fetch&lt;br /&gt;     exit&lt;br /&gt;  elsif ARGV[0] == "delete"&lt;br /&gt;    if Service.status(SERVICE_NAME).current_state == "running"&lt;br /&gt;      Service.stop(SERVICE_NAME)&lt;br /&gt;      end&lt;br /&gt;    Service.delete(SERVICE_NAME)&lt;br /&gt;else &lt;br /&gt;    if ENV["HOMEDRIVE"] !=nil&lt;br /&gt;    puts "Usage: ruby airfetchservice.rb [options]"&lt;br /&gt;    puts "       where options are: register or delete"&lt;br /&gt;    exit&lt;br /&gt;    end &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;class MyDaemon &lt; Win32::Daemon&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def service_init&lt;br /&gt;  sleep 1&lt;br /&gt;   $logger.info "Service Starting"&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def service_stop&lt;br /&gt;    $logger.info "AirFetchService Stopped"&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def service_main&lt;br /&gt;   $logger.info "Loading EMAIL Config"&lt;br /&gt;   @config = YAML.load_file("#{RAILS_ROOT}/config/mail.yml")&lt;br /&gt;   $logger.info "Setting up config"&lt;br /&gt;   @config = @config[RAILS_ENV].to_options&lt;br /&gt;   $logger.info "Setting up sleep time"&lt;br /&gt;   @sleep_time = @config.delete(:sleep_time) || 60&lt;br /&gt;   $logger.info "Service Init Complete"&lt;br /&gt;   $logger.info "AirFetchService Establish mail processor"&lt;br /&gt;   # Add your own receiver object below&lt;br /&gt;   @fetcher = Fetcher.create({:receiver =&gt; Mailman}.merge(@config))&lt;br /&gt;   $logger.info "AirFetchService Mail Processor Ready"&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;  $logger.info "AirFetchService: Service in Running State"&lt;br /&gt;    while state == RUNNING&lt;br /&gt;      #begin&lt;br /&gt;        @fetcher.fetch&lt;br /&gt;      #rescue&lt;br /&gt;      #end&lt;br /&gt;      sleep(@sleep_time)&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end &lt;br /&gt;&lt;br /&gt; d = MyDaemon.new&lt;br /&gt; d.mainloop &lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;end&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-8730086525029419213?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/8730086525029419213/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=8730086525029419213' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/8730086525029419213'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/8730086525029419213'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2007/10/fetcher-typos-resolved.html' title='Fetcher Typos Resolved'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-6768810304427629618</id><published>2007-09-28T20:19:00.000-07:00</published><updated>2007-09-28T20:48:15.603-07:00</updated><title type='text'>Getting Email from Exchange Into Rails</title><content type='html'>So here I was, lost on a windows box, looking for a way to get supplies &lt;br /&gt;that were badly needed. And what do you know, but Dan Weinand came to the rescue. Dan had written a plug-in for rails that "does" fetching of a IMAP server. &lt;br /&gt;&lt;br /&gt;Dan Weinand site: http://www.danweinand.com/ &lt;br /&gt;&lt;br /&gt;In my application, I wanted my "clients" existing email infrastructure which consisted of Exchange 2003 soon to be exchange 2007. Just wanted to fetch a "email" address from the existing server.&lt;br /&gt;&lt;br /&gt;So after asking permision we enable IMAP on exchange. And I pulled in the "fetcher"&lt;br /&gt;into the application. Of course I wanted it to run as a "service" on windows. The original was designed for Linux. So I converted to a windows service. In addition&lt;br /&gt;I found that the "standard" authentications in the fetcher for IMAP needed a "tweak" to do a "login" at the IMAP level, rather than "authorize".&lt;br /&gt;So I added "dumb" authentication to the code.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The imap.rb in vendors/plugins/fetcher/lib needed the two patches&lt;br /&gt;1. Added dumb authentication&lt;br /&gt;2. Fixed the "recovery" so it would not cause a exception on a empty mailbox&lt;br /&gt;&lt;br /&gt;--- imap.rb ---&lt;br /&gt;module Fetcher&lt;br /&gt;  class Imap &lt; Base&lt;br /&gt;    &lt;br /&gt;    protected&lt;br /&gt;    &lt;br /&gt;    # Additional Options:&lt;br /&gt;    # * &lt;tt&gt;:authentication&lt;/tt&gt; - authentication type to use, defaults to DUMB&lt;br /&gt;    def initialize(options={})&lt;br /&gt;      @authentication = options.delete(:authentication) || 'DUMB'&lt;br /&gt;      super(options)&lt;br /&gt;    end&lt;br /&gt;    &lt;br /&gt;    # Open connection and login to server&lt;br /&gt;    def establish_connection&lt;br /&gt;      @connection = Net::IMAP.new(@server)&lt;br /&gt;      if (@authentication == "DUMB")&lt;br /&gt;        @connection.login(@username,@password)&lt;br /&gt;       elsif&lt;br /&gt;      @connection.authenticate(@authentication, @username, @password)&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;    &lt;br /&gt;    # Retrieve messages from server&lt;br /&gt;    def get_messages&lt;br /&gt;      @connection.select('INBOX')&lt;br /&gt;      @connection.search(['ALL']).each do |message_id|&lt;br /&gt;        msg = @connection.fetch(message_id,'RFC822')[0].attr['RFC822']&lt;br /&gt;        begin&lt;br /&gt;          process_message(msg)&lt;br /&gt;        rescue&lt;br /&gt;          # handle_bogus_message(msg)&lt;br /&gt;        end&lt;br /&gt;        # Mark message as deleted &lt;br /&gt;        @connection.store(message_id, "+FLAGS", [:Deleted])&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;    &lt;br /&gt;&lt;br /&gt;The Fetcher is designed with a bit of "meta" programming so it can "submit" the email to the activerecord model. &lt;br /&gt;&lt;br /&gt;-- script/AirFetchservice.rb&lt;br /&gt;require 'rubygems'&lt;br /&gt;require 'win32/service'&lt;br /&gt;require 'logger'&lt;br /&gt;require 'net/imap'&lt;br /&gt;require 'net/pop'&lt;br /&gt;include Win32&lt;br /&gt;&lt;br /&gt;Dir.chdir("\\projects\\ror\\AirCenter")&lt;br /&gt;require File.dirname(__FILE__) + '/../config/environment.rb'   &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SERVICE_NAME = 'AirFetchService'&lt;br /&gt;SERVICE_DISPLAYNAME = 'AirCenterEmailFetcherService'&lt;br /&gt;$logger = Logger.new("c:\\projects\\ror\\AirCenter\\log\\AirFetchService.log")&lt;br /&gt;&lt;br /&gt;class Mailman &lt; ActionMailer::Base&lt;br /&gt;  def receive(email)&lt;br /&gt;    sender = email.from.to_s()&lt;br /&gt;    subject = email.subject.to_s()&lt;br /&gt;    body = email.body.to_s()&lt;br /&gt;    subjectparts = subject.split(/ /)&lt;br /&gt;    classname = subjectparts[0]&lt;br /&gt;    $logger.info("Mailman: Sender = #{sender} Class = #{classname} Subject = #{subject}")&lt;br /&gt;    myclass = Object.const_get(classname)&lt;br /&gt;    if myclass&lt;br /&gt;      myclass.ReceiveEmail(sender,subject,subjectparts,body)&lt;br /&gt;      else $logger.warn("Mailman: Invalid class #{classname}")&lt;br /&gt;     end&lt;br /&gt;  end&lt;br /&gt;end  &lt;br /&gt;&lt;br /&gt;if ARGV[0] == "register"&lt;br /&gt; #Start The Service&lt;br /&gt; svc = Service.new&lt;br /&gt; svc.create_service do |s|&lt;br /&gt;  s.service_name = SERVICE_NAME&lt;br /&gt;  s.display_name = SERVICE_DISPLAYNAME&lt;br /&gt;  s.binary_path_name = "c:\\ruby\\bin\\ruby.exe c:\\projects\\ror\\AirCenter\\script\\AirFetchService.rb"&lt;br /&gt;    # + File.expand_path($0)&lt;br /&gt;  s.dependencies = []&lt;br /&gt;  end&lt;br /&gt; svc.close&lt;br /&gt; puts "Registered Service - " + SERVICE_DISPLAYNAME&lt;br /&gt;elsif ARGV[0] == "test"&lt;br /&gt;     $logger.info "Service Starting"&lt;br /&gt;     $logger.info "Loading EMAIL Config"&lt;br /&gt;     @config = YAML.load_file("#{RAILS_ROOT}/config/mail.yml")&lt;br /&gt;     $logger.info "Setting up config"&lt;br /&gt;     @config = @config[RAILS_ENV].to_options&lt;br /&gt;     $logger.info "Setting up sleep time"&lt;br /&gt;     @sleep_time = @config.delete(:sleep_time) || 60&lt;br /&gt;     $logger.info "Service Init Complete"&lt;br /&gt;     $logger.info "AirFetchService Establish mail processor"&lt;br /&gt;     # Add your own receiver object below&lt;br /&gt;     @fetcher = Fetcher.create({:receiver =&gt; Mailman}.merge(@config))&lt;br /&gt;     @fetcher.fetch&lt;br /&gt;     exit&lt;br /&gt;  elsif ARGV[0] == "delete"&lt;br /&gt;    if Service.status(SERVICE_NAME).current_state == "running"&lt;br /&gt;      Service.stop(SERVICE_NAME)&lt;br /&gt;      end&lt;br /&gt;    Service.delete(SERVICE_NAME)&lt;br /&gt;else &lt;br /&gt;    if ENV["HOMEDRIVE"] !=nil&lt;br /&gt;    puts "Usage: ruby airfetchservice.rb [options]"&lt;br /&gt;    puts "       where options are: register or delete"&lt;br /&gt;    exit&lt;br /&gt;    end &lt;br /&gt;&lt;br /&gt;$stderr = $logger&lt;br /&gt;$stdout = $logger&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;class MyDaemon &lt; Win32::Daemon&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def service_init&lt;br /&gt;  sleep 1&lt;br /&gt;   $logger.info "Service Starting"&lt;br /&gt;   $logger.info "Loading EMAIL Config"&lt;br /&gt;   @config = YAML.load_file("#{RAILS_ROOT}/config/mail.yml")&lt;br /&gt;   $logger.info "Setting up config"&lt;br /&gt;   @config = @config[RAILS_ENV].to_options&lt;br /&gt;   $logger.info "Setting up sleep time"&lt;br /&gt;   @sleep_time = @config.delete(:sleep_time) || 60&lt;br /&gt;   $logger.info "Service Init Complete"&lt;br /&gt;   $logger.info "AirFetchService Establish mail processor"&lt;br /&gt;   # Add your own receiver object below&lt;br /&gt;   @fetcher = Fetcher.create({:receiver =&gt; Mailman.receive}.merge(@config))&lt;br /&gt;  &lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def service_stop&lt;br /&gt;    $logger.info "AirFetchService Stopped"&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def service_main&lt;br /&gt;  $logger.info "AirFetchService: Service in Running State"&lt;br /&gt;    while state == RUNNING&lt;br /&gt;      @fetcher.fetch&lt;br /&gt;      sleep(@sleep_time)&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end &lt;br /&gt;&lt;br /&gt; d = MyDaemon.new&lt;br /&gt; d.mainloop &lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;end&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-6768810304427629618?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://railspikes.com/tags/imap' title='Getting Email from Exchange Into Rails'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/6768810304427629618/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=6768810304427629618' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/6768810304427629618'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/6768810304427629618'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2007/09/getting-email-from-exchange-into-rails.html' title='Getting Email from Exchange Into Rails'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-1974670951535096562</id><published>2007-09-28T20:07:00.000-07:00</published><updated>2007-09-28T20:18:13.129-07:00</updated><title type='text'>My Life On Rails</title><content type='html'>I've been looking for a "idea" environment to do "applications".&lt;br /&gt;I used to do alot of VB6, and felt that Microsoft "messed" things up&lt;br /&gt;after that. My apps didnt move, and my mind was even less willing to&lt;br /&gt;face the "explosion" of technology and "false" starts that Microsoft&lt;br /&gt;offered in the way of programming.&lt;br /&gt;&lt;br /&gt;My background covers C,assembler,Cobol,VB, PL1 and a variety of others.&lt;br /&gt;I found Python about a year and a half ago, and did lots of small backend&lt;br /&gt;projects with it for "backend" processes. Everything from colecting router&lt;br /&gt;logs to database conversion, and realtime "interconnect" between legacy &lt;br /&gt;applications. Python could not be beat. My problem was doing a "gui". The&lt;br /&gt;gui must connect to a "database" and our database of choice is Oracle. In addition it should connect to a variety of others. As well as have libraries for everything else.&lt;br /&gt;&lt;br /&gt;Enter "Stage-left" ruby and its framework ruby-on-rails.&lt;br /&gt;&lt;br /&gt;Now I can develop a variety of applications with lovely "web" based gui in no time flat. &lt;br /&gt;&lt;br /&gt;My technology stack:&lt;br /&gt;             active-scaffold &lt;br /&gt;                   This take care of all the java-script for me. :)&lt;br /&gt;             tabnav/widgets&lt;br /&gt;             ruby-on-rails&lt;br /&gt;                   activerecord - Manages the database&lt;br /&gt;                   activemailer - Handles outgoing and incoming mail&lt;br /&gt;             ruby&lt;br /&gt;            &lt;br /&gt;Supporting cast:&lt;br /&gt;             Oracle (10g, Oracle XE)&lt;br /&gt;             win32-service - Lets me make my background rails functions run&lt;br /&gt;                             as windows services&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-1974670951535096562?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/1974670951535096562/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=1974670951535096562' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/1974670951535096562'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/1974670951535096562'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2007/09/my-life-on-rails.html' title='My Life On Rails'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-8836922270338642540</id><published>2007-08-12T23:25:00.000-07:00</published><updated>2007-08-12T23:34:58.798-07:00</updated><title type='text'>Malaria Killer</title><content type='html'>Hmm. Here's a interesting weekend project. (Wish I had time, but got two others ahead of this one).&lt;br /&gt;&lt;br /&gt;Use one of the NEW high performance IR(Infrared LEDS) they now can handle 1-2 watts sustained, maybe more in flash mode. Use a "microcontroller", such as a Cypress PSOC to do a "simulation" of human breething using the IR LED. Using the PSOC capacitive sensing detect with a Mosquito has "entered" the kill zone, and then bump up the power to max power (Can add a few LEDS to increase the "flash" to 100watts) to &lt;br /&gt;"fry" the insect, then return to "breathing" mode. &lt;br /&gt;&lt;br /&gt;This should reduce the population of mosquitos very nicely and reduce the chance of malaria and other mosquito born infections.&lt;br /&gt;&lt;br /&gt;I know mosquitos are "drawn" to CO2 and IR, the question is a "IR" simulation of breathing may be enough to get them going. The other question is the kill ration.&lt;br /&gt;Its a simple and inexpensive design. Considering the "breathing" can be realtive low level and kill is "pulse" mode, you may even be able to solar power it. &lt;br /&gt;&lt;br /&gt;If your a mosquito researcher, drop me a line.&lt;br /&gt;&lt;br /&gt;References:&lt;br /&gt;LED Example - Hmm What Frequency will have best effect?&lt;br /&gt;http://catalog.osram-os.com/catalogue/catalogue.do?favOid=000000030002856201230023&amp;act=showBookmark&lt;br /&gt;&lt;br /&gt;Processor with Cap Sense&lt;br /&gt;http://www.cypress.com/portal/server.pt?space=CommunityPage&amp;control=SetCommunity&amp;CommunityID=209&amp;PageID=215&amp;gid=13&amp;fid=24&amp;category=All&amp;showall=false&amp;CID=ILC-shortlinks&amp;shk=psoc&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-8836922270338642540?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/8836922270338642540/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=8836922270338642540' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/8836922270338642540'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/8836922270338642540'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2007/08/malaria-killer.html' title='Malaria Killer'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-114240240520335019</id><published>2006-03-14T19:44:00.000-08:00</published><updated>2006-03-14T22:00:05.233-08:00</updated><title type='text'>New "Water" Economy</title><content type='html'>Everyone is talking about the new "Hydrogen" Economy, and what changes is will make.&lt;br /&gt;In reality this is a misnomer, its actually the new "Water" economy. When you burn "hydrogen" and when I say burn that applies to "fuel" cells, or just converting a internal combustion engine (read "Car" engine) to burn hydrogen you get water. The flip side is to get hydrogen the best source is water. &lt;br /&gt;&lt;br /&gt;There are several ways of doing this, "electrolysis" being the first that comes to mind, but the far better is algae. Electrolysis is sticking "two" wires, (Actually electrodes) in water and separating the two. Here, unless you want to build lots of new Nuclear plants, is rather costly. (And even if you are into pebble bed n-plants, its still not cheap, just cheaper than tradional plants). The far better approach, where rather progress is algae. There is already algae that does this on a small scale, and with genetic engineering, its gotten about 100,000 times better already. Another 100x improvement will make it "production" ready.&lt;br /&gt;&lt;br /&gt;So projecting the future, you will have "algae" farms producing hydrogen, at affordable rates.&lt;br /&gt;&lt;br /&gt;So what is needed, and how do we get there.&lt;br /&gt;&lt;br /&gt;Things that are needed:&lt;br /&gt;&lt;br /&gt;1. Water - Its our raw material, high-quality, pure in large amounts &lt;br /&gt;   Solution - Think desalination or better yet "membranes", check out http://www.hyflux.com While there are others, these guys are smaller in size and hungry. Idea "site" is near a ocean if possible&lt;br /&gt;&lt;br /&gt;2. Land - Lots and lots of it. Hmm. It would be handy and generally favorable to use deserts for this. The middle-east has plenty, as well as dont mind a large scale investment to make things happen. Of course that means the oil-producing nations have three of the things needed to do this, land, water, and lots of sunshine.&lt;br /&gt;&lt;br /&gt;3. Investment - Need to start looking at "all" the needs now, building pilot plants, building "foundation" for the whole eco-system&lt;br /&gt;&lt;br /&gt;4. Farming "System" - A system of encapsulating the algae, circulating, and growing them on huge scale with exposure to sunshine. This is the "hardware" of the whole system. Since we are looking at desert locale, doing this in safety glass may be idea. A "plant" producing the panels is one of the pieces of infrastrucutor that is needed. The control software, prodcess monitoring, etc also need to be developed. All of this is "sellable" to all other parties wanting to do the farming.&lt;br /&gt;&lt;br /&gt;5. Storage/Transport - Lots of work has been done on the foundation of "storage" of hydrogen, further applications need to be developed. ie. containers ("Think the standard size container used in the "container" industry), do user replaceble fuel modules, to large scale tankers. A plan needs to be done to address all the products for the ecosystem.&lt;br /&gt;&lt;br /&gt;6. Algae - Lots of groups are already doing this, operational knowledge and license needs to be built. This will allow the customization of #4 to increase production. Not that generally the algae can be changed and readly updated to allow the farm production to increase over time. So you build a "plant" that covers 100 square miles, and every year you will get better production as you improve the algae.&lt;br /&gt;&lt;br /&gt;Hydrogen can be safely transported today, but we have to start on the products that will make it useful everywhere. Corporate, utilities and the public are interested in "clean" energy today. Large scale hydogen production can start, its just a matter of "doing" now, and making it happen.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-114240240520335019?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/114240240520335019/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=114240240520335019' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/114240240520335019'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/114240240520335019'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2006/03/new-water-economy.html' title='New &quot;Water&quot; Economy'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-113627316006468045</id><published>2006-01-02T23:18:00.000-08:00</published><updated>2006-01-02T23:26:00.076-08:00</updated><title type='text'>Python - Microsoft Excel And Telnet = MRTG</title><content type='html'>Hmm. Got a unreliable T1 line in one of my sites, so I wanted to monitor it. Of course I could use MRTG, but then I want to run it on windows xp machine. (And yes I know I can do that with MRTG as well)&lt;br /&gt;&lt;br /&gt;Ok, lets use Excel for our data repository, and formating. For gatering the data, lets use telnet. (Yes, I know I could also use ssh, but the router is a old one) And python to put it all togeather. &lt;br /&gt;&lt;br /&gt;This "example" uses .split as the basis of parsing the telnet output, and updates a excel spreadsheet with the results. The spreadsheet is saved. The "whole" script is run once a hour to collect the data. For simplicity, I use the microsoft task scheduler.&lt;br /&gt;&lt;br /&gt;Of course, this can easily be expanded to support multiple routers and multiple serial interfaces. &lt;br /&gt;&lt;br /&gt;If anyone wants to "see" the final spreadsheet, drop me a email.&lt;br /&gt;&lt;br /&gt;## check-the-line.py&lt;br /&gt;port sys&lt;br /&gt;import telnetlib&lt;br /&gt;from win32com.client import Dispatch&lt;br /&gt;import pywintypes&lt;br /&gt;import datetime&lt;br /&gt;import time&lt;br /&gt;import pythoncom&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;prevupdate = 6&lt;br /&gt;lastupdate = 5&lt;br /&gt;deltaslot = 7&lt;br /&gt;&lt;br /&gt;tn = telnetlib.Telnet("1.2.3.4") # Change your ip address&lt;br /&gt;&lt;br /&gt;tn.read_until("Password: ")&lt;br /&gt;tn.write("your.password.here.for.telnet\n")&lt;br /&gt;tn.read_until("&gt;")&lt;br /&gt;tn.write("show interface serial 0\n")  # The interface&lt;br /&gt;router_status = tn.read_until("&gt;")&lt;br /&gt;tn.write("exit\n")&lt;br /&gt;&lt;br /&gt;thelines = router_status.split("\n")&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;for theline in thelines:&lt;br /&gt;    thelen = len(theline) - 1&lt;br /&gt;    theline = theline[:thelen]&lt;br /&gt;  &lt;br /&gt;recvcnt = thelines[16].split()&lt;br /&gt;recverr = thelines[17].split()&lt;br /&gt;sentcnt = thelines[18].split()&lt;br /&gt;senterr = thelines[19].split()&lt;br /&gt;&lt;br /&gt;x1 = Dispatch("Excel.Application")&lt;br /&gt;x1.Visible = 0&lt;br /&gt;x1.Workbooks.Open("mn-line.xls")&lt;br /&gt;&lt;br /&gt;myc = x1.ActiveSheet.Cells&lt;br /&gt;&lt;br /&gt;#     Received 11045 broadcasts, 0 runts, 0 giants, 0 throttles&lt;br /&gt;#     3 input errors, 3 CRC, 0 frame, 0 overrun, 0 ignored, 3 abort&lt;br /&gt;#     332207 packets output, 54998720 bytes, 0 underruns&lt;br /&gt;#     0 output errors, 0 collisions, 15 interface resets&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;now = datetime.datetime.now()&lt;br /&gt;&lt;br /&gt;#save the old&lt;br /&gt;for thecol in range(1,18):&lt;br /&gt;    myc(prevupdate,thecol).Value = myc(lastupdate,thecol).Value&lt;br /&gt;&lt;br /&gt;myc(lastupdate,1).Value = pythoncom.MakeTime(time.time())&lt;br /&gt;&lt;br /&gt;#recvcnt&lt;br /&gt;myc(lastupdate,2).Value = recvcnt[1]&lt;br /&gt;myc(lastupdate,3).Value = recvcnt[3]&lt;br /&gt;myc(lastupdate,4).Value = recvcnt[5]&lt;br /&gt;myc(lastupdate,5).Value = recvcnt[7]&lt;br /&gt;#recverr&lt;br /&gt;myc(lastupdate,6).Value = recverr[0]&lt;br /&gt;myc(lastupdate,7).Value = recverr[3]&lt;br /&gt;myc(lastupdate,8).Value = recverr[5]&lt;br /&gt;myc(lastupdate,9).Value = recverr[7]&lt;br /&gt;myc(lastupdate,10).Value = recverr[9]&lt;br /&gt;myc(lastupdate,11).Value = recverr[11]&lt;br /&gt;#sentcnt&lt;br /&gt;myc(lastupdate,12).Value = sentcnt[0]&lt;br /&gt;myc(lastupdate,13).Value = sentcnt[3]&lt;br /&gt;myc(lastupdate,14).Value = sentcnt[5]&lt;br /&gt;myc(lastupdate,15).Value = senterr[0]&lt;br /&gt;myc(lastupdate,16).Value = senterr[3]&lt;br /&gt;myc(lastupdate,17).Value = senterr[5]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#put the deltas in the hour slot&lt;br /&gt;thehour = now.hour&lt;br /&gt;hourslot = 10 + thehour&lt;br /&gt;for thecol in range(2,18):&lt;br /&gt;    myc(hourslot,thecol).Value = myc(deltaslot,thecol).Value&lt;br /&gt;myc(hourslot,1).Value = myc(lastupdate,1).Value&lt;br /&gt;&lt;br /&gt;x1.ActiveWorkbook.Save()&lt;br /&gt;if thehour == 23: # Witching hour - Save a copy for reference&lt;br /&gt;    filename = "ml-line-" + now.strftime("%y-%m-%d")&lt;br /&gt;    x1.ActiveWorkbook.SaveAs(filename)&lt;br /&gt;&lt;br /&gt;if thehour == 0: # Reset the Spreadsheet Date&lt;br /&gt;    myc(1,2).Value = myc(lastupdate,1).Value&lt;br /&gt;                             &lt;br /&gt;x1.ActiveWorkbook.Close(0) &lt;br /&gt;x1.Quit()&lt;br /&gt;del x1&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-113627316006468045?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/113627316006468045/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=113627316006468045' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/113627316006468045'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/113627316006468045'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2006/01/python-microsoft-excel-and-telnet-mrtg.html' title='Python - Microsoft Excel And Telnet = MRTG'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-113221574070285594</id><published>2005-11-17T00:17:00.000-08:00</published><updated>2005-11-17T00:22:20.716-08:00</updated><title type='text'>PIX Wars - CISCO Pix Bug</title><content type='html'>Unrelated Comment: If your going to leave me a comment, and want a answer, please add your email address. The normal form does not give me the address.&lt;br /&gt;&lt;br /&gt;In helping out a friend of mine, I was debugging a CISCO firewall. Of course the normal thing in the process is to setup a SYSLOG server to capture the bulk of what is going on. CISCO now recommends the TCP syslog. Well, of course prefer to follow there recomendation, so I set it up. Used there Windows Based SysLog server. Of course when I rebooted I didnt notice the logger process did not restart. Now my firewall was not taking any new connections. &lt;br /&gt;&lt;br /&gt;"What did I do?" was what I was thinking. Check every setting, and come to fine out&lt;br /&gt;there is a bug, if the destination is not available, it keeps spawning logging connections till all available connections are used up. After switching to UDP based logging, everything is fine. &lt;br /&gt;&lt;br /&gt;Comming soon, Python scripts to automatically parse PIX logs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-113221574070285594?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/113221574070285594/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=113221574070285594' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/113221574070285594'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/113221574070285594'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2005/11/pix-wars-cisco-pix-bug.html' title='PIX Wars - CISCO Pix Bug'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10247947.post-113031677886809049</id><published>2005-10-26T01:43:00.000-07:00</published><updated>2005-10-26T01:54:23.916-07:00</updated><title type='text'>Thermal Radiance - A way to cool your PC using Quantum Mechanics</title><content type='html'>Your PC has lots of "glow", that really increases the bling factor, but does nothing to keep it actually cooler. There may be a way to "convert" the heat to light, giving that "nice" glow, while actually helping with the cooling.&lt;br /&gt;&lt;br /&gt;In a recent invention, "Quantum" dots, which have 25 +/- electrons per dot, converted a blue LED, into a "white" led. No big deal to most people, but the physics of it, opens up several possibilities.&lt;br /&gt;&lt;br /&gt;The first is a modification of your heat-sink, with tuning of the Quantum Dots to allow the conversion of heat to light. Since the light will stream nicely out of the case, it allows another way of getting heat out of the case quicker. &lt;br /&gt;&lt;br /&gt;The technique should be relatively low-cost, and massed produced. &lt;br /&gt;&lt;br /&gt;Note that another technique is to excite the quantum dots with electrical standing waves. (Think tesla coil). This should allow the production of large amounts of light, at high efficiently.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/10247947-113031677886809049?l=mentalpagingspace.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.livescience.com/technology/051021_nano_light.html' title='Thermal Radiance - A way to cool your PC using Quantum Mechanics'/><link rel='replies' type='application/atom+xml' href='http://mentalpagingspace.blogspot.com/feeds/113031677886809049/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=10247947&amp;postID=113031677886809049' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/113031677886809049'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10247947/posts/default/113031677886809049'/><link rel='alternate' type='text/html' href='http://mentalpagingspace.blogspot.com/2005/10/thermal-radiance-way-to-cool-your-pc.html' title='Thermal Radiance - A way to cool your PC using Quantum Mechanics'/><author><name>Glenn West</name><uri>http://www.blogger.com/profile/13871653110682325004</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/__O7-qQKRRFU/SK0WCKzeltI/AAAAAAAAAAQ/ySN1Pcg3PhA/S220/Glenn+Passport+Photo+-+Crop.JPG'/></author><thr:total>2</thr:total></entry></feed>
